Skip to content

Commit

Permalink
Merge pull request #80 from miloyip/issue31optimizeitoa
Browse files Browse the repository at this point in the history
Issue31optimizeitoa
  • Loading branch information
miloyip committed Jul 27, 2014
2 parents a7dca0d + 6f16461 commit c4ce48c
Show file tree
Hide file tree
Showing 9 changed files with 28,280 additions and 33 deletions.
280 changes: 280 additions & 0 deletions include/rapidjson/internal/itoa.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,280 @@
#ifndef RAPIDJSON_ITOA_
#define RAPIDJSON_ITOA_

namespace rapidjson {
namespace internal {

// Modified from https://github.com/miloyip/itoa-benchmark/blob/master/src/branchlut.cpp
// API is changed to return the character passed the end of string, without writing '\0'

inline const char* GetDigitsLut() {
static const char cDigitsLut[200] = {
'0','0','0','1','0','2','0','3','0','4','0','5','0','6','0','7','0','8','0','9',
'1','0','1','1','1','2','1','3','1','4','1','5','1','6','1','7','1','8','1','9',
'2','0','2','1','2','2','2','3','2','4','2','5','2','6','2','7','2','8','2','9',
'3','0','3','1','3','2','3','3','3','4','3','5','3','6','3','7','3','8','3','9',
'4','0','4','1','4','2','4','3','4','4','4','5','4','6','4','7','4','8','4','9',
'5','0','5','1','5','2','5','3','5','4','5','5','5','6','5','7','5','8','5','9',
'6','0','6','1','6','2','6','3','6','4','6','5','6','6','6','7','6','8','6','9',
'7','0','7','1','7','2','7','3','7','4','7','5','7','6','7','7','7','8','7','9',
'8','0','8','1','8','2','8','3','8','4','8','5','8','6','8','7','8','8','8','9',
'9','0','9','1','9','2','9','3','9','4','9','5','9','6','9','7','9','8','9','9'
};
return cDigitsLut;
}

inline char* u32toa(uint32_t value, char* buffer) {
const char* cDigitsLut = GetDigitsLut();

if (value < 10000) {
const uint32_t d1 = (value / 100) << 1;
const uint32_t d2 = (value % 100) << 1;

if (value >= 1000)
*buffer++ = cDigitsLut[d1];
if (value >= 100)
*buffer++ = cDigitsLut[d1 + 1];
if (value >= 10)
*buffer++ = cDigitsLut[d2];
*buffer++ = cDigitsLut[d2 + 1];
}
else if (value < 100000000) {
// value = bbbbcccc
const uint32_t b = value / 10000;
const uint32_t c = value % 10000;

const uint32_t d1 = (b / 100) << 1;
const uint32_t d2 = (b % 100) << 1;

const uint32_t d3 = (c / 100) << 1;
const uint32_t d4 = (c % 100) << 1;

if (value >= 10000000)
*buffer++ = cDigitsLut[d1];
if (value >= 1000000)
*buffer++ = cDigitsLut[d1 + 1];
if (value >= 100000)
*buffer++ = cDigitsLut[d2];
*buffer++ = cDigitsLut[d2 + 1];

*buffer++ = cDigitsLut[d3];
*buffer++ = cDigitsLut[d3 + 1];
*buffer++ = cDigitsLut[d4];
*buffer++ = cDigitsLut[d4 + 1];
}
else {
// value = aabbbbcccc in decimal

const uint32_t a = value / 100000000; // 1 to 42
value %= 100000000;

if (a >= 10) {
const unsigned i = a << 1;
*buffer++ = cDigitsLut[i];
*buffer++ = cDigitsLut[i + 1];
}
else
*buffer++ = '0' + static_cast<char>(a);

const uint32_t b = value / 10000; // 0 to 9999
const uint32_t c = value % 10000; // 0 to 9999

const uint32_t d1 = (b / 100) << 1;
const uint32_t d2 = (b % 100) << 1;

const uint32_t d3 = (c / 100) << 1;
const uint32_t d4 = (c % 100) << 1;

*buffer++ = cDigitsLut[d1];
*buffer++ = cDigitsLut[d1 + 1];
*buffer++ = cDigitsLut[d2];
*buffer++ = cDigitsLut[d2 + 1];
*buffer++ = cDigitsLut[d3];
*buffer++ = cDigitsLut[d3 + 1];
*buffer++ = cDigitsLut[d4];
*buffer++ = cDigitsLut[d4 + 1];
}
return buffer;
}

inline char* i32toa(int32_t value, char* buffer) {
if (value < 0) {
*buffer++ = '-';
value = -value;
}

return u32toa(static_cast<uint32_t>(value), buffer);
}

inline char* u64toa(uint64_t value, char* buffer) {
const char* cDigitsLut = GetDigitsLut();

if (value < 100000000) {
uint32_t v = static_cast<uint32_t>(value);
if (v < 10000) {
const uint32_t d1 = (v / 100) << 1;
const uint32_t d2 = (v % 100) << 1;

if (v >= 1000)
*buffer++ = cDigitsLut[d1];
if (v >= 100)
*buffer++ = cDigitsLut[d1 + 1];
if (v >= 10)
*buffer++ = cDigitsLut[d2];
*buffer++ = cDigitsLut[d2 + 1];
}
else {
// value = bbbbcccc
const uint32_t b = v / 10000;
const uint32_t c = v % 10000;

const uint32_t d1 = (b / 100) << 1;
const uint32_t d2 = (b % 100) << 1;

const uint32_t d3 = (c / 100) << 1;
const uint32_t d4 = (c % 100) << 1;

if (value >= 10000000)
*buffer++ = cDigitsLut[d1];
if (value >= 1000000)
*buffer++ = cDigitsLut[d1 + 1];
if (value >= 100000)
*buffer++ = cDigitsLut[d2];
*buffer++ = cDigitsLut[d2 + 1];

*buffer++ = cDigitsLut[d3];
*buffer++ = cDigitsLut[d3 + 1];
*buffer++ = cDigitsLut[d4];
*buffer++ = cDigitsLut[d4 + 1];
}
}
else if (value < 10000000000000000) {
const uint32_t v0 = static_cast<uint32_t>(value / 100000000);
const uint32_t v1 = static_cast<uint32_t>(value % 100000000);

const uint32_t b0 = v0 / 10000;
const uint32_t c0 = v0 % 10000;

const uint32_t d1 = (b0 / 100) << 1;
const uint32_t d2 = (b0 % 100) << 1;

const uint32_t d3 = (c0 / 100) << 1;
const uint32_t d4 = (c0 % 100) << 1;

const uint32_t b1 = v1 / 10000;
const uint32_t c1 = v1 % 10000;

const uint32_t d5 = (b1 / 100) << 1;
const uint32_t d6 = (b1 % 100) << 1;

const uint32_t d7 = (c1 / 100) << 1;
const uint32_t d8 = (c1 % 100) << 1;

if (value >= 1000000000000000)
*buffer++ = cDigitsLut[d1];
if (value >= 100000000000000)
*buffer++ = cDigitsLut[d1 + 1];
if (value >= 10000000000000)
*buffer++ = cDigitsLut[d2];
if (value >= 1000000000000)
*buffer++ = cDigitsLut[d2 + 1];
if (value >= 100000000000)
*buffer++ = cDigitsLut[d3];
if (value >= 10000000000)
*buffer++ = cDigitsLut[d3 + 1];
if (value >= 1000000000)
*buffer++ = cDigitsLut[d4];
if (value >= 100000000)
*buffer++ = cDigitsLut[d4 + 1];

*buffer++ = cDigitsLut[d5];
*buffer++ = cDigitsLut[d5 + 1];
*buffer++ = cDigitsLut[d6];
*buffer++ = cDigitsLut[d6 + 1];
*buffer++ = cDigitsLut[d7];
*buffer++ = cDigitsLut[d7 + 1];
*buffer++ = cDigitsLut[d8];
*buffer++ = cDigitsLut[d8 + 1];
}
else {
const uint32_t a = static_cast<uint32_t>(value / 10000000000000000); // 1 to 1844
value %= 10000000000000000;

if (a < 10)
*buffer++ = '0' + static_cast<char>(a);
else if (a < 100) {
const uint32_t i = a << 1;
*buffer++ = cDigitsLut[i];
*buffer++ = cDigitsLut[i + 1];
}
else if (a < 1000) {
*buffer++ = '0' + static_cast<char>(a / 100);

const uint32_t i = (a % 100) << 1;
*buffer++ = cDigitsLut[i];
*buffer++ = cDigitsLut[i + 1];
}
else {
const uint32_t i = (a / 100) << 1;
const uint32_t j = (a % 100) << 1;
*buffer++ = cDigitsLut[i];
*buffer++ = cDigitsLut[i + 1];
*buffer++ = cDigitsLut[j];
*buffer++ = cDigitsLut[j + 1];
}

const uint32_t v0 = static_cast<uint32_t>(value / 100000000);
const uint32_t v1 = static_cast<uint32_t>(value % 100000000);

const uint32_t b0 = v0 / 10000;
const uint32_t c0 = v0 % 10000;

const uint32_t d1 = (b0 / 100) << 1;
const uint32_t d2 = (b0 % 100) << 1;

const uint32_t d3 = (c0 / 100) << 1;
const uint32_t d4 = (c0 % 100) << 1;

const uint32_t b1 = v1 / 10000;
const uint32_t c1 = v1 % 10000;

const uint32_t d5 = (b1 / 100) << 1;
const uint32_t d6 = (b1 % 100) << 1;

const uint32_t d7 = (c1 / 100) << 1;
const uint32_t d8 = (c1 % 100) << 1;

*buffer++ = cDigitsLut[d1];
*buffer++ = cDigitsLut[d1 + 1];
*buffer++ = cDigitsLut[d2];
*buffer++ = cDigitsLut[d2 + 1];
*buffer++ = cDigitsLut[d3];
*buffer++ = cDigitsLut[d3 + 1];
*buffer++ = cDigitsLut[d4];
*buffer++ = cDigitsLut[d4 + 1];
*buffer++ = cDigitsLut[d5];
*buffer++ = cDigitsLut[d5 + 1];
*buffer++ = cDigitsLut[d6];
*buffer++ = cDigitsLut[d6 + 1];
*buffer++ = cDigitsLut[d7];
*buffer++ = cDigitsLut[d7 + 1];
*buffer++ = cDigitsLut[d8];
*buffer++ = cDigitsLut[d8 + 1];
}

return buffer;
}

inline char* i64toa(int64_t value, char* buffer) {
if (value < 0) {
*buffer++ = '-';
value = -value;
}

return u64toa(static_cast<uint64_t>(value), buffer);
}

} // namespace internal
} // namespace rapidjson

