merge revision(s) 27721:27725,27738:27740:

* pack.c: backport integer pack/unpack from 1.9 for [ruby-core:21937].
	* configure.in: backport RUBY_DEFINT and fixed size integer checks.
	* ruby.h: include stdint.h if available.
	* bignum.c (rb_big_pack): defined..
	  (rb_big_unpack): defined.
	* intern.h (rb_big_pack): declared.
	  (rb_big_unpack): declared.
	* pack.c (pack_pack): call rb_quad_pack to preserve RangeError.


git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_1_8_7@28220 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
shyouhei 2010-06-08 08:42:55 +00:00
parent 8c788b8a43
commit 98e7a2abca
8 changed files with 973 additions and 490 deletions

View file

@ -1,3 +1,21 @@
Tue Jun 8 17:32:37 2010 Tanaka Akira <akr@fsij.org>
* pack.c (pack_pack): call rb_quad_pack to preserve RangeError.
Tue Jun 8 17:32:37 2010 Tanaka Akira <akr@fsij.org>
* pack.c: backport integer pack/unpack from 1.9 for [ruby-core:21937].
* configure.in: backport RUBY_DEFINT and fixed size integer checks.
* ruby.h: include stdint.h if available.
* bignum.c (rb_big_pack): defined..
(rb_big_unpack): defined.
* intern.h (rb_big_pack): declared.
(rb_big_unpack): declared.
Tue Jun 8 16:52:35 2010 Nobuyoshi Nakada <nobu@ruby-lang.org>
* regex.c (read_special): get rid of overrun.

133
bignum.c
View file

