/* -*- Mode: C -*- */
#define PERL_NO_GET_CONTEXT 1
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#include "ppport.h"
static const char bit_count[] = { 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8 };
typedef void (*iterate_cb)(pTHX_ UV ix, SV *ele, void *ptr);
static void
iterate(pTHX_ SV *vec, SV **eles, UV size, iterate_cb cb, void *ptr) {
STRLEN bits_len;
const char *bits = SvPV_const(vec, bits_len);
UV bits_size = bits_len * 8;
UV i = 0;
if (size > bits_size) size = bits_size;
while (i < size) {
char byte = *(bits++);
int j;
for (j = 0; j < 8; j++) {
if (i == size) return;
if ((byte >> j) & 1) (*cb)(aTHX_ i, eles[i], ptr);
i++;
}
}
}
static void
bg_sum_cb(pTHX_ UV ix, SV *ele, void *nv) {
*(NV*)nv += SvNV(ele);
}
struct bg_stats_state {
UV count;
NV sum;
NV sum2;
};
static void
bg_count_and_sum_cb(pTHX_ UV ix, SV *ele, void *state) {
((struct bg_stats_state*)state)->count++;
((struct bg_stats_state*)state)->sum += SvNV(ele);
}
static void
bg_count_sum_and_sum2_cb(pTHX_ UV ix, SV *ele, void *state) {
NV nv = SvNV(ele);
((struct bg_stats_state*)state)->count++;
((struct bg_stats_state*)state)->sum += nv;
((struct bg_stats_state*)state)->sum2 += nv * nv;
}
static void
bg_grep_cb(pTHX_ UV ix, SV *ele, void *state) {
SV **to = (*(SV***)state)++;
*to = ele;
}
MODULE = Bit::Grep PACKAGE = Bit::Grep
PROTOTYPES: DISABLE
void
bg_grep(vec, ...)
SV *vec;
PREINIT:
SV **to;
PPCODE:
to = &(ST(0));
iterate(aTHX_ vec, &(ST(1)), items - 1, &bg_grep_cb, &to);
XSRETURN(to - &(ST(0)));
NV
bg_sum(vec, ...)
SV *vec;
CODE:
RETVAL = 0;
iterate(aTHX_ vec, &(ST(1)), items - 1, &bg_sum_cb, &RETVAL);
OUTPUT:
RETVAL
void
bg_count_and_sum(vec, ...)
SV *vec;
PREINIT:
struct bg_stats_state state;
PPCODE:
state.count = 0;
state.sum = 0;
iterate(aTHX_ vec, &(ST(1)), items - 1, &bg_count_and_sum_cb, &state);
mXPUSHi(state.count);
mXPUSHn(state.sum);
XSRETURN(2);
void
bg_count_sum_and_sum2(vec, ...)
SV *vec;
PREINIT:
struct bg_stats_state state;
PPCODE:
state.count = 0;
state.sum = 0;
state.sum2 = 0;
iterate(aTHX_ vec, &(ST(1)), items - 1, &bg_count_sum_and_sum2_cb, &state);
mXPUSHi(state.count);
mXPUSHn(state.sum);
mXPUSHn(state.sum2);
XSRETURN(3);
SV *
bg_avg(vec, ...)
SV *vec;
PREINIT:
struct bg_stats_state state;
CODE:
state.count = 0;
state.sum = 0;
iterate(aTHX_ vec, &(ST(1)), items -1, &bg_count_and_sum_cb, &state);
RETVAL = (state.count ? newSVnv(state.sum/state.count) : &PL_sv_undef);
OUTPUT:
RETVAL