#endif // RAPIDJSON_ITOA_
38 changes: 37 additions & 1 deletion include/rapidjson/msinttypes/stdint.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,44 @@
#endif

// miloyip: Originally Visual Studio 2010 uses its own stdint.h. However it generates warning with INT64_C(), so change to use this file for vs2010.
#if _MSC_VER >= 1700 // [
#if _MSC_VER >= 1600 // [
#include <stdint.h>

#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260

#undef INT8_C
#undef INT16_C
#undef INT32_C
#undef INT64_C
#undef UINT8_C
#undef UINT16_C
#undef UINT32_C
#undef UINT64_C

// 7.18.4.1 Macros for minimum-width integer constants

#define INT8_C(val) val##i8
#define INT16_C(val) val##i16
#define INT32_C(val) val##i32
#define INT64_C(val) val##i64

#define UINT8_C(val) val##ui8
#define UINT16_C(val) val##ui16
#define UINT32_C(val) val##ui32
#define UINT64_C(val) val##ui64

// 7.18.4.2 Macros for greatest-width integer constants
// These #ifndef's are needed to prevent collisions with <boost/cstdint.hpp>.
// Check out Issue 9 for the details.
#ifndef INTMAX_C // [
# define INTMAX_C INT64_C
#endif // INTMAX_C ]
#ifndef UINTMAX_C // [
# define UINTMAX_C UINT64_C
#endif // UINTMAX_C ]

