Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 35 additions & 33 deletions mrbgems/mruby-pack/src/pack.c
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ static const int le_idx16[2] = {0, 1}; /* little-endian 16-bit: LSB, MS
static const int be_idx32[4] = {3, 2, 1, 0}; /* big-endian 32-bit: MSB...LSB */
static const int le_idx32[4] = {0, 1, 2, 3}; /* little-endian 32-bit: LSB...MSB */
static const int be_idx64[8] = {7, 6, 5, 4, 3, 2, 1, 0}; /* big-endian 64-bit: MSB...LSB */
static const int le_idx64[8] = {0, 1, 2, 3, 4, 5, 6, 7}; /* little-endian 64-bit: LSB...MSB */ /* little-endian 64-bit */
static const int le_idx64[8] = {0, 1, 2, 3, 4, 5, 6, 7}; /* little-endian 64-bit: LSB...MSB */
/* lookup tables for binary string optimization */
/* Convert character to bit value (0 or 1) */
static inline uint8_t char_to_bit(unsigned char c) {
Expand Down Expand Up @@ -681,23 +681,24 @@ pack_double(mrb_state *mrb, mrb_value o, mrb_value str, mrb_int sidx, unsigned i
{
union {
double d;
uint8_t bytes[8];
uint64_t u;
} converter;

str = str_len_ensure(mrb, str, sidx + 8);
converter.d = mrb_float(o);
char *dptr = RSTRING_PTR(str) + sidx;

/* use lookup tables to eliminate branching */
/* Use bit shifts for endian-independent byte extraction (same as pack_quad) */
uint64_t n = converter.u;
const int *idx = (flags & PACK_FLAG_LITTLEENDIAN) ? le_idx64 : be_idx64;
dptr[idx[0]] = converter.bytes[0];
dptr[idx[1]] = converter.bytes[1];
dptr[idx[2]] = converter.bytes[2];
dptr[idx[3]] = converter.bytes[3];
dptr[idx[4]] = converter.bytes[4];
dptr[idx[5]] = converter.bytes[5];
dptr[idx[6]] = converter.bytes[6];
dptr[idx[7]] = converter.bytes[7];
dptr[idx[0]] = (char)(n & 0xff);
dptr[idx[1]] = (char)((n >> 8) & 0xff);
dptr[idx[2]] = (char)((n >> 16) & 0xff);
dptr[idx[3]] = (char)((n >> 24) & 0xff);
dptr[idx[4]] = (char)((n >> 32) & 0xff);
dptr[idx[5]] = (char)((n >> 40) & 0xff);
dptr[idx[6]] = (char)((n >> 48) & 0xff);
dptr[idx[7]] = (char)((n >> 56) & 0xff);

return 8;
}
Expand All @@ -707,19 +708,19 @@ unpack_double(mrb_state *mrb, const unsigned char * src, mrb_int srclen, mrb_val
{
union {
double d;
uint8_t bytes[8];
uint64_t u;
} converter;

/* use lookup tables to eliminate branching */
/* Use bit shifts for endian-independent byte assembly (same as unpack_quad) */
const int *idx = (flags & PACK_FLAG_LITTLEENDIAN) ? le_idx64 : be_idx64;
converter.bytes[0] = src[idx[0]];
converter.bytes[1] = src[idx[1]];
converter.bytes[2] = src[idx[2]];
converter.bytes[3] = src[idx[3]];
converter.bytes[4] = src[idx[4]];
converter.bytes[5] = src[idx[5]];
converter.bytes[6] = src[idx[6]];
converter.bytes[7] = src[idx[7]];
converter.u = ((uint64_t)src[idx[7]] << 56) |
((uint64_t)src[idx[6]] << 48) |
((uint64_t)src[idx[5]] << 40) |
((uint64_t)src[idx[4]] << 32) |
((uint64_t)src[idx[3]] << 24) |
((uint64_t)src[idx[2]] << 16) |
((uint64_t)src[idx[1]] << 8) |
((uint64_t)src[idx[0]]);

mrb_ary_push(mrb, ary, mrb_float_value(mrb, converter.d));

Expand All @@ -731,19 +732,20 @@ pack_float(mrb_state *mrb, mrb_value o, mrb_value str, mrb_int sidx, unsigned in
{
union {
float f;
uint8_t bytes[4];
uint32_t u;
} converter;

str = str_len_ensure(mrb, str, sidx + 4);
converter.f = (float)mrb_float(o);
char *dptr = RSTRING_PTR(str) + sidx;

/* use lookup tables to eliminate branching */
/* Use bit shifts for endian-independent byte extraction (same as pack_long) */
uint32_t n = converter.u;
const int *idx = (flags & PACK_FLAG_LITTLEENDIAN) ? le_idx32 : be_idx32;
dptr[idx[0]] = converter.bytes[0];
dptr[idx[1]] = converter.bytes[1];
dptr[idx[2]] = converter.bytes[2];
dptr[idx[3]] = converter.bytes[3];
dptr[idx[0]] = (char)(n & 0xff);
dptr[idx[1]] = (char)((n >> 8) & 0xff);
dptr[idx[2]] = (char)((n >> 16) & 0xff);
dptr[idx[3]] = (char)((n >> 24) & 0xff);

return 4;
}
Expand All @@ -753,15 +755,15 @@ unpack_float(mrb_state *mrb, const unsigned char * src, mrb_int srclen, mrb_valu
{
union {
float f;
uint8_t bytes[4];
uint32_t u;
} converter;

/* use lookup tables to eliminate branching */
/* Use bit shifts for endian-independent byte assembly (same as unpack_long) */
const int *idx = (flags & PACK_FLAG_LITTLEENDIAN) ? le_idx32 : be_idx32;
converter.bytes[0] = src[idx[0]];
converter.bytes[1] = src[idx[1]];
converter.bytes[2] = src[idx[2]];
converter.bytes[3] = src[idx[3]];
converter.u = ((uint32_t)src[idx[3]] << 24) |
((uint32_t)src[idx[2]] << 16) |
((uint32_t)src[idx[1]] << 8) |
((uint32_t)src[idx[0]]);

mrb_ary_push(mrb, ary, mrb_float_value(mrb, converter.f));

Expand Down
Loading