Skip to content

Instantly share code, notes, and snippets.

@nrdvana
Created June 2, 2022 17:16
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nrdvana/8a79e0c37838c7b7f5829ca2df9c862b to your computer and use it in GitHub Desktop.
Save nrdvana/8a79e0c37838c7b7f5829ca2df9c862b to your computer and use it in GitHub Desktop.
TreeRBXS.c Iter_next method
XS_EUPXS(XS_Tree__RB__XS__Iter_next); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_Tree__RB__XS__Iter_next)
{
dVAR; dXSARGS;
dXSI32;
if (items < 1 || items > 2)
croak_xs_usage(cv, "iter, count_sv= NULL");
PERL_UNUSED_VAR(ax); /* -Wall */
SP -= items;
{
struct TreeRBXS_iter * iter;
SV* count_sv;
iter= TreeRBXS_get_magic_iter(ST(0), OR_DIE)
;
if (items < 2)
count_sv = NULL;
else {
count_sv = ST(1)
;
}
#line 1857 "TreeRBXS.xs"
size_t pos, n, i, tree_count= TreeRBXS_get_count(iter->tree);
IV request;
rbtree_node_t *node;
rbtree_node_t *(*step)(rbtree_node_t *)= iter->reverse? &rbtree_node_prev : rbtree_node_next;
#line 2761 "TreeRBXS.c"
#line 1862 "TreeRBXS.xs"
if (iter->item) {
request= !count_sv? 1
: SvPOK(count_sv) && *SvPV_nolen(count_sv) == '*'? tree_count
: SvIV(count_sv);
if (request < 1) {
n= i= 0;
}
// A request for 1 is simpler because there is no need to count how many will be returned.
// iter->item wasn't NULL so it is guaranteed to be 1.
else if (GIMME_V == G_VOID) {
// skip all the busywork if called in void context
// (but still advance the iterator below)
n= request;
i= 0;
}
else if (request == 1) {
n= i= 1;
ST(0)= ix == 0? sv_2mortal(TreeRBXS_wrap_item(iter->item))
: ix == 2? iter->item->value
: sv_2mortal(TreeRBXS_item_wrap_key(iter->item));
if (ix == 3) {
warn("EXTEND(SP, %d)", 2);
EXTEND(SP, 2);
ST(1)= iter->item->value;
}
}
else {
pos= rbtree_node_index(&iter->item->rbnode);
// calculate how many nodes will be returned
n= iter->reverse? 1 + pos : tree_count - pos;
if (n > request) n= request;
node= &iter->item->rbnode;
warn("EXTEND(SP, %ld", ix == 3? 2*n : n);
EXTEND(SP, ix == 3? 2*n : n);
if (ix == 0) {
for (i= 0; i < n && node; i++, node= step(node)) {
warn("Accessing ST(%ld)", i);
ST(i)= sv_2mortal(TreeRBXS_wrap_item(GET_TreeRBXS_item_FROM_rbnode(node)));
}
}
else if (ix == 1) {
for (i= 0; i < n && node; i++, node= step(node)) {
warn("Accessing ST(%ld)", i);
ST(i)= sv_2mortal(TreeRBXS_item_wrap_key(GET_TreeRBXS_item_FROM_rbnode(node)));
}
}
else if (ix == 2) {
for (i= 0; i < n && node; i++, node= step(node)) {
warn("Accessing ST(%ld)", i);
ST(i)= GET_TreeRBXS_item_FROM_rbnode(node)->value;
}
}
else {
for (i= 0; i < n && node; i++, node= step(node)) {
warn("Accessing ST(%ld), ST(%ld)", i*2, i*2+1);
ST(i*2)= sv_2mortal(TreeRBXS_item_wrap_key(GET_TreeRBXS_item_FROM_rbnode(node)));
ST(i*2+1)= GET_TreeRBXS_item_FROM_rbnode(node)->value;
}
}
if (i != n)
croak("BUG: expected %ld nodes but found %ld", (long) n, (long) i);
}
TreeRBXS_iter_advance(iter, n);
warn("XSRETURN(%ld)", ix == 3? 2*i : i);
XSRETURN(ix == 3? 2*i : i);
} else {
// end of iteration, nothing to do
ST(0)= &PL_sv_undef;
// return the undef only if the user didn't specify a count
warn("XSRETURN(%d)", count_sv? 0 : 1);
XSRETURN(count_sv? 0 : 1);
}
#line 2835 "TreeRBXS.c"
PUTBACK;
return;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment