perl: PreferInteger: faster string to integer conversion; support negative value

This commit is contained in:
frsyuki 2009-07-03 02:08:22 +09:00
parent 0f9dcb8610
commit eaa8be8ddd
2 changed files with 64 additions and 13 deletions

View File

@ -26,7 +26,7 @@ typedef struct {
char *end; /* SvEND (sv) */ char *end; /* SvEND (sv) */
SV *sv; /* result scalar */ SV *sv; /* result scalar */
} enc_t; } enc_t;
void need(enc_t *enc, STRLEN len); static void need(enc_t *enc, STRLEN len);
#define msgpack_pack_user enc_t* #define msgpack_pack_user enc_t*
@ -41,7 +41,7 @@ void need(enc_t *enc, STRLEN len);
#define PACK_WRAPPER(t) _PACK_WRAPPER(t) #define PACK_WRAPPER(t) _PACK_WRAPPER(t)
#define INIT_SIZE 32 /* initial scalar size to be allocated */ #define INIT_SIZE 32 /* initial scalar size to be allocated */
void need(enc_t *enc, STRLEN len) static void need(enc_t *enc, STRLEN len)
{ {
if (enc->cur + len >= enc->end) { if (enc->cur + len >= enc->end) {
STRLEN cur = enc->cur - (char *)SvPVX (enc->sv); STRLEN cur = enc->cur - (char *)SvPVX (enc->sv);
@ -83,16 +83,60 @@ void boot_Data__MessagePack_pack(void) {
} }
static int looks_like_int(const char *str, size_t len) { static int try_int(enc_t* enc, const char *p, size_t len) {
int i; int negative = 0;
for (i=0; i<len; i++) { const char* pe = p + len;
if (!isDIGIT(str[i])) { uint64_t num = 0;
return 0;
} if (len == 0) { return 0; }
if (*p == '-') {
/* length(-0x80000000) == 11 */
if (len <= 1 || len > 11) { return 0; }
negative = 1;
++p;
} else {
/* length(0xFFFFFFFF) == 10 */
if (len > 10) { return 0; }
} }
#if '9'=='8'+1 && '8'=='7'+1 && '7'=='6'+1 && '6'=='5'+1 && '5'=='4'+1 \
&& '4'=='3'+1 && '3'=='2'+1 && '2'=='1'+1 && '1'=='0'+1
do {
unsigned int c = ((int)*(p++)) - '0';
if (c > 9) { return 0; }
num = num * 10 + c;
} while(p < pe);
#else
do {
switch (*(p++)) {
case '0': num = num * 10 + 0; break;
case '1': num = num * 10 + 1; break;
case '2': num = num * 10 + 2; break;
case '3': num = num * 10 + 3; break;
case '4': num = num * 10 + 4; break;
case '5': num = num * 10 + 5; break;
case '6': num = num * 10 + 6; break;
case '7': num = num * 10 + 7; break;
case '8': num = num * 10 + 8; break;
case '9': num = num * 10 + 9; break;
default: return 0;
}
} while(p < pe);
#endif
if (negative) {
if (num > 0x80000000) { return 0; }
msgpack_pack_int32(enc, ((int32_t)num) * -1);
} else {
if (num > 0xFFFFFFFF) { return 0; }
msgpack_pack_uint32(enc, (uint32_t)num);
}
return 1; return 1;
} }
static void _msgpack_pack_sv(enc_t *enc, SV* val) { static void _msgpack_pack_sv(enc_t *enc, SV* val) {
if (val==NULL) { if (val==NULL) {
msgpack_pack_nil(enc); msgpack_pack_nil(enc);
@ -163,10 +207,8 @@ static void _msgpack_pack_sv(enc_t *enc, SV* val) {
if (SvPOKp(val)) { if (SvPOKp(val)) {
STRLEN len; STRLEN len;
char * cval = SvPV(val, len); char * cval = SvPV(val, len);
const int U32_STRLEN = 10; /* length(0xFFFFFFFF) */
if (s_pref_int && len <= U32_STRLEN && looks_like_int(cval, len) && SvUV(val) < U32_MAX) { if (s_pref_int && try_int(enc, cval, len)) {
PACK_WRAPPER(uint32)(enc, SvUV(val));
return; return;
} }

View File

@ -17,15 +17,24 @@ sub pis ($$) {
} }
my @dat = ( my @dat = (
'', 'a0',
'0', '00', '0', '00',
'1', '01', '1', '01',
'10', '0a', '10', '0a',
'-1', 'ff',
'-10', 'f6',
'-', 'a1 2d',
''.0xEFFF => 'cd ef ff', ''.0xEFFF => 'cd ef ff',
''.0xFFFF => 'cd ff ff', ''.0xFFFF => 'cd ff ff',
''.0xFFFFFF => 'ce 00 ff ff ff', ''.0xFFFFFF => 'ce 00 ff ff ff',
''.0xFFFFFFFF => 'aa 34 32 39 34 39 36 37 32 39 35', ''.0xFFFFFFFF => 'ce ff ff ff ff',
''.0xFFFFFFFFF => 'ab 36 38 37 31 39 34 37 36 37 33 35', ''.0xFFFFFFFFF => 'ab 36 38 37 31 39 34 37 36 37 33 35',
''.0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFF => 'b4 38 2e 33 30 37 36 37 34 39 37 33 36 35 35 37 32 65 2b 33 34', ''.0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFF => 'b4 38 2e 33 30 37 36 37 34 39 37 33 36 35 35 37 32 65 2b 33 34',
'-'.0x8000000 => 'd2 f8 00 00 00',
'-'.0x80000000 => 'd2 80 00 00 00',
'-'.0x800000000 => 'ac 2d 33 34 33 35 39 37 33 38 33 36 38',
'-'.0x8000000000 => 'ad 2d 35 34 39 37 35 35 38 31 33 38 38 38',
'-'.0x800000000000000000000000000000 => 'b5 2d 36 2e 36 34 36 31 33 39 39 37 38 39 32 34 35 38 65 2b 33 35',
{'0' => '1'}, '81 00 01', {'0' => '1'}, '81 00 01',
{'abc' => '1'}, '81 a3 61 62 63 01', {'abc' => '1'}, '81 a3 61 62 63 01',
); );