Ejemplo n.º 1
0
guint64 amglue_SvU64(SV *sv)
{
    if (SvIOK(sv)) {
	if (SvIsUV(sv)) {
	    return SvUV(sv);
	} else if (SvIV(sv) < 0) {
	    croak("Expected an unsigned value, got a negative integer");
	    return 0;
	} else {
	    return (guint64)SvIV(sv);
	}
    } else if (SvNOK(sv)) {
	double dv = SvNV(sv);
	if (dv < 0.0) {
	    croak("Expected an unsigned value, got a negative integer");
	    return 0;
	} else if (dv > (double)G_MAXUINT64) {
	    croak("Expected an unsigned 64-bit value or smaller; value out of range");
	    return 0;
	} else {
	    return (guint64)dv;
	}
    } else {
	return bigint2uint64(sv);
    }
}
Ejemplo n.º 2
0
gint64 amglue_SvI64(SV *sv)
{
    if (SvIOK(sv)) {
	if (SvIsUV(sv)) {
	    return SvUV(sv);
	} else {
	    return SvIV(sv);
	}
    } else if (SvNOK(sv)) {
	double dv = SvNV(sv);

	/* preprocessor constants seem to have trouble here, so we convert to gint64 and
	 * back, and if the result differs, then we have lost something.  Note that this will
	 * also error out on integer truncation .. which is probably OK */
	gint64 iv = (gint64)dv;
	if (dv != (double)iv) {
	    croak("Expected a signed 64-bit value or smaller; value '%.0f' out of range", (float)dv);
	    return 0;
	} else {
	    return iv;
	}
    } else {
	return bigint2int64(sv);
    }
}
Ejemplo n.º 3
0
/* 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 {
Ejemplo n.º 4
0
UV
Perl_sv_uv(pTHX_ SV *sv)
{
    PERL_ARGS_ASSERT_SV_UV;

    if (SvIOK(sv)) {
        if (SvIsUV(sv))
            return SvUVX(sv);
        return (UV)SvIVX(sv);
    }
    return sv_2uv(sv);
}
Ejemplo n.º 5
0
IV
Perl_sv_iv(pTHX_ SV *sv)
{
    PERL_ARGS_ASSERT_SV_IV;

    if (SvIOK(sv)) {
        if (SvIsUV(sv))
            return (IV)SvUVX(sv);
        return SvIVX(sv);
    }
    return sv_2iv(sv);
}