Skip to content

Commit 868788c

Browse files
committed
Refine Array#pack r/R directives
* remove temporary buffer object. * simplify the condition needs an extra byte for sign extension. * raise before packing if negative number for `R`.
1 parent 2007a2a commit 868788c

File tree

2 files changed

+23
-23
lines changed

2 files changed

+23
-23
lines changed

depend

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10411,6 +10411,7 @@ pack.$(OBJEXT): $(top_srcdir)/internal/box.h
1041110411
pack.$(OBJEXT): $(top_srcdir)/internal/compilers.h
1041210412
pack.$(OBJEXT): $(top_srcdir)/internal/gc.h
1041310413
pack.$(OBJEXT): $(top_srcdir)/internal/imemo.h
10414+
pack.$(OBJEXT): $(top_srcdir)/internal/numeric.h
1041410415
pack.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
1041510416
pack.$(OBJEXT): $(top_srcdir)/internal/serial.h
1041610417
pack.$(OBJEXT): $(top_srcdir)/internal/set_table.h

pack.c

Lines changed: 22 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "internal.h"
2020
#include "internal/array.h"
2121
#include "internal/bits.h"
22+
#include "internal/numeric.h"
2223
#include "internal/string.h"
2324
#include "internal/symbol.h"
2425
#include "internal/variable.h"
@@ -677,43 +678,41 @@ pack_pack(rb_execution_context_t *ec, VALUE ary, VALUE fmt, VALUE buffer)
677678
}
678679

679680
while (len-- > 0) {
680-
size_t numbytes;
681-
int sign;
681+
size_t numbytes, nlz_bits;
682+
int sign, extra = 0;
682683
char *cp;
684+
long start = RSTRING_LEN(res);
683685

684686
from = NEXTFROM;
685687
from = rb_to_int(from);
686-
numbytes = rb_absint_numwords(from, 7, NULL);
687-
if (numbytes == 0)
688-
numbytes = 1;
689-
VALUE buf = rb_str_new(NULL, numbytes);
690-
691-
sign = rb_integer_pack(from, RSTRING_PTR(buf), RSTRING_LEN(buf), 1, 1, pack_flags);
692-
693-
if (sign < 0 && type == 'R') {
688+
if (type == 'R' && rb_int_negative_p(from)) {
694689
rb_raise(rb_eArgError, "can't encode negative numbers in ULEB128");
695690
}
696691

697-
if (type == 'r') {
698-
/* Check if we need an extra byte for sign extension */
699-
unsigned char last_byte = (unsigned char)RSTRING_PTR(buf)[numbytes - 1];
700-
if ((sign >= 0 && (last_byte & 0x40)) || /* positive but sign bit set */
701-
(sign < 0 && !(last_byte & 0x40))) { /* negative but sign bit clear */
702-
/* Need an extra byte */
703-
rb_str_resize(buf, numbytes + 1);
704-
RSTRING_PTR(buf)[numbytes] = sign < 0 ? 0x7f : 0x00;
705-
numbytes++;
706-
}
692+
numbytes = rb_absint_numwords(from, 7, &nlz_bits);
693+
if (numbytes == 0) {
694+
numbytes = 1;
707695
}
696+
else if (nlz_bits == 0 && type == 'r') {
697+
/* No leading zero bits, we need an extra byte for sign extension */
698+
extra = 1;
699+
}
700+
rb_str_modify_expand(res, numbytes + extra);
701+
702+
cp = RSTRING_PTR(res) + start;
703+
sign = rb_integer_pack(from, cp, numbytes, 1, 1, pack_flags);
704+
705+
if (extra) {
706+
/* Need an extra byte */
707+
cp[numbytes++] = sign < 0 ? 0x7f : 0x00;
708+
}
709+
rb_str_set_len(res, start + numbytes);
708710

709-
cp = RSTRING_PTR(buf);
710711
while (1 < numbytes) {
711712
*cp |= 0x80;
712713
cp++;
713714
numbytes--;
714715
}
715-
716-
rb_str_buf_cat(res, RSTRING_PTR(buf), RSTRING_LEN(buf));
717716
}
718717
}
719718
break;

0 commit comments

Comments
 (0)