The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
#define PERL_NO_GET_CONTEXT
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"

#define MAX(a,b) (((a)>(b))?(a):(b))
#define MIN(a,b) (((a)<(b))?(a):(b))

/* use the system malloc and free */
#undef malloc
#undef free

MODULE = Text::Levenshtein::XS    PACKAGE = Text::Levenshtein::XS

PROTOTYPES: ENABLE

void
xs_distance (arraySource, arrayTarget)
  AV *    arraySource
  AV *    arrayTarget
PPCODE:
  {
  dXSTARG;
  PUSHs(TARG);
  PUTBACK;
  {
  unsigned int i,j,edits,retval,lenSource,lenTarget;
  lenSource = av_len(arraySource)+2;
  lenTarget = av_len(arrayTarget)+2;

  if(lenSource > 1 && lenTarget > 1) {
    unsigned int srctgt_max = MAX(lenSource,lenTarget);
    unsigned int * arrTarget = malloc(sizeof(int) * lenTarget );
    unsigned int * arrSource = malloc(sizeof(int) * lenSource );
    unsigned int *scores = malloc( (lenSource) * (lenTarget) * sizeof(unsigned int) );
    SV* elem01 = sv_2mortal(av_shift(arraySource));
    SV* elem02 = sv_2mortal(av_shift(arrayTarget));
    arrSource[ 0 ] = (int)SvIV((SV *)elem01);
    arrTarget[ 0 ] = (int)SvIV((SV *)elem02);
    scores[0] = 0;

    for (i=1; i < lenSource; i++) {
          SV* elem1 = sv_2mortal(av_shift(arraySource));
          arrSource[ i ] = (int)SvIV((SV *)elem1);
          scores[i] = i;

          for(j=1; j < lenTarget; j++) {
              if(i == 1) { 
                  SV* elem2 = sv_2mortal(av_shift(arrayTarget));
                  arrTarget[ j ] = (int)SvIV((SV *)elem2);

                  scores[j*lenSource] = j;
              }

              if(arrSource[i-1] == arrTarget[j-1]) 
                 edits = 0;
              else
                 edits = 1;

              scores[j*lenSource+i] = MIN(scores[(j-1)*lenSource+i]+1, 
						MIN(scores[j*lenSource+i-1]+1, scores[(j-1)*lenSource+i-1]+edits)
					   );
          }
    }

    retval = scores[lenSource*lenTarget-1];
    free(scores);
    free(arrSource);
    free(arrTarget);
  }
  else {
    /* handle a blank string */
    retval = (lenSource>lenTarget)?--lenSource:--lenTarget;
  }
  sv_setiv_mg(TARG, retval);
  return; /*we did a PUTBACK earlier, do not let xsubpp's PUTBACK run */
  }
  }