Algorithm-Permute
view release on metacpan or search on metacpan
if (RETVAL->ptr_head == NULL)
XSRETURN_UNDEF;
q = RETVAL->ptr_head;
RETVAL->ptr = safemalloc(sizeof(listrecord*) * (num + 1));
if (RETVAL->ptr == NULL)
XSRETURN_UNDEF;
RETVAL->pred = safemalloc(sizeof(listrecord*) * (num + 1));
if (RETVAL->pred == NULL)
XSRETURN_UNDEF;
#else
RETVAL->p = (UINT*) safemalloc(sizeof(UINT) * (num + 1));
if (RETVAL->p == NULL)
XSRETURN_UNDEF;
RETVAL->loc = (UINT*) safemalloc(sizeof(UINT) * (num + 1));
if (RETVAL->loc == NULL)
XSRETURN_UNDEF;
#endif
/* initialize items, p, and loc */
for (i = 1; i <= num; i++) {
if (has_combination) {
*(RETVAL->items + i) = &PL_sv_undef;
} else {
*(RETVAL->items + i) = av_shift(av);
}
#ifdef USE_LINKEDLIST
q->link = safemalloc(sizeof(listrecord));
if (q->link == NULL)
XSRETURN_UNDEF;
q = q->link;
q->info = num - i + 1;
RETVAL->ptr[q->info] = q;
RETVAL->pred[i] = RETVAL->ptr_head; /* all predecessors point to ptr_head */
#else
*(RETVAL->p + i) = num - i + 1;
*(RETVAL->loc + i) = 1;
#endif
}
#ifdef USE_LINKEDLIST
q->link = NULL; /* the tail of list points to NULL */
#endif
if (has_combination) {
if(!reset_combination(RETVAL, av, r)) {
XSRETURN_UNDEF;
}
}
OUTPUT:
RETVAL
void
next(self)
Permute *self
PREINIT:
int i;
#ifdef USE_LINKEDLIST
listrecord *q; /* temporary holder */
#endif
PPCODE:
if (self->is_done) { /* done permutation for all combination */
if (self->c) {
free_combination(self->c);
self->c = NULL;
}
XSRETURN_EMPTY;
}
else {
EXTEND(sp, self->num);
#ifdef USE_LINKEDLIST
q = self->ptr_head->link;
while (q) {
PUSHs(sv_2mortal(newSVsv(*(self->items + q->info))));
/* PerlIO_stdoutf("%d\n", q->info); */
q = q->link;
}
self->is_done = _next(self->num, self->ptr_head, self->ptr, self->pred);
#else
for (i = 1; i <= self->num; i++) {
PUSHs(sv_2mortal(newSVsv(*(self->items + *(self->p + i)))));
}
self->is_done = _next(self->num, self->p, self->loc);
#endif
}
/* generate next combination if necessary */
if (self->is_done && self->c) { /* permutation done */
self->is_done = coollex(self->c); /* generate next combination */
#ifdef USE_LINKEDLIST
q = self->ptr_head;
for (i = 1; i <= self->num; i++) {
q = q->link;
q->info = self->num - i + 1;
self->pred[i] = self->ptr_head;
}
/* q->link = NULL; */
assert(q->link == NULL); /* should point to NULL */
#else
/* reset self->p and self->loc */
for (i = 1; i <= self->num; i++) {
*(self->p + i) = self->num - i + 1;
*(self->loc + i) = 1;
}
#endif
/* and update self->items */
coollex_visit(self->c, self->items + 1);
}
void
DESTROY(self)
Permute *self
PREINIT:
int i;
#ifdef USE_LINKEDLIST
listrecord *q;
#endif
CODE:
SvREFCNT_dec(self->aryref);
#ifdef USE_LINKEDLIST
q = self->ptr_head;
for (i = 1; i <= self->num; i++) {
safefree(self->ptr[i]);
/* No need to deallocate this, in fact, it would be disaster */
/* safefree(self->pred[i]); */
SvREFCNT_dec(*(self->items + i));
}
safefree(self->ptr);
safefree(self->pred);
safefree(self->ptr_head);
#else
safefree(self->p); /* must free elements first? */
safefree(self->loc);
for (i = 1; i <= self->num; i++) { /* leakproof! */
SvREFCNT_dec(*(self->items + i));
}
#endif
safefree(self->items);
safefree(self);
void
peek(self)
Permute *self
PREINIT:
#ifdef USE_LINKEDLIST
listrecord *q;
#else
int i;
#endif
PPCODE:
if (self->is_done)
XSRETURN_EMPTY;
EXTEND(sp, self->num);
#ifdef USE_LINKEDLIST
q = self->ptr_head->link;
while (q) {
PUSHs(sv_2mortal(newSVsv(*(self->items + q->info))));
q = q->link;
}
#else
for (i = 1; i <= self->num; i++)
PUSHs(sv_2mortal(newSVsv(*(self->items + *(self->p + i)))));
#endif
void
reset(self)
Permute *self
PREINIT:
int i;
AV* av;
COMBINATION *c;
UV n;
#ifdef USE_LINKEDLIST
listrecord *q;
#endif
CODE:
self->is_done = FALSE;
reset_combination(self, (AV*)(SvRV(self->aryref)), self->num);
#ifdef USE_LINKEDLIST
q = self->ptr_head;
for (i = 1; i <= self->num; i++) {
q = q->link;
q->info = self->num - i + 1;
self->pred[i] = self->ptr_head;
}
assert(q->link == NULL);
#else
for (i = 1; i <= self->num; i++) {
*(self->p + i) = self->num - i + 1;
*(self->loc + i) = 1;
}
#endif
void
permute(callback_sv, array_sv)
SV* callback_sv;
SV* array_sv;
PROTOTYPE: &\@
PREINIT:
CV* callback;
GV* agv;
I32 x;
PERL_CONTEXT* cx;
I32 gimme = G_VOID; /* We call our callback in VOID context */
bool old_catch;
struct afp_cache *c;
I32 hasargs = 0;
SV** newsp;
PPCODE:
{
if (!SvROK(callback_sv) || SvTYPE(SvRV(callback_sv)) != SVt_PVCV)
Perl_croak(aTHX_ "Callback is not a CODE reference");
if (!SvROK(array_sv) || SvTYPE(SvRV(array_sv)) != SVt_PVAV)
Perl_croak(aTHX_ "Array is not an ARRAY reference");
c = malloc(sizeof(struct afp_cache));
callback = (CV*)SvRV(callback_sv);
c->array = (AV*)SvRV(array_sv);
c->len = 1 + av_len(c->array);
agv = gv_fetchpv("A", TRUE, SVt_PVAV);
SAVESPTR(GvSV(agv));
if (SvREADONLY(c->array))
Perl_croak(aTHX_ "Can't permute a read-only array");
if (c->len == 0) {
/* Should we warn here? */
free(c);
return;
}
c->array_array = AvARRAY(c->array);
c->array_flags = SvFLAGS(c->array);
c->array_fill = AvFILLp(c->array);
/* Magical array. Realise it temporarily. */
if (SvRMAGICAL(c->array)) {
c->copy = (SV**) malloc (c->len * sizeof *(c->copy));
for (x = 0; x < c->len; x++) {
SV **svp = av_fetch(c->array, x, FALSE);
c->copy[x] = (svp) ? SvREFCNT_inc(*svp) : &PL_sv_undef;
}
SvRMAGICAL_off(c->array);
AvARRAY_set(c->array, c->copy);
AvFILLp(c->array) = c->len - 1;
} else {
c->copy = 0;
}
SvREADONLY_on(c->array); /* Can't change the array during permute */
/* Allocate memory for the engine to scribble on */
c->tmparea = (SV***) malloc((c->len + 1) * sizeof *(c->tmparea));
for (x = c->len; x >= 0; x--)
c->tmparea[x] = malloc(c->len * sizeof **(c->tmparea));
{
dMULTICALL;
PUSH_MULTICALL(callback);
SAVEDESTRUCTOR(afp_destructor, c);
permute_engine(c->array, AvARRAY(c->array), 0, c->len,
c->tmparea, multicall_cop);
POP_MULTICALL;
}
}
( run in 1.435 second using v1.01-cache-2.11-cpan-71847e10f99 )