#endif // __STDC_CONSTANT_MACROS ]

#else // ] _MSC_VER >= 1700 [

#include <limits.h>
Expand Down
8 changes: 6 additions & 2 deletions include/rapidjson/rapidjson.h
Original file line number Diff line number Diff line change
Expand Up @@ -360,10 +360,14 @@ struct GenericInsituStringStream {
size_t Tell() { return static_cast<size_t>(src_ - head_); }

// Write
Ch* PutBegin() { return dst_ = src_; }
void Put(Ch c) { RAPIDJSON_ASSERT(dst_ != 0); *dst_++ = c; }
void Flush() {}

Ch* PutBegin() { return dst_ = src_; }
size_t PutEnd(Ch* begin) { return static_cast<size_t>(dst_ - begin); }
void Flush() {}

Ch* Push(size_t count) { Ch* begin = dst_; dst_ += count; return begin; }
void Pop(size_t count) { dst_ -= count; }

Ch* src_;
Ch* dst_;
Expand Down
2 changes: 2 additions & 0 deletions include/rapidjson/stringbuffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ struct GenericStringBuffer {
void Flush() {}

void Clear() { stack_.Clear(); }
Ch* Push(size_t count) { return stack_.template Push<Ch>(count); }
void Pop(size_t count) { stack_.template Pop<Ch>(count); }

const Ch* GetString() const {
// Push and pop a null terminator. This is safe.
Expand Down
Loading

0 comments on commit c4ce48c

Please sign in to comment.