#define MYPUSHMARK(p) \ ( *PL_markstack_ptr = ( ++PL_markstack_ptr == PL_markstack_max ) \ ? ( markstack_grow(), (p) - PL_stack_base ) \ : ( (p) - PL_stack_base ) ) #define CMP( callback, aa, bb ) ( \ ( GvSV( a ) = ( aa ) ), \ ( GvSV( b ) = ( bb ) ), \ ( MYPUSHMARK(SP) ), \ ( call_sv( callback, G_SCALAR|G_NOARGS ) ), \ ( SPAGAIN ), \ ( POPi ) \ ) void topNbsAB( int n, SV *cmp, AV*data ) { int i, k; int left, right; int len = av_len( data ); GV* a = gv_fetchpv( "main::a", TRUE, SVt_PV ); GV* b = gv_fetchpv( "main::b", TRUE, SVt_PV ); dSP; dMARK; dAX; POPMARK; POPs; POPs; POPs; EXTEND( SP, n ); PUSHMARK( SP ); for( i = 0; i < n; i++ ) { PUSHs( newSViv( 0 ) ); } PUTBACK; for( i = 0; i <= len; i++ ) { SV *val = *av_fetch( data, i, 0 ); if( CMP( cmp, val, ST( n-1 ) ) < 0 ) continue; left = 0; right = n; while (left < right) { int middle = ( left + right ) >> 1; if( CMP( cmp, val, ST( middle ) ) <= 0 ) { left = middle + 1; } else { right = middle; } } for( k = n; k >= left; k-- ) ST( k ) = ST( k - 1 ); ST( left ) = val; } XSRETURN( n ); }