#include "perl.h"
#include "XSUB.h"
-#define __PACKAGE__ "Scalar::Vec::Util"
+#define __PACKAGE__ "Scalar::Vec::Util"
+#define __PACKAGE_LEN__ (sizeof(__PACKAGE__)-1)
#include "bitvect.h"
-STATIC const char svu_error_invarg[] = "Invalid argument";
+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, j1, j2, k, z;
+ char *p;
+
+ SvUPGRADE(sv, SVt_PV);
+
+ p = SvGROW(sv, BV_SIZE(n));
+ c = SvCUR(sv);
+
+ j1 = (s / BITS(BV_UNIT)) * sizeof(BV_UNIT);
+ k = j1 + sizeof(BV_UNIT);
+ for (i = c < j1 ? j1 : c; i < k; ++i)
+ p[i] = 0;
+
+ j2 = ((s + l - 1) / BITS(BV_UNIT)) * sizeof(BV_UNIT);
+ if (j2 > j1) {
+ k = j2 + sizeof(BV_UNIT);
+ for (i = c < j2 ? j2 : c; i < k; ++i)
+ p[i] = 0;
+ }
+
+ z = 1 + ((s + l - 1) / CHAR_BIT);
+ if (c < z)
+ SvCUR_set(sv, z);
+
+ return p;
+}
/* --- XS ------------------------------------------------------------------ */
BOOT:
{
- HV *stash = gv_stashpv(__PACKAGE__, 1);
+ 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, n, o;
+ size_t s, l;
char f, *v;
CODE:
- if (!SvOK(sv) || !SvOK(ss) || !SvOK(sl) || !SvOK(sf)) {
- croak(svu_error_invarg);
- }
-
- l = SvUV(sl);
- if (!l) { XSRETURN(0); }
- s = SvUV(ss);
+ 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);
- if (SvTYPE(sv) < SVt_PV) { SvUPGRADE(sv, SVt_PV); }
-
- n = BV_SIZE(s + l);
- o = SvLEN(sv);
- if (n > o) {
- v = SvGROW(sv, n);
- Zero(v + o, n - o, char);
- } else {
- v = SvPVX(sv);
- }
- if (SvCUR(sv) < n) {
- SvCUR_set(sv, n);
- }
bv_fill(v, s, l, f);
void
vcopy(SV *sf, SV *sfs, SV *st, SV *sts, SV *sl)
+PROTOTYPE: $$$$$
PREINIT:
- size_t fs, ts, l, lf = 0, n, o;
+ size_t fs, ts, l, lf = 0, c;
char *t, *f;
CODE:
- if (!SvOK(sf) || !SvOK(sfs) || !SvOK(st) || !SvOK(sts) || !SvOK(sl)) {
- croak(svu_error_invarg);
- }
+ l = svu_validate_uv(sl, "length");
+ if (!l)
+ XSRETURN(0);
+ fs = svu_validate_uv(sfs, "offset");
+ ts = svu_validate_uv(sts, "offset");
- l = SvUV(sl);
- if (!l) { XSRETURN(0); }
- fs = SvUV(sfs);
- ts = SvUV(sts);
- if (SvTYPE(sf) < SVt_PV) { SvUPGRADE(sf, SVt_PV); }
- if (SvTYPE(st) < SVt_PV) { SvUPGRADE(st, SVt_PV); }
+ t = svu_prepare_sv(st, ts, l);
- n = BV_SIZE(ts + l);
- o = SvLEN(st);
- if (n > o) {
- t = SvGROW(st, n);
- Zero(t + o, n - o, char);
- } else {
- t = SvPVX(st);
- }
- if (SvCUR(st) < n) {
- SvCUR_set(st, n);
- }
f = SvPVX(sf); /* We do it there in case st == sf. */
-
- n = BV_SIZE(fs + l);
- o = SvLEN(sf);
- if (n > o) {
- lf = fs + l - o * CHAR_BIT;
- l = o * CHAR_BIT - fs;
+ 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) {
SV *
veq(SV *sv1, SV *ss1, SV *sv2, SV *ss2, SV *sl)
+PROTOTYPE: $$$$$
PREINIT:
size_t s1, s2, l, o, n;
char *v1, *v2;
CODE:
- if (!SvOK(sv1) || !SvOK(ss1) || !SvOK(sv2) || !SvOK(ss2) || !SvOK(sl)) {
- croak(svu_error_invarg);
- }
-
- l = SvUV(sl);
- s1 = SvUV(ss1);
- s2 = SvUV(ss2);
- if (SvTYPE(sv1) < SVt_PV) { SvUPGRADE(sv1, SVt_PV); }
- if (SvTYPE(sv2) < SVt_PV) { SvUPGRADE(sv2, SVt_PV); }
+ l = svu_validate_uv(sl, "length");
+ if (!l)
+ XSRETURN_YES;
+ s1 = svu_validate_uv(ss1, "offset");
+ s2 = svu_validate_uv(ss2, "offset");
+ SvUPGRADE(sv1, SVt_PV);
+ SvUPGRADE(sv2, SVt_PV);
n = BV_SIZE(s1 + l);
o = SvLEN(sv1);