Home | History | Annotate | Download | only in perftest
      1 // Tencent is pleased to support the open source community by making RapidJSON available.
      2 //
      3 // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
      4 //
      5 // Licensed under the MIT License (the "License"); you may not use this file except
      6 // in compliance with the License. You may obtain a copy of the License at
      7 //
      8 // http://opensource.org/licenses/MIT
      9 //
     10 // Unless required by applicable law or agreed to in writing, software distributed
     11 // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
     12 // CONDITIONS OF ANY KIND, either express or implied. See the License for the
     13 // specific language governing permissions and limitations under the License.
     14 
     15 #include "perftest.h"
     16 
     17 #if TEST_MISC
     18 
     19 #define __STDC_FORMAT_MACROS
     20 #include "rapidjson/stringbuffer.h"
     21 
     22 #define protected public
     23 #include "rapidjson/writer.h"
     24 #undef private
     25 
     26 class Misc : public PerfTest {
     27 };
     28 
     29 // Copyright (c) 2008-2010 Bjoern Hoehrmann <bjoern (at) hoehrmann.de>
     30 // See http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ for details.
     31 
     32 #define UTF8_ACCEPT 0
     33 #define UTF8_REJECT 12
     34 
     35 static const unsigned char utf8d[] = {
     36     // The first part of the table maps bytes to character classes that
     37     // to reduce the size of the transition table and create bitmasks.
     38     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
     39     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
     40     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
     41     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
     42     1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,  9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,
     43     7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,  7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
     44     8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2,  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
     45     10,3,3,3,3,3,3,3,3,3,3,3,3,4,3,3, 11,6,6,6,5,8,8,8,8,8,8,8,8,8,8,8,
     46 
     47     // The second part is a transition table that maps a combination
     48     // of a state of the automaton and a character class to a state.
     49     0,12,24,36,60,96,84,12,12,12,48,72, 12,12,12,12,12,12,12,12,12,12,12,12,
     50     12, 0,12,12,12,12,12, 0,12, 0,12,12, 12,24,12,12,12,12,12,24,12,24,12,12,
     51     12,12,12,12,12,12,12,24,12,12,12,12, 12,24,12,12,12,12,12,12,12,24,12,12,
     52     12,12,12,12,12,12,12,36,12,36,12,12, 12,36,12,12,12,12,12,36,12,36,12,12,
     53     12,36,12,12,12,12,12,12,12,12,12,12,
     54 };
     55 
     56 static unsigned inline decode(unsigned* state, unsigned* codep, unsigned byte) {
     57     unsigned type = utf8d[byte];
     58 
     59     *codep = (*state != UTF8_ACCEPT) ?
     60         (byte & 0x3fu) | (*codep << 6) :
     61     (0xff >> type) & (byte);
     62 
     63     *state = utf8d[256 + *state + type];
     64     return *state;
     65 }
     66 
     67 static bool IsUTF8(unsigned char* s) {
     68     unsigned codepoint, state = 0;
     69 
     70     while (*s)
     71         decode(&state, &codepoint, *s++);
     72 
     73     return state == UTF8_ACCEPT;
     74 }
     75 
     76 TEST_F(Misc, Hoehrmann_IsUTF8) {
     77     for (size_t i = 0; i < kTrialCount; i++) {
     78         EXPECT_TRUE(IsUTF8((unsigned char*)json_));
     79     }
     80 }
     81 
     82 ////////////////////////////////////////////////////////////////////////////////
     83 // CountDecimalDigit: Count number of decimal places
     84 
     85 inline unsigned CountDecimalDigit_naive(unsigned n) {
     86     unsigned count = 1;
     87     while (n >= 10) {
     88         n /= 10;
     89         count++;
     90     }
     91     return count;
     92 }
     93 
     94 inline unsigned CountDecimalDigit_enroll4(unsigned n) {
     95     unsigned count = 1;
     96     while (n >= 10000) {
     97         n /= 10000u;
     98         count += 4;
     99     }
    100     if (n < 10) return count;
    101     if (n < 100) return count + 1;
    102     if (n < 1000) return count + 2;
    103     return count + 3;
    104 }
    105 
    106 inline unsigned CountDecimalDigit64_enroll4(uint64_t n) {
    107     unsigned count = 1;
    108     while (n >= 10000) {
    109         n /= 10000u;
    110         count += 4;
    111     }
    112     if (n < 10) return count;
    113     if (n < 100) return count + 1;
    114     if (n < 1000) return count + 2;
    115     return count + 3;
    116 }
    117 
    118 inline unsigned CountDecimalDigit_fast(unsigned n) {
    119     static const uint32_t powers_of_10[] = {
    120         0,
    121         10,
    122         100,
    123         1000,
    124         10000,
    125         100000,
    126         1000000,
    127         10000000,
    128         100000000,
    129         1000000000
    130     };
    131 
    132 #if defined(_M_IX86) || defined(_M_X64)
    133     unsigned long i = 0;
    134     _BitScanReverse(&i, n | 1);
    135     uint32_t t = (i + 1) * 1233 >> 12;
    136 #elif defined(__GNUC__)
    137     uint32_t t = (32 - __builtin_clz(n | 1)) * 1233 >> 12;
    138 #else
    139 #error
    140 #endif
    141     return t - (n < powers_of_10[t]) + 1;
    142 }
    143 
    144 inline unsigned CountDecimalDigit64_fast(uint64_t n) {
    145     static const uint64_t powers_of_10[] = {
    146         0,
    147         10,
    148         100,
    149         1000,
    150         10000,
    151         100000,
    152         1000000,
    153         10000000,
    154         100000000,
    155         1000000000,
    156         10000000000,
    157         100000000000,
    158         1000000000000,
    159         10000000000000,
    160         100000000000000,
    161         1000000000000000,
    162         10000000000000000,
    163         100000000000000000,
    164         1000000000000000000,
    165         10000000000000000000U
    166     };
    167 
    168 #if defined(_M_IX86)
    169     uint64_t m = n | 1;
    170     unsigned long i = 0;
    171     if (_BitScanReverse(&i, m >> 32))
    172         i += 32;
    173     else
    174         _BitScanReverse(&i, m & 0xFFFFFFFF);
    175     uint32_t t = (i + 1) * 1233 >> 12;
    176 #elif defined(_M_X64)
    177     unsigned long i = 0;
    178     _BitScanReverse64(&i, n | 1);
    179     uint32_t t = (i + 1) * 1233 >> 12;
    180 #elif defined(__GNUC__)
    181     uint32_t t = (64 - __builtin_clzll(n | 1)) * 1233 >> 12;
    182 #else
    183 #error
    184 #endif
    185 
    186     return t - (n < powers_of_10[t]) + 1;
    187 }
    188 
    189 #if 0
    190 // Exhaustive, very slow
    191 TEST_F(Misc, CountDecimalDigit_Verify) {
    192     unsigned i = 0;
    193     do {
    194         if (i % (65536 * 256) == 0)
    195             printf("%u\n", i);
    196         ASSERT_EQ(CountDecimalDigit_enroll4(i), CountDecimalDigit_fast(i));
    197         i++;
    198     } while (i != 0);
    199 }
    200 
    201 static const unsigned kDigits10Trial = 1000000000u;
    202 TEST_F(Misc, CountDecimalDigit_naive) {
    203     unsigned sum = 0;
    204     for (unsigned i = 0; i < kDigits10Trial; i++)
    205         sum += CountDecimalDigit_naive(i);
    206     printf("%u\n", sum);
    207 }
    208 
    209 TEST_F(Misc, CountDecimalDigit_enroll4) {
    210     unsigned sum = 0;
    211     for (unsigned i = 0; i < kDigits10Trial; i++)
    212         sum += CountDecimalDigit_enroll4(i);
    213     printf("%u\n", sum);
    214 }
    215 
    216 TEST_F(Misc, CountDecimalDigit_fast) {
    217     unsigned sum = 0;
    218     for (unsigned i = 0; i < kDigits10Trial; i++)
    219         sum += CountDecimalDigit_fast(i);
    220     printf("%u\n", sum);
    221 }
    222 #endif
    223 
    224 TEST_F(Misc, CountDecimalDigit64_VerifyFast) {
    225     uint64_t i = 1, j;
    226     do {
    227         //printf("%" PRIu64 "\n", i);
    228         ASSERT_EQ(CountDecimalDigit64_enroll4(i), CountDecimalDigit64_fast(i));
    229         j = i;
    230         i *= 3;
    231     } while (j < i);
    232 }
    233 
    234 ////////////////////////////////////////////////////////////////////////////////
    235 // integer-to-string conversion
    236 
    237 // https://gist.github.com/anonymous/7179097
    238 static const int randval[] ={
    239      936116,  369532,  453755,  -72860,  209713,  268347,  435278, -360266, -416287, -182064,
    240     -644712,  944969,  640463, -366588,  471577,  -69401, -744294, -505829,  923883,  831785,
    241     -601136, -636767, -437054,  591718,  100758,  231907, -719038,  973540, -605220,  506659,
    242     -871653,  462533,  764843, -919138,  404305, -630931, -288711, -751454, -173726, -718208,
    243      432689, -281157,  360737,  659827,   19174, -376450,  769984, -858198,  439127,  734703,
    244     -683426,       7,  386135,  186997, -643900, -744422, -604708, -629545,   42313, -933592,
    245     -635566,  182308,  439024, -367219,  -73924, -516649,  421935, -470515,  413507,  -78952,
    246     -427917, -561158,  737176,   94538,  572322,  405217,  709266, -357278, -908099, -425447,
    247      601119,  750712, -862285, -177869,  900102,  384877,  157859, -641680,  503738, -702558,
    248      278225,  463290,  268378, -212840,  580090,  347346, -473985, -950968, -114547, -839893,
    249     -738032, -789424,  409540,  493495,  432099,  119755,  905004, -174834,  338266,  234298,
    250       74641, -965136, -754593,  685273,  466924,  920560,  385062,  796402,  -67229,  994864,
    251      376974,  299869, -647540, -128724,  469890, -163167, -547803, -743363,  486463, -621028,
    252      612288,   27459, -514224,  126342,  -66612,  803409, -777155, -336453, -284002,  472451,
    253      342390, -163630,  908356, -456147, -825607,  268092, -974715,  287227,  227890, -524101,
    254      616370, -782456,  922098, -624001, -813690,  171605, -192962,  796151,  707183,  -95696,
    255      -23163, -721260,  508892,  430715,  791331,  482048, -996102,  863274,  275406,   -8279,
    256     -556239, -902076,  268647, -818565,  260069, -798232, -172924, -566311, -806503, -885992,
    257      813969,  -78468,  956632,  304288,  494867, -508784,  381751,  151264,  762953,   76352,
    258      594902,  375424,  271700, -743062,  390176,  924237,  772574,  676610,  435752, -153847,
    259        3959, -971937, -294181, -538049, -344620, -170136,   19120, -703157,  868152, -657961,
    260     -818631,  219015, -872729, -940001, -956570,  880727, -345910,  942913, -942271, -788115,
    261      225294,  701108, -517736, -416071,  281940,  488730,  942698,  711494,  838382, -892302,
    262     -533028,  103052,  528823,  901515,  949577,  159364,  718227, -241814, -733661, -462928,
    263     -495829,  165170,  513580, -629188, -509571, -459083,  198437,   77198, -644612,  811276,
    264     -422298, -860842,  -52584,  920369,  686424, -530667, -243476,   49763,  345866, -411960,
    265     -114863,  470810, -302860,  683007, -509080,       2, -174981, -772163,  -48697,  447770,
    266     -268246,  213268,  269215,   78810, -236340, -639140, -864323,  505113, -986569, -325215,
    267      541859,  163070, -819998, -645161, -583336,  573414,  696417, -132375,       3, -294501,
    268      320435,  682591,  840008,  351740,  426951,  609354,  898154, -943254,  227321, -859793,
    269     -727993,   44137, -497965, -782239,   14955, -746080, -243366,    9837, -233083,  606507,
    270     -995864, -615287, -994307,  602715,  770771, -315040,  610860,  446102, -307120,  710728,
    271     -590392, -230474, -762625, -637525,  134963, -202700, -766902, -985541,  218163,  682009,
    272      926051,  525156,  -61195,  403211, -810098,  245539, -431733,  179998, -806533,  745943,
    273      447597,  131973, -187130,  826019,  286107, -937230, -577419,   20254,  681802, -340500,
    274      323080,  266283, -667617,  309656,  416386,  611863,  759991, -534257,  523112, -634892,
    275     -169913, -204905, -909867, -882185, -944908,  741811, -717675,  967007, -317396,  407230,
    276     -412805,  792905,  994873,  744793, -456797,  713493,  355232,  116900, -945199,  880539,
    277      342505, -580824, -262273,  982968, -349497, -735488,  311767, -455191,  570918,  389734,
    278     -958386,   10262,  -99267,  155481,  304210,  204724,  704367, -144893, -233664, -671441,
    279      896849,  408613,  762236,  322697,  981321,  688476,   13663, -970704, -379507,  896412,
    280      977084,  348869,  875948,  341348,  318710,  512081,    6163,  669044,  833295,  811883,
    281      708756, -802534, -536057,  608413, -389625, -694603,  541106, -110037,  720322, -540581,
    282      645420,   32980,   62442,  510157, -981870,  -87093, -325960, -500494, -718291,  -67889,
    283      991501,  374804,  769026, -978869,  294747,  714623,  413327, -199164,  671368,  804789,
    284     -362507,  798196, -170790, -568895, -869379,   62020, -316693, -837793,  644994,  -39341,
    285     -417504, -243068, -957756,   99072,  622234, -739992,  225668,    8863, -505910,   82483,
    286     -559244,  241572,    1315,  -36175,  -54990,  376813,     -11,  162647, -688204, -486163,
    287      -54934, -197470,  744223, -762707,  732540,  996618,  351561, -445933, -898491,  486531,
    288      456151,   15276,  290186, -817110,  -52995,  313046, -452533,  -96267,   94470, -500176,
    289     -818026, -398071, -810548, -143325, -819741,    1338, -897676, -101577, -855445,   37309,
    290      285742,  953804, -777927, -926962, -811217, -936744, -952245, -802300, -490188, -964953,
    291     -552279,  329142, -570048, -505756,  682898, -381089,  -14352,  175138,  152390, -582268,
    292     -485137,  717035,  805329,  239572, -730409,  209643, -184403, -385864,  675086,  819648,
    293      629058, -527109, -488666, -171981,  532788,  552441,  174666,  984921,  766514,  758787,
    294      716309,  338801, -978004, -412163,  876079, -734212,  789557, -160491, -522719,   56644,
    295        -991, -286038,  -53983,  663740,  809812,  919889, -717502, -137704,  220511,  184396,
    296     -825740, -588447,  430870,  124309,  135956,  558662, -307087, -788055, -451328,  812260,
    297      931601,  324347, -482989, -117858, -278861,  189068, -172774,  929057,  293787,  198161,
    298     -342386,  -47173,  906555, -759955,  -12779,  777604,  -97869,  899320,  927486,  -25284,
    299     -848550,  259450, -485856,  -17820,      88,  171400,  235492, -326783, -340793,  886886,
    300      112428, -246280,    5979,  648444, -114982,  991013,  -56489,   -9497,  419706,  632820,
    301     -341664,  393926, -848977,  -22538,  257307,  773731, -905319,  491153,  734883, -868212,
    302     -951053,  644458, -580758,  764735,  584316,  297077,   28852, -397710, -953669,  201772,
    303      879050, -198237, -588468,  448102, -116837,  770007, -231812,  642906, -582166, -885828,
    304           9,  305082, -996577,  303559,   75008, -772956, -447960,  599825, -295552,  870739,
    305     -386278, -950300,  485359, -457081,  629461, -850276,  550496, -451755, -620841,  -11766,
    306     -950137,  832337,   28711, -273398, -507197,   91921, -271360, -705991, -753220, -388968,
    307      967945,  340434, -320883, -662793, -554617, -574568,  477946,   -6148, -129519,  689217,
    308      920020, -656315, -974523, -212525,   80921, -612532,  645096,  545655,  655713, -591631,
    309     -307385, -816688, -618823, -113713,  526430,  673063,  735916, -809095, -850417,  639004,
    310      432281, -388185,  270708,  860146,  -39902, -786157, -258180, -246169, -966720, -264957,
    311      548072, -306010,  -57367, -635665,  933824,   70553, -989936, -488741,   72411, -452509,
    312      529831,  956277,  449019, -577850, -360986, -803418,   48833,  296073,  203430,  609591,
    313      715483,  470964,  658106, -718254,  -96424,  790163,  334739,  181070, -373578,       5,
    314     -435088,  329841,  330939, -256602,  394355,  912412,  231910,  927278, -661933,  788539,
    315     -769664, -893274,  -96856,  298205,  901043, -608122, -527430,  183618, -553963,  -35246,
    316     -393924,  948832, -483198,  594501,   35460, -407007,   93494, -336881, -634072,  984205,
    317     -812161,  944664,  -31062,  753872,  823933,  -69566,   50445,  290147,   85134,   34706,
    318      551902,  405202, -991246,  -84642,  154341,  316432, -695101, -651588,   -5030,  137564,
    319     -294665,  332541,  528307,  -90572, -344923,  523766, -758498, -968047,  339028,  494578,
    320      593129, -725773,   31834, -718406, -208638,  159665,   -2043,  673344, -442767,   75816,
    321      755442,  769257, -158730, -410272,  691688,  589550, -878398, -184121,  460679,  346312,
    322      294163, -544602,  653308,  254167, -276979,   52073, -892684,  887653,  -41222,  983065,
    323      -68258, -408799,  -99069, -674069, -863635,  -32890,  622757, -743862,   40872,   -4837,
    324     -967228,  522370, -903951, -818669,  524459,  514702,  925801,   20007, -299229,  579348,
    325      626021,  430089,  348139, -562692, -607728, -130606, -928451, -424793, -458647, -448892,
    326     -312230,  143337,  109746,  880042, -339658, -785614,  938995,  540916,  118429,  661351,
    327     -402967,  404729,  -40918, -976535,  743230,  713110,  440182, -381314, -499252,   74613,
    328      193652,  912717,  491323,  583633,  324691,  459397,  281253,  195540,   -2764, -888651,
    329      892449,  132663, -478373, -430002, -314551,  527826,  247165,  557966,  554778,  481531,
    330     -946634,  431685, -769059, -348371,  174046,  184597, -354867,  584422,  227390, -850397,
    331     -542924, -849093, -737769,  325359,  736314,  269101,  767940,  674809,   81413, -447458,
    332      445076,  189072,  906218,  502688, -718476, -863827, -731381,  100660,  623249,  710008,
    333      572060,  922203,  685740,   55096,  263394, -243695, -353910, -516788,  388471,  455165,
    334      844103, -643772,  363976,  268875, -899450,  104470,  104029, -238874, -274659,  732969,
    335     -676443,  953291, -916289, -861849, -242344,  958083, -479593, -970395,  799831,  277841,
    336     -243236, -283462, -201510,  166263, -259105, -575706,  878926,  891064,  895297,  655262,
    337      -34807, -809833,  -89281,  342585,  554920,       1,  902141, -333425,  139703,  852318,
    338     -618438,  329498, -932596, -692836, -513372,  733656, -523411,   85779,  500478, -682697,
    339     -502836,  138776,  156341, -420037, -557964, -556378,  710993,  -50383, -877159,  916334,
    340      132996,  583516, -603392, -111615,  -12288, -780214,  476780,  123327,  137607,  519956,
    341      745837,   17358, -158581,  -53490
    342 };
    343 static const size_t randvalCount = sizeof(randval) / sizeof(randval[0]);
    344 static const size_t kItoaTrialCount = 10000;
    345 
    346 static const char digits[201] =
    347 "0001020304050607080910111213141516171819"
    348 "2021222324252627282930313233343536373839"
    349 "4041424344454647484950515253545556575859"
    350 "6061626364656667686970717273747576777879"
    351 "8081828384858687888990919293949596979899";
    352 
    353 // Prevent code being optimized out
    354 //#define OUTPUT_LENGTH(length) printf("", length)
    355 #define OUTPUT_LENGTH(length) printf("%u\n", (unsigned)length)
    356 
    357 template<typename OutputStream>
    358 class Writer1 {
    359 public:
    360     Writer1() : os_() {}
    361     Writer1(OutputStream& os) : os_(&os) {}
    362 
    363     void Reset(OutputStream& os) {
    364         os_ = &os;
    365     }
    366 
    367     bool WriteInt(int i) {
    368         if (i < 0) {
    369             os_->Put('-');
    370             i = -i;
    371         }
    372         return WriteUint((unsigned)i);
    373     }
    374 
    375     bool WriteUint(unsigned u) {
    376         char buffer[10];
    377         char *p = buffer;
    378         do {
    379             *p++ = char(u % 10) + '0';
    380             u /= 10;
    381         } while (u > 0);
    382 
    383         do {
    384             --p;
    385             os_->Put(*p);
    386         } while (p != buffer);
    387         return true;
    388     }
    389 
    390     bool WriteInt64(int64_t i64) {
    391         if (i64 < 0) {
    392             os_->Put('-');
    393             i64 = -i64;
    394         }
    395         WriteUint64((uint64_t)i64);
    396         return true;
    397     }
    398 
    399     bool WriteUint64(uint64_t u64) {
    400         char buffer[20];
    401         char *p = buffer;
    402         do {
    403             *p++ = char(u64 % 10) + '0';
    404             u64 /= 10;
    405         } while (u64 > 0);
    406 
    407         do {
    408             --p;
    409             os_->Put(*p);
    410         } while (p != buffer);
    411         return true;
    412     }
    413 
    414 private:
    415     OutputStream* os_;
    416 };
    417 
    418 template<>
    419 bool Writer1<rapidjson::StringBuffer>::WriteUint(unsigned u) {
    420     char buffer[10];
    421     char* p = buffer;
    422     do {
    423         *p++ = char(u % 10) + '0';
    424         u /= 10;
    425     } while (u > 0);
    426 
    427     char* d = os_->Push(p - buffer);
    428     do {
    429         --p;
    430         *d++ = *p;
    431     } while (p != buffer);
    432     return true;
    433 }
    434 
    435 // Using digits LUT to reduce divsion/modulo
    436 template<typename OutputStream>
    437 class Writer2 {
    438 public:
    439     Writer2() : os_() {}
    440     Writer2(OutputStream& os) : os_(&os) {}
    441 
    442     void Reset(OutputStream& os) {
    443         os_ = &os;
    444     }
    445 
    446     bool WriteInt(int i) {
    447         if (i < 0) {
    448             os_->Put('-');
    449             i = -i;
    450         }
    451         return WriteUint((unsigned)i);
    452     }
    453 
    454     bool WriteUint(unsigned u) {
    455         char buffer[10];
    456         char* p = buffer;
    457         while (u >= 100) {
    458             const unsigned i = (u % 100) << 1;
    459             u /= 100;
    460             *p++ = digits[i + 1];
    461             *p++ = digits[i];
    462         }
    463         if (u < 10)
    464             *p++ = char(u) + '0';
    465         else {
    466             const unsigned i = u << 1;
    467             *p++ = digits[i + 1];
    468             *p++ = digits[i];
    469         }
    470 
    471         do {
    472             --p;
    473             os_->Put(*p);
    474         } while (p != buffer);
    475         return true;
    476     }
    477 
    478     bool WriteInt64(int64_t i64) {
    479         if (i64 < 0) {
    480             os_->Put('-');
    481             i64 = -i64;
    482         }
    483         WriteUint64((uint64_t)i64);
    484         return true;
    485     }
    486 
    487     bool WriteUint64(uint64_t u64) {
    488         char buffer[20];
    489         char* p = buffer;
    490         while (u64 >= 100) {
    491             const unsigned i = static_cast<unsigned>(u64 % 100) << 1;
    492             u64 /= 100;
    493             *p++ = digits[i + 1];
    494             *p++ = digits[i];
    495         }
    496         if (u64 < 10)
    497             *p++ = char(u64) + '0';
    498         else {
    499             const unsigned i = static_cast<unsigned>(u64) << 1;
    500             *p++ = digits[i + 1];
    501             *p++ = digits[i];
    502         }
    503 
    504         do {
    505             --p;
    506             os_->Put(*p);
    507         } while (p != buffer);
    508         return true;
    509     }
    510 
    511 private:
    512     OutputStream* os_;
    513 };
    514 
    515 // First pass to count digits
    516 template<typename OutputStream>
    517 class Writer3 {
    518 public:
    519     Writer3() : os_() {}
    520     Writer3(OutputStream& os) : os_(&os) {}
    521 
    522     void Reset(OutputStream& os) {
    523         os_ = &os;
    524     }
    525 
    526     bool WriteInt(int i) {
    527         if (i < 0) {
    528             os_->Put('-');
    529             i = -i;
    530         }
    531         return WriteUint((unsigned)i);
    532     }
    533 
    534     bool WriteUint(unsigned u) {
    535         char buffer[10];
    536         char *p = buffer;
    537         do {
    538             *p++ = char(u % 10) + '0';
    539             u /= 10;
    540         } while (u > 0);
    541 
    542         do {
    543             --p;
    544             os_->Put(*p);
    545         } while (p != buffer);
    546         return true;
    547     }
    548 
    549     bool WriteInt64(int64_t i64) {
    550         if (i64 < 0) {
    551             os_->Put('-');
    552             i64 = -i64;
    553         }
    554         WriteUint64((uint64_t)i64);
    555         return true;
    556     }
    557 
    558     bool WriteUint64(uint64_t u64) {
    559         char buffer[20];
    560         char *p = buffer;
    561         do {
    562             *p++ = char(u64 % 10) + '0';
    563             u64 /= 10;
    564         } while (u64 > 0);
    565 
    566         do {
    567             --p;
    568             os_->Put(*p);
    569         } while (p != buffer);
    570         return true;
    571     }
    572 
    573 private:
    574     void WriteUintReverse(char* d, unsigned u) {
    575         do {
    576             *--d = char(u % 10) + '0';
    577             u /= 10;
    578         } while (u > 0);
    579     }
    580 
    581     void WriteUint64Reverse(char* d, uint64_t u) {
    582         do {
    583             *--d = char(u % 10) + '0';
    584             u /= 10;
    585         } while (u > 0);
    586     }
    587 
    588     OutputStream* os_;
    589 };
    590 
    591 template<>
    592 inline bool Writer3<rapidjson::StringBuffer>::WriteUint(unsigned u) {
    593     unsigned digit = CountDecimalDigit_fast(u);
    594     WriteUintReverse(os_->Push(digit) + digit, u);
    595     return true;
    596 }
    597 
    598 template<>
    599 inline bool Writer3<rapidjson::InsituStringStream>::WriteUint(unsigned u) {
    600     unsigned digit = CountDecimalDigit_fast(u);
    601     WriteUintReverse(os_->Push(digit) + digit, u);
    602     return true;
    603 }
    604 
    605 template<>
    606 inline bool Writer3<rapidjson::StringBuffer>::WriteUint64(uint64_t u) {
    607     unsigned digit = CountDecimalDigit64_fast(u);
    608     WriteUint64Reverse(os_->Push(digit) + digit, u);
    609     return true;
    610 }
    611 
    612 template<>
    613 inline bool Writer3<rapidjson::InsituStringStream>::WriteUint64(uint64_t u) {
    614     unsigned digit = CountDecimalDigit64_fast(u);
    615     WriteUint64Reverse(os_->Push(digit) + digit, u);
    616     return true;
    617 }
    618 
    619 // Using digits LUT to reduce divsion/modulo, two passes
    620 template<typename OutputStream>
    621 class Writer4 {
    622 public:
    623     Writer4() : os_() {}
    624     Writer4(OutputStream& os) : os_(&os) {}
    625 
    626     void Reset(OutputStream& os) {
    627         os_ = &os;
    628     }
    629 
    630     bool WriteInt(int i) {
    631         if (i < 0) {
    632             os_->Put('-');
    633             i = -i;
    634         }
    635         return WriteUint((unsigned)i);
    636     }
    637 
    638     bool WriteUint(unsigned u) {
    639         char buffer[10];
    640         char* p = buffer;
    641         while (u >= 100) {
    642             const unsigned i = (u % 100) << 1;
    643             u /= 100;
    644             *p++ = digits[i + 1];
    645             *p++ = digits[i];
    646         }
    647         if (u < 10)
    648             *p++ = char(u) + '0';
    649         else {
    650             const unsigned i = u << 1;
    651             *p++ = digits[i + 1];
    652             *p++ = digits[i];
    653         }
    654 
    655         do {
    656             --p;
    657             os_->Put(*p);
    658         } while (p != buffer);
    659         return true;
    660     }
    661 
    662     bool WriteInt64(int64_t i64) {
    663         if (i64 < 0) {
    664             os_->Put('-');
    665             i64 = -i64;
    666         }
    667         WriteUint64((uint64_t)i64);
    668         return true;
    669     }
    670 
    671     bool WriteUint64(uint64_t u64) {
    672         char buffer[20];
    673         char* p = buffer;
    674         while (u64 >= 100) {
    675             const unsigned i = static_cast<unsigned>(u64 % 100) << 1;
    676             u64 /= 100;
    677             *p++ = digits[i + 1];
    678             *p++ = digits[i];
    679         }
    680         if (u64 < 10)
    681             *p++ = char(u64) + '0';
    682         else {
    683             const unsigned i = static_cast<unsigned>(u64) << 1;
    684             *p++ = digits[i + 1];
    685             *p++ = digits[i];
    686         }
    687 
    688         do {
    689             --p;
    690             os_->Put(*p);
    691         } while (p != buffer);
    692         return true;
    693     }
    694 
    695 private:
    696     void WriteUintReverse(char* d, unsigned u) {
    697         while (u >= 100) {
    698             const unsigned i = (u % 100) << 1;
    699             u /= 100;
    700             *--d = digits[i + 1];
    701             *--d = digits[i];
    702         }
    703         if (u < 10) {
    704             *--d = char(u) + '0';
    705         }
    706         else {
    707             const unsigned i = u << 1;
    708             *--d = digits[i + 1];
    709             *--d = digits[i];
    710         }
    711     }
    712 
    713     void WriteUint64Reverse(char* d, uint64_t u) {
    714         while (u >= 100) {
    715             const unsigned i = (u % 100) << 1;
    716             u /= 100;
    717             *--d = digits[i + 1];
    718             *--d = digits[i];
    719         }
    720         if (u < 10) {
    721             *--d = char(u) + '0';
    722         }
    723         else {
    724             const unsigned i = u << 1;
    725             *--d = digits[i + 1];
    726             *--d = digits[i];
    727         }
    728     }
    729 
    730     OutputStream* os_;
    731 };
    732 
    733 template<>
    734 inline bool Writer4<rapidjson::StringBuffer>::WriteUint(unsigned u) {
    735     unsigned digit = CountDecimalDigit_fast(u);
    736     WriteUintReverse(os_->Push(digit) + digit, u);
    737     return true;
    738 }
    739 
    740 template<>
    741 inline bool Writer4<rapidjson::InsituStringStream>::WriteUint(unsigned u) {
    742     unsigned digit = CountDecimalDigit_fast(u);
    743     WriteUintReverse(os_->Push(digit) + digit, u);
    744     return true;
    745 }
    746 
    747 template<>
    748 inline bool Writer4<rapidjson::StringBuffer>::WriteUint64(uint64_t u) {
    749     unsigned digit = CountDecimalDigit64_fast(u);
    750     WriteUint64Reverse(os_->Push(digit) + digit, u);
    751     return true;
    752 }
    753 
    754 template<>
    755 inline bool Writer4<rapidjson::InsituStringStream>::WriteUint64(uint64_t u) {
    756     unsigned digit = CountDecimalDigit64_fast(u);
    757     WriteUint64Reverse(os_->Push(digit) + digit, u);
    758     return true;
    759 }
    760 
    761 template <typename Writer>
    762 void itoa_Writer_StringBufferVerify() {
    763     rapidjson::StringBuffer sb;
    764     Writer writer(sb);
    765     for (size_t j = 0; j < randvalCount; j++) {
    766         char buffer[32];
    767         sprintf(buffer, "%d", randval[j]);
    768         writer.WriteInt(randval[j]);
    769         ASSERT_STREQ(buffer, sb.GetString());
    770         sb.Clear();
    771     }
    772 }
    773 
    774 template <typename Writer>
    775 void itoa_Writer_InsituStringStreamVerify() {
    776     Writer writer;
    777     for (size_t j = 0; j < randvalCount; j++) {
    778         char buffer[32];
    779         sprintf(buffer, "%d", randval[j]);
    780         char buffer2[32];
    781         rapidjson::InsituStringStream ss(buffer2);
    782         writer.Reset(ss);
    783         char* begin = ss.PutBegin();
    784         writer.WriteInt(randval[j]);
    785         ss.Put('\0');
    786         ss.PutEnd(begin);
    787         ASSERT_STREQ(buffer, buffer2);
    788     }
    789 }
    790 
    791 template <typename Writer>
    792 void itoa_Writer_StringBuffer() {
    793     size_t length = 0;
    794 
    795     rapidjson::StringBuffer sb;
    796     Writer writer(sb);
    797 
    798     for (size_t i = 0; i < kItoaTrialCount; i++) {
    799         for (size_t j = 0; j < randvalCount; j++) {
    800             writer.WriteInt(randval[j]);
    801             length += sb.GetSize();
    802             sb.Clear();
    803         }
    804     }
    805     OUTPUT_LENGTH(length);
    806 }
    807 
    808 template <typename Writer>
    809 void itoa_Writer_InsituStringStream() {
    810     size_t length = 0;
    811 
    812     char buffer[32];
    813     Writer writer;
    814     for (size_t i = 0; i < kItoaTrialCount; i++) {
    815         for (size_t j = 0; j < randvalCount; j++) {
    816             rapidjson::InsituStringStream ss(buffer);
    817             writer.Reset(ss);
    818             char* begin = ss.PutBegin();
    819             writer.WriteInt(randval[j]);
    820             length += ss.PutEnd(begin);
    821         }
    822     }
    823     OUTPUT_LENGTH(length);
    824 };
    825 
    826 template <typename Writer>
    827 void itoa64_Writer_StringBufferVerify() {
    828     rapidjson::StringBuffer sb;
    829     Writer writer(sb);
    830     for (size_t j = 0; j < randvalCount; j++) {
    831         char buffer[32];
    832         int64_t x = randval[j] * randval[j];
    833         sprintf(buffer, "%" PRIi64, x);
    834         writer.WriteInt64(x);
    835         ASSERT_STREQ(buffer, sb.GetString());
    836         sb.Clear();
    837     }
    838 }
    839 
    840 template <typename Writer>
    841 void itoa64_Writer_InsituStringStreamVerify() {
    842     Writer writer;
    843     for (size_t j = 0; j < randvalCount; j++) {
    844         char buffer[32];
    845         int64_t x = randval[j] * randval[j];
    846         sprintf(buffer, "%" PRIi64, x);
    847         char buffer2[32];
    848         rapidjson::InsituStringStream ss(buffer2);
    849         writer.Reset(ss);
    850         char* begin = ss.PutBegin();
    851         writer.WriteInt64(x);
    852         ss.Put('\0');
    853         ss.PutEnd(begin);
    854         ASSERT_STREQ(buffer, buffer2);
    855     }
    856 }
    857 
    858 template <typename Writer>
    859 void itoa64_Writer_StringBuffer() {
    860     size_t length = 0;
    861 
    862     rapidjson::StringBuffer sb;
    863     Writer writer(sb);
    864 
    865     for (size_t i = 0; i < kItoaTrialCount; i++) {
    866         for (size_t j = 0; j < randvalCount; j++) {
    867             writer.WriteInt64(randval[j] * randval[j]);
    868             length += sb.GetSize();
    869             sb.Clear();
    870         }
    871     }
    872     OUTPUT_LENGTH(length);
    873 }
    874 
    875 template <typename Writer>
    876 void itoa64_Writer_InsituStringStream() {
    877     size_t length = 0;
    878 
    879     char buffer[32];
    880     Writer writer;
    881     for (size_t i = 0; i < kItoaTrialCount; i++) {
    882         for (size_t j = 0; j < randvalCount; j++) {
    883             rapidjson::InsituStringStream ss(buffer);
    884             writer.Reset(ss);
    885             char* begin = ss.PutBegin();
    886             writer.WriteInt64(randval[j] * randval[j]);
    887             length += ss.PutEnd(begin);
    888         }
    889     }
    890     OUTPUT_LENGTH(length);
    891 };
    892 
    893 // Full specialization for InsituStringStream to prevent memory copying
    894 // (normally we will not use InsituStringStream for writing, just for testing)
    895 
    896 namespace rapidjson {
    897 
    898 template<>
    899 bool rapidjson::Writer<InsituStringStream>::WriteInt(int i) {
    900     char *buffer = os_->Push(11);
    901     const char* end = internal::i32toa(i, buffer);
    902     os_->Pop(11 - (end - buffer));
    903     return true;
    904 }
    905 
    906 template<>
    907 bool Writer<InsituStringStream>::WriteUint(unsigned u) {
    908     char *buffer = os_->Push(10);
    909     const char* end = internal::u32toa(u, buffer);
    910     os_->Pop(10 - (end - buffer));
    911     return true;
    912 }
    913 
    914 template<>
    915 bool Writer<InsituStringStream>::WriteInt64(int64_t i64) {
    916     char *buffer = os_->Push(21);
    917     const char* end = internal::i64toa(i64, buffer);
    918     os_->Pop(21 - (end - buffer));
    919     return true;
    920 }
    921 
    922 template<>
    923 bool Writer<InsituStringStream>::WriteUint64(uint64_t u) {
    924     char *buffer = os_->Push(20);
    925     const char* end = internal::u64toa(u, buffer);
    926     os_->Pop(20 - (end - buffer));
    927     return true;
    928 }
    929 
    930 } // namespace rapidjson
    931 
    932 TEST_F(Misc, itoa_Writer_StringBufferVerify) { itoa_Writer_StringBufferVerify<rapidjson::Writer<rapidjson::StringBuffer> >(); }
    933 TEST_F(Misc, itoa_Writer1_StringBufferVerify) { itoa_Writer_StringBufferVerify<Writer1<rapidjson::StringBuffer> >(); }
    934 TEST_F(Misc, itoa_Writer2_StringBufferVerify) { itoa_Writer_StringBufferVerify<Writer2<rapidjson::StringBuffer> >(); }
    935 TEST_F(Misc, itoa_Writer3_StringBufferVerify) { itoa_Writer_StringBufferVerify<Writer3<rapidjson::StringBuffer> >(); }
    936 TEST_F(Misc, itoa_Writer4_StringBufferVerify) { itoa_Writer_StringBufferVerify<Writer4<rapidjson::StringBuffer> >(); }
    937 TEST_F(Misc, itoa_Writer_InsituStringStreamVerify) { itoa_Writer_InsituStringStreamVerify<rapidjson::Writer<rapidjson::InsituStringStream> >(); }
    938 TEST_F(Misc, itoa_Writer1_InsituStringStreamVerify) { itoa_Writer_InsituStringStreamVerify<Writer1<rapidjson::InsituStringStream> >(); }
    939 TEST_F(Misc, itoa_Writer2_InsituStringStreamVerify) { itoa_Writer_InsituStringStreamVerify<Writer2<rapidjson::InsituStringStream> >(); }
    940 TEST_F(Misc, itoa_Writer3_InsituStringStreamVerify) { itoa_Writer_InsituStringStreamVerify<Writer3<rapidjson::InsituStringStream> >(); }
    941 TEST_F(Misc, itoa_Writer4_InsituStringStreamVerify) { itoa_Writer_InsituStringStreamVerify<Writer4<rapidjson::InsituStringStream> >(); }
    942 TEST_F(Misc, itoa_Writer_StringBuffer) { itoa_Writer_StringBuffer<rapidjson::Writer<rapidjson::StringBuffer> >(); }
    943 TEST_F(Misc, itoa_Writer1_StringBuffer) { itoa_Writer_StringBuffer<Writer1<rapidjson::StringBuffer> >(); }
    944 TEST_F(Misc, itoa_Writer2_StringBuffer) { itoa_Writer_StringBuffer<Writer2<rapidjson::StringBuffer> >(); }
    945 TEST_F(Misc, itoa_Writer3_StringBuffer) { itoa_Writer_StringBuffer<Writer3<rapidjson::StringBuffer> >(); }
    946 TEST_F(Misc, itoa_Writer4_StringBuffer) { itoa_Writer_StringBuffer<Writer4<rapidjson::StringBuffer> >(); }
    947 TEST_F(Misc, itoa_Writer_InsituStringStream) { itoa_Writer_InsituStringStream<rapidjson::Writer<rapidjson::InsituStringStream> >(); }
    948 TEST_F(Misc, itoa_Writer1_InsituStringStream) { itoa_Writer_InsituStringStream<Writer1<rapidjson::InsituStringStream> >(); }
    949 TEST_F(Misc, itoa_Writer2_InsituStringStream) { itoa_Writer_InsituStringStream<Writer2<rapidjson::InsituStringStream> >(); }
    950 TEST_F(Misc, itoa_Writer3_InsituStringStream) { itoa_Writer_InsituStringStream<Writer3<rapidjson::InsituStringStream> >(); }
    951 TEST_F(Misc, itoa_Writer4_InsituStringStream) { itoa_Writer_InsituStringStream<Writer4<rapidjson::InsituStringStream> >(); }
    952 
    953 TEST_F(Misc, itoa64_Writer_StringBufferVerify) { itoa64_Writer_StringBufferVerify<rapidjson::Writer<rapidjson::StringBuffer> >(); }
    954 TEST_F(Misc, itoa64_Writer1_StringBufferVerify) { itoa64_Writer_StringBufferVerify<Writer1<rapidjson::StringBuffer> >(); }
    955 TEST_F(Misc, itoa64_Writer2_StringBufferVerify) { itoa64_Writer_StringBufferVerify<Writer2<rapidjson::StringBuffer> >(); }
    956 TEST_F(Misc, itoa64_Writer3_StringBufferVerify) { itoa64_Writer_StringBufferVerify<Writer3<rapidjson::StringBuffer> >(); }
    957 TEST_F(Misc, itoa64_Writer4_StringBufferVerify) { itoa64_Writer_StringBufferVerify<Writer4<rapidjson::StringBuffer> >(); }
    958 TEST_F(Misc, itoa64_Writer_InsituStringStreamVerify) { itoa64_Writer_InsituStringStreamVerify<rapidjson::Writer<rapidjson::InsituStringStream> >(); }
    959 TEST_F(Misc, itoa64_Writer1_InsituStringStreamVerify) { itoa64_Writer_InsituStringStreamVerify<Writer1<rapidjson::InsituStringStream> >(); }
    960 TEST_F(Misc, itoa64_Writer2_InsituStringStreamVerify) { itoa64_Writer_InsituStringStreamVerify<Writer2<rapidjson::InsituStringStream> >(); }
    961 TEST_F(Misc, itoa64_Writer3_InsituStringStreamVerify) { itoa64_Writer_InsituStringStreamVerify<Writer3<rapidjson::InsituStringStream> >(); }
    962 TEST_F(Misc, itoa64_Writer4_InsituStringStreamVerify) { itoa64_Writer_InsituStringStreamVerify<Writer4<rapidjson::InsituStringStream> >(); }
    963 TEST_F(Misc, itoa64_Writer_StringBuffer) { itoa64_Writer_StringBuffer<rapidjson::Writer<rapidjson::StringBuffer> >(); }
    964 TEST_F(Misc, itoa64_Writer1_StringBuffer) { itoa64_Writer_StringBuffer<Writer1<rapidjson::StringBuffer> >(); }
    965 TEST_F(Misc, itoa64_Writer2_StringBuffer) { itoa64_Writer_StringBuffer<Writer2<rapidjson::StringBuffer> >(); }
    966 TEST_F(Misc, itoa64_Writer3_StringBuffer) { itoa64_Writer_StringBuffer<Writer3<rapidjson::StringBuffer> >(); }
    967 TEST_F(Misc, itoa64_Writer4_StringBuffer) { itoa64_Writer_StringBuffer<Writer4<rapidjson::StringBuffer> >(); }
    968 TEST_F(Misc, itoa64_Writer_InsituStringStream) { itoa64_Writer_InsituStringStream<rapidjson::Writer<rapidjson::InsituStringStream> >(); }
    969 TEST_F(Misc, itoa64_Writer1_InsituStringStream) { itoa64_Writer_InsituStringStream<Writer1<rapidjson::InsituStringStream> >(); }
    970 TEST_F(Misc, itoa64_Writer2_InsituStringStream) { itoa64_Writer_InsituStringStream<Writer2<rapidjson::InsituStringStream> >(); }
    971 TEST_F(Misc, itoa64_Writer3_InsituStringStream) { itoa64_Writer_InsituStringStream<Writer3<rapidjson::InsituStringStream> >(); }
    972 TEST_F(Misc, itoa64_Writer4_InsituStringStream) { itoa64_Writer_InsituStringStream<Writer4<rapidjson::InsituStringStream> >(); }
    973 
    974 #endif // TEST_MISC
    975