#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>
AV * ALPHA;
HV * INDEX;
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
out[100] =
""
;
while
(id > 0) {
sprintf
(out,
"%s%s"
, out, SvPV_nolen(*av_fetch(ALPHA, id % COUNT, 0)));
id =
floor
(id / COUNT);
}
reverse(out);
return
out;
}
static
int
_inverse (
char
* id) {
dTHX;
int
out = 0;
for
(
int
i = 0; i <
strlen
(id); i++) {
out = out * COUNT + SvIV(*hv_fetch(INDEX, &id[i], 1, 0));
}
return
out - OFFSET;
}
MODULE = Bijection::XS PACKAGE = Bijection::XS
PROTOTYPES: ENABLE
SV *
bijection_set(...)
CODE:
ALPHA = av_make(items, MARK+1);
SV * first = *av_fetch(ALPHA, 0, 0);
if
(SvTYPE(first) == SVt_IV && SvIV(first) > 0) {
OFFSET = SvIV(av_shift(ALPHA));
}
else
{
OFFSET = av_len(ALPHA) + 1;
}
COUNT = av_len(ALPHA) + 1;
INDEX = newHV();
for
(
int
i = 0; i < COUNT; i++) {
char
* key = SvPV_nolen(*av_fetch(ALPHA, i, 0));
hv_store(INDEX, key,
strlen
(key), newSViv(i), 0);
}
RETVAL = newSViv(COUNT);
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:
RETVAL = newSViv(_inverse(SvPV_nolen(str)));
OUTPUT:
RETVAL