[前][次][番号順一覧][スレッド一覧]

ruby-changes:29661

From: akr <ko1@a...>
Date: Sun, 30 Jun 2013 22:16:20 +0900 (JST)
Subject: [ruby-changes:29661] akr:r41713 (trunk): * bignum.c (rb_cstr_to_inum): Use rb_integer_unpack if base is a power

akr	2013-06-30 22:16:08 +0900 (Sun, 30 Jun 2013)

  New Revision: 41713

  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=41713

  Log:
    * bignum.c (rb_cstr_to_inum): Use rb_integer_unpack if base is a power
      of 2.

  Modified files:
    trunk/ChangeLog
    trunk/bignum.c

Index: ChangeLog
===================================================================
--- ChangeLog	(revision 41712)
+++ ChangeLog	(revision 41713)
@@ -1,3 +1,8 @@ https://github.com/ruby/ruby/blob/trunk/ChangeLog#L1
+Sun Jun 30 21:53:38 2013  Tanaka Akira  <akr@f...>
+
+	* bignum.c (rb_cstr_to_inum): Use rb_integer_unpack if base is a power
+	  of 2.
+
 Sun Jun 30 10:59:23 2013  Nobuyoshi Nakada  <nobu@r...>
 
 	* win32/win32.c (join_argv): use backslash instead of slash in program
