Created
November 1, 2013 00:14
-
-
Save anonymous/7259276 to your computer and use it in GitHub Desktop.
Fast C++ Integer To String Conversion
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
******************************************************************************* | |
* The C++ Integer To String Conversion Benchmark * | |
* * | |
* This benchmark is based on the solutions provided in the following * | |
* stackoverflow question: * | |
* * | |
* http://stackoverflow.com/q/4351371 (Date: 20101204) * | |
* * | |
* Title: C++ Performance Challenge - Integer To std::string Conversion * | |
* * | |
* 0. sprintf (libc) * | |
* 1. hopman_fast (Chris Hopman) * | |
* 2. karma (Boost.Spirit) * | |
* 3. timo (Timo ???) * | |
* 4. so (user434507) * | |
* 5. strtk (Arash Partow) * | |
* 6. voigt (Richard Benjamin Voigt) * | |
* 7. zverovich (Victor Zverovich) * | |
* * | |
* RESULTS: * | |
* Integer To String Test * | |
* [sprintf ] Numbers: 240000000 Time: 58.4877sec Rate: 4103425.8081nums/sec * | |
* [karma ] Numbers: 240000000 Time: 15.8808sec Rate: 15112628.3947nums/sec * | |
* [strtk ] Numbers: 240000000 Time: 5.7537sec Rate: 41712168.1004nums/sec * | |
* [so ] Numbers: 240000000 Time: 6.7677sec Rate: 35462365.3011nums/sec * | |
* [timo ] Numbers: 240000000 Time: 8.8778sec Rate: 27033588.5472nums/sec * | |
* [voigt ] Numbers: 240000000 Time: 10.5976sec Rate: 22646661.9538nums/sec * | |
* [hopman ] Numbers: 240000000 Time: 9.7909sec Rate: 24512562.7480nums/sec * | |
* [zverovich] Numbers: 240000000 Time: 11.2721sec Rate: 21291497.6905nums/sec * | |
* * | |
* Details: * | |
* 0. Intel Xeon W3680 3.3GHz * | |
* 1. Mint 15 (Kernel 3.11) * | |
* 2. GCC 4.8, O2, PGO * | |
* * | |
* Note: Copyright of portions of the code below other than StrTk is the * | |
* purview of its owner. * | |
* * | |
******************************************************************************* | |
*/ | |
#include <cstddef> | |
#include <cstdio> | |
#include <iostream> | |
#include <string> | |
#include <iterator> | |
#include "strtk.hpp" | |
#include <boost/lexical_cast.hpp> | |
//Note: Define USE_SPIRIT to include Karma (requires Boost 1.45+) | |
#define USE_SPIRIT | |
#ifdef USE_SPIRIT | |
#define INCLUDE_KARMA | |
#include <boost/spirit/include/karma.hpp> | |
#endif | |
#include "format.h" | |
void print_mode(const std::string& mode) | |
{ | |
static const std::size_t test_mode_length = sizeof("[ ]"); | |
printf("%s", strtk::text::left_align(test_mode_length, ' ', mode).c_str()); | |
fflush(stdout); | |
} | |
#define enable_test_type01 | |
#define enable_test_type02 | |
#define enable_test_type03 | |
static const int randval[] = | |
{ | |
936116, 369532, 453755, -72860, 209713, 268347, 435278, -360266, -416287, -182064, | |
-644712, 944969, 640463, -366588, 471577, -69401, -744294, -505829, 923883, 831785, | |
-601136, -636767, -437054, 591718, 100758, 231907, -719038, 973540, -605220, 506659, | |
-871653, 462533, 764843, -919138, 404305, -630931, -288711, -751454, -173726, -718208, | |
432689, -281157, 360737, 659827, 19174, -376450, 769984, -858198, 439127, 734703, | |
-683426, 7, 386135, 186997, -643900, -744422, -604708, -629545, 42313, -933592, | |
-635566, 182308, 439024, -367219, -73924, -516649, 421935, -470515, 413507, -78952, | |
-427917, -561158, 737176, 94538, 572322, 405217, 709266, -357278, -908099, -425447, | |
601119, 750712, -862285, -177869, 900102, 384877, 157859, -641680, 503738, -702558, | |
278225, 463290, 268378, -212840, 580090, 347346, -473985, -950968, -114547, -839893, | |
-738032, -789424, 409540, 493495, 432099, 119755, 905004, -174834, 338266, 234298, | |
74641, -965136, -754593, 685273, 466924, 920560, 385062, 796402, -67229, 994864, | |
376974, 299869, -647540, -128724, 469890, -163167, -547803, -743363, 486463, -621028, | |
612288, 27459, -514224, 126342, -66612, 803409, -777155, -336453, -284002, 472451, | |
342390, -163630, 908356, -456147, -825607, 268092, -974715, 287227, 227890, -524101, | |
616370, -782456, 922098, -624001, -813690, 171605, -192962, 796151, 707183, -95696, | |
-23163, -721260, 508892, 430715, 791331, 482048, -996102, 863274, 275406, -8279, | |
-556239, -902076, 268647, -818565, 260069, -798232, -172924, -566311, -806503, -885992, | |
813969, -78468, 956632, 304288, 494867, -508784, 381751, 151264, 762953, 76352, | |
594902, 375424, 271700, -743062, 390176, 924237, 772574, 676610, 435752, -153847, | |
3959, -971937, -294181, -538049, -344620, -170136, 19120, -703157, 868152, -657961, | |
-818631, 219015, -872729, -940001, -956570, 880727, -345910, 942913, -942271, -788115, | |
225294, 701108, -517736, -416071, 281940, 488730, 942698, 711494, 838382, -892302, | |
-533028, 103052, 528823, 901515, 949577, 159364, 718227, -241814, -733661, -462928, | |
-495829, 165170, 513580, -629188, -509571, -459083, 198437, 77198, -644612, 811276, | |
-422298, -860842, -52584, 920369, 686424, -530667, -243476, 49763, 345866, -411960, | |
-114863, 470810, -302860, 683007, -509080, 2, -174981, -772163, -48697, 447770, | |
-268246, 213268, 269215, 78810, -236340, -639140, -864323, 505113, -986569, -325215, | |
541859, 163070, -819998, -645161, -583336, 573414, 696417, -132375, 3, -294501, | |
320435, 682591, 840008, 351740, 426951, 609354, 898154, -943254, 227321, -859793, | |
-727993, 44137, -497965, -782239, 14955, -746080, -243366, 9837, -233083, 606507, | |
-995864, -615287, -994307, 602715, 770771, -315040, 610860, 446102, -307120, 710728, | |
-590392, -230474, -762625, -637525, 134963, -202700, -766902, -985541, 218163, 682009, | |
926051, 525156, -61195, 403211, -810098, 245539, -431733, 179998, -806533, 745943, | |
447597, 131973, -187130, 826019, 286107, -937230, -577419, 20254, 681802, -340500, | |
323080, 266283, -667617, 309656, 416386, 611863, 759991, -534257, 523112, -634892, | |
-169913, -204905, -909867, -882185, -944908, 741811, -717675, 967007, -317396, 407230, | |
-412805, 792905, 994873, 744793, -456797, 713493, 355232, 116900, -945199, 880539, | |
342505, -580824, -262273, 982968, -349497, -735488, 311767, -455191, 570918, 389734, | |
-958386, 10262, -99267, 155481, 304210, 204724, 704367, -144893, -233664, -671441, | |
896849, 408613, 762236, 322697, 981321, 688476, 13663, -970704, -379507, 896412, | |
977084, 348869, 875948, 341348, 318710, 512081, 6163, 669044, 833295, 811883, | |
708756, -802534, -536057, 608413, -389625, -694603, 541106, -110037, 720322, -540581, | |
645420, 32980, 62442, 510157, -981870, -87093, -325960, -500494, -718291, -67889, | |
991501, 374804, 769026, -978869, 294747, 714623, 413327, -199164, 671368, 804789, | |
-362507, 798196, -170790, -568895, -869379, 62020, -316693, -837793, 644994, -39341, | |
-417504, -243068, -957756, 99072, 622234, -739992, 225668, 8863, -505910, 82483, | |
-559244, 241572, 1315, -36175, -54990, 376813, -11, 162647, -688204, -486163, | |
-54934, -197470, 744223, -762707, 732540, 996618, 351561, -445933, -898491, 486531, | |
456151, 15276, 290186, -817110, -52995, 313046, -452533, -96267, 94470, -500176, | |
-818026, -398071, -810548, -143325, -819741, 1338, -897676, -101577, -855445, 37309, | |
285742, 953804, -777927, -926962, -811217, -936744, -952245, -802300, -490188, -964953, | |
-552279, 329142, -570048, -505756, 682898, -381089, -14352, 175138, 152390, -582268, | |
-485137, 717035, 805329, 239572, -730409, 209643, -184403, -385864, 675086, 819648, | |
629058, -527109, -488666, -171981, 532788, 552441, 174666, 984921, 766514, 758787, | |
716309, 338801, -978004, -412163, 876079, -734212, 789557, -160491, -522719, 56644, | |
-991, -286038, -53983, 663740, 809812, 919889, -717502, -137704, 220511, 184396, | |
-825740, -588447, 430870, 124309, 135956, 558662, -307087, -788055, -451328, 812260, | |
931601, 324347, -482989, -117858, -278861, 189068, -172774, 929057, 293787, 198161, | |
-342386, -47173, 906555, -759955, -12779, 777604, -97869, 899320, 927486, -25284, | |
-848550, 259450, -485856, -17820, 88, 171400, 235492, -326783, -340793, 886886, | |
112428, -246280, 5979, 648444, -114982, 991013, -56489, -9497, 419706, 632820, | |
-341664, 393926, -848977, -22538, 257307, 773731, -905319, 491153, 734883, -868212, | |
-951053, 644458, -580758, 764735, 584316, 297077, 28852, -397710, -953669, 201772, | |
879050, -198237, -588468, 448102, -116837, 770007, -231812, 642906, -582166, -885828, | |
9, 305082, -996577, 303559, 75008, -772956, -447960, 599825, -295552, 870739, | |
-386278, -950300, 485359, -457081, 629461, -850276, 550496, -451755, -620841, -11766, | |
-950137, 832337, 28711, -273398, -507197, 91921, -271360, -705991, -753220, -388968, | |
967945, 340434, -320883, -662793, -554617, -574568, 477946, -6148, -129519, 689217, | |
920020, -656315, -974523, -212525, 80921, -612532, 645096, 545655, 655713, -591631, | |
-307385, -816688, -618823, -113713, 526430, 673063, 735916, -809095, -850417, 639004, | |
432281, -388185, 270708, 860146, -39902, -786157, -258180, -246169, -966720, -264957, | |
548072, -306010, -57367, -635665, 933824, 70553, -989936, -488741, 72411, -452509, | |
529831, 956277, 449019, -577850, -360986, -803418, 48833, 296073, 203430, 609591, | |
715483, 470964, 658106, -718254, -96424, 790163, 334739, 181070, -373578, 5, | |
-435088, 329841, 330939, -256602, 394355, 912412, 231910, 927278, -661933, 788539, | |
-769664, -893274, -96856, 298205, 901043, -608122, -527430, 183618, -553963, -35246, | |
-393924, 948832, -483198, 594501, 35460, -407007, 93494, -336881, -634072, 984205, | |
-812161, 944664, -31062, 753872, 823933, -69566, 50445, 290147, 85134, 34706, | |
551902, 405202, -991246, -84642, 154341, 316432, -695101, -651588, -5030, 137564, | |
-294665, 332541, 528307, -90572, -344923, 523766, -758498, -968047, 339028, 494578, | |
593129, -725773, 31834, -718406, -208638, 159665, -2043, 673344, -442767, 75816, | |
755442, 769257, -158730, -410272, 691688, 589550, -878398, -184121, 460679, 346312, | |
294163, -544602, 653308, 254167, -276979, 52073, -892684, 887653, -41222, 983065, | |
-68258, -408799, -99069, -674069, -863635, -32890, 622757, -743862, 40872, -4837, | |
-967228, 522370, -903951, -818669, 524459, 514702, 925801, 20007, -299229, 579348, | |
626021, 430089, 348139, -562692, -607728, -130606, -928451, -424793, -458647, -448892, | |
-312230, 143337, 109746, 880042, -339658, -785614, 938995, 540916, 118429, 661351, | |
-402967, 404729, -40918, -976535, 743230, 713110, 440182, -381314, -499252, 74613, | |
193652, 912717, 491323, 583633, 324691, 459397, 281253, 195540, -2764, -888651, | |
892449, 132663, -478373, -430002, -314551, 527826, 247165, 557966, 554778, 481531, | |
-946634, 431685, -769059, -348371, 174046, 184597, -354867, 584422, 227390, -850397, | |
-542924, -849093, -737769, 325359, 736314, 269101, 767940, 674809, 81413, -447458, | |
445076, 189072, 906218, 502688, -718476, -863827, -731381, 100660, 623249, 710008, | |
572060, 922203, 685740, 55096, 263394, -243695, -353910, -516788, 388471, 455165, | |
844103, -643772, 363976, 268875, -899450, 104470, 104029, -238874, -274659, 732969, | |
-676443, 953291, -916289, -861849, -242344, 958083, -479593, -970395, 799831, 277841, | |
-243236, -283462, -201510, 166263, -259105, -575706, 878926, 891064, 895297, 655262, | |
-34807, -809833, -89281, 342585, 554920, 1, 902141, -333425, 139703, 852318, | |
-618438, 329498, -932596, -692836, -513372, 733656, -523411, 85779, 500478, -682697, | |
-502836, 138776, 156341, -420037, -557964, -556378, 710993, -50383, -877159, 916334, | |
132996, 583516, -603392, -111615, -12288, -780214, 476780, 123327, 137607, 519956, | |
745837, 17358, -158581, -53490 | |
}; | |
static const int max_i2s = 80000000; | |
void sprintf_lexical_cast_test_i2s() | |
{ | |
print_mode("[sprintf]"); | |
std::string s; | |
s.reserve(32); | |
std::size_t total_length = 0; | |
strtk::util::timer t; | |
t.start(); | |
for (int i = (-max_i2s / 2); i < (max_i2s / 2); ++i) | |
{ | |
#ifdef enable_test_type01 | |
s.resize(sprintf(const_cast<char*>(s.c_str()),"%d",((i & 1) ? i : -i))); | |
total_length += s.size(); | |
#endif | |
#ifdef enable_test_type02 | |
s.resize(sprintf(const_cast<char*>(s.c_str()),"%d",max_i2s + i)); | |
total_length += s.size(); | |
#endif | |
#ifdef enable_test_type03 | |
s.resize(sprintf(const_cast<char*>(s.c_str()),"%d",randval[(max_i2s + i) & 1023])); | |
total_length += s.size(); | |
#endif | |
} | |
t.stop(); | |
printf("Numbers:%10lu\tTotal:%12lu\tTime:%8.4fsec\tRate:%14.4fnums/sec\n", | |
static_cast<unsigned long>(3 * max_i2s), | |
static_cast<unsigned long>(total_length), | |
t.time(), | |
(3.0 * max_i2s) / t.time()); | |
} | |
void boost_lexical_cast_test_i2s() | |
{ | |
print_mode("[boost]"); | |
std::string s; | |
s.reserve(32); | |
std::size_t total_length = 0; | |
strtk::util::timer t; | |
t.start(); | |
for (int i = (-max_i2s / 2); i < (max_i2s / 2); ++i) | |
{ | |
#ifdef enable_test_type01 | |
s = boost::lexical_cast<std::string>(((i & 1) ? i : -i)); | |
total_length += s.size(); | |
#endif | |
#ifdef enable_test_type02 | |
s = boost::lexical_cast<std::string>(max_i2s + i); | |
total_length += s.size(); | |
#endif | |
#ifdef enable_test_type03 | |
s = boost::lexical_cast<std::string>(randval[(max_i2s + i) & 1023]); | |
total_length += s.size(); | |
#endif | |
} | |
t.stop(); | |
printf("Numbers:%10lu\tTotal:%12lu\tTime:%8.4fsec\tRate:%14.4fnums/sec\n", | |
static_cast<unsigned long>(3 * max_i2s), | |
static_cast<unsigned long>(total_length), | |
t.time(), | |
(3.0 * max_i2s) / t.time()); | |
} | |
#ifdef INCLUDE_KARMA | |
#include <boost/spirit/include/karma.hpp> | |
inline bool karma_int_to_string(const int& value, std::string& str) | |
{ | |
using namespace boost::spirit; | |
using boost::spirit::karma::generate; | |
char buffer[16]; | |
char* x = buffer; | |
if (!generate(x, int_, value)) | |
return false; | |
str.assign(buffer, x - buffer); | |
return true; | |
} | |
void karma_lexical_cast_test_i2s() | |
{ | |
print_mode("[karma]"); | |
std::string s; | |
s.reserve(32); | |
std::size_t total_length = 0; | |
strtk::util::timer t; | |
t.start(); | |
for (int i = (-max_i2s / 2); i < (max_i2s / 2); ++i) | |
{ | |
#ifdef enable_test_type01 | |
karma_int_to_string(((i & 1) ? i : -i),s); | |
total_length += s.size(); | |
#endif | |
#ifdef enable_test_type02 | |
karma_int_to_string(max_i2s + i,s); | |
total_length += s.size(); | |
#endif | |
#ifdef enable_test_type03 | |
karma_int_to_string(randval[(max_i2s + i) & 1023],s); | |
total_length += s.size(); | |
#endif | |
} | |
t.stop(); | |
printf("Numbers:%10lu\tTotal:%12lu\tTime:%8.4fsec\tRate:%14.4fnums/sec\n", | |
static_cast<unsigned long>(3 * max_i2s), | |
static_cast<unsigned long>(total_length), | |
t.time(), | |
(3.0 * max_i2s) / t.time()); | |
} | |
#else | |
void karma_lexical_cast_test_i2s(){} | |
#endif | |
void strtk_lexical_cast_test_i2s() | |
{ | |
print_mode("[strtk]"); | |
std::string s; | |
s.reserve(32); | |
std::size_t total_length = 0; | |
strtk::util::timer t; | |
t.start(); | |
for (int i = (-max_i2s / 2); i < (max_i2s / 2); ++i) | |
{ | |
#ifdef enable_test_type01 | |
strtk::type_to_string(((i & 1) ? i : -i),s); | |
total_length += s.size(); | |
#endif | |
#ifdef enable_test_type02 | |
strtk::type_to_string(max_i2s + i,s); | |
total_length += s.size(); | |
#endif | |
#ifdef enable_test_type03 | |
strtk::type_to_string(randval[(max_i2s + i) & 1023],s); | |
total_length += s.size(); | |
#endif | |
} | |
t.stop(); | |
printf("Numbers:%10lu\tTotal:%12lu\tTime:%8.4fsec\tRate:%14.4fnums/sec\n", | |
static_cast<unsigned long>(3 * max_i2s), | |
static_cast<unsigned long>(total_length), | |
t.time(), | |
(3.0 * max_i2s) / t.time()); | |
} | |
namespace so | |
{ | |
std::string& itostr(int n, std::string& s) | |
{ | |
if (n == 0) | |
{ | |
s = "0"; | |
return s; | |
} | |
int sign = -(n < 0); | |
unsigned int val = (n ^ sign) - sign; | |
int size; | |
if (val >= 10000) | |
{ | |
if (val >= 10000000) | |
{ | |
if (val >= 1000000000) | |
size = 10; | |
else if (val >= 100000000) | |
size = 9; | |
else | |
size = 8; | |
} | |
else | |
{ | |
if (val >= 1000000) | |
size = 7; | |
else if (val >= 100000) | |
size = 6; | |
else | |
size = 5; | |
} | |
} | |
else | |
{ | |
if (val >= 100) | |
{ | |
if (val >= 1000) | |
size = 4; | |
else | |
size = 3; | |
} | |
else | |
{ | |
if (val>=10) | |
size = 2; | |
else | |
size = 1; | |
} | |
} | |
s.resize(-sign + size); | |
char* c = &s[0]; | |
if (sign) | |
*c++='-'; | |
char* d = c + size - 1; | |
while(val > 0) | |
{ | |
*d-- = '0' + (val % 10); | |
val /= 10; | |
} | |
return s; | |
} | |
} | |
void so_lexical_cast_test_i2s() | |
{ | |
print_mode("[so ]"); | |
std::string s; | |
s.reserve(32); | |
std::size_t total_length = 0; | |
strtk::util::timer t; | |
t.start(); | |
for (int i = (-max_i2s / 2); i < (max_i2s / 2); ++i) | |
{ | |
#ifdef enable_test_type01 | |
so::itostr(((i & 1) ? i : -i),s); | |
total_length += s.size(); | |
#endif | |
#ifdef enable_test_type02 | |
so::itostr(max_i2s + i,s); | |
total_length += s.size(); | |
#endif | |
#ifdef enable_test_type03 | |
so::itostr(randval[(max_i2s + i) & 1023],s); | |
total_length += s.size(); | |
#endif | |
} | |
t.stop(); | |
printf("Numbers:%10lu\tTotal:%12lu\tTime:%8.4fsec\tRate:%14.4fnums/sec\n", | |
static_cast<unsigned long>(3 * max_i2s), | |
static_cast<unsigned long>(total_length), | |
t.time(), | |
(3.0 * max_i2s) / t.time()); | |
} | |
const char digit_pairs[201] = { | |
"00010203040506070809" | |
"10111213141516171819" | |
"20212223242526272829" | |
"30313233343536373839" | |
"40414243444546474849" | |
"50515253545556575859" | |
"60616263646566676869" | |
"70717273747576777879" | |
"80818283848586878889" | |
"90919293949596979899" | |
}; | |
static const int BUFFER_SIZE = 11; | |
std::string timo_itostr(int val) | |
{ | |
char buf[BUFFER_SIZE]; | |
char *it = &buf[BUFFER_SIZE - 2]; | |
if (val >= 0) | |
{ | |
int div = val / 100; | |
while(div) | |
{ | |
memcpy(it,&digit_pairs[2 * (val - div * 100)],2); | |
val = div; | |
it -= 2; | |
div = val / 100; | |
} | |
memcpy(it,&digit_pairs[2 * val],2); | |
if (val < 10) | |
it++; | |
} | |
else | |
{ | |
int div = val / 100; | |
while(div) | |
{ | |
memcpy(it,&digit_pairs[-2 * (val - div * 100)],2); | |
val = div; | |
it -= 2; | |
div = val / 100; | |
} | |
memcpy(it,&digit_pairs[-2 * val],2); | |
if (val <= -10) | |
it--; | |
*it = '-'; | |
} | |
return std::string(it,&buf[BUFFER_SIZE] - it); | |
} | |
void timo_lexical_cast_test_i2s() | |
{ | |
print_mode("[timo ]"); | |
std::string s; | |
s.reserve(32); | |
std::size_t total_length = 0; | |
strtk::util::timer t; | |
t.start(); | |
for (int i = (-max_i2s / 2); i < (max_i2s / 2); ++i) | |
{ | |
#ifdef enable_test_type01 | |
s = timo_itostr(((i & 1) ? i : -i)); | |
total_length += s.size(); | |
#endif | |
#ifdef enable_test_type02 | |
s = timo_itostr(max_i2s + i); | |
total_length += s.size(); | |
#endif | |
#ifdef enable_test_type03 | |
s = timo_itostr(randval[(max_i2s + i) & 1023]); | |
total_length += s.size(); | |
#endif | |
} | |
t.stop(); | |
printf("Numbers:%10lu\tTotal:%12lu\tTime:%8.4fsec\tRate:%14.4fnums/sec\n", | |
static_cast<unsigned long>(3 * max_i2s), | |
static_cast<unsigned long>(total_length), | |
t.time(), | |
(3.0 * max_i2s) / t.time()); | |
} | |
namespace voigt | |
{ | |
template<typename T> | |
struct assert_integral | |
{ | |
enum { value = (T)0.5 }; | |
char test[1 - 4 * value]; | |
}; | |
template<typename T, bool is_signed, size_t bits> | |
struct itostr_impl { }; | |
template<typename T, bool is_signed> | |
struct itostr_impl<T,is_signed,8> | |
{ | |
static std::string cvt(T val) | |
{ | |
std::string retval(5, '\0'); | |
int i = 0; | |
char ch = 0; | |
if (is_signed) | |
{ | |
if (val < 0) | |
{ | |
retval[i] = '-'; | |
++i; | |
if (val <= -100) | |
{ | |
ch = '1'; | |
val += 100; | |
} | |
val = -val; | |
} | |
else if (val >= 100) | |
{ | |
ch |= '1'; | |
val -= 100; | |
} | |
} | |
else | |
{ | |
if (val >= 200) | |
{ | |
ch |= '2'; | |
val -= 200; | |
} | |
else if (val >= 100) | |
{ | |
ch |= '1'; | |
val -= 100; | |
} | |
} | |
if (ch) | |
{ | |
retval[i] = ch; | |
++i; | |
ch = '0'; | |
} | |
if (val >= 80) | |
{ | |
ch |= '8'; | |
val -= 80; | |
} | |
else if (val >= 40) | |
{ | |
ch |= '4'; | |
val -= 40; | |
} | |
if (val >= 20) | |
{ | |
ch |= '2'; | |
val -= 20; | |
} | |
if (val >= 10) | |
{ | |
ch |= '1'; | |
val -= 10; | |
} | |
if (ch) | |
{ | |
retval[i] = ch; | |
++i; | |
} | |
retval[i] = '0' + val; | |
retval.resize(i+1); | |
return retval; | |
} | |
}; | |
template<typename T, bool is_signed> | |
struct itostr_impl<T,is_signed,16> | |
{ | |
static std::string cvt(T val) | |
{ | |
std::string retval(7, '\0'); | |
int i = 0; | |
char ch = 0; | |
if (is_signed) | |
{ | |
if (val < 0) | |
{ | |
retval[i] = '-'; | |
++i; | |
if (val <= -20000) | |
{ | |
ch = '2'; | |
val += 20000; | |
} | |
val = -val; | |
} | |
else if (val >= 20000) | |
{ | |
ch |= '2'; | |
val -= 20000; | |
} | |
} | |
else | |
{ | |
if (val >= 40000) | |
{ | |
ch |= '4'; | |
val -= 40000; | |
} | |
else if (val >= 20000) | |
{ | |
ch |= '2'; | |
val -= 20000; | |
} | |
} | |
if (val >= 10000) | |
{ | |
ch |= '1'; | |
val -= 10000; | |
} | |
if (ch) | |
{ | |
retval[i] = ch; | |
++i; | |
ch = '0'; | |
} | |
if (val >= 8000) | |
{ | |
ch |= '8'; | |
val -= 8000; | |
} | |
else if (val >= 4000) | |
{ | |
ch |= '4'; | |
val -= 4000; | |
} | |
if (val >= 2000) | |
{ | |
ch |= '2'; | |
val -= 2000; | |
} | |
if (val >= 1000) | |
{ | |
ch |= '1'; | |
val -= 1000; | |
} | |
if (ch) | |
{ | |
retval[i] = ch; | |
++i; | |
ch = '0'; | |
} | |
if (val >= 800) | |
{ | |
ch |= '8'; | |
val -= 800; | |
} | |
else if (val >= 400) | |
{ | |
ch |= '4'; | |
val -= 400; | |
} | |
if (val >= 200) | |
{ | |
ch |= '2'; | |
val -= 200; | |
} | |
if (val >= 100) | |
{ | |
ch |= '1'; | |
val -= 100; | |
} | |
if (ch) | |
{ | |
retval[i] = ch; | |
++i; | |
ch = '0'; | |
} | |
if (val >= 80) | |
{ | |
ch |= '8'; | |
val -= 80; | |
} | |
else if (val >= 40) | |
{ | |
ch |= '4'; | |
val -= 40; | |
} | |
if (val >= 20) | |
{ | |
ch |= '2'; | |
val -= 20; | |
} | |
if (val >= 10) | |
{ | |
ch |= '1'; | |
val -= 10; | |
} | |
if (ch) | |
{ | |
retval[i] = ch; | |
++i; | |
} | |
retval[i] = '0' + val; | |
retval.resize(i+1); | |
return retval; | |
} | |
}; | |
const char digit_pair_table[201] = { | |
"00010203040506070809" | |
"10111213141516171819" | |
"20212223242526272829" | |
"30313233343536373839" | |
"40414243444546474849" | |
"50515253545556575859" | |
"60616263646566676869" | |
"70717273747576777879" | |
"80818283848586878889" | |
"90919293949596979899" | |
}; | |
template<typename T, bool is_signed> | |
struct itostr_impl<T,is_signed,32> | |
{ | |
static std::string cvt(T val) | |
{ | |
char buf[11], ch = 0; | |
char* start = buf + 1; | |
char* p = start; | |
bool neg = val < 0; | |
int digit; | |
if (is_signed) | |
{ | |
if (neg) | |
{ | |
if (val <= -2000000000) | |
{ | |
ch = '2'; | |
val += 2000000000; | |
} | |
val = -val; | |
} | |
else if (val >= 2000000000) | |
{ | |
ch = '2'; | |
val -= 2000000000; | |
} | |
} | |
else | |
{ | |
if (val >= 4000000000U) | |
{ | |
ch |= '4'; | |
val -= 4000000000U; | |
} | |
else if (val >= 2000000000) | |
{ | |
ch |= '2'; | |
val -= 2000000000; | |
} | |
} | |
if (val >= 1000000000) | |
{ | |
ch |= '1'; | |
val -= 1000000000; | |
} | |
if (ch) | |
{ | |
*p = ch; | |
++p; | |
ch = '0'; | |
} | |
else if (val < 1000) | |
{ | |
if (val < 10) goto d1; | |
if (val < 1000) goto d10; | |
} | |
else | |
{ | |
if (val < 100000) goto d1000; | |
if (val < 10000000) goto d100000; | |
} | |
#define DO_PAIR(n) \ | |
d##n: \ | |
digit = val / n; \ | |
*(p++) = digit_pair_table[digit * 2]; \ | |
*(p++) = digit_pair_table[digit * 2 + 1]; \ | |
val -= n * digit; | |
DO_PAIR(10000000); | |
DO_PAIR(100000); | |
DO_PAIR(1000); | |
DO_PAIR(10); | |
d1: | |
*p = '0' | static_cast<char>(val); | |
if (p > start && *start == '0') ++start; | |
if (is_signed && neg) *--start = '-'; | |
return std::string(start, p + 1 - start); | |
} | |
}; | |
template<typename T> | |
std::string itostr(T val) | |
{ | |
sizeof(assert_integral<T>); | |
return itostr_impl<T,((T)-1) < 0,sizeof(T) * CHAR_BIT>::cvt(val); | |
} | |
} | |
void voigt_lexical_cast_test_i2s() | |
{ | |
print_mode("[voigt]"); | |
std::string s; | |
s.reserve(32); | |
std::size_t total_length = 0; | |
strtk::util::timer t; | |
t.start(); | |
for (int i = (-max_i2s / 2); i < (max_i2s / 2); ++i) | |
{ | |
#ifdef enable_test_type01 | |
s = voigt::itostr(((i & 1) ? i : -i)); | |
total_length += s.size(); | |
#endif | |
#ifdef enable_test_type02 | |
s = voigt::itostr(max_i2s + i); | |
total_length += s.size(); | |
#endif | |
#ifdef enable_test_type03 | |
s = voigt::itostr(randval[(max_i2s + i) & 1023]); | |
total_length += s.size(); | |
#endif | |
} | |
t.stop(); | |
printf("Numbers:%10lu\tTotal:%12lu\tTime:%8.4fsec\tRate:%14.4fnums/sec\n", | |
static_cast<unsigned long>(3 * max_i2s), | |
static_cast<unsigned long>(total_length), | |
t.time(), | |
(3.0 * max_i2s) / t.time()); | |
} | |
namespace hopman_fast | |
{ | |
struct itostr_helper | |
{ | |
static unsigned out[10000]; | |
itostr_helper() | |
{ | |
for (int i = 0; i < 10000; i++) | |
{ | |
unsigned v = i; | |
char * o = (char*)(out + i); | |
o[3] = v % 10 + '0'; | |
o[2] = (v % 100) / 10 + '0'; | |
o[1] = static_cast<char>((v % 1000) / 100) + '0'; | |
o[0] = static_cast<char>((v % 10000) / 1000); | |
if (o[0]) o[0] |= 0x30; | |
else if (o[1] != '0') o[0] |= 0x20; | |
else if (o[2] != '0') o[0] |= 0x10; | |
else o[0] |= 0x00; | |
} | |
} | |
}; | |
unsigned itostr_helper::out[10000]; | |
itostr_helper hlp_init; | |
template <typename T> | |
std::string itostr(T o) | |
{ | |
typedef itostr_helper hlp; | |
unsigned blocks[3], *b = blocks + 2; | |
blocks[0] = o < 0 ? ~o + 1 : o; | |
blocks[2] = blocks[0] % 10000; blocks[0] /= 10000; | |
blocks[2] = hlp::out[blocks[2]]; | |
if (blocks[0]) | |
{ | |
blocks[1] = blocks[0] % 10000; blocks[0] /= 10000; | |
blocks[1] = hlp::out[blocks[1]]; | |
blocks[2] |= 0x30303030; | |
b--; | |
} | |
if (blocks[0]) | |
{ | |
blocks[0] = hlp::out[blocks[0] % 10000]; | |
blocks[1] |= 0x30303030; | |
b--; | |
} | |
char* f = ((char*)b); | |
f += 3 - (*f >> 4); | |
char* str = (char*)blocks; | |
if (o < 0) *--f = '-'; | |
return std::string(f, (str + 12) - f); | |
} | |
} | |
void hopman_fast_lexical_cast_test_i2s() | |
{ | |
print_mode("[hopman]"); | |
std::string s; | |
s.reserve(32); | |
std::size_t total_length = 0; | |
strtk::util::timer t; | |
t.start(); | |
for (int i = (-max_i2s / 2); i < (max_i2s / 2); ++i) | |
{ | |
#ifdef enable_test_type01 | |
s = hopman_fast::itostr(((i & 1) ? i : -i)); | |
total_length += s.size(); | |
#endif | |
#ifdef enable_test_type02 | |
s = hopman_fast::itostr(max_i2s + i); | |
total_length += s.size(); | |
#endif | |
#ifdef enable_test_type03 | |
s = hopman_fast::itostr(randval[(max_i2s + i) & 1023]); | |
total_length += s.size(); | |
#endif | |
} | |
t.stop(); | |
printf("Numbers:%10lu\tTotal:%12lu\tTime:%8.4fsec\tRate:%14.4fnums/sec\n", | |
static_cast<unsigned long>(3 * max_i2s), | |
static_cast<unsigned long>(total_length), | |
t.time(), | |
(3.0 * max_i2s) / t.time()); | |
} | |
void zverovich_lexical_cast_test_i2s() | |
{ | |
print_mode("[zverovich]"); | |
std::string s; | |
s.reserve(32); | |
std::size_t total_length = 0; | |
strtk::util::timer t; | |
t.start(); | |
for (int i = (-max_i2s / 2); i < (max_i2s / 2); ++i) | |
{ | |
#ifdef enable_test_type01 | |
s = fmt::FormatInt(((i & 1) ? i : -i)).c_str(); | |
total_length += s.size(); | |
#endif | |
#ifdef enable_test_type02 | |
s = fmt::FormatInt(max_i2s + i).c_str(); | |
total_length += s.size(); | |
#endif | |
#ifdef enable_test_type03 | |
s = fmt::FormatInt(randval[(max_i2s + i) & 1023]).c_str(); | |
total_length += s.size(); | |
#endif | |
} | |
t.stop(); | |
printf("Numbers:%10lu\tTotal:%12lu\tTime:%8.4fsec\tRate:%14.4fnums/sec\n", | |
static_cast<unsigned long>(3 * max_i2s), | |
static_cast<unsigned long>(total_length), | |
t.time(), | |
(3.0 * max_i2s) / t.time()); | |
} | |
int main() | |
{ | |
std::cout << "Integer To String Test" << std::endl; | |
sprintf_lexical_cast_test_i2s(); | |
//boost_lexical_cast_test_i2s(); too slow to even be considered. | |
karma_lexical_cast_test_i2s(); | |
strtk_lexical_cast_test_i2s(); | |
so_lexical_cast_test_i2s(); | |
timo_lexical_cast_test_i2s(); | |
voigt_lexical_cast_test_i2s(); | |
hopman_fast_lexical_cast_test_i2s(); | |
zverovich_lexical_cast_test_i2s(); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
s.resize(sprintf(const_cast<char*>(s.c_str()),"%d",((i & 1) ? i : -i)));
Is
const_cast<char*>(s.c_str())
a well-defined behavior? Since s.c_str() should be immutable, it may cause bugs on compilers which still using COW std::string implementation ( such as GCC before 5.0 )