/* 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" #ifndef SVU_SIZE # define SVU_SIZE (CHAR_BIT * sizeof(BV_UNIT)) #endif 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, e, lf, cf; char *vt, *vf; CODE: l = svu_validate_uv(sl, "length"); if (!l) XSRETURN(0); fs = svu_validate_uv(sfs, "offset"); ts = svu_validate_uv(sts, "offset"); SvUPGRADE(sf, SVt_PV); vt = svu_prepare_sv(st, ts, l); /* We fetch vf after upgrading st in case st == sf. */ vf = SvPVX(sf); cf = SvCUR(sf) * CHAR_BIT; lf = fs + l; e = lf > cf ? lf - cf : 0; l = l > e ? l - e : 0; if (l) { if (vf == vt) bv_move(vf, ts, fs, l); else bv_copy(vt, ts, vf, fs, l); } if (e) bv_fill(vt, ts + l, e, 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);