List-BinarySearch-XS
view release on metacpan or search on metacpan
SV* binsearch_pos( SV* block, SV* needle, SV* aref_haystack ) {
dTHX;
dSP;
dMULTICALL;
GV *gv;
HV *stash;
I32 gimme = G_SCALAR;
CV *cv = sv_2cv(block, &stash, &gv, 0);
I32 low = 0;
I32 high = 0;
GV *agv = gv_fetchpv("a", GV_ADD, SVt_PV);
GV *bgv = gv_fetchpv("b", GV_ADD, SVt_PV);
AV *haystack = 0;
SAVESPTR(GvSV(agv));
SAVESPTR(GvSV(bgv));
/* We must have a valid subref, and aref for the haystack. */
if( cv == Nullcv )
croak("Not a subroutine reference.");
if( ! SvROK( aref_haystack ) || SvTYPE(SvRV(aref_haystack)) != SVt_PVAV )
croak( "Argument must be an array ref.\n" );
haystack = (AV*)SvRV(aref_haystack);
high = av_len(haystack) + 1; /* scalar @{$aref} (Perl 5.16 introduced av_top_index synonym.) */
if( high <= 0 ) return newSViv(low); /* Empty list; insert at zero. */
PUSH_MULTICALL(cv);
while( low < high ) {
I32 cur = ( high - low ) / 2 + low;
/* Fetch value at aref_haystack->[mid] */
GvSV(agv) = needle;
GvSV(bgv) = *av_fetch(haystack,cur,0); /* Hay */
MULTICALL;
if( SvIV( *PL_stack_sp ) > 0 ) { /* if ($a<=>$b) > 0 */
low = cur + 1;
}
else {
high = cur;
}
}
POP_MULTICALL;
return newSViv(low);
}
MODULE = List::BinarySearch::XS PACKAGE = List::BinarySearch::XS
PROTOTYPES: ENABLE
SV *
binsearch (block, needle, aref_haystack)
SV * block
SV * needle
SV * aref_haystack
PROTOTYPE: &$\@
PPCODE:
/* We need binsearch to return undef or empty list on no match, depending
* on context. This snippet detects an undef rv, and just massages it
* into an empty list.
*/
I32 rv = binsearch( block, needle, aref_haystack );
if( rv == -1 ) {
XSRETURN_EMPTY;
}
else {
SV* output = sv_2mortal(newSViv(rv));
PUSHs(output);
}
/* In other words, only return something if our search was successful. */
SV *
binsearch_pos (block, needle, aref_haystack)
SV * block
SV * needle
SV * aref_haystack
PROTOTYPE: &$\@
( run in 1.222 second using v1.01-cache-2.11-cpan-5511b514fd6 )