ruby-changes:29212
From: akr <ko1@a...>
Date: Thu, 13 Jun 2013 00:19:28 +0900 (JST)
Subject: [ruby-changes:29212] akr:r41264 (trunk): * bignum.c (rb_integer_unpack_2comp): New function.
akr 2013-06-13 00:18:00 +0900 (Thu, 13 Jun 2013) New Revision: 41264 http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=41264 Log: * bignum.c (rb_integer_unpack_2comp): New function. (rb_integer_unpack_internal): Extracted from rb_integer_unpack and nlp_bits_ret argument added. (integer_unpack_num_bdigits_small): nlp_bits_ret argument added to return number of leading padding bits. (integer_unpack_num_bdigits_generic): Ditto. * internal.h (rb_integer_unpack_2comp): Declared. * pack.c (pack_unpack): Use rb_integer_unpack_2comp and rb_integer_unpack. Modified files: trunk/ChangeLog trunk/bignum.c trunk/ext/-test-/bignum/pack.c trunk/internal.h trunk/pack.c trunk/test/-ext-/bignum/test_pack.rb Index: ChangeLog =================================================================== --- ChangeLog (revision 41263) +++ ChangeLog (revision 41264) @@ -1,3 +1,17 @@ https://github.com/ruby/ruby/blob/trunk/ChangeLog#L1 +Thu Jun 13 00:17:18 2013 Tanaka Akira <akr@f...> + + * bignum.c (rb_integer_unpack_2comp): New function. + (rb_integer_unpack_internal): Extracted from rb_integer_unpack and + nlp_bits_ret argument added. + (integer_unpack_num_bdigits_small): nlp_bits_ret argument added to + return number of leading padding bits. + (integer_unpack_num_bdigits_generic): Ditto. + + * internal.h (rb_integer_unpack_2comp): Declared. + + * pack.c (pack_unpack): Use rb_integer_unpack_2comp and + rb_integer_unpack. + Wed Jun 12 23:27:03 2013 Shugo Maeda <shugo@r...> * eval.c (mod_using): new method Module#using, which activates Index: pack.c =================================================================== --- pack.c (revision 41263) +++ pack.c (revision 41264) @@ -1725,38 +1725,16 @@ pack_unpack(VALUE str, VALUE fmt) https://github.com/ruby/ruby/blob/trunk/pack.c#L1725 #endif default: - if (integer_size > MAX_INTEGER_PACK_SIZE) - rb_bug("unexpected integer size for pack: %d", integer_size); PACK_LENGTH_ADJUST_SIZE(integer_size); while (len-- > 0) { - union { - unsigned long i[(MAX_INTEGER_PACK_SIZE+SIZEOF_LONG)/SIZEOF_LONG]; - char a[(MAX_INTEGER_PACK_SIZE+SIZEOF_LONG)/SIZEOF_LONG*SIZEOF_LONG]; - } v; - int num_longs = (integer_size+SIZEOF_LONG)/SIZEOF_LONG; - int i; - - if (signed_p && (signed char)s[bigendian_p ? 0 : (integer_size-1)] < 0) - memset(v.a, 0xff, sizeof(long)*num_longs); - else - memset(v.a, 0, sizeof(long)*num_longs); - if (bigendian_p) - memcpy(v.a + sizeof(long)*num_longs - integer_size, s, integer_size); + int flags = bigendian_p ? INTEGER_PACK_BIG_ENDIAN : INTEGER_PACK_LITTLE_ENDIAN; + VALUE val; + if (signed_p) + val = rb_integer_unpack_2comp(s, integer_size, 1, 0, flags); else - memcpy(v.a, s, integer_size); - if (bigendian_p) { - for (i = 0; i < num_longs/2; i++) { - unsigned long t = v.i[i]; - v.i[i] = v.i[num_longs-1-i]; - v.i[num_longs-1-i] = t; - } - } - if (bigendian_p != BIGENDIAN_P()) { - for (i = 0; i < num_longs; i++) - v.i[i] = swapl(v.i[i]); - } + val = rb_integer_unpack(s, integer_size, 1, 0, flags); + UNPACK_PUSH(val); s += integer_size; - UNPACK_PUSH(rb_big_unpack(v.i, num_longs)); } PACK_ITEM_ADJUST(); break; Index: ext/-test-/bignum/pack.c =================================================================== --- ext/-test-/bignum/pack.c (revision 41263) +++ ext/-test-/bignum/pack.c (revision 41264) @@ -63,6 +63,16 @@ rb_integer_unpack_m(VALUE klass, VALUE b https://github.com/ruby/ruby/blob/trunk/ext/-test-/bignum/pack.c#L63 NUM2SIZET(nails), NUM2INT(flags)); } +static VALUE +rb_integer_unpack_2comp_m(VALUE klass, VALUE buf, VALUE numwords, VALUE wordsize, VALUE nails, VALUE flags) +{ + StringValue(buf); + + return rb_integer_unpack_2comp(RSTRING_PTR(buf), + NUM2SIZET(numwords), NUM2SIZET(wordsize), + NUM2SIZET(nails), NUM2INT(flags)); +} + void Init_pack(VALUE klass) { @@ -70,6 +80,7 @@ Init_pack(VALUE klass) https://github.com/ruby/ruby/blob/trunk/ext/-test-/bignum/pack.c#L80 rb_define_method(rb_cInteger, "test_pack", rb_integer_pack_m, 4); rb_define_method(rb_cInteger, "test_pack_2comp", rb_integer_pack_2comp_m, 4); rb_define_singleton_method(rb_cInteger, "test_unpack", rb_integer_unpack_m, 5); + rb_define_singleton_method(rb_cInteger, "test_unpack_2comp", rb_integer_unpack_2comp_m, 5); rb_define_const(rb_cInteger, "INTEGER_PACK_MSWORD_FIRST", INT2NUM(INTEGER_PACK_MSWORD_FIRST)); rb_define_const(rb_cInteger, "INTEGER_PACK_LSWORD_FIRST", INT2NUM(INTEGER_PACK_LSWORD_FIRST)); rb_define_const(rb_cInteger, "INTEGER_PACK_MSBYTE_FIRST", INT2NUM(INTEGER_PACK_MSBYTE_FIRST)); Index: internal.h =================================================================== --- internal.h (revision 41263) +++ internal.h (revision 41264) @@ -451,6 +451,7 @@ VALUE rb_thread_io_blocking_region(rb_bl https://github.com/ruby/ruby/blob/trunk/internal.h#L451 int rb_integer_pack(VALUE val, void *words, size_t numwords, size_t wordsize, size_t nails, int flags); VALUE rb_integer_unpack(const void *words, size_t numwords, size_t wordsize, size_t nails, int flags); int rb_integer_pack_2comp(VALUE val, void *words, size_t numwords, size_t wordsize, size_t nails, int flags); +VALUE rb_integer_unpack_2comp(const void *words, size_t numwords, size_t wordsize, size_t nails, int flags); /* io.c */ void rb_maygvl_fd_fix_cloexec(int fd); Index: bignum.c =================================================================== --- bignum.c (revision 41263) +++ bignum.c (revision 41264) @@ -1120,15 +1120,17 @@ rb_integer_pack_2comp(VALUE val, void *w https://github.com/ruby/ruby/blob/trunk/bignum.c#L1120 } static size_t -integer_unpack_num_bdigits_small(size_t numwords, size_t wordsize, size_t nails) +integer_unpack_num_bdigits_small(size_t numwords, size_t wordsize, size_t nails, int *nlp_bits_ret) { - size_t num_bits; - num_bits = (wordsize * CHAR_BIT - nails) * numwords; - return (num_bits + SIZEOF_BDIGITS*CHAR_BIT - 1) / (SIZEOF_BDIGITS*CHAR_BIT); + /* nlp_bits stands for number of leading padding bits */ + size_t num_bits = (wordsize * CHAR_BIT - nails) * numwords; + size_t num_bdigits = (num_bits + BITSPERDIG - 1) / BITSPERDIG; + *nlp_bits_ret = num_bdigits * BITSPERDIG - num_bits; + return num_bdigits; } static size_t -integer_unpack_num_bdigits_generic(size_t numwords, size_t wordsize, size_t nails) +integer_unpack_num_bdigits_generic(size_t numwords, size_t wordsize, size_t nails, int *nlp_bits_ret) { /* BITSPERDIG = SIZEOF_BDIGITS * CHAR_BIT */ /* num_bits = (wordsize * CHAR_BIT - nails) * numwords */ @@ -1172,13 +1174,17 @@ integer_unpack_num_bdigits_generic(size_ https://github.com/ruby/ruby/blob/trunk/bignum.c#L1174 if (CHAR_BIT * r3 >= r1 * r2) { size_t tmp1 = CHAR_BIT * BITSPERDIG - (CHAR_BIT * r3 - r1 * r2); size_t q4 = tmp1 / BITSPERDIG; + int r4 = tmp1 % BITSPERDIG; size_t num_digits2 = num_digits1 + CHAR_BIT - q4; + *nlp_bits_ret = r4; return num_digits2; } else { size_t tmp1 = - (CHAR_BIT * r3 - r1 * r2); size_t q4 = tmp1 / BITSPERDIG; + int r4 = tmp1 % BITSPERDIG; size_t num_digits2 = num_digits1 - q4; + *nlp_bits_ret = r4; return num_digits2; } } @@ -1195,25 +1201,8 @@ integer_unpack_push_bits(int data, int n https://github.com/ruby/ruby/blob/trunk/bignum.c#L1201 } } -/* - * Import an integer into a buffer. - * - * [words] buffer to import. - * [numwords] the size of given buffer as number of words. - * [wordsize] the size of word as number of bytes. - * [nails] number of padding bits in a word. - * Most significant nails bits of each word are ignored. - * [flags] bitwise or of constants which name starts "INTEGER_PACK_". - * It specifies word order and byte order. - * [INTEGER_PACK_FORCE_BIGNUM] the result will be a Bignum - * even if it is representable as a Fixnum. - * [INTEGER_PACK_NEGATIVE] Returns non-positive value. - * (Returns non-negative value if not specified.) - * - * This function returns the imported integer as Fixnum or Bignum. - */ -VALUE -rb_integer_unpack(const void *words, size_t numwords, size_t wordsize, size_t nails, int flags) +static VALUE +rb_integer_unpack_internal(const void *words, size_t numwords, size_t wordsize, size_t nails, int flags, int *nlp_bits_ret) { VALUE result; const unsigned char *buf = words; @@ -1235,30 +1224,21 @@ rb_integer_unpack(const void *words, siz https://github.com/ruby/ruby/blob/trunk/bignum.c#L1224 BDIGIT_DBL dd; int numbits_in_dd; - validate_integer_pack_format(numwords, wordsize, nails, flags, - INTEGER_PACK_MSWORD_FIRST| - INTEGER_PACK_LSWORD_FIRST| - INTEGER_PACK_MSBYTE_FIRST| - INTEGER_PACK_LSBYTE_FIRST| - INTEGER_PACK_NATIVE_BYTE_ORDER| - INTEGER_PACK_FORCE_BIGNUM| - INTEGER_PACK_NEGATIVE); - if (numwords <= (SIZE_MAX - (SIZEOF_BDIGITS*CHAR_BIT-1)) / CHAR_BIT / wordsize) { - num_bdigits = integer_unpack_num_bdigits_small(numwords, wordsize, nails); + num_bdigits = integer_unpack_num_bdigits_small(numwords, wordsize, nails, nlp_bits_ret); #if 0 { - size_t num_bdigits1 = integer_unpack_num_bdigits_generic(numwords, wordsize, nails); + int nlp_bits1; + size_t num_bdigits1 = integer_unpack_num_bdigits_generic(numwords, wordsize, nails, &nlp_bits1); assert(num_bdigits == num_bdigits1); + assert(*nlp_bits_ret == nlp_bits1); } #endif } else { - num_bdigits = integer_unpack_num_bdigits_generic(numwords, wordsize, nails); + num_bdigits = integer_unpack_num_bdigits_generic(numwords, wordsize, nails, nlp_bits_ret); } if (num_bdigits == 0) { - if (flags & INTEGER_PACK_FORCE_BIGNUM) - return rb_int2big(0); return LONG2FIX(0); } if (LONG_MAX < num_bdigits) @@ -1305,12 +1285,119 @@ rb_integer_unpack(const void *words, siz https://github.com/ruby/ruby/blob/trunk/bignum.c#L1285 while (dp < de) *dp++ = 0; - if (flags & INTEGER_PACK_FORCE_BIGNUM) - return bigtrunc(result); - return bignorm(result); + return result; #undef PUSH_BITS } +/* + * Import an integer into a buffer. + * + * [words] buffer to import. + * [numwords] the size of given buffer as number of words. + * [wordsize] the size of word as number of bytes. + * [nails] number of padding bits in a word. + * Most significant nails bits of each word are ignored. + * [flags] bitwise or of constants which name starts "INTEGER_PACK_". + * It specifies word order and byte order. + * [INTEGER_PACK_FORCE_BIGNUM] the result will be a Bignum + * even if it is representable as a Fixnum. + * [INTEGER_PACK_NEGATIVE] Returns non-positive value. + * (Returns non-negative value if not specified.) + * + * This function returns the imported integer as Fixnum or Bignum. + */ +VALUE +rb_integer_unpack(const void *words, size_t numwords, size_t wordsize, size_t nails, int flags) +{ + int nlp_bits; + VALUE val; + + validate_integer_pack_format(numwords, wordsize, nails, flags, + INTEGER_PACK_MSWORD_FIRST| + INTEGER_PACK_LSWORD_FIRST| + INTEGER_PACK_MSBYTE_FIRST| + INTEGER_PACK_LSBYTE_FIRST| + INTEGER_PACK_NATIVE_BYTE_ORDER| + INTEGER_PACK_FORCE_BIGNUM| + INTEGER_PACK_NEGATIVE); + + val = rb_integer_unpack_internal(words, numwords, wordsize, nails, flags, &nlp_bits); + + if (val == LONG2FIX(0)) { + if (flags & INTEGER_PACK_FORCE_BIGNUM) + return rb_int2big(0); + return LONG2FIX(0); + } + if (flags & INTEGER_PACK_FORCE_BIGNUM) + return bigtrunc(val); + return bignorm(val); +} + +/* + * Import an integer into a buffer. + * + * [words] buffer to import. + * [numwords] the size of given buffer as number of words. + * [wordsize] the size of word as number of bytes. + * [nails] number of padding bits in a word. + * Most significant nails bits of each word are ignored. + * [flags] bitwise or of constants which name starts "INTEGER_PACK_". + * It specifies word order and byte order. + * [INTEGER_PACK_FORCE_BIGNUM] the result will be a Bignum + * even if it is representable as a Fixnum. + * [INTEGER_PACK_NEGATIVE] Assume the higher bits are 1. + * (If INTEGER_PACK_NEGATIVE is not specified, the higher bits are + * assumed same as the most significant bit. + * i.e. sign extension is applied.) + * + * This function returns the imported integer as Fixnum or Bignum. + */ +VALUE +rb_integer_unpack_2comp(const void *words, size_t numwords, size_t wordsize, size_t nails, int flags) +{ + VALUE val; + int nlp_bits; + + validate_integer_pack_format(numwords, wordsize, nails, flags, + INTEGER_PACK_MSWORD_FIRST| + INTEGER_PACK_LSWORD_FIRST| + INTEGER_PACK_MSBYTE_FIRST| + INTEGER_PACK_LSBYTE_FIRST| + INTEGER_PACK_NATIVE_BYTE_ORDER| + INTEGER_PACK_FORCE_BIGNUM| + INTEGER_PACK_NEGATIVE); + + val = rb_integer_unpack_internal(words, numwords, wordsize, nails, + (flags & (INTEGER_PACK_WORDORDER_MASK|INTEGER_PACK_BYTEORDER_MASK) | + INTEGER_PACK_FORCE_BIGNUM), + &nlp_bits); + + if (val == LONG2FIX(0)) { + /* num_bdigits == 0 i.e. num_bits == 0 */ + int v; + if (flags & INTEGER_PACK_NEGATIVE) + v = -1; + else + v = 0; + if (flags & INTEGER_PACK_FORCE_BIGNUM) + return rb_int2big(v); + else + return LONG2FIX(v); + } + else if ((flags & INTEGER_PACK_NEGATIVE) || + (RBIGNUM_LEN(val) != 0 && + (RBIGNUM_DIGITS(val)[RBIGNUM_LEN(val)-1] >> (BITSPERDIG - nlp_bits - 1)))) { + if (nlp_bits) + RBIGNUM_DIGITS(val)[RBIGNUM_LEN(val)-1] |= (~(BDIGIT)0) << (BITSPERDIG - nlp_bits); + rb_big_2comp(val); + RBIGNUM_SET_SIGN(val, 0); + } + + if (flags & INTEGER_PACK_FORCE_BIGNUM) + return bigtrunc(val); + return bignorm(val); +} + #define QUAD_SIZE 8 #if SIZEOF_LONG_LONG == QUAD_SIZE && SIZEOF_BDIGITS*2 == SIZEOF_LONG_LONG Index: test/-ext-/bignum/test_pack.rb =================================================================== --- test/-ext-/bignum/test_pack.rb (revision 41263) +++ test/-ext-/bignum/test_pack.rb (revision 41264) @@ -162,5 +162,36 @@ class TestBignum < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/-ext-/bignum/test_pack.rb#L162 assert_equal(-0x8070605040302010, Integer.test_unpack("\x80\x70\x60\x50\x40\x30\x20\x10", 8, 1, 0, BIG_ENDIAN|NEGATIVE)) end + def test_unpack2comp_single_byte + assert_equal(-128, Integer.test_unpack_2comp("\x80", 1, 1, 0, BIG_ENDIAN)) + assert_equal( -2, Integer.test_unpack_2comp("\xFE", 1, 1, 0, BIG_ENDIAN)) + assert_equal( -1, Integer.test_unpack_2comp("\xFF", 1, 1, 0, BIG_ENDIAN)) + assert_equal( 0, Integer.test_unpack_2comp("\x00", 1, 1, 0, BIG_ENDIAN)) + assert_equal( 1, Integer.test_unpack_2comp("\x01", 1, 1, 0, BIG_ENDIAN)) + assert_equal( 2, Integer.test_unpack_2comp("\x02", 1, 1, 0, BIG_ENDIAN)) + assert_equal( 127, Integer.test_unpack_2comp("\x7F", 1, 1, 0, BIG_ENDIAN)) + end + + def test_unpack2comp_sequence_of_ff + assert_equal(-1, Integer.test_unpack_2comp("\xFF"*2, 2, 1, 0, BIG_ENDIAN)) + assert_equal(-1, Integer.test_unpack_2comp("\xFF"*3, 3, 1, 0, BIG_ENDIAN)) + assert_equal(-1, Integer.test_unpack_2comp("\xFF"*4, 4, 1, 0, BIG_ENDIAN)) + assert_equal(-1, Integer.test_unpack_2comp("\xFF"*5, 5, 1, 0, BIG_ENDIAN)) + assert_equal(-1, Integer.test_unpack_2comp("\xFF"*6, 6, 1, 0, BIG_ENDIAN)) + assert_equal(-1, Integer.test_unpack_2comp("\xFF"*7, 7, 1, 0, BIG_ENDIAN)) + assert_equal(-1, Integer.test_unpack_2comp("\xFF"*8, 8, 1, 0, BIG_ENDIAN)) + assert_equal(-1, Integer.test_unpack_2comp("\xFF"*9, 9, 1, 0, BIG_ENDIAN)) + end + + def test_unpack2comp_negative_single_byte + assert_equal(-256, Integer.test_unpack_2comp("\x00", 1, 1, 0, BIG_ENDIAN|NEGATIVE)) + assert_equal(-255, Integer.test_unpack_2comp("\x01", 1, 1, 0, BIG_ENDIAN|NEGATIVE)) + assert_equal(-254, Integer.test_unpack_2comp("\x02", 1, 1, 0, BIG_ENDIAN|NEGATIVE)) + assert_equal(-129, Integer.test_unpack_2comp("\x7F", 1, 1, 0, BIG_ENDIAN|NEGATIVE)) + assert_equal(-128, Integer.test_unpack_2comp("\x80", 1, 1, 0, BIG_ENDIAN|NEGATIVE)) + assert_equal( -2, Integer.test_unpack_2comp("\xFE", 1, 1, 0, BIG_ENDIAN|NEGATIVE)) + assert_equal( -1, Integer.test_unpack_2comp("\xFF", 1, 1, 0, BIG_ENDIAN|NEGATIVE)) + end + end end -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/