ClickHouse-Encoder

 view release on metacpan or  search on metacpan

Encoder.xs  view on Meta::CPAN

    RETVAL = (UV)(av_len(s->buffer) + 1);
}
OUTPUT:
    RETVAL

bool
is_empty(self)
    SV *self
CODE:
{
    Streamer *s;
    if (!sv_isobject(self)) croak("Not an object");
    s = INT2PTR(Streamer *, SvIV(SvRV(self)));
    RETVAL = (av_len(s->buffer) < 0);
}
OUTPUT:
    RETVAL

void
DESTROY(self)
    SV *self
CODE:
{
    Streamer *s;
    if (!sv_isobject(self)) return;
    s = INT2PTR(Streamer *, SvIV(SvRV(self)));
    free_streamer(aTHX_ s);
}

MODULE = ClickHouse::Encoder  PACKAGE = ClickHouse::Encoder::TCP

# Pack an unsigned varint (LEB128 / CH varuint form). Used by the
# protocol-packet builders in ClickHouse::Encoder::TCP. Equivalent
# to the buf_varint() internal helper but exposed as a Perl callable
# so the pure-Perl module can produce wire-format bytes via XS rather
# than a per-byte chr/shift loop.
SV *
pack_varint(v)
    UV v
CODE:
{
    char buf[10];
    int i = 0;
    while (v >= 0x80) {
        buf[i++] = (char)((v & 0x7f) | 0x80);
        v >>= 7;
    }
    buf[i++] = (char)v;
    RETVAL = newSVpvn(buf, i);
}
OUTPUT:
    RETVAL

# Unpack one varint from a byte string starting at the given offset.
# Returns (value, new_offset). Croaks on truncated input or a varint
# wider than 64 bits.
void
unpack_varint(bytes, offset)
    SV *bytes
    UV offset
PPCODE:
{
    STRLEN len;
    const unsigned char *p = (const unsigned char *)SvPVbyte(bytes, len);
    UV v = tcp_read_varint(aTHX_ p, (UV)len, &offset);
    EXTEND(SP, 2);
    PUSHs(sv_2mortal(newSVuv(v)));
    PUSHs(sv_2mortal(newSVuv(offset)));
}

# Pack a length-prefixed string (varint length + UTF-8 bytes). The
# caller should pass Perl strings; we encode to UTF-8 explicitly so
# non-ASCII chars get the right byte length on the wire.
SV *
pack_string(s)
    SV *s
CODE:
{
    STRLEN len;
    const char *p;
    if (!SvOK(s)) {
        p = ""; len = 0;
    } else {
        /* SvPVutf8 returns the UTF-8 byte form */
        p = SvPVutf8(s, len);
    }
    /* Build prefix + bytes. */
    char prefix[10];
    int pi = 0;
    UV vv = (UV)len;
    while (vv >= 0x80) {
        prefix[pi++] = (char)((vv & 0x7f) | 0x80);
        vv >>= 7;
    }
    prefix[pi++] = (char)vv;
    RETVAL = newSVpvn(prefix, pi);
    sv_catpvn(RETVAL, p, len);
}
OUTPUT:
    RETVAL

# Unpack a length-prefixed string at the given offset. Returns (string,
# new_offset). String bytes are returned without decoding (caller
# decides UTF-8 vs binary).
void
unpack_string(bytes, offset)
    SV *bytes
    UV offset
PPCODE:
{
    STRLEN buf_len;
    const unsigned char *p = (const unsigned char *)SvPVbyte(bytes, buf_len);
    UV slen = tcp_read_varint(aTHX_ p, (UV)buf_len, &offset);
    /* Subtraction form: addition (offset + slen) can wrap UV_MAX when
     * slen is attacker-controlled via a crafted varint. tcp_read_varint
     * guarantees offset <= buf_len on return, so buf_len - offset is
     * safe. */
    if (slen > (UV)buf_len - offset)
        croak("string: truncated at offset %lu (need %lu)",
              (unsigned long)offset, (unsigned long)slen);
    SV *out = newSVpvn((const char *)(p + offset), (STRLEN)slen);
    EXTEND(SP, 2);
    PUSHs(sv_2mortal(out));
    PUSHs(sv_2mortal(newSVuv(offset + slen)));
}



( run in 2.415 seconds using v1.01-cache-2.11-cpan-71847e10f99 )