List-Flatten-XS
view release on metacpan or search on metacpan
lib/List/Flatten/XS.xs view on Meta::CPAN
return sv_2mortal(newRV_inc((SV *)result));
}
static SV *
_flatten_per_level(pTHX_ SV *ref, IV level)
{
AV *stack = (AV *)sv_2mortal((SV *)newAV());
AV *result = (AV *)sv_2mortal((SV *)newAV());
// This is to detect circular reference
HV *memo = (HV *)sv_2mortal((SV *)newHV());
IV i = 0;
SV *tmp;
AV *ary = (AV *)SvRV(ref);
while (1) {
while (i < av_len(ary) + 1) {
tmp = AV_FETCH_MUST(ary, i++);
if ((av_len(stack) + 1) / 2 >= level) {
AV_PUSH_INC(result, tmp);
continue;
}
if (IS_ARRAYREF(tmp)) {
if (hv_exists_ent(memo, tmp, 0)) {
SvREFCNT_inc(stack);
Perl_croak(aTHX_ "tried to flatten recursive list(circular references)");
}
// store the pointer of array reference
hv_store_ent(memo, tmp, &PL_sv_undef, 0);
// push value to the stack
av_push(stack, (SV *)ary);
av_push(stack, sv_2mortal(newSViv(i)));
ary = (AV *)SvRV(tmp);
i = 0;
} else {
AV_PUSH_INC(result, tmp);
}
}
if (av_len(stack) + 1 == 0) break;
SV *idx = av_pop(stack);
i = SvIV(idx);
SV *poped = av_pop(stack);
ary = (AV *)poped; // Already done SvRV(SV *)
}
return sv_2mortal(newRV_inc((SV *)result));
}
MODULE = List::Flatten::XS PACKAGE = List::Flatten::XS
PROTOTYPES: DISABLE
void *
flatten(ref, svlevel = sv_2mortal(newSViv(-1)))
SV *ref;
SV *svlevel;
PPCODE:
{
if (!SvROK(ref) || SvTYPE(SvRV(ref)) != SVt_PVAV)
Perl_croak(aTHX_ "Please pass an array reference to the first argument");
IV level = SvIV(svlevel);
SV *result = (level < 0) ? _fast_flatten(aTHX_ ref)
: _flatten_per_level(aTHX_ ref, level);
if (GIMME_V == G_ARRAY) {
AV *av_result = (AV *)SvRV(result);
IV len = av_len(av_result) + 1;
for (IV i = 0; i < len; i++)
ST(i) = AV_FETCH_MUST(av_result, i);
XSRETURN(len);
}
ST(0) = result;
XSRETURN(1);
}
( run in 1.481 second using v1.01-cache-2.11-cpan-5511b514fd6 )