Index: bignum.c
===================================================================
--- bignum.c	(revision 41712)
+++ bignum.c	(revision 41713)
@@ -1777,11 +1777,16 @@ rb_cstr_to_inum(const char *str, int bas https://github.com/ruby/ruby/blob/trunk/bignum.c#L1777
     char sign = 1, nondigit = 0;
     int c;
     BDIGIT_DBL num;
-    long len, blen = 1;
-    long i;
     VALUE z;
     BDIGIT *zds;
 
+    int bits_per_digit;
+    size_t size, len, i;
+    size_t blen = 1;
+    VALUE v = 0;
+    uint8_t *buf;
+    uint8_t *p;
+
 #undef ISDIGIT
 #define ISDIGIT(c) ('0' <= (c) && (c) <= '9')
 #define conv_digit(c) \
@@ -1813,15 +1818,19 @@ rb_cstr_to_inum(const char *str, int bas https://github.com/ruby/ruby/blob/trunk/bignum.c#L1818
 	    switch (str[1]) {
 	      case 'x': case 'X':
 		base = 16;
+                str += 2;
 		break;
 	      case 'b': case 'B':
 		base = 2;
+                str += 2;
 		break;
 	      case 'o': case 'O':
 		base = 8;
+                str += 2;
 		break;
 	      case 'd': case 'D':
 		base = 10;
+                str += 2;
 		break;
 	      default:
 		base = 8;
@@ -1834,47 +1843,28 @@ rb_cstr_to_inum(const char *str, int bas https://github.com/ruby/ruby/blob/trunk/bignum.c#L1843
 	    base = 10;
 	}
     }
-    switch (base) {
-      case 2:
-	len = 1;
+    else if (base == 2) {
 	if (str[0] == '0' && (str[1] == 'b'||str[1] == 'B')) {
 	    str += 2;
 	}
-	break;
-      case 3:
-	len = 2;
-	break;
-      case 8:
+    }
+    else if (base == 8) {
 	if (str[0] == '0' && (str[1] == 'o'||str[1] == 'O')) {
 	    str += 2;
 	}
-      case 4: case 5: case 6: case 7:
-	len = 3;
-	break;
-      case 10:
+    }
+    else if (base == 10) {
 	if (str[0] == '0' && (str[1] == 'd'||str[1] == 'D')) {
 	    str += 2;
 	}
-      case 9: case 11: case 12: case 13: case 14: case 15:
-	len = 4;
-	break;
-      case 16:
-	len = 4;
+    }
+    else if (base == 16) {
 	if (str[0] == '0' && (str[1] == 'x'||str[1] == 'X')) {
 	    str += 2;
 	}
-	break;
-      default:
-	if (base < 2 || 36 < base) {
-	    rb_raise(rb_eArgError, "invalid radix %d", base);
-	}
-	if (base <= 32) {
-	    len = 5;
-	}
-	else {
-	    len = 6;
-	}
-	break;
+    }
+    if (base < 2 || 36 < base) {
+        rb_raise(rb_eArgError, "invalid radix %d", base);
     }
     if (*str == '0') {		/* squeeze preceding 0s */
 	int us = 0;
@@ -1893,9 +1883,11 @@ rb_cstr_to_inum(const char *str, int bas https://github.com/ruby/ruby/blob/trunk/bignum.c#L1883
 	if (badcheck) goto bad;
 	return INT2FIX(0);
     }
-    len *= strlen(str)*sizeof(char);
 
-    if ((size_t)len <= (sizeof(long)*CHAR_BIT)) {
+    size = strlen(str);
+    bits_per_digit = BITSPERDIG - nlz(base-1);
+    len = bits_per_digit * size;
+    if (len <= (sizeof(long)*CHAR_BIT)) {
 	unsigned long val = STRTOUL(str, &end, base);
 
 	if (str < end && *end == '_') goto bigparse;
@@ -1919,12 +1911,11 @@ rb_cstr_to_inum(const char *str, int bas https://github.com/ruby/ruby/blob/trunk/bignum.c#L1911
 	}
     }
   bigparse:
-    len = (len/BITSPERDIG)+1;
+    buf = ALLOCV(v, size+1);
+    p = buf;
+
     if (badcheck && *str == '_') goto bad;
 
-    z = bignew(len, sign);
-    zds = BDIGITS(z);
-    for (i=len;i--;) zds[i]=0;
     while ((c = *str++) != 0) {
 	if (c == '_') {
 	    if (nondigit) {
@@ -1939,20 +1930,7 @@ rb_cstr_to_inum(const char *str, int bas https://github.com/ruby/ruby/blob/trunk/bignum.c#L1930
 	}
 	if (c >= base) break;
 	nondigit = 0;
-	i = 0;
-	num = c;
-	for (;;) {
-	    while (i<blen) {
-		num += (BDIGIT_DBL)zds[i]*base;
-		zds[i++] = BIGLO(num);
-		num = BIGDN(num);
-	    }
-	    if (num) {
-		blen++;
-		continue;
-	    }
-	    break;
-	}
+        *p++ = (uint8_t)c;
     }
     if (badcheck) {
 	str--;
@@ -1960,10 +1938,45 @@ rb_cstr_to_inum(const char *str, int bas https://github.com/ruby/ruby/blob/trunk/bignum.c#L1938
 	while (*str && ISSPACE(*str)) str++;
 	if (*str) {
 	  bad:
+	    if (v)
+		ALLOCV_END(v);
 	    rb_invalid_str(s, "Integer()");
 	}
     }
 
+    if (POW2_P(base)) {
+        int flags = INTEGER_PACK_BIG_ENDIAN;
+        if (!sign)
+            flags |= INTEGER_PACK_NEGATIVE;
+        z = rb_integer_unpack(buf, p - buf, 1, CHAR_BIT - bits_per_digit, flags);
+    }
+    else {
+        len = (len/BITSPERDIG)+1;
+        z = bignew(len, sign);
+        zds = BDIGITS(z);
+        for (i=len;i--;) zds[i]=0;
+
+        size = p - buf;
+        for (p = buf; p < buf + size; p++) {
+            num = *p;
+            i = 0;
+            for (;;) {
+                while (i<blen) {
+                    num += (BDIGIT_DBL)zds[i]*base;
+                    zds[i++] = BIGLO(num);
+                    num = BIGDN(num);
+                }
+                if (num) {
+                    blen++;
+                    continue;
+                }
+                break;
+            }
+        }
+    }
+
+    if (v)
+        ALLOCV_END(v);
     return bignorm(z);
 }
 

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]