List-SomeUtils-XS
view release on metacpan or search on metacpan
PROTOTYPE: ;$
CODE:
{
int i;
int exhausted = 1;
/* 'cv' is the hidden argument with which
* XS_List__SomeUtils__XS__array_iterator (this XSUB) is called. The
* closure_arg struct is stored in this CV. */
arrayeach_args *args = (arrayeach_args *)(CvXSUBANY(cv).any_ptr);
if (strEQ(method, "index")) {
EXTEND(SP, 1);
ST(0) = args->curidx > 0 ? sv_2mortal(newSViv(args->curidx-1)) : &PL_sv_undef;
XSRETURN(1);
}
EXTEND(SP, args->navs);
for (i = 0; i < args->navs; i++) {
AV *av = args->avs[i];
if (args->curidx <= av_len(av)) {
ST(i) = sv_2mortal(newSVsv(*av_fetch(av, args->curidx, FALSE)));
exhausted = 0;
continue;
}
ST(i) = &PL_sv_undef;
}
if (exhausted)
XSRETURN_EMPTY;
args->curidx++;
XSRETURN(args->navs);
}
SV *
each_array (...)
PROTOTYPE: \@;\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@
CODE:
{
EACH_ARRAY_BODY;
}
OUTPUT:
RETVAL
SV *
each_arrayref (...)
CODE:
{
EACH_ARRAY_BODY;
}
OUTPUT:
RETVAL
void
pairwise (code, ...)
SV *code;
PROTOTYPE: &\@\@
PPCODE:
{
#define av_items(a) (av_len(a)+1)
/* This function is not quite as efficient as it ought to be: We call
* 'code' multiple times and want to gather its return values all in one
* list. However, each call resets the stack pointer so there is no
* obvious way to get the return values onto the stack without making
* intermediate copies of the pointers. The above disabled solution would
* be more efficient. Unfortunately it doesn't work (and, as of now,
* wouldn't deal with 'code' returning more than one value).
*
* The current solution is a fair trade-off. It only allocates memory for
* a list of SV-pointers, as many as there are return values. It
* temporarily stores 'code's return values in this list and, when done,
* copies them down to SP. */
int i, j;
AV *avs[2];
SV **buf, **p; /* gather return values here and later copy down to SP */
int alloc;
int nitems = 0, maxitems = 0;
int d;
if (!codelike(code))
croak_xs_usage(cv, "code, list, list");
if (!arraylike(ST(1)))
croak_xs_usage(cv, "code, list, list");
if (!arraylike(ST(2)))
croak_xs_usage(cv, "code, list, list");
if (in_pad(aTHX_ code)) {
croak("Can't use lexical $a or $b in pairwise code block");
}
/* deref AV's for convenience and
* get maximum items */
avs[0] = (AV*)SvRV(ST(1));
avs[1] = (AV*)SvRV(ST(2));
maxitems = av_items(avs[0]);
if (av_items(avs[1]) > maxitems)
maxitems = av_items(avs[1]);
if (!PL_firstgv || !PL_secondgv) {
SAVESPTR(PL_firstgv);
SAVESPTR(PL_secondgv);
PL_firstgv = gv_fetchpv("a", TRUE, SVt_PV);
PL_secondgv = gv_fetchpv("b", TRUE, SVt_PV);
}
New(0, buf, alloc = maxitems, SV*);
ENTER;
for (d = 0, i = 0; i < maxitems; i++) {
int nret;
SV **svp = av_fetch(avs[0], i, FALSE);
GvSV(PL_firstgv) = svp ? *svp : &PL_sv_undef;
svp = av_fetch(avs[1], i, FALSE);
GvSV(PL_secondgv) = svp ? *svp : &PL_sv_undef;
PUSHMARK(SP);
OUTPUT:
RETVAL
int
bsearchidx (code, ...)
SV *code;
PROTOTYPE: &@
CODE:
{
dMULTICALL;
HV *stash;
GV *gv;
I32 gimme = GIMME_V; /* perl-5.5.4 bus-errors out later when using GIMME
therefore we save its value in a fresh variable */
SV **args = &PL_stack_base[ax];
long i, j;
int val = -1;
if (!codelike(code))
croak_xs_usage(cv, "code, ...");
RETVAL = -1;
if (items > 1) {
CV *_cv = sv_2cv(code, &stash, &gv, 0);
PUSH_MULTICALL(_cv);
SAVESPTR(GvSV(PL_defgv));
i = 0;
j = items - 1;
do {
long k = (i + j) / 2;
if (k >= items-1)
break;
GvSV(PL_defgv) = args[1+k];
MULTICALL;
val = SvIV(*PL_stack_sp);
if (val == 0) {
RETVAL = k;
break;
}
if (val < 0) {
i = k+1;
} else {
j = k-1;
}
} while (i <= j);
POP_MULTICALL;
}
}
OUTPUT:
RETVAL
void
mode (...)
PROTOTYPE: @
PPCODE:
{
int i;
unsigned int max = 0;
unsigned int c = 0;
unsigned int modality = 0;
SV **args = &PL_stack_base[ax];
HV *hv = newHV();
SV *tmp = sv_newmortal();
HE *he;
sv_2mortal(newRV_noinc((SV*)hv));
if (!items) {
if (GIMME_V == G_SCALAR) {
mPUSHi(0);
PUTBACK;
return;
}
else {
XSRETURN_EMPTY;
}
}
for (i = 0; i < items; i++) {
SvGETMAGIC(args[i]);
SvSetSV_nosteal(tmp, args[i]);
he = hv_fetch_ent(hv, tmp, 0, 0);
if (NULL == he) {
hv_store_ent(hv, tmp, newSViv(1), 0);
}
else {
SV *v = HeVAL(he);
IV how_many = SvIVX(v);
sv_setiv(v, ++how_many);
}
}
hv_iterinit(hv);
while ((he = hv_iternext(hv))) {
c = SvIV(HeVAL(he));
if (c > max) {
max = c;
}
}
i = 0;
hv_iterinit(hv);
while ((he = hv_iternext(hv))) {
if (SvIV(HeVAL(he)) == max) {
if (GIMME_V == G_SCALAR) {
modality++;
} else {
XPUSHs(HeSVKEY_force(he));
}
}
}
if (GIMME_V == G_SCALAR) {
mXPUSHu(modality);
( run in 1.374 second using v1.01-cache-2.11-cpan-5511b514fd6 )