Hash-GuavaRing

 view release on metacpan or  search on metacpan

GuavaRing.xs  view on Meta::CPAN

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

#include "ppport.h"

/////////////////////////// guava-hash code ///////////////////////////////
int guava(long long state, unsigned int buckets);

static const long long
	K   = 2862933555777941757L;

static const double
	D   = 0x1.0p31;

int guava(long long state, unsigned int buckets) {
	int candidate = 0;
	int next;
	while (1) {
		state = K * state + 1;
		next = (int) ( (double) (candidate + 1) / ( (double)( (int)( (long long unsigned) state >> 33 ) + 1 ) / D ) );
		// printf("\nstate=%lld next=%d\n",stat,next);
		if ( ( next >= 0 ) && ( next < buckets )) {
			candidate = next;
		} else {
			return candidate;
		}
	}
}


/////////////////////// END guava-hash code ///////////////////////////////

#ifndef likely
#define likely(x)       __builtin_expect(!!(x), 1)
#define unlikely(x)     __builtin_expect(!!(x), 0)
#endif

typedef struct {
	SV * self;
	HV * stash;
	AV * nodes;
} GuavaRing;

#define svstrcmp(a,b) strcmp(SvPV_nolen(a),b)

MODULE = Hash::GuavaRing		PACKAGE = Hash::GuavaRing

void new(...)
	PPCODE:
		if (items < 1) croak("Usage: %s->new(...)",SvPV_nolen(ST(0)));
		GuavaRing * self = (GuavaRing *) safemalloc( sizeof(GuavaRing) );
		if (unlikely(!self)) croak("Failed to allocate memory");
		memset(self,0,sizeof(GuavaRing));
		self->stash = gv_stashpv(SvPV_nolen(ST(0)), TRUE);
		{
			SV *iv = newSViv(PTR2IV( self ));
			self->self = sv_bless(newRV_noinc (iv), self->stash);
			ST(0) = sv_2mortal(self->self);
		}
		int i;
		SV **key;
		AV *nodes = 0;
		for ( i=1; i < items; i=i+2) {
			if ( !svstrcmp(ST(i),"nodes") ) {
				if (SvROK(ST(i+1)) && SvTYPE(SvRV(ST(i+1))) == SVt_PVAV) {
					nodes = (AV *) SvRV( ST(i+1) );
				} else {
					croak("nodes must be arrayref, but got %s", SvPV_nolen(ST(i+1)));
				}
			}
			else {
				croak("Uknown option '%s'", SvPV_nolen(ST(i)));
			}
		}
		self->nodes = newAV();
		for ( i = 0; i <= av_len(nodes); i++ ) {
			key = av_fetch( nodes, i, 0 );
			av_store(self->nodes, i, SvREFCNT_inc(*key));
		}

		XSRETURN(1);

void DESTROY(SV *)
	PPCODE:
		register GuavaRing *self = ( GuavaRing * ) SvUV( SvRV( ST(0) ) );
		if (self->nodes) SvREFCNT_dec(self->nodes);
		if (self->self && SvOK(self->self) && SvOK( SvRV(self->self) )) {
			SvREFCNT_inc(SvRV(self->self));
			SvREFCNT_dec(self->self);
		}
		safefree(self);
		XSRETURN_UNDEF;

void get (SV *, SV * key)
	PPCODE:
		register GuavaRing *self = ( GuavaRing * ) SvUV( SvRV( ST(0) ) );
		// fprintf(stderr,"\nav_len(self->nodes) = %i\n",av_len(self->nodes));
		int idx = guava( SvIV(key), av_len(self->nodes)+1 );

		SV **node = av_fetch(self->nodes, idx, 0);

		ST(0) = *node;
		XSRETURN(1);



( run in 0.460 second using v1.01-cache-2.11-cpan-5511b514fd6 )