mirror of
https://github.com/mruby/mruby
synced 2026-06-08 16:11:16 +00:00
mruby-sprintf: support dots expression of negative integer format
For specifiers assume unsigned integers, negative numbers show dots (..) to indicate virtual infinite 1s at the MSB side of 2's compliment.
This commit is contained in:
@@ -1626,3 +1626,41 @@ mrb_bint_hash(mrb_state *mrb, mrb_value x)
|
||||
hash = mrb_byte_hash_step((uint8_t*)&b->mp.sn, sizeof(b->mp.sn), hash);
|
||||
return mrb_int_value(mrb, hash);
|
||||
}
|
||||
|
||||
mrb_value
|
||||
mrb_bint_2comp(mrb_state *mrb, mrb_value x, mrb_int base)
|
||||
{
|
||||
struct RBigint *b = RBIGINT(x);
|
||||
mrb_int i;
|
||||
|
||||
for (i=b->mp.sz-1; i>=0; i--) {
|
||||
if (b->mp.p[i] > 0) break;
|
||||
}
|
||||
|
||||
#ifdef __GNUC__
|
||||
mrb_int dbits = __builtin_ctz(base);
|
||||
#else
|
||||
mrb_int dbits;
|
||||
switch (base) {
|
||||
case 16: dbits = 4; break;
|
||||
case 8: dbits = 3; break;
|
||||
case 2: dbits = 1; break;
|
||||
}
|
||||
#endif
|
||||
mrb_int topbit = DIG_SIZE * (i+1) - lzb(b->mp.p[i]);
|
||||
mrb_int nbits = (topbit / dbits + 1) * dbits;
|
||||
|
||||
mpz_t one;
|
||||
mpz_t up;
|
||||
struct RBigint *b2 = bint_new(mrb);
|
||||
|
||||
/* rounding up to nearest power of 2 */
|
||||
mpz_init_set_int(mrb, &one, 1);
|
||||
mpz_init(mrb, &up);
|
||||
mpz_mul_2exp(mrb, &up, &one, nbits);
|
||||
mpz_clear(mrb, &one);
|
||||
mpz_add(mrb, &b2->mp, &up, &b->mp);
|
||||
mpz_clear(mrb, &up);
|
||||
|
||||
return mrb_obj_value(b2);
|
||||
}
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
#define BITSPERDIG MRB_INT_BIT
|
||||
#define EXTENDSIGN(n, l) (((~0U << (n)) >> (((n)*(l)) % BITSPERDIG)) & ~(~0U << (n)))
|
||||
|
||||
mrb_value mrb_bint_2comp(mrb_state *mrb, mrb_value x, mrb_int base);
|
||||
|
||||
static char*
|
||||
remove_sign_bits(char *str, int base)
|
||||
{
|
||||
@@ -594,6 +596,13 @@ retry:
|
||||
#ifdef MRB_USE_BIGINT
|
||||
case MRB_TT_BIGINT:
|
||||
{
|
||||
mrb_int n = (mrb_bint_cmp(mrb, val, mrb_fixnum_value(0)));
|
||||
mrb_bool need_dots = ((flags & FPLUS) == 0) && (base == 16 || base == 8 || base == 2) && n < 0;
|
||||
if (need_dots) {
|
||||
val = mrb_bint_2comp(mrb, val, base);
|
||||
dots = 1;
|
||||
v = -1;
|
||||
}
|
||||
mrb_value str = mrb_bint_to_s(mrb, val, base);
|
||||
s = RSTRING_PTR(str);
|
||||
len = RSTRING_LEN(str);
|
||||
@@ -644,7 +653,9 @@ retry:
|
||||
len = (int)size;
|
||||
}
|
||||
|
||||
#ifdef MRB_USE_BIGINT
|
||||
str_skip:
|
||||
#endif
|
||||
switch (base) {
|
||||
case 16:
|
||||
fc = 'f'; break;
|
||||
|
||||
Reference in New Issue
Block a user