@ -222,7 +222,110 @@ rb_int2inum(n)
return rb_int2big(n);
}
#ifdef HAVE_LONG_LONG
#if SIZEOF_LONG % SIZEOF_BDIGITS != 0
# error unexpected SIZEOF_LONG : SIZEOF_BDIGITS ratio
#endif
/*
* buf is an array of long integers.
* buf is ordered from least significant word to most significant word.
* buf[0] is the least significant word and
* buf[num_longs-1] is the most significant word.
* This means words in buf is little endian.
* However each word in buf is native endian.
* (buf[i]&1) is the least significant bit and
* (buf[i]&(1<<(SIZEOF_LONG*CHAR_BIT-1))) is the most significant bit
* for each 0 <= i < num_longs.
* So buf is little endian at whole on a little endian machine.
* But buf is mixed endian on a big endian machine.
*/
void
rb_big_pack(VALUE val, unsigned long *buf, long num_longs)
{
val = rb_to_int(val);
if (num_longs == 0)
return;
if (FIXNUM_P(val)) {
long i;
long tmp = FIX2LONG(val);
buf[0] = (unsigned long)tmp;
tmp = tmp < 0 ? ~0L : 0;
for (i = 1; i < num_longs; i++)
buf[i] = (unsigned long)tmp;
return;
}
else {
long len = RBIGNUM_LEN(val);
BDIGIT *ds = BDIGITS(val), *dend = ds + len;
long i, j;
for (i = 0; i < num_longs && ds < dend; i++) {
unsigned long l = 0;
for (j = 0; j < DIGSPERLONG && ds < dend; j++, ds++) {
l |= ((unsigned long)*ds << (j * BITSPERDIG));
}
buf[i] = l;
}
for (; i < num_longs; i++)
buf[i] = 0;
if (RBIGNUM_NEGATIVE_P(val)) {
for (i = 0; i < num_longs; i++) {
buf[i] = ~buf[i];
}
for (i = 0; i < num_longs; i++) {
buf[i]++;
if (buf[i] != 0)
return;
}
}
}
}
/* See rb_big_pack comment for endianness of buf. */
VALUE
rb_big_unpack(unsigned long *buf, long num_longs)
{
while (2 <= num_longs) {
if (buf[num_longs-1] == 0 && (long)buf[num_longs-2] >= 0)
num_longs--;
else if (buf[num_longs-1] == ~0UL && (long)buf[num_longs-2] < 0)
num_longs--;
else
break;
}
if (num_longs == 0)
return INT2FIX(0);
else if (num_longs == 1)
return LONG2NUM((long)buf[0]);
else {
VALUE big;
BDIGIT *ds;
long len = num_longs * DIGSPERLONG;
long i;
big = bignew(len, 1);
ds = BDIGITS(big);
for (i = 0; i < num_longs; i++) {
unsigned long d = buf[i];
#if SIZEOF_LONG == SIZEOF_BDIGITS
*ds++ = d;
#else
int j;
for (j = 0; j < DIGSPERLONG; j++) {
*ds++ = BIGLO(d);
d = BIGDN(d);
}
#endif
}
if ((long)buf[num_longs-1] < 0) {
get2comp(big);
RBIGNUM_SET_SIGN(big, 0);
}
return bignorm(big);
}
}
#define QUAD_SIZE 8
#if SIZEOF_LONG_LONG == QUAD_SIZE && SIZEOF_BDIGITS*2 == SIZEOF_LONG_LONG
void
rb_quad_pack(buf, val)
@ -295,7 +398,19 @@ rb_quad_unpack(buf, sign)
#else
#define QUAD_SIZE 8
static int
quad_buf_complement(char *buf, size_t len)
{
size_t i;
for (i = 0; i < len; i++)
buf[i] = ~buf[i];
for (i = 0; i < len; i++) {
buf[i]++;
if (buf[i] != 0)
return 0;
}
return 1;
}
void
rb_quad_pack(buf, val)
@ -314,12 +429,8 @@ rb_quad_pack(buf, val)
rb_raise(rb_eRangeError, "bignum too big to convert into `quad int'");
}
memcpy(buf, (char*)BDIGITS(val), len);
if (!RBIGNUM(val)->sign) {
len = QUAD_SIZE;
while (len--) {
*buf = ~*buf;
buf++;
}
if (RBIGNUM_NEGATIVE_P(val)) {
quad_buf_complement(buf, QUAD_SIZE);
}
}
@ -334,14 +445,10 @@ rb_quad_unpack(buf, sign)
memcpy((char*)BDIGITS(big), buf, QUAD_SIZE);
if (sign && BNEG(buf)) {
long len = QUAD_SIZE;
char *tmp = (char*)BDIGITS(big);
RBIGNUM(big)->sign = 0;
while (len--) {
*tmp = ~*tmp;
tmp++;
}
quad_buf_complement(tmp, QUAD_SIZE);
}
return bignorm(big);

View file

