#define CMP( callback, aa, bb ) \ ( ( GvSV( a ) = ( aa ) ), ( GvSV( b ) = ( bb ) ), CmpAB( callback ) ) int CmpAB( SV* cmp ) { int rv; dSP; PUSHMARK(SP); if( call_sv( cmp, G_SCALAR|G_NOARGS ) != 1 ) croak( "Bad comparator" ); SPAGAIN; rv = POPi; PUTBACK; return rv; } void topNbsAB( int n, SV *cmp, AV*data ) { SV* *topN; int len = av_len( data ); int i, k; int left, right; SV* a = gv_fetchpv( "main::a", TRUE, SVt_PV ); SV* b = gv_fetchpv( "main::b", TRUE, SVt_PV ); Inline_Stack_Vars; Newz( 1, topN, n + 1, SV* ); for( i = 0; i < n+1; i++ ) { topN[ i ] = newSViv( 0 ); } for( i = 0; i <= len; i++ ) { SV *val = *av_fetch( data, i, 0 ); if( CMP( cmp, val, topN[ n - 1] ) < 0 ) continue; left = 0; right = n - 1; while (left < right) { int middle = ( left + right ) >> 1; if( CMP( cmp, val, topN[ middle ] ) <= 0 ) { left = middle + 1; } else { right = middle; } } for( k = n; k > left; k-- ) topN[ k ] = topN[ k-1 ]; topN[ left ] = val; } Inline_Stack_Reset; for( i = 0; i < n; i++ ) Inline_Stack_Push( sv_2mortal( newSVsv( topN[ i ] ) ) ); Safefree( topN ); Inline_Stack_Done; }