/* Entry point for serialization. Dumps generic SVs and delegates * to more specialized functions for RVs, etc. */ void ddl_dump_sv(pTHX_ ddl_encoder_t *enc, SV *src) { SvGETMAGIC(src); /* dump strings */ if (SvPOKp(src)) { STRLEN len; char *str = SvPV(src, len); BUF_SIZE_ASSERT(enc, 2 + len); ddl_dump_pv(aTHX_ enc, str, len, SvUTF8(src)); } /* dump floats */ else if (SvNOKp(src)) { BUF_SIZE_ASSERT(enc, NV_DIG + 32); Gconvert(SvNVX(src), NV_DIG, 0, enc->pos); enc->pos += strlen(enc->pos); } /* dump ints */ else if (SvIOKp(src)) { /* we assume we can always read an IV as a UV and vice versa * we assume two's complement * we assume no aliasing issues in the union */ if (SvIsUV(src) ? SvUVX(src) <= 59000 : SvIVX(src) <= 59000 && SvIVX(src) >= -59000) { /* optimise the "small number case" * code will likely be branchless and use only a single multiplication * works for numbers up to 59074 */ I32 i = SvIVX(src); U32 u; char digit, nz = 0; BUF_SIZE_ASSERT(enc, 6); *enc->pos = '-'; enc->pos += i < 0 ? 1 : 0; u = i < 0 ? -i : i; /* convert to 4.28 fixed-point representation */ u *= ((0xfffffff + 10000) / 10000); /* 10**5, 5 fractional digits */ /* now output digit by digit, each time masking out the integer part * and multiplying by 5 while moving the decimal point one to the right, * resulting in a net multiplication by 10. * we always write the digit to memory but conditionally increment * the pointer, to enable the use of conditional move instructions. */ digit = u >> 28; *enc->pos = digit + '0'; enc->pos += (nz = nz || digit); u = (u & 0xfffffffUL) * 5; digit = u >> 27; *enc->pos = digit + '0'; enc->pos += (nz = nz || digit); u = (u & 0x7ffffffUL) * 5; digit = u >> 26; *enc->pos = digit + '0'; enc->pos += (nz = nz || digit); u = (u & 0x3ffffffUL) * 5; digit = u >> 25; *enc->pos = digit + '0'; enc->pos += (nz = nz || digit); u = (u & 0x1ffffffUL) * 5; digit = u >> 24; *enc->pos = digit + '0'; enc->pos += 1; /* correctly generate '0' */ } else {
/* Code for serializing floats */ static SRL_INLINE void srl_dump_nv(pTHX_ srl_encoder_t *enc, SV *src) { NV nv= SvNV(src); float f= nv; double d= nv; if ( f == nv || nv != nv ) { BUF_SIZE_ASSERT(enc, 1 + sizeof(f)); /* heuristic: header + string + simple value */ srl_buf_cat_char_nocheck(enc,SRL_HDR_FLOAT); Copy((char *)&f, enc->pos, sizeof(f), char); enc->pos += sizeof(f); } else if (d == nv) {
/* Code for serializing floats */ SRL_STATIC_INLINE void srl_dump_nv(pTHX_ srl_encoder_t *enc, SV *src) { NV nv= SvNV(src); MS_VC6_WORKAROUND_VOLATILE float f= (float)nv; MS_VC6_WORKAROUND_VOLATILE double d= (double)nv; /* TODO: this logic could be reworked to not duplicate so much code, which will help on win32 */ if ( f == nv || nv != nv ) { BUF_SIZE_ASSERT(enc, 1 + sizeof(f)); /* heuristic: header + string + simple value */ srl_buf_cat_char_nocheck(enc,SRL_HDR_FLOAT); Copy((char *)&f, enc->pos, sizeof(f), char); enc->pos += sizeof(f); } else if (d == nv) {
void srl_write_header(pTHX_ srl_encoder_t *enc) { /* 4th to 8th bit are flags. Using 4th for snappy flag. FIXME needs to go in spec. */ const U8 version_and_flags = SRL_PROTOCOL_VERSION | ( SRL_ENC_HAVE_OPTION(enc, SRL_F_COMPRESS_SNAPPY) ? SRL_PROTOCOL_ENCODING_SNAPPY : SRL_PROTOCOL_ENCODING_RAW ); /* 4 byte magic string + proto version * + potentially uncompressed size varint * + 1 byte varint that indicates zero-length header */ BUF_SIZE_ASSERT(enc, sizeof(SRL_MAGIC_STRING) + 1 + 1); srl_buf_cat_str_s_nocheck(enc, SRL_MAGIC_STRING); srl_buf_cat_char_nocheck(enc, version_and_flags); srl_buf_cat_char_nocheck(enc, '\0'); /* variable header length (0 right now) */ }