@ -544,6 +544,43 @@ AC_STRUCT_ST_BLKSIZE
AC_STRUCT_ST_BLOCKS
AC_STRUCT_ST_RDEV
dnl RUBY_DEFINT TYPENAME, SIZE, [SIGNED-OR-UNSIGNED], [INCLUDES = DEFAULT-INCLUDES]
AC_DEFUN([RUBY_DEFINT], [dnl
AC_CACHE_CHECK([for $1], [rb_cv_type_$1],
[AC_COMPILE_IFELSE([AC_LANG_PROGRAM([AC_INCLUDES_DEFAULT([$4])
typedef $1 t; int s = sizeof(t) == 42;])],
[rb_cv_type_$1=yes],
[AS_CASE([m4_bmatch([$2], [^[1-9][0-9]*$], $2, [$ac_cv_sizeof_]AS_TR_SH($2))],
["1"], [ rb_cv_type_$1="m4_if([$3], [], [signed ], [$3 ])char"],
["$ac_cv_sizeof_short"], [ rb_cv_type_$1="m4_if([$3], [], [], [$3 ])short"],
["$ac_cv_sizeof_int"], [ rb_cv_type_$1="m4_if([$3], [], [], [$3 ])int"],
["$ac_cv_sizeof_long"], [ rb_cv_type_$1="m4_if([$3], [], [], [$3 ])long"],
["$ac_cv_sizeof_long_long"], [ rb_cv_type_$1="m4_if([$3], [], [], [$3 ])long long"],
["$ac_cv_sizeof___int64"], [ rb_cv_type_$1="m4_if([$3], [], [], [$3 ])__int64"],
[ rb_cv_type_$1=no])])])
if test "${rb_cv_type_$1}" != no; then
AC_DEFINE([HAVE_]AS_TR_CPP($1), 1)
if test "${rb_cv_type_$1}" = yes; then
m4_bmatch([$2], [^[1-9][0-9]*$], [AC_CHECK_SIZEOF([$1], 0, [AC_INCLUDES_DEFAULT([$4])])],
[RUBY_CHECK_SIZEOF([$1], [$2], [], [AC_INCLUDES_DEFAULT([$4])])])
else
AC_DEFINE_UNQUOTED($1, [$rb_cv_type_$1])
AC_DEFINE_UNQUOTED([SIZEOF_]AS_TR_CPP($1), [SIZEOF_]AS_TR_CPP([$rb_cv_type_$1]))
fi
fi
])
RUBY_DEFINT(int8_t, 1)
RUBY_DEFINT(uint8_t, 1, unsigned)
RUBY_DEFINT(int16_t, 2)
RUBY_DEFINT(uint16_t, 2, unsigned)
RUBY_DEFINT(int32_t, 4)
RUBY_DEFINT(uint32_t, 4, unsigned)
RUBY_DEFINT(int64_t, 8)
RUBY_DEFINT(uint64_t, 8, unsigned)
RUBY_DEFINT(int128_t, 16)
RUBY_DEFINT(uint128_t, 16, unsigned)
dnl Checks for library functions.
AC_TYPE_GETGROUPS
AC_TYPE_SIGNAL

View file

@ -83,6 +83,8 @@ unsigned LONG_LONG rb_big2ull _((VALUE));
#endif /* HAVE_LONG_LONG */
void rb_quad_pack _((char*,VALUE));
VALUE rb_quad_unpack _((const char*,int));
void rb_big_pack(VALUE val, unsigned long *buf, long num_longs);
VALUE rb_big_unpack(unsigned long *buf, long num_longs);
VALUE rb_dbl2big _((double));
double rb_big2dbl _((VALUE));
VALUE rb_big_plus _((VALUE, VALUE));

1046
pack.c

File diff suppressed because it is too large Load diff

4
ruby.h
View file

