Skip to content

Commit

Permalink
Reduce Pointer parsing/copying to single allocation
Browse files Browse the repository at this point in the history
  • Loading branch information
miloyip committed May 11, 2015
1 parent 0edd743 commit 7eb117a
Showing 1 changed file with 20 additions and 23 deletions.
43 changes: 20 additions & 23 deletions include/rapidjson/pointer.h
Original file line number Diff line number Diff line change
Expand Up @@ -161,21 +161,17 @@ class GenericPointer {

//! Destructor.
~GenericPointer() {
if (nameBuffer_) { // If user-supplied tokens constructor is used, nameBuffer_ is nullptr and tokens_ are not deallocated.
Allocator::Free(nameBuffer_);
if (nameBuffer_) // If user-supplied tokens constructor is used, nameBuffer_ is nullptr and tokens_ are not deallocated.
Allocator::Free(tokens_);
}
RAPIDJSON_DELETE(ownAllocator_);
}

//! Assignment operator.
GenericPointer& operator=(const GenericPointer& rhs) {
if (this != &rhs) {
// Do not delete ownAllcator
if (nameBuffer_) {
Allocator::Free(nameBuffer_);
if (nameBuffer_)
Allocator::Free(tokens_);
}

tokenCount_ = rhs.tokenCount_;
parseErrorOffset_ = rhs.parseErrorOffset_;
Expand Down Expand Up @@ -735,12 +731,12 @@ class GenericPointer {
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 + extraNameBufferSize) * sizeof(Ch));
std::memcpy(nameBuffer_, rhs.nameBuffer_, nameBufferSize * sizeof(Ch));

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(nameBuffer_, rhs.nameBuffer_, nameBufferSize * sizeof(Ch));

// Adjust pointers to name buffer
std::ptrdiff_t diff = nameBuffer_ - rhs.nameBuffer_;
Expand Down Expand Up @@ -774,11 +770,14 @@ class GenericPointer {
if (!allocator_)
ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator());

// Create a buffer as same size of source
nameBuffer_ = (Ch*)allocator_->Malloc(length * sizeof(Ch));
tokens_ = (Token*)allocator_->Malloc(length * sizeof(Token)); // Maximum possible tokens in the source
// Count number of '/' as tokenCount
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;

// Detect if it is a URI fragment
Expand All @@ -797,8 +796,7 @@ class GenericPointer {
RAPIDJSON_ASSERT(source[i] == '/');
i++; // consumes '/'

Token& token = tokens_[tokenCount_++];
token.name = name;
token->name = name;
bool isNumber = true;

while (i < length && source[i] != '/') {
Expand Down Expand Up @@ -856,20 +854,20 @@ class GenericPointer {

*name++ = c;
}
token.length = name - token.name;
if (token.length == 0)
token->length = name - token->name;
if (token->length == 0)
isNumber = false;
*name++ = '\0'; // Null terminator

// 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;

// String to SizeType conversion
SizeType n = 0;
if (isNumber) {
for (size_t j = 0; j < token.length; j++) {
SizeType m = n * 10 + static_cast<SizeType>(token.name[j] - '0');
for (size_t j = 0; j < token->length; j++) {
SizeType m = n * 10 + static_cast<SizeType>(token->name[j] - '0');
if (m < n) { // overflow detection
isNumber = false;
break;
Expand All @@ -878,16 +876,15 @@ class GenericPointer {
}
}

token.index = isNumber ? n : kPointerInvalidIndex;
token->index = isNumber ? n : kPointerInvalidIndex;
token++;
}

RAPIDJSON_ASSERT(name <= nameBuffer_ + length); // Should not overflow buffer
tokens_ = (Token*)allocator_->Realloc(tokens_, length * sizeof(Token), tokenCount_ * sizeof(Token)); // Shrink tokens_
parseErrorCode_ = kPointerParseErrorNone;
return;

error:
Allocator::Free(nameBuffer_);
Allocator::Free(tokens_);
nameBuffer_ = 0;
tokens_ = 0;
Expand Down

0 comments on commit 7eb117a

Please sign in to comment.