#define PERL_NO_GET_CONTEXT // we'll define thread context if necessary (faster)
#include "EXTERN.h" // globals/constant import locations
#include "perl.h" // Perl symbols, structures and constants definition
#include "XSUB.h" // xsubpp functions and macros
#include <math.h>
char * ALPHA[256];
int INDEX[256];
int OFFSET;
int COUNT;
void reverse(char *s) {
size_t len = strlen(s);
char *a = s;
char *b = &s[(int)len - 1];
char tmp;
for (; a < b; ++a, --b) {
tmp = *a;
*a = *b;
*b = tmp;
}
}
static char * _biject (int id) {
dTHX;
id = id + OFFSET;
char * outs = (char*) calloc(100, sizeof(char*));;
while (id > 0) {
strncat(outs, ALPHA[id % COUNT], 1);
id = floor(id / COUNT);
}
reverse(outs);
return outs;
}
static int _inverse (char * id) {
dTHX;
int out = 0, i = 0;
for (i = 0; i < strlen(id); i++) {
out = out * COUNT + INDEX[(int)id[i]];
}
return out - OFFSET;
}
MODULE = Bijection::XS PACKAGE = Bijection::XS
PROTOTYPES: ENABLE
SV *
bijection_set(...)
CODE:
AV * args = av_make(items, MARK+1);
SV * first = *av_fetch(args, 0, 0);
int i = 0;
if (SvTYPE(first) == SVt_IV && SvIV(first) > 0) {
OFFSET = SvIV(first);
av_shift(args);
} else {
OFFSET = av_len(args) + 1;
}
COUNT = av_len(args) + 1;
for (i = 0; i < COUNT; i++) {
STRLEN retlen;
char * key = SvPV(*av_fetch(args, i, 0), retlen);
ALPHA[i] = key;
INDEX[(int)key[0]] = i;
}
RETVAL = newSViv(OFFSET);
OUTPUT:
RETVAL
void
offset_set(offset)
SV * offset
CODE:
OFFSET = SvIV(offset);
SV *
biject(id)
SV * id
CODE:
if (SvIV(id) < 0) {
croak("id to encode must be an integer and non-negative");
}
char * str = _biject(SvIV(id));
RETVAL = newSVpv(str, strlen(str));
OUTPUT:
RETVAL
SV *
inverse(str)
SV * str
CODE:
STRLEN retlen;
RETVAL = newSViv(_inverse(SvPV(str, retlen)));
OUTPUT:
RETVAL