@ -50,6 +50,10 @@ extern "C" {
# include <intrinsics.h>
#endif
#ifdef HAVE_STDINT_H
# include <stdint.h>
#endif
#include <stddef.h>
#include <stdio.h>

View file

@ -20,6 +20,31 @@ class TestPack < Test::Unit::TestCase
assert_equal($x, $x.pack("l").unpack("l"))
end
def test_pack_n
assert_equal "\000\000", [0].pack('n')
assert_equal "\000\001", [1].pack('n')
assert_equal "\000\002", [2].pack('n')
assert_equal "\000\003", [3].pack('n')
assert_equal "\377\376", [65534].pack('n')
assert_equal "\377\377", [65535].pack('n')
assert_equal "\200\000", [2**15].pack('n')
assert_equal "\177\377", [-2**15-1].pack('n')
assert_equal "\377\377", [-1].pack('n')
assert_equal "\000\001\000\001", [1,1].pack('n*')
assert_equal "\000\001\000\001\000\001", [1,1,1].pack('n*')
end
def test_unpack_n
assert_equal 1, "\000\001".unpack('n')[0]
assert_equal 2, "\000\002".unpack('n')[0]
assert_equal 3, "\000\003".unpack('n')[0]
assert_equal 65535, "\377\377".unpack('n')[0]
assert_equal [1,1], "\000\001\000\001".unpack('n*')
assert_equal [1,1,1], "\000\001\000\001\000\001".unpack('n*')
end
def test_pack_N
assert_equal "\000\000\000\000", [0].pack('N')
assert_equal "\000\000\000\001", [1].pack('N')
@ -40,22 +65,206 @@ class TestPack < Test::Unit::TestCase
assert_equal 1, "\000\000\000\001".unpack('N')[0]
assert_equal 2, "\000\000\000\002".unpack('N')[0]
assert_equal 3, "\000\000\000\003".unpack('N')[0]
assert_equal 3, "\000\000\000\003".unpack('N')[0]
assert_equal 4294967295, "\377\377\377\377".unpack('N')[0]
assert_equal [1,1], "\000\000\000\001\000\000\000\001".unpack('N*')
assert_equal [1,1,1], "\000\000\000\001\000\000\000\001\000\000\000\001".unpack('N*')
end
def test_integer_endian
s = [1].pack("s")
assert_operator(["\0\1", "\1\0"], :include?, s)
if s == "\0\1"
# big endian
assert_equal("\x01\x02", [0x0102].pack("s"))
assert_equal("\x01\x02", [0x0102].pack("S"))
assert_equal("\x01\x02\x03\x04", [0x01020304].pack("l"))
assert_equal("\x01\x02\x03\x04", [0x01020304].pack("L"))
assert_equal("\x01\x02\x03\x04\x05\x06\x07\x08", [0x0102030405060708].pack("q"))
assert_equal("\x01\x02\x03\x04\x05\x06\x07\x08", [0x0102030405060708].pack("Q"))
assert_match(/\A\x00*\x01\x02\z/, [0x0102].pack("s!"))
assert_match(/\A\x00*\x01\x02\z/, [0x0102].pack("S!"))
assert_match(/\A\x00*\x01\x02\x03\x04\z/, [0x01020304].pack("i"))
assert_match(/\A\x00*\x01\x02\x03\x04\z/, [0x01020304].pack("I"))
assert_match(/\A\x00*\x01\x02\x03\x04\z/, [0x01020304].pack("i!"))
assert_match(/\A\x00*\x01\x02\x03\x04\z/, [0x01020304].pack("I!"))
assert_match(/\A\x00*\x01\x02\x03\x04\z/, [0x01020304].pack("l!"))
assert_match(/\A\x00*\x01\x02\x03\x04\z/, [0x01020304].pack("L!"))
%w[s S l L q Q s! S! i I i! I! l! L!].each {|fmt|
nuls = [0].pack(fmt)
v = 0
s = ""
nuls.bytesize.times {|i|
j = i + 40
v = v * 256 + j
s << [j].pack("C")
}
assert_equal(s, [v].pack(fmt), "[#{v}].pack(#{fmt.dump})")
assert_equal([v], s.unpack(fmt), "#{s.dump}.unpack(#{fmt.dump})")
s2 = s+s
fmt2 = fmt+"*"
assert_equal([v,v], s2.unpack(fmt2), "#{s2.dump}.unpack(#{fmt2.dump})")
}
else
# little endian
assert_equal("\x02\x01", [0x0102].pack("s"))
assert_equal("\x02\x01", [0x0102].pack("S"))
assert_equal("\x04\x03\x02\x01", [0x01020304].pack("l"))
assert_equal("\x04\x03\x02\x01", [0x01020304].pack("L"))
assert_equal("\x08\x07\x06\x05\x04\x03\x02\x01", [0x0102030405060708].pack("q"))
assert_equal("\x08\x07\x06\x05\x04\x03\x02\x01", [0x0102030405060708].pack("Q"))
assert_match(/\A\x02\x01\x00*\z/, [0x0102].pack("s!"))
assert_match(/\A\x02\x01\x00*\z/, [0x0102].pack("S!"))
assert_match(/\A\x04\x03\x02\x01\x00*\z/, [0x01020304].pack("i"))
assert_match(/\A\x04\x03\x02\x01\x00*\z/, [0x01020304].pack("I"))
assert_match(/\A\x04\x03\x02\x01\x00*\z/, [0x01020304].pack("i!"))
assert_match(/\A\x04\x03\x02\x01\x00*\z/, [0x01020304].pack("I!"))
assert_match(/\A\x04\x03\x02\x01\x00*\z/, [0x01020304].pack("l!"))
assert_match(/\A\x04\x03\x02\x01\x00*\z/, [0x01020304].pack("L!"))
%w[s S l L q Q s! S! i I i! I! l! L!].each {|fmt|
nuls = [0].pack(fmt)
v = 0
s = ""
nuls.bytesize.times {|i|
j = i+40
v = v * 256 + j
s << [j].pack("C")
}
s.reverse!
assert_equal(s, [v].pack(fmt), "[#{v}].pack(#{fmt.dump})")
assert_equal([v], s.unpack(fmt), "#{s.dump}.unpack(#{fmt.dump})")
s2 = s+s
fmt2 = fmt+"*"
assert_equal([v,v], s2.unpack(fmt2), "#{s2.dump}.unpack(#{fmt2.dump})")
}
end
end
def test_pack_U
assert_raises(RangeError) { [-0x40000001].pack("U") }
assert_raises(RangeError) { [-0x40000000].pack("U") }
assert_raises(RangeError) { [-1].pack("U") }
assert_raise(RangeError) { [-0x40000001].pack("U") }
assert_raise(RangeError) { [-0x40000000].pack("U") }
assert_raise(RangeError) { [-1].pack("U") }
assert_equal "\000", [0].pack("U")
assert_equal "\374\277\277\277\277\277", [0x3fffffff].pack("U")
assert_equal "\375\200\200\200\200\200", [0x40000000].pack("U")
assert_equal "\375\277\277\277\277\277", [0x7fffffff].pack("U")
assert_raises(RangeError) { [0x80000000].pack("U") }
assert_raises(RangeError) { [0x100000000].pack("U") }
assert_raise(RangeError) { [0x80000000].pack("U") }
assert_raise(RangeError) { [0x100000000].pack("U") }
end
def test_pack_P
a = ["abc"]
assert_equal a, a.pack("P").unpack("P*")
assert_equal "a", a.pack("P").unpack("P")[0]
assert_equal a, a.pack("P").freeze.unpack("P*")
assert_raise(ArgumentError) { (a.pack("P") + "").unpack("P*") }
end
def test_pack_p
a = ["abc"]
assert_equal a, a.pack("p").unpack("p*")
assert_equal a[0], a.pack("p").unpack("p")[0]
assert_equal a, a.pack("p").freeze.unpack("p*")
assert_raise(ArgumentError) { (a.pack("p") + "").unpack("p*") }
end
def test_format_string_modified
fmt = "CC"
o = Object.new
class << o; self; end.class_eval do
define_method(:to_int) { fmt.replace ""; 0 }
end
assert_raise(RuntimeError) do
[o, o].pack(fmt)
end
end
def test_comment
assert_equal("\0\1", [0,1].pack(" C #foo \n C "))
assert_equal([0,1], "\0\1".unpack(" C #foo \n C "))
end
def test_illegal_bang
assert_raise(ArgumentError) { [].pack("a!") }
assert_raise(ArgumentError) { "".unpack("a!") }
end
def test_pack_unpack_aA
assert_equal("f", ["foo"].pack("A"))
assert_equal("f", ["foo"].pack("a"))
assert_equal("foo", ["foo"].pack("A*"))
assert_equal("foo", ["foo"].pack("a*"))
assert_equal("fo", ["foo"].pack("A2"))
assert_equal("fo", ["foo"].pack("a2"))
assert_equal("foo ", ["foo"].pack("A4"))
assert_equal("foo\0", ["foo"].pack("a4"))
assert_equal(" ", [nil].pack("A"))
assert_equal("\0", [nil].pack("a"))
assert_equal("", [nil].pack("A*"))
assert_equal("", [nil].pack("a*"))
assert_equal(" ", [nil].pack("A2"))
assert_equal("\0\0", [nil].pack("a2"))
assert_equal("foo" + "\0" * 27, ["foo"].pack("a30"))
assert_equal(["f"], "foo\0".unpack("A"))
assert_equal(["f"], "foo\0".unpack("a"))
assert_equal(["foo"], "foo\0".unpack("A4"))
assert_equal(["foo\0"], "foo\0".unpack("a4"))
assert_equal(["foo"], "foo ".unpack("A4"))
assert_equal(["foo "], "foo ".unpack("a4"))
assert_equal(["foo"], "foo".unpack("A4"))
assert_equal(["foo"], "foo".unpack("a4"))
end
def test_pack_unpack_Z
assert_equal("f", ["foo"].pack("Z"))
assert_equal("foo\0", ["foo"].pack("Z*"))
assert_equal("fo", ["foo"].pack("Z2"))
assert_equal("foo\0\0", ["foo"].pack("Z5"))
assert_equal("\0", [nil].pack("Z"))
assert_equal("\0", [nil].pack("Z*"))
assert_equal("\0\0", [nil].pack("Z2"))
assert_equal(["f"], "foo\0".unpack("Z"))
assert_equal(["foo"], "foo".unpack("Z*"))
assert_equal(["foo"], "foo\0".unpack("Z*"))
assert_equal(["foo"], "foo".unpack("Z5"))
end
def test_pack_unpack_bB
assert_equal("\xff\x00", ["1111111100000000"].pack("b*"))
assert_equal("\x01\x02", ["1000000001000000"].pack("b*"))
assert_equal("", ["1"].pack("b0"))
assert_equal("\x01", ["1"].pack("b1"))
assert_equal("\x01\x00", ["1"].pack("b2"))
assert_equal("\x01\x00", ["1"].pack("b3"))
assert_equal("\x01\x00\x00", ["1"].pack("b4"))
assert_equal("\x01\x00\x00", ["1"].pack("b5"))
assert_equal("\x01\x00\x00\x00", ["1"].pack("b6"))
assert_equal("\xff\x00", ["1111111100000000"].pack("B*"))
assert_equal("\x01\x02", ["0000000100000010"].pack("B*"))
assert_equal("", ["1"].pack("B0"))
assert_equal("\x80", ["1"].pack("B1"))
assert_equal("\x80\x00", ["1"].pack("B2"))
assert_equal("\x80\x00", ["1"].pack("B3"))
assert_equal("\x80\x00\x00", ["1"].pack("B4"))
assert_equal("\x80\x00\x00", ["1"].pack("B5"))
assert_equal("\x80\x00\x00\x00", ["1"].pack("B6"))
assert_equal(["1111111100000000"], "\xff\x00".unpack("b*"))
assert_equal(["1000000001000000"], "\x01\x02".unpack("b*"))
assert_equal([""], "".unpack("b0"))
assert_equal(["1"], "\x01".unpack("b1"))
assert_equal(["10"], "\x01".unpack("b2"))
assert_equal(["100"], "\x01".unpack("b3"))
assert_equal(["1111111100000000"], "\xff\x00".unpack("B*"))
assert_equal(["0000000100000010"], "\x01\x02".unpack("B*"))
assert_equal([""], "".unpack("B0"))
assert_equal(["1"], "\x80".unpack("B1"))
assert_equal(["10"], "\x80".unpack("B2"))
assert_equal(["100"], "\x80".unpack("B3"))
end
def test_pack_unpack_hH

View file

@ -2,7 +2,7 @@
#define RUBY_RELEASE_DATE "2010-06-08"
#define RUBY_VERSION_CODE 187
#define RUBY_RELEASE_CODE 20100608
#define RUBY_PATCHLEVEL 284
#define RUBY_PATCHLEVEL 285
#define RUBY_VERSION_MAJOR 1
#define RUBY_VERSION_MINOR 8