зеркало из https://github.com/github/ruby.git
* bignum.c (rb_int_import): New function.
(int_import_push_bits): Ditto. * internal.h (rb_int_import): Declared. * pack.c (pack_unpack): Use rb_int_import for BER compressed integer. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@41111 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
Родитель
64ed7df543
Коммит
c9c67d2fe0
|
@ -1,3 +1,12 @@
|
|||
Fri Jun 7 06:15:31 2013 Tanaka Akira <akr@fsij.org>
|
||||
|
||||
* bignum.c (rb_int_import): New function.
|
||||
(int_import_push_bits): Ditto.
|
||||
|
||||
* internal.h (rb_int_import): Declared.
|
||||
|
||||
* pack.c (pack_unpack): Use rb_int_import for BER compressed integer.
|
||||
|
||||
Thu Jun 6 22:24:00 2013 Kenta Murata <mrkn@mrkn.jp>
|
||||
|
||||
* numeric.c (num_quo): Use to_r method to convert the receiver to
|
||||
|
|
155
bignum.c
155
bignum.c
|
@ -607,7 +607,7 @@ rb_int_export(VALUE val, int *signp, void *bufarg, size_t *countp, int wordorder
|
|||
#ifdef WORDS_BIGENDIAN
|
||||
endian = 1;
|
||||
#else
|
||||
endian = 0;
|
||||
endian = -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -770,6 +770,159 @@ rb_int_export(VALUE val, int *signp, void *bufarg, size_t *countp, int wordorder
|
|||
#undef TAKE_LOWBITS
|
||||
}
|
||||
|
||||
static inline void
|
||||
int_import_push_bits(int data, int numbits, BDIGIT_DBL *ddp, int *numbits_in_dd_p, BDIGIT **dpp)
|
||||
{
|
||||
(*ddp) |= ((BDIGIT_DBL)data) << (*numbits_in_dd_p);
|
||||
*numbits_in_dd_p += numbits;
|
||||
while (SIZEOF_BDIGITS*CHAR_BIT <= *numbits_in_dd_p) {
|
||||
*(*dpp)++ = (*ddp) & (((BDIGIT_DBL)1 << (SIZEOF_BDIGITS*CHAR_BIT))-1);
|
||||
*ddp >>= SIZEOF_BDIGITS*CHAR_BIT;
|
||||
*numbits_in_dd_p -= SIZEOF_BDIGITS*CHAR_BIT;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Import an integer into a buffer.
|
||||
*
|
||||
* [sign] signedness of the value.
|
||||
* -1 for non-positive. 0 or 1 for non-negative.
|
||||
* [bufarg] buffer to import.
|
||||
* [wordcount] the size of given buffer as number of words.
|
||||
* [wordorder] order of words: 1 for most significant word first. -1 for least significant word first.
|
||||
* [wordsize] the size of word as number of bytes.
|
||||
* [endian] order of bytes in a word: 1 for most significant byte first. -1 for least significant byte first. 0 for native endian.
|
||||
* [nails] number of padding bits in a word. Most significant nails bits of each word are filled by zero.
|
||||
*
|
||||
* This function returns the imported integer as Fixnum or Bignum.
|
||||
*/
|
||||
VALUE
|
||||
rb_int_import(int sign, const void *bufarg, size_t wordcount, int wordorder, size_t wordsize, int endian, size_t nails)
|
||||
{
|
||||
VALUE num_bits, num_bdigits;
|
||||
VALUE result;
|
||||
const unsigned char *buf = bufarg;
|
||||
|
||||
BDIGIT *dp;
|
||||
BDIGIT *de;
|
||||
|
||||
int word_num_partialbits;
|
||||
size_t word_num_fullbytes;
|
||||
|
||||
ssize_t word_step;
|
||||
size_t byte_start;
|
||||
int byte_step;
|
||||
|
||||
const unsigned char *bytep, *wordp, *last_wordp;
|
||||
size_t index_in_word;
|
||||
BDIGIT_DBL dd;
|
||||
int numbits_in_dd;
|
||||
|
||||
if (sign != 1 && sign != 0 && sign != -1)
|
||||
rb_raise(rb_eArgError, "unexpected sign: %d", sign);
|
||||
if (wordorder != 1 && wordorder != -1)
|
||||
rb_raise(rb_eArgError, "unexpected wordorder: %d", wordorder);
|
||||
if (endian != 1 && endian != -1 && endian != 0)
|
||||
rb_raise(rb_eArgError, "unexpected endian: %d", endian);
|
||||
if (wordsize == 0)
|
||||
rb_raise(rb_eArgError, "invalid wordsize: %"PRI_SIZE_PREFIX"u", wordsize);
|
||||
if (SSIZE_MAX < wordsize)
|
||||
rb_raise(rb_eArgError, "too big wordsize: %"PRI_SIZE_PREFIX"u", wordsize);
|
||||
if (SIZE_MAX / wordsize < wordcount)
|
||||
rb_raise(rb_eArgError, "too big wordcount * wordsize: %"PRI_SIZE_PREFIX"u * %"PRI_SIZE_PREFIX"u", wordcount, wordsize);
|
||||
if (wordsize <= nails / CHAR_BIT)
|
||||
rb_raise(rb_eArgError, "too big nails: %"PRI_SIZE_PREFIX"u", nails);
|
||||
|
||||
if (endian == 0) {
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
endian = 1;
|
||||
#else
|
||||
endian = -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* num_bits = (wordsize * CHAR_BIT - nails) * count
|
||||
* num_bdigits = (num_bits + SIZEOF_BDIGITS*CHAR_BIT - 1) / (SIZEOF_BDIGITS*CHAR_BIT)
|
||||
*/
|
||||
num_bits = SIZE2NUM(wordsize);
|
||||
num_bits = rb_funcall(num_bits, '*', 1, LONG2FIX(CHAR_BIT));
|
||||
num_bits = rb_funcall(num_bits, '-', 1, SIZE2NUM(nails));
|
||||
num_bits = rb_funcall(num_bits, '*', 1, SIZE2NUM(wordcount));
|
||||
|
||||
if (num_bits == LONG2FIX(0))
|
||||
return LONG2FIX(0);
|
||||
|
||||
num_bdigits = rb_funcall(num_bits, '+', 1, LONG2FIX(SIZEOF_BDIGITS*CHAR_BIT-1));
|
||||
num_bdigits = rb_funcall(num_bdigits, '/', 1, LONG2FIX(SIZEOF_BDIGITS*CHAR_BIT));
|
||||
|
||||
result = bignew(NUM2LONG(num_bdigits), 0 <= sign);
|
||||
|
||||
dp = BDIGITS(result);
|
||||
de = dp + RBIGNUM_LEN(result);
|
||||
|
||||
word_num_partialbits = CHAR_BIT - (int)(nails % CHAR_BIT);
|
||||
if (word_num_partialbits == CHAR_BIT)
|
||||
word_num_partialbits = 0;
|
||||
word_num_fullbytes = wordsize - (nails / CHAR_BIT);
|
||||
if (word_num_partialbits != 0) {
|
||||
word_num_fullbytes--;
|
||||
}
|
||||
|
||||
if (wordorder == 1) {
|
||||
word_step = -(ssize_t)wordsize;
|
||||
wordp = buf + wordsize*(wordcount-1);
|
||||
last_wordp = buf;
|
||||
}
|
||||
else {
|
||||
word_step = wordsize;
|
||||
wordp = buf;
|
||||
last_wordp = buf + wordsize*(wordcount-1);
|
||||
}
|
||||
|
||||
if (endian == 1) {
|
||||
byte_step = -1;
|
||||
byte_start = wordsize-1;
|
||||
}
|
||||
else {
|
||||
byte_step = 1;
|
||||
byte_start = 0;
|
||||
}
|
||||
|
||||
dd = 0;
|
||||
numbits_in_dd = 0;
|
||||
|
||||
#define PUSH_BITS(data, numbits) \
|
||||
int_import_push_bits(data, numbits, &dd, &numbits_in_dd, &dp)
|
||||
|
||||
while (1) {
|
||||
index_in_word = 0;
|
||||
bytep = wordp + byte_start;
|
||||
while (index_in_word < word_num_fullbytes) {
|
||||
PUSH_BITS(*bytep, CHAR_BIT);
|
||||
bytep += byte_step;
|
||||
index_in_word++;
|
||||
}
|
||||
if (word_num_partialbits) {
|
||||
PUSH_BITS(*bytep & ((1 << word_num_partialbits) - 1), word_num_partialbits);
|
||||
bytep += byte_step;
|
||||
index_in_word++;
|
||||
}
|
||||
|
||||
if (wordp == last_wordp)
|
||||
break;
|
||||
|
||||
wordp += word_step;
|
||||
}
|
||||
if (dd)
|
||||
*dp++ = dd;
|
||||
while (dp < de)
|
||||
*dp++ = 0;
|
||||
|
||||
return bignorm(result);
|
||||
#undef PUSH_BITS
|
||||
}
|
||||
|
||||
#define QUAD_SIZE 8
|
||||
|
||||
#if SIZEOF_LONG_LONG == QUAD_SIZE && SIZEOF_BDIGITS*2 == SIZEOF_LONG_LONG
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
$(OBJS): $(HDRS) $(ruby_headers)
|
||||
|
||||
export.o: export.c $(top_srcdir)/internal.h
|
||||
import.o: import.c $(top_srcdir)/internal.h
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
#include "ruby.h"
|
||||
#include "internal.h"
|
||||
|
||||
static VALUE
|
||||
rb_int_import_m(VALUE klass, VALUE sign, VALUE buf, VALUE wordcount, VALUE wordorder, VALUE wordsize, VALUE endian, VALUE nails)
|
||||
{
|
||||
StringValue(buf);
|
||||
|
||||
return rb_int_import(NUM2INT(sign), RSTRING_PTR(buf),
|
||||
NUM2SIZE(wordcount), NUM2INT(wordorder), NUM2SIZE(wordsize),
|
||||
NUM2INT(endian), NUM2SIZE(nails));
|
||||
}
|
||||
|
||||
void
|
||||
Init_import(VALUE klass)
|
||||
{
|
||||
rb_define_singleton_method(rb_cInteger, "test_import", rb_int_import_m, 7);
|
||||
}
|
|
@ -427,6 +427,7 @@ VALUE rb_thread_io_blocking_region(rb_blocking_function_t *func, void *data1, in
|
|||
|
||||
/* bignum.c */
|
||||
void *rb_int_export(VALUE val, int *signp, void *bufarg, size_t *countp, int wordorder, size_t wordsize, int endian, size_t nails);
|
||||
VALUE rb_int_import(int sign, const void *bufarg, size_t wordcount, int wordorder, size_t wordsize, int endian, size_t nails);
|
||||
|
||||
/* io.c */
|
||||
void rb_maygvl_fd_fix_cloexec(int fd);
|
||||
|
|
38
pack.c
38
pack.c
|
@ -2137,32 +2137,18 @@ pack_unpack(VALUE str, VALUE fmt)
|
|||
|
||||
case 'w':
|
||||
{
|
||||
unsigned long ul = 0;
|
||||
unsigned long ulmask = 0xfeUL << ((sizeof(unsigned long) - 1) * 8);
|
||||
|
||||
while (len > 0 && s < send) {
|
||||
ul <<= 7;
|
||||
ul |= (*s & 0x7f);
|
||||
if (!(*s++ & 0x80)) {
|
||||
UNPACK_PUSH(ULONG2NUM(ul));
|
||||
len--;
|
||||
ul = 0;
|
||||
}
|
||||
else if (ul & ulmask) {
|
||||
VALUE big = rb_uint2big(ul);
|
||||
VALUE big128 = rb_uint2big(128);
|
||||
while (s < send) {
|
||||
big = rb_big_mul(big, big128);
|
||||
big = rb_big_plus(big, rb_uint2big(*s & 0x7f));
|
||||
if (!(*s++ & 0x80)) {
|
||||
UNPACK_PUSH(big);
|
||||
len--;
|
||||
ul = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
char *s0 = s;
|
||||
while (len > 0 && s < send) {
|
||||
if (*s & 0x80) {
|
||||
s++;
|
||||
}
|
||||
else {
|
||||
s++;
|
||||
UNPACK_PUSH(rb_int_import(1, s0, s-s0, 1, 1, 1, 1));
|
||||
len--;
|
||||
s0 = s;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
# coding: ASCII-8BIT
|
||||
|
||||
require 'test/unit'
|
||||
require "-test-/bignum"
|
||||
|
||||
class TestBignum < Test::Unit::TestCase
|
||||
class TestExport < Test::Unit::TestCase
|
||||
def test_import_zero
|
||||
assert_equal(0, Integer.test_import(0, "", 1, 1, 1, 1, 0))
|
||||
end
|
||||
|
||||
def test_argument_check
|
||||
assert_raise(ArgumentError) { Integer.test_import(1, "x", 1, 0, 1, 1, 0) }
|
||||
assert_raise(ArgumentError) { Integer.test_import(1, "x", 1, 1, 1, 2, 0) }
|
||||
assert_raise(ArgumentError) { Integer.test_import(1, "x", 1, 1, 0, 1, 0) }
|
||||
assert_raise(ArgumentError) { Integer.test_import(1, "x", 1, 1, 1, 1, 8) }
|
||||
|
||||
# assume sizeof(ssize_t) == sizeof(intptr_t)
|
||||
assert_raise(ArgumentError) { Integer.test_import(1, "x", 1, 1, 1 << ([""].pack("p").length * 8 - 1), 1, 0) }
|
||||
end
|
||||
|
||||
def test_import_wordsize
|
||||
assert_equal(1, Integer.test_import(1, "\x01", 1, 1, 1, 1, 0))
|
||||
assert_equal(1, Integer.test_import(1, "\x00\x01", 1, 1, 2, 1, 0))
|
||||
assert_equal(1, Integer.test_import(1, "\x00\x00\x01", 1, 1, 3, 1, 0))
|
||||
assert_equal(1, Integer.test_import(1, "\x01", 1, 1, 1, -1, 0))
|
||||
assert_equal(1, Integer.test_import(1, "\x01\x00", 1, 1, 2, -1, 0))
|
||||
assert_equal(1, Integer.test_import(1, "\x01\x00\x00", 1, 1, 3, -1, 0))
|
||||
end
|
||||
|
||||
def test_import_wordorder_and_endian
|
||||
assert_equal(0x01020304, Integer.test_import(1, "\x01\x02\x03\x04", 2, 1, 2, 1, 0))
|
||||
assert_equal(0x02010403, Integer.test_import(1, "\x01\x02\x03\x04", 2, 1, 2, -1, 0))
|
||||
assert_equal(0x03040102, Integer.test_import(1, "\x01\x02\x03\x04", 2, -1, 2, 1, 0))
|
||||
assert_equal(0x04030201, Integer.test_import(1, "\x01\x02\x03\x04", 2, -1, 2, -1, 0))
|
||||
end
|
||||
|
||||
def test_import_native_endian
|
||||
assert_equal("\x12\x34".unpack("S!")[0], Integer.test_import(1, "\x12\x34", 1, 1, 2, 0, 0))
|
||||
end
|
||||
|
||||
def test_import_nail
|
||||
assert_equal(0b100011, Integer.test_import(1, "\x01\x00\x00\x00\x01\x01", 6, 1, 1, 1, 7))
|
||||
assert_equal(0x12345678, Integer.test_import(1, "\x01\x02\x03\x04\x05\x06\x07\x08", 8, 1, 1, 1, 4))
|
||||
assert_equal(0x12345678, Integer.test_import(1, "\x00\x12\x00\x34\x00\x56\x00\x78", 4, 1, 2, 1, 8))
|
||||
end
|
||||
|
||||
def test_import_sign
|
||||
assert_equal(-1, Integer.test_import(-1, "\x01", 1, 1, 1, 1, 0))
|
||||
assert_equal(-0x8070605040302010, Integer.test_import(-1, "\x80\x70\x60\x50\x40\x30\x20\x10", 8, 1, 1, 1, 0))
|
||||
end
|
||||
|
||||
end
|
||||
end
|
Загрузка…
Ссылка в новой задаче