Commit 7eb117a2 authored by miloyip's avatar miloyip

Reduce Pointer parsing/copying to single allocation

parent 0edd743c
...@@ -161,10 +161,8 @@ public: ...@@ -161,10 +161,8 @@ public:
//! Destructor. //! Destructor.
~GenericPointer() { ~GenericPointer() {
if (nameBuffer_) { // If user-supplied tokens constructor is used, nameBuffer_ is nullptr and tokens_ are not deallocated. if (nameBuffer_) // If user-supplied tokens constructor is used, nameBuffer_ is nullptr and tokens_ are not deallocated.
Allocator::Free(nameBuffer_);
Allocator::Free(tokens_); Allocator::Free(tokens_);
}
RAPIDJSON_DELETE(ownAllocator_); RAPIDJSON_DELETE(ownAllocator_);
} }
...@@ -172,10 +170,8 @@ public: ...@@ -172,10 +170,8 @@ public:
GenericPointer& operator=(const GenericPointer& rhs) { GenericPointer& operator=(const GenericPointer& rhs) {
if (this != &rhs) { if (this != &rhs) {
// Do not delete ownAllcator // Do not delete ownAllcator
if (nameBuffer_) { if (nameBuffer_)
Allocator::Free(nameBuffer_);
Allocator::Free(tokens_); Allocator::Free(tokens_);
}
tokenCount_ = rhs.tokenCount_; tokenCount_ = rhs.tokenCount_;
parseErrorOffset_ = rhs.parseErrorOffset_; parseErrorOffset_ = rhs.parseErrorOffset_;
...@@ -735,12 +731,12 @@ private: ...@@ -735,12 +731,12 @@ private:
size_t nameBufferSize = rhs.tokenCount_; // null terminators for tokens size_t nameBufferSize = rhs.tokenCount_; // null terminators for tokens
for (Token *t = rhs.tokens_; t != rhs.tokens_ + rhs.tokenCount_; ++t) for (Token *t = rhs.tokens_; t != rhs.tokens_ + rhs.tokenCount_; ++t)
nameBufferSize += t->length; nameBufferSize += t->length;
nameBuffer_ = (Ch*)allocator_->Malloc((nameBufferSize + extraNameBufferSize) * sizeof(Ch));
std::memcpy(nameBuffer_, rhs.nameBuffer_, nameBufferSize * sizeof(Ch));
tokenCount_ = rhs.tokenCount_ + extraToken; tokenCount_ = rhs.tokenCount_ + extraToken;
tokens_ = (Token*)allocator_->Malloc(tokenCount_ * sizeof(Token)); tokens_ = static_cast<Token *>(allocator_->Malloc(tokenCount_ * sizeof(Token) + (nameBufferSize + extraNameBufferSize) * sizeof(Ch)));
nameBuffer_ = reinterpret_cast<Ch *>(tokens_ + tokenCount_);
std::memcpy(tokens_, rhs.tokens_, rhs.tokenCount_ * sizeof(Token)); std::memcpy(tokens_, rhs.tokens_, rhs.tokenCount_ * sizeof(Token));
std::memcpy(nameBuffer_, rhs.nameBuffer_, nameBufferSize * sizeof(Ch));
// Adjust pointers to name buffer // Adjust pointers to name buffer
std::ptrdiff_t diff = nameBuffer_ - rhs.nameBuffer_; std::ptrdiff_t diff = nameBuffer_ - rhs.nameBuffer_;
...@@ -774,11 +770,14 @@ private: ...@@ -774,11 +770,14 @@ private:
if (!allocator_) if (!allocator_)
ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator()); ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator());
// Create a buffer as same size of source // Count number of '/' as tokenCount
nameBuffer_ = (Ch*)allocator_->Malloc(length * sizeof(Ch));
tokens_ = (Token*)allocator_->Malloc(length * sizeof(Token)); // Maximum possible tokens in the source
tokenCount_ = 0; tokenCount_ = 0;
Ch* name = nameBuffer_; for (const Ch* s = source; s != source + length; s++)
if (*s == '/')
tokenCount_++;
Token* token = tokens_ = static_cast<Token *>(allocator_->Malloc(tokenCount_ * sizeof(Token) + length * sizeof(Ch)));
Ch* name = nameBuffer_ = reinterpret_cast<Ch *>(tokens_ + tokenCount_);
size_t i = 0; size_t i = 0;
// Detect if it is a URI fragment // Detect if it is a URI fragment
...@@ -797,8 +796,7 @@ private: ...@@ -797,8 +796,7 @@ private:
RAPIDJSON_ASSERT(source[i] == '/'); RAPIDJSON_ASSERT(source[i] == '/');
i++; // consumes '/' i++; // consumes '/'
Token& token = tokens_[tokenCount_++]; token->name = name;
token.name = name;
bool isNumber = true; bool isNumber = true;
while (i < length && source[i] != '/') { while (i < length && source[i] != '/') {
...@@ -856,20 +854,20 @@ private: ...@@ -856,20 +854,20 @@ private:
*name++ = c; *name++ = c;
} }
token.length = name - token.name; token->length = name - token->name;
if (token.length == 0) if (token->length == 0)
isNumber = false; 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
if (isNumber && token.length > 1 && token.name[0] == '0') if (isNumber && token->length > 1 && token->name[0] == '0')
isNumber = false; isNumber = false;
// String to SizeType conversion // String to SizeType conversion
SizeType n = 0; SizeType n = 0;
if (isNumber) { if (isNumber) {
for (size_t j = 0; j < token.length; j++) { for (size_t j = 0; j < token->length; j++) {
SizeType m = n * 10 + static_cast<SizeType>(token.name[j] - '0'); SizeType m = n * 10 + static_cast<SizeType>(token->name[j] - '0');
if (m < n) { // overflow detection if (m < n) { // overflow detection
isNumber = false; isNumber = false;
break; break;
...@@ -878,16 +876,15 @@ private: ...@@ -878,16 +876,15 @@ private:
} }
} }
token.index = isNumber ? n : kPointerInvalidIndex; token->index = isNumber ? n : kPointerInvalidIndex;
token++;
} }
RAPIDJSON_ASSERT(name <= nameBuffer_ + length); // Should not overflow buffer RAPIDJSON_ASSERT(name <= nameBuffer_ + length); // Should not overflow buffer
tokens_ = (Token*)allocator_->Realloc(tokens_, length * sizeof(Token), tokenCount_ * sizeof(Token)); // Shrink tokens_
parseErrorCode_ = kPointerParseErrorNone; parseErrorCode_ = kPointerParseErrorNone;
return; return;
error: error:
Allocator::Free(nameBuffer_);
Allocator::Free(tokens_); Allocator::Free(tokens_);
nameBuffer_ = 0; nameBuffer_ = 0;
tokens_ = 0; tokens_ = 0;
......
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