/* This file is part of the Scalar::Vec::Util Perl module. * See http://search.cpan.org/dist/Scalar-Vec-Util/ */ #define PERL_NO_GET_CONTEXT #include "EXTERN.h" #include "perl.h" #include "XSUB.h" #define __PACKAGE__ "Scalar::Vec::Util" #define __PACKAGE_LEN__ (sizeof(__PACKAGE__)-1) #include "bitvect.h" STATIC size_t svu_validate_uv(pTHX_ SV *sv, const char *desc) { #define svu_validate_uv(S, D) svu_validate_uv(aTHX_ (S), (D)) IV i; if (SvOK(sv) && SvIOK(sv)) { if (SvIsUV(sv)) return SvUVX(sv); else { i = SvIVX(sv); if (i >= 0) return i; } } else { i = SvIV(sv); if (i >= 0) return i; } croak("Invalid negative %s", desc ? desc : "integer"); return 0; } STATIC char *svu_prepare_sv(pTHX_ SV *sv, size_t s, size_t l) { #define svu_prepare_sv(S, I, L) svu_prepare_sv(aTHX_ (S), (I), (L)) STRLEN c; size_t n = s + l, i, js, jz, k, z; char *p; SvUPGRADE(sv, SVt_PV); p = SvGROW(sv, BV_SIZE(n)); c = SvCUR(sv); js = (s / BITS(BV_UNIT)) * sizeof(BV_UNIT); k = js + sizeof(BV_UNIT); for (i = c < js ? js : c; i < k; ++i) p[i] = 0; jz = ((s + l - 1) / BITS(BV_UNIT)) * sizeof(BV_UNIT); if (jz > js) { k = jz + sizeof(BV_UNIT); for (i = c < jz ? jz : c; i < k; ++i) p[i] = 0; } z = 1 + ((s + l - 1) / CHAR_BIT); if (c < z) SvCUR_set(sv, z); return p; } /* --- XS ------------------------------------------------------------------ */ MODULE = Scalar::Vec::Util PACKAGE = Scalar::Vec::Util PROTOTYPES: ENABLE BOOT: { HV *stash = gv_stashpvn(__PACKAGE__, __PACKAGE_LEN__, 1); newCONSTSUB(stash, "SVU_PP", newSVuv(0)); newCONSTSUB(stash, "SVU_SIZE", newSVuv(SVU_SIZE)); } void vfill(SV *sv, SV *ss, SV *sl, SV *sf) PROTOTYPE: $$$$ PREINIT: size_t s, l; char f, *v; CODE: l = svu_validate_uv(sl, "length"); if (!l) XSRETURN(0); s = svu_validate_uv(ss, "offset"); v = svu_prepare_sv(sv, s, l); f = SvTRUE(sf); bv_fill(v, s, l, f); XSRETURN(0); void vcopy(SV *sf, SV *sfs, SV *st, SV *sts, SV *sl) PROTOTYPE: $$$$$ PREINIT: size_t fs, ts, l, lf = 0, c; char *t, *f; CODE: l = svu_validate_uv(sl, "length"); if (!l) XSRETURN(0); fs = svu_validate_uv(sfs, "offset"); ts = svu_validate_uv(sts, "offset"); t = svu_prepare_sv(st, ts, l); f = SvPVX(sf); /* We do it there in case st == sf. */ c = SvCUR(sf); if (c * CHAR_BIT <= fs + l && c <= SvCUR(st)) { lf = fs + l - c * CHAR_BIT; l = c * CHAR_BIT - fs; } if (f == t) { bv_move(f, ts, fs, l); } else { bv_copy(t, ts, f, fs, l); } if (lf) { bv_fill(t, ts + l, lf, 0); } XSRETURN(0); void veq(SV *sv1, SV *ss1, SV *sv2, SV *ss2, SV *sl) PROTOTYPE: $$$$$ PREINIT: size_t s1, s2, l, l1, l2, c1, c2, e1, e2, e; int res = 1; char *v1, *v2; CODE: l = svu_validate_uv(sl, "length"); if (!l) goto done; s1 = svu_validate_uv(ss1, "offset"); s2 = svu_validate_uv(ss2, "offset"); SvUPGRADE(sv1, SVt_PV); SvUPGRADE(sv2, SVt_PV); v1 = SvPVX(sv1); v2 = SvPVX(sv2); c1 = SvCUR(sv1) * CHAR_BIT; c2 = SvCUR(sv2) * CHAR_BIT; redo: l1 = s1 + l; l2 = s2 + l; e1 = l1 > c1 ? l1 - c1 : 0; e2 = l2 > c2 ? l2 - c2 : 0; e = e1 > e2 ? e1 : e2; if (l > e) { size_t p = l - e; res = bv_eq(v1, s1, v2, s2, p); if (!res || e == 0) goto done; /* Bit vectors are equal up to p < l */ s1 += p; s2 += p; l = e; goto redo; } /* l <= max(e1, e2), at least one of the vectors is completely out of bounds */ e = e1 < e2 ? e1 : e2; if (l > e) { size_t q = l - e; if (s1 < c1) res = bv_zero(v1, s1, q); else if (s2 < c2) res = bv_zero(v2, s2, q); } done: ST(0) = res ? &PL_sv_yes : &PL_sv_no; XSRETURN(1);