summaryrefslogtreecommitdiff
path: root/bignum.c
diff options
context:
space:
mode:
authorakr <akr@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2013-06-09 00:36:58 +0000
committerakr <akr@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2013-06-09 00:36:58 +0000
commitf6757f080c9201de6fbd1d25b663c37341ef2305 (patch)
tree5c056965bc439081abe243b6e9304f754d4fbbdf /bignum.c
parent4ff3b7cf05cc409216f248860c3c1312443943cf (diff)
* bignum.c (big2str_base_powerof2): New function.
(rb_big2str0): Use big2str_base_powerof2 if base is 2, 4, 8, 16 or 32. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@41194 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'bignum.c')
-rw-r--r--bignum.c37
1 files changed, 37 insertions, 0 deletions
diff --git a/bignum.c b/bignum.c
index af19b695ac..9e0b185e91 100644
--- a/bignum.c
+++ b/bignum.c
@@ -1684,6 +1684,37 @@ calc_hbase(int base, BDIGIT *hbase_p, int *hbase_numdigits_p)
*hbase_numdigits_p = hbase_numdigits;
}
+static VALUE
+big2str_base_powerof2(VALUE x, size_t len, int base, int trim)
+{
+ int word_numbits = ffs(base) - 1;
+ size_t numwords;
+ VALUE result;
+ char *ptr;
+ numwords = trim ? rb_absint_size_in_word(x, word_numbits, NULL) : len;
+ if (RBIGNUM_NEGATIVE_P(x) || !trim) {
+ if (LONG_MAX-1 < numwords)
+ rb_raise(rb_eArgError, "too big number");
+ result = rb_usascii_str_new(0, 1+numwords);
+ ptr = RSTRING_PTR(result);
+ *ptr++ = RBIGNUM_POSITIVE_P(x) ? '+' : '-';
+ }
+ else {
+ if (LONG_MAX < numwords)
+ rb_raise(rb_eArgError, "too big number");
+ result = rb_usascii_str_new(0, numwords);
+ ptr = RSTRING_PTR(result);
+ }
+ rb_integer_pack(x, NULL, NULL, ptr, numwords, 1, CHAR_BIT-word_numbits,
+ INTEGER_PACK_BIG_ENDIAN);
+ while (0 < numwords) {
+ *ptr = ruby_digitmap[*(unsigned char *)ptr];
+ ptr++;
+ numwords--;
+ }
+ return result;
+}
+
VALUE
rb_big2str0(VALUE x, int base, int trim)
{
@@ -1705,6 +1736,12 @@ rb_big2str0(VALUE x, int base, int trim)
rb_raise(rb_eArgError, "invalid radix %d", base);
n2 = big2str_find_n1(x, base);
+
+ if (base & (base - 1) == 0) {
+ /* base == 2 || base == 4 || base == 8 || base == 16 || base == 32 */
+ return big2str_base_powerof2(x, (size_t)n2, base, trim);
+ }
+
n1 = (n2 + 1) / 2;
ss = rb_usascii_str_new(0, n2 + 1); /* plus one for sign */
ptr = RSTRING_PTR(ss);