Algorithm-Statistic

 view release on metacpan or  search on metacpan

Statistic.xs  view on Meta::CPAN

#ifdef __cplusplus
extern "C" {
#endif

#define PERL_NO_GET_CONTEXT
#include "EXTERN.h"
#include "perl.h"
#define NO_XSLOCKS 
#include "XSUB.h"

#ifdef __cplusplus
} /* extern "C" */
#endif

#include "ppport.h"

#define NDEBUG
#include <memory>

#include "kth_order_statistic.hpp"
#include "debug.hpp"

/**
 * Default comparator for numerics
 */
class PerlDefaultCompare {
public:
    virtual ~PerlDefaultCompare() {}

    virtual int operator()(SV* const x, SV* const y) const {
        dTHX; 
        SV *z = x;
        if (SvTYPE(x) < SvTYPE(y)) {
            // For comparison betwee flaot and int
            z = y;
        }

        int res = 0;

        switch (SvTYPE(y)) {
            case SVt_PVIV:
            case SVt_IV: {
                int a = SvIV(x),
                    b = SvIV(y);

                res = a < b ? -1 : a > b ? 1 : 0;
                break;
            }
            case SVt_PVNV:
            case SVt_NV:
            default: {
                float a = SvNV(x),
                      b = SvNV(y);
            
                res = a < b ? -1 : a > b ? 1 : 0;
                break;
            }
        }
    
        return res;
    }
};

/**
 * Extended comparator specified from perl
 */
class PerlCompare : public PerlDefaultCompare {
public:
    PerlCompare(SV* compare) : compare_(compare), PerlDefaultCompare() {}

    int operator()(SV* const x, SV* const y) const {
        dTHX;
        dSP;

        ENTER;
        SAVETMPS;

        PUSHMARK(SP);
        EXTEND(SP, 2);
        PUSHs(x);
        PUSHs(y);
        PUTBACK;

        call_sv(compare_, G_SCALAR);
        SPAGAIN;
        int const ret = POPi;
        PUTBACK;

        FREETMPS;
        LEAVE;

        return ret;
    }
private:
    SV* compare_;
};


bool is_array_ref(const SV * const  a) {
    return (SvROK(a) && SvTYPE(SvRV(a)) == SVt_PVAV);
}

bool is_sub_ref(const SV * const cv) {
    return (SvROK(cv) && SvTYPE(SvRV(cv)) == SVt_PVCV);
}


MODULE = Algorithm::Statistic      PACKAGE = Algorithm::Statistic



SV *
kth_order_statistic(SV *array_ref, SV *k, ...)
    PROTOTYPE: $$;&
    CODE:
    {
        if (!is_array_ref(array_ref)) {
            warn("Not an array reference passed"); 
            XSRETURN_UNDEF;
        }
       
        std::shared_ptr<PerlDefaultCompare> comparator(new PerlDefaultCompare());
        // compare declared?
        if (items > 2) {
            if (is_sub_ref(ST(2))) {
                SV* compare = ST(2);    
                comparator = std::shared_ptr<PerlCompare>(new PerlCompare(compare));
            }



( run in 1.524 second using v1.01-cache-2.11-cpan-39bf76dae61 )