#if !defined __PMP_MULTILINEAR_HASHER_H__
#define __PMP_MULTILINEAR_HASHER_H__
#define __MULTILINEARPRIMESTRINGHASHFUNCTOR_CPP_H__REVISION_ "$Rev: 453 $"
#include "PMP_Multilinear_common.h"
#ifdef _MSC_VER
#define PMPML_CHUNK_OPTIMIZATION_TYPE 2
#define PMPML_MSC_32_WORKAROUND
#else
#if (defined __arm__ || defined __aarch64__)
#define PMPML_CHUNK_OPTIMIZATION_TYPE 1
#else
#ifdef __INTEL_COMPILER
#define PMPML_CHUNK_OPTIMIZATION_TYPE 1
#else
#define PMPML_CHUNK_OPTIMIZATION_TYPE 2
#endif #endif #endif
#if defined __arm__ || defined __aarch64__
#endif
#ifdef PMPML_STRICT_UNALIGNED_HANDLING
#endif
#if (PMPML_CHUNK_OPTIMIZATION_TYPE== 1)
#define PMPML_CHUNK_LOOP_INTRO_L0 \
ULARGE_INTEGER__XX ctr; \
ctr.QuadPart = 0; \
ULARGE_INTEGER__XX mul;
#define PMPML_CHUNK_LOOP_BODY_ULI_T1( i ) \
mul.QuadPart = UInt32x32To64( coeff[ i ], x[ i ] ); \
constTerm.QuadPart += mul.LowPart; \
ctr.QuadPart += mul.HighPart;
#ifdef PMPML_STRICT_UNALIGNED_HANDLING
#define PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( shift, i ) \
mul.QuadPart = UInt32x32To64( coeff[ i ], x | ( xx[ i ] << (32-shift) ) ); \
x = xx[ i ] >> shift; \
constTerm.QuadPart += mul.LowPart; \
ctr.QuadPart += mul.HighPart;
#define PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL_PTR( i ) \
mul.QuadPart = UInt32x32To64( coeff[ i ], xun[ i ].value ); \
constTerm.QuadPart += mul.LowPart; \
ctr.QuadPart += mul.HighPart;
#endif
#define PMPML_CHUNK_LOOP_BODY_ULI_T1_LAST \
mul.QuadPart = UInt32x32To64(xLast, (uint32_t)(coeff[ size ])); \
constTerm.QuadPart += mul.LowPart; \
ctr.QuadPart += mul.HighPart;
#define PMPML_CHUNK_LOOP_BODY_ULI_T1_LAST_FOR_JUST_1 \
constTerm.QuadPart += coeff[ size ];
#define PMPML_CHUNK_LOOP_PRE_REDUCE_L0
#define PMPML_FULL_REDUCE_MOD_2_32_PLUS_15_AND_RETURN \
{ \
ctr.QuadPart += constTerm.HighPart; \
constTerm.HighPart = ctr.LowPart; \
ULARGE_INTEGER__XX hilo; \
hilo.QuadPart = constTerm.HighPart * UINT64_C( 15 ); \
uint32_t part = ctr.HighPart * 225 + (hilo.HighPart << 4) - hilo.HighPart + 15; \
constTerm.LowPart += part; \
constTerm.HighPart = 1 + (constTerm.LowPart < part); \
constTerm.HighPart -= (constTerm.LowPart < hilo.LowPart); \
constTerm.LowPart -= hilo.LowPart; \
if ( _LIKELY_BRANCH_( constTerm.LowPart >= 30) ) { constTerm.LowPart -= constTerm.HighPart * 15; constTerm.HighPart = 0; } \
else \
{ \
constTerm.LowPart -= constTerm.HighPart * 15; \
if ( constTerm.LowPart < 30 ) constTerm.HighPart = 0; \
else \
{ \
constTerm.LowPart += 15; \
if ( constTerm.LowPart < 15 ) constTerm.HighPart = 1; \
else constTerm.HighPart = 0; \
} \
} \
return constTerm.QuadPart; \
}
#define PMPML_FULL_REDUCE_MOD_2_32_PLUS_15_AND_RETURN_RETURN \
{ \
ctr.QuadPart += constTerm.HighPart; \
constTerm.HighPart = ctr.LowPart; \
ULARGE_INTEGER__XX hilo; \
hilo.QuadPart = constTerm.HighPart * UINT64_C( 15 ); \
uint32_t part = ctr.HighPart * 225 + (hilo.HighPart << 4) - hilo.HighPart + 15; \
constTerm.LowPart += part; \
constTerm.HighPart = 1 + (constTerm.LowPart < part); \
constTerm.HighPart -= (constTerm.LowPart < hilo.LowPart); \
constTerm.LowPart -= hilo.LowPart; \
if ( _LIKELY_BRANCH_( constTerm.LowPart >= 30) ) { constTerm.LowPart -= (constTerm.HighPart << 4) - constTerm.HighPart; return fmix32_short( constTerm.LowPart ); } \
else \
{ \
constTerm.LowPart -= constTerm.HighPart * 15; \
if ( constTerm.LowPart < 30 ) return fmix32_short( constTerm.LowPart ); \
else \
{ \
constTerm.LowPart += 15; \
return fmix32_short( constTerm.LowPart ); \
} \
} \
}
#define PMPML_FULL_REDUCE_MOD_2_32_PLUS_15_AND_RETURN_RETURN_32x32_ONLY \
{ \
constTerm.QuadPart = constTerm.LowPart + PMPML_MAIN_PRIME - constTerm.HighPart * UINT64_C( 15 ); \
if ( _LIKELY_BRANCH_( constTerm.LowPart >= 30) ) { constTerm.LowPart -= (constTerm.HighPart << 4) - constTerm.HighPart; return fmix32_short( constTerm.LowPart ); } \
else \
{ \
constTerm.LowPart -= constTerm.HighPart * 15; \
if ( constTerm.LowPart < 30 ) return fmix32_short( constTerm.LowPart ); \
else \
{ \
constTerm.LowPart += 15; \
return fmix32_short( constTerm.LowPart ); \
} \
} \
}
#elif (PMPML_CHUNK_OPTIMIZATION_TYPE == 2)
#if defined(_MSC_VER)
FORCE_INLINE
void multiply32x32to64(uint32_t& rhi, uint32_t& rlo, uint32_t a, uint32_t b)
{
ULARGE_INTEGER__XX mul;
mul.QuadPart = UInt32x32To64( a, b );
rhi = mul.HighPart;
rlo = mul.LowPart;
}
FORCE_INLINE
void add64(uint32_t& loWord, uint32_t& hiWord, uint32_t& hhWord, uint32_t& loAdd, uint32_t& hiAdd )
{
loWord += loAdd;
uint64_t carry = loWord < loAdd;
hiWord += hiAdd;
uint64_t c1 = hiWord < hiAdd;
hhWord += c1;
hiWord += carry;
c1 = hiWord < carry;
hhWord += c1;
}
FORCE_INLINE
void mul32x32to64addto96(uint32_t& loWord, uint32_t& hiWord, uint32_t& hhWord, uint32_t a, uint32_t b )
{
ULARGE_INTEGER__XX mul;
mul.QuadPart = UInt32x32To64( a, b );
_addcarry_u32(_addcarry_u32(_addcarry_u32(0, loWord, mul.LowPart, reinterpret_cast<unsigned int*>(&(loWord))), hiWord, mul.HighPart, reinterpret_cast<unsigned int*>(&(hiWord))), hhWord, 0, reinterpret_cast<unsigned int*>(&(hhWord))); \
}
#else
inline
void multiply32x32to64(uint32_t& rhi, uint32_t& rlo, uint32_t a, uint32_t b)
{
#if defined __arm__ || defined __aarch64__
__asm("UMULL %0, %1, %2, %3\n"
: "+r" (rlo), "+r" (rhi)
: "r" (a), "r" (b) : "cc", "memory" );
#else
__asm__(
" mull %[b]\n"
:"=d"(rhi),"=a"(rlo)
:"1"(a),[b]"rm"(b));
#endif
}
inline
void add64(uint32_t& loWord, uint32_t& hiWord, uint32_t& hhWord, uint32_t& loAdd, uint32_t& hiAdd, uint32_t& hhAdd)
{
#if defined __arm__ || defined __aarch64__
__asm("ADDS %3, %3, %0\n"
"ADCS %1, %4, %1\n"
"ADC %2, %5, %2"
: "+r" (loWord), "+r" (hiWord), "+r" (hhWord)
: "r" (loAdd), "r" (hiAdd), "r" (hhAdd) : "cc", "memory" );
#else
__asm("addl %3, %0\n"
"adcl %4, %1\n"
"adcl %5, %2"
: "+g" (loWord), "+g" (hiWord), "+g" (hhWord)
: "g" (loAdd), "g" (hiAdd), "g" (hhAdd) : "cc", "memory" );
#endif
}
FORCE_INLINE
void mul32x32to64addto96(uint32_t& loWord, uint32_t& hiWord, uint32_t& hhWord, uint32_t a, uint32_t b)
{
uint32_t rhi;
#if defined __arm__ || defined __aarch64__
uint32_t rlo;
__asm("UMULL %3, %4, %5, %6\n"
"ADDS %0, %3, %0\n"
"ADCS %1, %4, %1\n"
"ADC %2, %2, #0x0"
: "+r" (loWord), "+r" (hiWord), "+r" (hhWord), "=r" (rlo), "=r" (rhi)
: "r" (a), "r" (b) : "cc" );
#else
__asm__( "mull %5\n"
"addl %%eax, %0\n"
"adcl %%edx, %1\n"
"adcl $0, %2\n"
: "+g" (loWord), "+g" (hiWord), "+g" (hhWord), "=a" (rhi)
:"a"(a), "g"(b) : "edx", "cc" );
#endif
}
#endif
#define PMPML_CHUNK_LOOP_INTRO_L0 \
uint32_t ctr; \
ctr = 0; \
ULARGE_INTEGER__XX mul;
#ifdef _MSC_VER
#define PMPML_CHUNK_LOOP_BODY_ULI_T1( i ) \
{ \
ULARGE_INTEGER__XX mul; \
mul.QuadPart = UInt32x32To64(x[i], coeff[i]); \
_addcarry_u32(_addcarry_u32(_addcarry_u32(0, constTerm.LowPart, mul.LowPart, reinterpret_cast<unsigned int*>(&(constTerm.LowPart))), constTerm.HighPart, mul.HighPart, reinterpret_cast<unsigned int*>(&(constTerm.HighPart))), ctr, 0, reinterpret_cast<unsigned int*>(&(ctr))); \
}
#define PMPML_CHUNK_LOOP_BODY_ULI_T1_LAST \
{\
ULARGE_INTEGER__XX mul; \
mul.QuadPart = UInt32x32To64(xLast, coeff[size]); \
_addcarry_u32(_addcarry_u32(_addcarry_u32(0, constTerm.LowPart, mul.LowPart, reinterpret_cast<unsigned int*>(&(constTerm.LowPart))), constTerm.HighPart, mul.HighPart, reinterpret_cast<unsigned int*>(&(constTerm.HighPart))), ctr, 0, reinterpret_cast<unsigned int*>(&(ctr))); \
}
#define PMPML_CHUNK_LOOP_BODY_ULI_T1_LAST_FOR_JUST_1 \
{\
_addcarry_u32(_addcarry_u32(_addcarry_u32(0, constTerm.LowPart, coeff[ size ], reinterpret_cast<unsigned int*>(&(constTerm.LowPart))), constTerm.HighPart, 0, reinterpret_cast<unsigned int*>(&(constTerm.HighPart))), ctr, 0, reinterpret_cast<unsigned int*>(&(ctr))); \
}
#else
#define PMPML_CHUNK_LOOP_BODY_ULI_T1( i ) \
\
mul32x32to64addto96(constTerm.LowPart, constTerm.HighPart, ctr, x[i], coeff[ i ]); \
#define PMPML_CHUNK_LOOP_BODY_ULI_T1_LAST \
\
mul32x32to64addto96(constTerm.LowPart, constTerm.HighPart, ctr, xLast, coeff[ size ]); \
#endif
#define PMPML_CHUNK_LOOP_PRE_REDUCE_L0
#define PMPML_CHUNK_REDUCE_96_TO_64
#define PMPML_CHUNK_REDUCE_64_TO_32 \
{ \
uint32_t lo, hi; \
multiply32x32to64(hi, lo, constTerm.HighPart, 15); \
uint32_t part = ctr * 225 + (hi << 4) - hi + 15; \
constTerm.LowPart += part; \
constTerm.HighPart = 1 + (constTerm.LowPart < part); \
constTerm.HighPart -= (constTerm.LowPart < lo); \
constTerm.LowPart -= lo; \
if ( _LIKELY_BRANCH_( constTerm.LowPart >= 30) ) { constTerm.LowPart -= constTerm.HighPart * 15; constTerm.HighPart = 0; } \
else \
{ \
if ( constTerm.HighPart ) \
{ \
constTerm.LowPart -= constTerm.HighPart * 15; \
constTerm.HighPart = 1; \
if ( _LIKELY_BRANCH_( constTerm.LowPart >= 15)) { constTerm.LowPart -= 15; constTerm.HighPart = 0; } \
else \
{ \
constTerm.LowPart -= 15; \
constTerm.HighPart = 0; \
} \
} \
} \
}
#define PMPML_FULL_REDUCE_MOD_2_32_PLUS_15_AND_RETURN \
PMPML_CHUNK_REDUCE_96_TO_64 \
PMPML_CHUNK_REDUCE_64_TO_32 \
return constTerm.QuadPart;
#define PMPML_FULL_REDUCE_MOD_2_32_PLUS_15_AND_RETURN_RETURN_32x32_ONLY \
{ \
constTerm.QuadPart = constTerm.LowPart + PMPML_MAIN_PRIME - constTerm.HighPart * UINT64_C( 15 ); \
if ( _LIKELY_BRANCH_( constTerm.LowPart >= 30) ) { constTerm.LowPart -= (constTerm.HighPart << 4) - constTerm.HighPart; return fmix32_short( constTerm.LowPart ); } \
else \
{ \
constTerm.LowPart -= constTerm.HighPart * 15; \
if ( constTerm.LowPart < 30 ) return fmix32_short( constTerm.LowPart ); \
else \
{ \
constTerm.LowPart += 15; \
return fmix32_short( constTerm.LowPart ); \
} \
} \
}
#define PMPML_FULL_REDUCE_MOD_2_32_PLUS_15_AND_RETURN_RETURN \
{ \
uint32_t lo, hi; \
multiply32x32to64(hi, lo, constTerm.HighPart, 15); \
uint32_t part = ctr * 225 + (hi << 4) - hi + 15; \
constTerm.LowPart += part; \
constTerm.HighPart = 1 + (constTerm.LowPart < part); \
constTerm.HighPart -= (constTerm.LowPart < lo); \
constTerm.LowPart -= lo; \
if ( _LIKELY_BRANCH_( constTerm.LowPart >= 30) ) { constTerm.LowPart -= (constTerm.HighPart << 4) - constTerm.HighPart; return fmix32_short( constTerm.LowPart ); } \
else \
{ \
if ( constTerm.HighPart ) \
{ \
constTerm.LowPart -= constTerm.HighPart * 15 - 15; \
constTerm.HighPart = 1; \
if ( _LIKELY_BRANCH_( constTerm.LowPart >= 15)) { constTerm.LowPart -= 15; return fmix32_short( constTerm.LowPart ); } \
else \
{ \
return constTerm.LowPart; \
} \
} \
else \
return fmix32_short( constTerm.LowPart ); \
} \
}
#endif
class PMP_Multilinear_Hasher
{
private:
random_data_for_MPSHF* curr_rd;
#ifdef PMPML_USE_SSE
const unsigned char* base_addr;
#endif
FORCE_INLINE
uint64_t hash_of_string_chunk_compact( const uint32_t* coeff, ULARGE_INTEGER__XX constTerm, const uint32_t* x ) const
{
PMPML_CHUNK_LOOP_INTRO_L0
#ifdef PMPML_USE_SSE
#if PMPML_USE_SSE_SIZE == 128
__m128i ctr0, ctr1, mask_low;
__m128i a, data, product, temp;
uint64_t temp_fin;
int i;
ctr0 = _mm_setzero_si128 (); ctr1 = _mm_setzero_si128 ();
mask_low = _mm_set_epi32 ( 0, -1, 0 , -1 );
uint32_t *x1, *x2, *x3, *c1, *c2, *c3;
#if (PMPML_CHUNK_SIZE >= 64)
for ( i=0; i<PMPML_CHUNK_SIZE; i+=64 )
#elif (PMPML_CHUNK_SIZE >= 32)
for ( i=0; i<PMPML_CHUNK_SIZE; i+=32 )
#elif (PMPML_CHUNK_SIZE >= 16)
for ( i=0; i<PMPML_CHUNK_SIZE; i+=16 )
#elif (PMPML_CHUNK_SIZE >= 8)
for ( i=0; i<PMPML_CHUNK_SIZE; i+=8 )
#elif (PMPML_CHUNK_SIZE >= 4)
for ( i=0; i<PMPML_CHUNK_SIZE; i+=4 )
#else
#error PMPML_CHUNK_SIZE is incompatible with PMPML_USE_SSE option
#endif
{
a = _mm_load_si128 ((__m128i *)(coeff+i)); data = _mm_loadu_si128 ((__m128i *)(x+i)); product = _mm_mul_epu32 ( data, a); temp = _mm_srli_epi64( product, 32 ); ctr1 = _mm_add_epi64 ( ctr1, temp );
ctr0 = _mm_add_epi64 ( ctr0, product );
a = _mm_shuffle_epi32( a, 1*1+0*4+3*16+2*64 );
data = _mm_shuffle_epi32( data, 1*1+0*4+3*16+2*64 );
product = _mm_mul_epu32 ( data, a);
temp = _mm_srli_epi64( product, 32 );
ctr1 = _mm_add_epi64 ( ctr1, temp );
ctr0 = _mm_add_epi64 ( ctr0, product );
#if ( PMPML_CHUNK_SIZE > 4 )
a = _mm_load_si128 ((__m128i *)(coeff+i+4));
data = _mm_loadu_si128 ((__m128i *)(x+i+4));
product = _mm_mul_epu32 ( data, a);
temp = _mm_srli_epi64( product, 32 );
ctr1 = _mm_add_epi64 ( ctr1, temp );
ctr0 = _mm_add_epi64 ( ctr0, product );
a = _mm_shuffle_epi32( a, 1*1+0*4+3*16+2*64 );
data = _mm_shuffle_epi32( data, 1*1+0*4+3*16+2*64 );
product = _mm_mul_epu32 ( data, a);
temp = _mm_srli_epi64( product, 32 );
ctr1 = _mm_add_epi64 ( ctr1, temp );
ctr0 = _mm_add_epi64 ( ctr0, product );
#endif #if ( PMPML_CHUNK_SIZE > 8 )
a = _mm_load_si128 ((__m128i *)(coeff+i+8));
data = _mm_loadu_si128 ((__m128i *)(x+i+8));
product = _mm_mul_epu32 ( data, a);
temp = _mm_srli_epi64( product, 32 );
ctr1 = _mm_add_epi64 ( ctr1, temp );
ctr0 = _mm_add_epi64 ( ctr0, product );
a = _mm_shuffle_epi32( a, 1*1+0*4+3*16+2*64 );
data = _mm_shuffle_epi32( data, 1*1+0*4+3*16+2*64 );
product = _mm_mul_epu32 ( data, a);
temp = _mm_srli_epi64( product, 32 );
ctr1 = _mm_add_epi64 ( ctr1, temp );
ctr0 = _mm_add_epi64 ( ctr0, product );
a = _mm_load_si128 ((__m128i *)(coeff+i+12));
data = _mm_loadu_si128 ((__m128i *)(x+i+12));
product = _mm_mul_epu32 ( data, a);
temp = _mm_srli_epi64( product, 32 );
ctr1 = _mm_add_epi64 ( ctr1, temp );
ctr0 = _mm_add_epi64 ( ctr0, product );
a = _mm_shuffle_epi32( a, 1*1+0*4+3*16+2*64 );
data = _mm_shuffle_epi32( data, 1*1+0*4+3*16+2*64 );
product = _mm_mul_epu32 ( data, a);
temp = _mm_srli_epi64( product, 32 );
ctr1 = _mm_add_epi64 ( ctr1, temp );
ctr0 = _mm_add_epi64 ( ctr0, product );
#endif #if ( PMPML_CHUNK_SIZE > 16 )
a = _mm_load_si128 ((__m128i *)(coeff+i+16));
data = _mm_loadu_si128 ((__m128i *)(x+i+16));
product = _mm_mul_epu32 ( data, a);
temp = _mm_srli_epi64( product, 32 );
ctr1 = _mm_add_epi64 ( ctr1, temp );
ctr0 = _mm_add_epi64 ( ctr0, product );
a = _mm_shuffle_epi32( a, 1*1+0*4+3*16+2*64 );
data = _mm_shuffle_epi32( data, 1*1+0*4+3*16+2*64 );
product = _mm_mul_epu32 ( data, a);
temp = _mm_srli_epi64( product, 32 );
ctr1 = _mm_add_epi64 ( ctr1, temp );
ctr0 = _mm_add_epi64 ( ctr0, product );
a = _mm_load_si128 ((__m128i *)(coeff+i+20));
data = _mm_loadu_si128 ((__m128i *)(x+i+20));
product = _mm_mul_epu32 ( data, a);
temp = _mm_srli_epi64( product, 32 );
ctr1 = _mm_add_epi64 ( ctr1, temp );
ctr0 = _mm_add_epi64 ( ctr0, product );
a = _mm_shuffle_epi32( a, 1*1+0*4+3*16+2*64 );
data = _mm_shuffle_epi32( data, 1*1+0*4+3*16+2*64 );
product = _mm_mul_epu32 ( data, a);
temp = _mm_srli_epi64( product, 32 );
ctr1 = _mm_add_epi64 ( ctr1, temp );
ctr0 = _mm_add_epi64 ( ctr0, product );
a = _mm_load_si128 ((__m128i *)(coeff+i+24));
data = _mm_loadu_si128 ((__m128i *)(x+i+24));
product = _mm_mul_epu32 ( data, a);
temp = _mm_srli_epi64( product, 32 );
ctr1 = _mm_add_epi64 ( ctr1, temp );
ctr0 = _mm_add_epi64 ( ctr0, product );
a = _mm_shuffle_epi32( a, 1*1+0*4+3*16+2*64 );
data = _mm_shuffle_epi32( data, 1*1+0*4+3*16+2*64 );
product = _mm_mul_epu32 ( data, a);
temp = _mm_srli_epi64( product, 32 );
ctr1 = _mm_add_epi64 ( ctr1, temp );
ctr0 = _mm_add_epi64 ( ctr0, product );
a = _mm_load_si128 ((__m128i *)(coeff+i+28));
data = _mm_loadu_si128 ((__m128i *)(x+i+28));
product = _mm_mul_epu32 ( data, a);
temp = _mm_srli_epi64( product, 32 );
ctr1 = _mm_add_epi64 ( ctr1, temp );
ctr0 = _mm_add_epi64 ( ctr0, product );
a = _mm_shuffle_epi32( a, 1*1+0*4+3*16+2*64 );
data = _mm_shuffle_epi32( data, 1*1+0*4+3*16+2*64 );
product = _mm_mul_epu32 ( data, a);
temp = _mm_srli_epi64( product, 32 );
ctr1 = _mm_add_epi64 ( ctr1, temp );
ctr0 = _mm_add_epi64 ( ctr0, product );
#endif #if ( PMPML_CHUNK_SIZE > 32 )
x1 = const_cast<uint32_t*>( x+i+36 );
x2 = const_cast<uint32_t*>( x+i+40 );
x3 = const_cast<uint32_t*>( x+i+44 );
c1 = const_cast<uint32_t*>( coeff+i+36 );
c2 = const_cast<uint32_t*>( coeff+i+40 );
c3 = const_cast<uint32_t*>( coeff+i+44 );
a = _mm_load_si128 ((__m128i *)(coeff+i+32));
data = _mm_loadu_si128 ((__m128i *)(x+i+32));
product = _mm_mul_epu32 ( data, a);
temp = _mm_srli_epi64( product, 32 );
ctr1 = _mm_add_epi64 ( ctr1, temp );
ctr0 = _mm_add_epi64 ( ctr0, product );
a = _mm_shuffle_epi32( a, 1*1+0*4+3*16+2*64 );
data = _mm_shuffle_epi32( data, 1*1+0*4+3*16+2*64 );
product = _mm_mul_epu32 ( data, a);
temp = _mm_srli_epi64( product, 32 );
ctr1 = _mm_add_epi64 ( ctr1, temp );
ctr0 = _mm_add_epi64 ( ctr0, product );
a = _mm_load_si128 ((__m128i *)(c1));
data = _mm_loadu_si128 ((__m128i *)(x1));
product = _mm_mul_epu32 ( data, a);
temp = _mm_srli_epi64( product, 32 );
ctr1 = _mm_add_epi64 ( ctr1, temp );
ctr0 = _mm_add_epi64 ( ctr0, product );
a = _mm_shuffle_epi32( a, 1*1+0*4+3*16+2*64 );
data = _mm_shuffle_epi32( data, 1*1+0*4+3*16+2*64 );
product = _mm_mul_epu32 ( data, a);
temp = _mm_srli_epi64( product, 32 );
ctr1 = _mm_add_epi64 ( ctr1, temp );
ctr0 = _mm_add_epi64 ( ctr0, product );
a = _mm_load_si128 ((__m128i *)(c2));
data = _mm_loadu_si128 ((__m128i *)(x2));
product = _mm_mul_epu32 ( data, a);
temp = _mm_srli_epi64( product, 32 );
ctr1 = _mm_add_epi64 ( ctr1, temp );
ctr0 = _mm_add_epi64 ( ctr0, product );
a = _mm_shuffle_epi32( a, 1*1+0*4+3*16+2*64 );
data = _mm_shuffle_epi32( data, 1*1+0*4+3*16+2*64 );
product = _mm_mul_epu32 ( data, a);
temp = _mm_srli_epi64( product, 32 );
ctr1 = _mm_add_epi64 ( ctr1, temp );
ctr0 = _mm_add_epi64 ( ctr0, product );
a = _mm_load_si128 ((__m128i *)(c3));
data = _mm_loadu_si128 ((__m128i *)(x3));
product = _mm_mul_epu32 ( data, a);
temp = _mm_srli_epi64( product, 32 );
ctr1 = _mm_add_epi64 ( ctr1, temp );
ctr0 = _mm_add_epi64 ( ctr0, product );
a = _mm_shuffle_epi32( a, 1*1+0*4+3*16+2*64 );
data = _mm_shuffle_epi32( data, 1*1+0*4+3*16+2*64 );
product = _mm_mul_epu32 ( data, a);
temp = _mm_srli_epi64( product, 32 );
ctr1 = _mm_add_epi64 ( ctr1, temp );
ctr0 = _mm_add_epi64 ( ctr0, product );
x1 = const_cast<uint32_t*>( x+i+52 );
x2 = const_cast<uint32_t*>( x+i+56 );
x3 = const_cast<uint32_t*>( x+i+60 );
c1 = const_cast<uint32_t*>( coeff+i+52 );
c2 = const_cast<uint32_t*>( coeff+i+56 );
c3 = const_cast<uint32_t*>( coeff+i+60 );
a = _mm_load_si128 ((__m128i *)(coeff+i+48));
data = _mm_loadu_si128 ((__m128i *)(x+i+48));
product = _mm_mul_epu32 ( data, a);
temp = _mm_srli_epi64( product, 32 );
ctr1 = _mm_add_epi64 ( ctr1, temp );
ctr0 = _mm_add_epi64 ( ctr0, product );
a = _mm_shuffle_epi32( a, 1*1+0*4+3*16+2*64 );
data = _mm_shuffle_epi32( data, 1*1+0*4+3*16+2*64 );
product = _mm_mul_epu32 ( data, a);
temp = _mm_srli_epi64( product, 32 );
ctr1 = _mm_add_epi64 ( ctr1, temp );
ctr0 = _mm_add_epi64 ( ctr0, product );
a = _mm_load_si128 ((__m128i *)(c1));
data = _mm_loadu_si128 ((__m128i *)(x1));
product = _mm_mul_epu32 ( data, a);
temp = _mm_srli_epi64( product, 32 );
ctr1 = _mm_add_epi64 ( ctr1, temp );
ctr0 = _mm_add_epi64 ( ctr0, product );
a = _mm_shuffle_epi32( a, 1*1+0*4+3*16+2*64 );
data = _mm_shuffle_epi32( data, 1*1+0*4+3*16+2*64 );
product = _mm_mul_epu32 ( data, a);
temp = _mm_srli_epi64( product, 32 );
ctr1 = _mm_add_epi64 ( ctr1, temp );
ctr0 = _mm_add_epi64 ( ctr0, product );
a = _mm_load_si128 ((__m128i *)(c2));
data = _mm_loadu_si128 ((__m128i *)(x2));
product = _mm_mul_epu32 ( data, a);
temp = _mm_srli_epi64( product, 32 );
ctr1 = _mm_add_epi64 ( ctr1, temp );
ctr0 = _mm_add_epi64 ( ctr0, product );
a = _mm_shuffle_epi32( a, 1*1+0*4+3*16+2*64 );
data = _mm_shuffle_epi32( data, 1*1+0*4+3*16+2*64 );
product = _mm_mul_epu32 ( data, a);
temp = _mm_srli_epi64( product, 32 );
ctr1 = _mm_add_epi64 ( ctr1, temp );
ctr0 = _mm_add_epi64 ( ctr0, product );
a = _mm_load_si128 ((__m128i *)(c3));
data = _mm_loadu_si128 ((__m128i *)(x3));
product = _mm_mul_epu32 ( data, a);
temp = _mm_srli_epi64( product, 32 );
ctr1 = _mm_add_epi64 ( ctr1, temp );
ctr0 = _mm_add_epi64 ( ctr0, product );
a = _mm_shuffle_epi32( a, 1*1+0*4+3*16+2*64 );
data = _mm_shuffle_epi32( data, 1*1+0*4+3*16+2*64 );
product = _mm_mul_epu32 ( data, a);
temp = _mm_srli_epi64( product, 32 );
ctr1 = _mm_add_epi64 ( ctr1, temp );
ctr0 = _mm_add_epi64 ( ctr0, product );#endif }
temp = _mm_unpackhi_epi64 ( ctr0, ctr1 ); data = _mm_unpacklo_epi64 ( ctr0, ctr1 ); ctr1 = _mm_add_epi64 ( data, temp );
#if (PMPML_CHUNK_OPTIMIZATION_TYPE== 1)
#if defined(_MSC_VER)
constTerm.QuadPart += ctr1.m128i_u32[0]; ctr.QuadPart += ctr1.m128i_u64[1] + ctr1.m128i_u32[1];
#elif defined( __SSE4_1__)
constTer.QuadPart += _mm_extract_epi32(ctr1,0);
ctr.QuadPart += _mm_extract_epi64(ctr1,0) + _mm_extract_epi32(ctr1,1);
#else
uint32_t b[4];
_mm_storeu_si128((__m128i *)b,ctr1);
constTerm.QuadPart += b[0];
ctr.QuadPart += b[1] + b[2] + ((uint64_t) b[3] <<32);
#endif
#elif (PMPML_CHUNK_OPTIMIZATION_TYPE== 2)
uint64_t lo = ((uint64_t*)(&ctr1))[0];
uint64_t hi = ((uint64_t*)(&ctr1))[1];
uint32_t lohi = lo >> 32;
uint32_t hilo = hi;
uint32_t diff = lohi - hilo;
hi += diff;
lo = (uint32_t)lo + (((uint64_t)(uint32_t)hi) << 32 );
constTerm.QuadPart += lo;
ctr += constTerm.QuadPart < lo;
ctr += hi >> 32;
#else
#error unexpected PMPML_CHUNK_OPTIMIZATION_TYPE
#endif
#elif PMPML_USE_SSE_SIZE == 256
__m256i ctr0, ctr1, mask_low;
__m256i a, data, product, temp;
uint64_t temp_fin;
int i;
ctr0 = _mm256_setzero_si256 (); ctr1 = _mm256_setzero_si256 ();
mask_low = _mm256_set_epi32 ( 0, -1, 0 , -1, 0, -1, 0 , -1 );
uint32_t *x1, *x2, *x3, *c1, *c2, *c3;
#if (PMPML_CHUNK_SIZE >= 64)
for ( i=0; i<PMPML_CHUNK_SIZE; i+=64 )
#elif (PMPML_CHUNK_SIZE >= 32)
for ( i=0; i<PMPML_CHUNK_SIZE; i+=32 )
#elif (PMPML_CHUNK_SIZE >= 16)
for ( i=0; i<PMPML_CHUNK_SIZE; i+=16 )
#elif (PMPML_CHUNK_SIZE >= 8)
for ( i=0; i<PMPML_CHUNK_SIZE; i+=8 )
#else
#error PMPML_CHUNK_SIZE is incompatible with PMPML_USE_SSE option
#endif
{
a = _mm256_load_si256 ((__m256i *)(coeff+i)); data = _mm256_loadu_si256 ((__m256i *)(x+i)); product = _mm256_mul_epu32 ( data, a); temp = _mm256_srli_epi64( product, 32 ); ctr1 = _mm256_add_epi64 ( ctr1, temp );
ctr0 = _mm256_add_epi64 ( ctr0, product );
a = _mm256_shuffle_epi32( a, 1*1+0*4+3*16+2*64 );
data = _mm256_shuffle_epi32( data, 1*1+0*4+3*16+2*64 );
product = _mm256_mul_epu32 ( data, a);
temp = _mm256_srli_epi64( product, 32 );
ctr1 = _mm256_add_epi64 ( ctr1, temp );
ctr0 = _mm256_add_epi64 ( ctr0, product );
#if ( PMPML_CHUNK_SIZE > 8 )
a = _mm256_load_si256 ((__m256i *)(coeff+i+8));
data = _mm256_loadu_si256 ((__m256i *)(x+i+8));
product = _mm256_mul_epu32 ( data, a);
temp = _mm256_srli_epi64( product, 32 );
ctr1 = _mm256_add_epi64 ( ctr1, temp );
ctr0 = _mm256_add_epi64 ( ctr0, product );
a = _mm256_shuffle_epi32( a, 1*1+0*4+3*16+2*64 );
data = _mm256_shuffle_epi32( data, 1*1+0*4+3*16+2*64 );
product = _mm256_mul_epu32 ( data, a);
temp = _mm256_srli_epi64( product, 32 );
ctr1 = _mm256_add_epi64 ( ctr1, temp );
ctr0 = _mm256_add_epi64 ( ctr0, product );
#endif #if ( PMPML_CHUNK_SIZE > 16 )
a = _mm256_load_si256 ((__m256i *)(coeff+i+16));
data = _mm256_loadu_si256 ((__m256i *)(x+i+16));
product = _mm256_mul_epu32 ( data, a);
temp = _mm256_srli_epi64( product, 32 );
ctr1 = _mm256_add_epi64 ( ctr1, temp );
ctr0 = _mm256_add_epi64 ( ctr0, product );
a = _mm256_shuffle_epi32( a, 1*1+0*4+3*16+2*64 );
data = _mm256_shuffle_epi32( data, 1*1+0*4+3*16+2*64 );
product = _mm256_mul_epu32 ( data, a);
temp = _mm256_srli_epi64( product, 32 );
ctr1 = _mm256_add_epi64 ( ctr1, temp );
ctr0 = _mm256_add_epi64 ( ctr0, product );
a = _mm256_load_si256 ((__m256i *)(coeff+i+24));
data = _mm256_loadu_si256 ((__m256i *)(x+i+24));
product = _mm256_mul_epu32 ( data, a);
temp = _mm256_srli_epi64( product, 32 );
ctr1 = _mm256_add_epi64 ( ctr1, temp );
ctr0 = _mm256_add_epi64 ( ctr0, product );
a = _mm256_shuffle_epi32( a, 1*1+0*4+3*16+2*64 );
data = _mm256_shuffle_epi32( data, 1*1+0*4+3*16+2*64 );
product = _mm256_mul_epu32 ( data, a);
temp = _mm256_srli_epi64( product, 32 );
ctr1 = _mm256_add_epi64 ( ctr1, temp );
ctr0 = _mm256_add_epi64 ( ctr0, product );
#endif #if ( PMPML_CHUNK_SIZE > 32 )
a = _mm256_load_si256 ((__m256i *)(coeff+i+32));
data = _mm256_loadu_si256 ((__m256i *)(x+i+32));
product = _mm256_mul_epu32 ( data, a);
temp = _mm256_srli_epi64( product, 32 );
ctr1 = _mm256_add_epi64 ( ctr1, temp );
ctr0 = _mm256_add_epi64 ( ctr0, product );
a = _mm256_shuffle_epi32( a, 1*1+0*4+3*16+2*64 );
data = _mm256_shuffle_epi32( data, 1*1+0*4+3*16+2*64 );
product = _mm256_mul_epu32 ( data, a);
temp = _mm256_srli_epi64( product, 32 );
ctr1 = _mm256_add_epi64 ( ctr1, temp );
ctr0 = _mm256_add_epi64 ( ctr0, product );
a = _mm256_load_si256 ((__m256i *)(coeff+i+40));
data = _mm256_loadu_si256 ((__m256i *)(x+i+40));
product = _mm256_mul_epu32 ( data, a);
temp = _mm256_srli_epi64( product, 32 );
ctr1 = _mm256_add_epi64 ( ctr1, temp );
ctr0 = _mm256_add_epi64 ( ctr0, product );
a = _mm256_shuffle_epi32( a, 1*1+0*4+3*16+2*64 );
data = _mm256_shuffle_epi32( data, 1*1+0*4+3*16+2*64 );
product = _mm256_mul_epu32 ( data, a);
temp = _mm256_srli_epi64( product, 32 );
ctr1 = _mm256_add_epi64 ( ctr1, temp );
ctr0 = _mm256_add_epi64 ( ctr0, product );
a = _mm256_load_si256 ((__m256i *)(coeff+i+48));
data = _mm256_loadu_si256 ((__m256i *)(x+i+48));
product = _mm256_mul_epu32 ( data, a);
temp = _mm256_srli_epi64( product, 32 );
ctr1 = _mm256_add_epi64 ( ctr1, temp );
ctr0 = _mm256_add_epi64 ( ctr0, product );
a = _mm256_shuffle_epi32( a, 1*1+0*4+3*16+2*64 );
data = _mm256_shuffle_epi32( data, 1*1+0*4+3*16+2*64 );
product = _mm256_mul_epu32 ( data, a);
temp = _mm256_srli_epi64( product, 32 );
ctr1 = _mm256_add_epi64 ( ctr1, temp );
ctr0 = _mm256_add_epi64 ( ctr0, product );
a = _mm256_load_si256 ((__m256i *)(coeff+i+56));
data = _mm256_loadu_si256 ((__m256i *)(x+i+56));
product = _mm256_mul_epu32 ( data, a);
temp = _mm256_srli_epi64( product, 32 );
ctr1 = _mm256_add_epi64 ( ctr1, temp );
ctr0 = _mm256_add_epi64 ( ctr0, product );
a = _mm256_shuffle_epi32( a, 1*1+0*4+3*16+2*64 );
data = _mm256_shuffle_epi32( data, 1*1+0*4+3*16+2*64 );
product = _mm256_mul_epu32 ( data, a);
temp = _mm256_srli_epi64( product, 32 );
ctr1 = _mm256_add_epi64 ( ctr1, temp );
ctr0 = _mm256_add_epi64 ( ctr0, product );
#endif }
temp = _mm256_unpackhi_epi64 ( ctr0, ctr1 ); data = _mm256_unpacklo_epi64 ( ctr0, ctr1 ); ctr1 = _mm256_add_epi64 ( data, temp );
#if (PMPML_CHUNK_OPTIMIZATION_TYPE== 1)
#ifdef 0
#if defined(_MSC_VER)
constTerm.QuadPart += ctr1.m128i_u32[0]; ctr.QuadPart += ctr1.m128i_u64[1] + ctr1.m128i_u32[1];
#elif defined( __SSE4_1__)
constTer.QuadPart += _mm_extract_epi32(ctr1,0);
ctr.QuadPart += _mm_extract_epi64(ctr1,0) + _mm_extract_epi32(ctr1,1);
#else
uint32_t b[4];
_mm_storeu_si128((__m128i *)b,ctr1);
constTerm.QuadPart += b[0];
ctr.QuadPart += b[1] + b[2] + ((uint64_t) b[3] <<32);
#endif
#else
#error unsupported
#endif #elif (PMPML_CHUNK_OPTIMIZATION_TYPE== 2)
uint64_t lo = *(uint64_t*)(&ctr1) + ((uint64_t*)(&ctr1))[2];
uint64_t hi = ((uint64_t*)(&ctr1))[1] + ((uint64_t*)(&ctr1))[3];
uint32_t lohi = lo >> 32;
uint32_t hilo = hi;
uint32_t diff = lohi - hilo;
hi += diff;
lo = (uint32_t)lo + (((uint64_t)(uint32_t)hi) << 32 );
constTerm.QuadPart += lo;
ctr += constTerm.QuadPart < lo;
ctr += hi >> 32;
#else
#error unexpected PMPML_CHUNK_OPTIMIZATION_TYPE
#endif
#else
#error unsupported PMPML_USE_SSE_SIZE value
#endif
#else
for ( uint32_t i=0; i<PMPML_CHUNK_SIZE; i+=8 )
{
PMPML_CHUNK_LOOP_BODY_ULI_T1( 0 + i )
PMPML_CHUNK_LOOP_BODY_ULI_T1( 1 + i )
PMPML_CHUNK_LOOP_BODY_ULI_T1( 2 + i )
PMPML_CHUNK_LOOP_BODY_ULI_T1( 3 + i )
#if ( PMPML_CHUNK_SIZE > 4 )
PMPML_CHUNK_LOOP_BODY_ULI_T1( 4 + i )
PMPML_CHUNK_LOOP_BODY_ULI_T1( 5 + i )
PMPML_CHUNK_LOOP_BODY_ULI_T1( 6 + i )
PMPML_CHUNK_LOOP_BODY_ULI_T1( 7 + i )
#endif
}
#endif
PMPML_CHUNK_LOOP_PRE_REDUCE_L0
PMPML_FULL_REDUCE_MOD_2_32_PLUS_15_AND_RETURN
}
#ifdef PMPML_STRICT_UNALIGNED_HANDLING
FORCE_INLINE
uint64_t hash_of_string_chunk_compact_un_1( const uint32_t* coeff, ULARGE_INTEGER__XX constTerm, const unsigned char* _x ) const
{
PMPML_CHUNK_LOOP_INTRO_L0
const uint32_t* xx = (const uint32_t*)( _x + 3 );
uint32_t x = xx[ -1 ] >> 8;
for ( uint32_t i=0; i<PMPML_CHUNK_SIZE; i+=8 )
{
PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 8, 0 + i )
PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 8, 1 + i )
PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 8, 2 + i )
PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 8, 3 + i )
#if ( PMPML_CHUNK_SIZE > 4 )
PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 8, 4 + i )
PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 8, 5 + i )
PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 8, 6 + i )
PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 8, 7 + i )
#endif
}
PMPML_CHUNK_LOOP_PRE_REDUCE_L0
PMPML_FULL_REDUCE_MOD_2_32_PLUS_15_AND_RETURN
}
FORCE_INLINE
uint64_t hash_of_string_chunk_compact_un_2( const uint32_t* coeff, ULARGE_INTEGER__XX constTerm, const unsigned char* _x ) const
{
PMPML_CHUNK_LOOP_INTRO_L0
const uint32_t* xx = (const uint32_t*)( _x + 2 );
uint32_t x = xx[ -1 ] >> 16;
for ( uint32_t i=0; i<PMPML_CHUNK_SIZE; i+=8 )
{
PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 16, 0 + i )
PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 16, 1 + i )
PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 16, 2 + i )
PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 16, 3 + i )
#if ( PMPML_CHUNK_SIZE > 4 )
PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 16, 4 + i )
PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 16, 5 + i )
PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 16, 6 + i )
PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 16, 7 + i )
#endif
}
PMPML_CHUNK_LOOP_PRE_REDUCE_L0
PMPML_FULL_REDUCE_MOD_2_32_PLUS_15_AND_RETURN
}
FORCE_INLINE
uint64_t hash_of_string_chunk_compact_un_3( const uint32_t* coeff, ULARGE_INTEGER__XX constTerm, const unsigned char* _x ) const
{
PMPML_CHUNK_LOOP_INTRO_L0
const uint32_t* xx = (const uint32_t*)( _x + 1 );
uint32_t x = xx[ -1 ] >> 24;
for ( uint32_t i=0; i<PMPML_CHUNK_SIZE; i+=8 )
{
PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 16, 0 + i )
PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 16, 1 + i )
PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 16, 2 + i )
PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 16, 3 + i )
#if ( PMPML_CHUNK_SIZE > 4 )
PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 16, 4 + i )
PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 16, 5 + i )
PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 16, 6 + i )
PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 16, 7 + i )
#endif
}
PMPML_CHUNK_LOOP_PRE_REDUCE_L0
PMPML_FULL_REDUCE_MOD_2_32_PLUS_15_AND_RETURN
}
#endif
FORCE_INLINE
uint64_t hash_of_beginning_of_string_chunk_type2( const uint32_t* coeff, ULARGE_INTEGER__XX constTerm, const unsigned char* tail, unsigned int tail_size ) const
{
PMPML_CHUNK_LOOP_INTRO_L0
uint32_t size = tail_size >> PMPML_WORD_SIZE_BYTES_LOG2;
const uint32_t* x = (const uint32_t*)tail;
#ifdef PMPML_USE_SSE
__m128i ctr0, ctr1, a, data, product, temp, mask_low;
int i;
ctr0 = _mm_setzero_si128 (); ctr1 = _mm_setzero_si128 ();
mask_low = _mm_set_epi32 ( 0, -1, 0 , -1 );
for ( i=0; i<(size&0xFFFFFFF8); i+=4 )
{
a = _mm_load_si128 ((__m128i *)(coeff+i)); data = _mm_loadu_si128 ((__m128i *)(x+i)); product = _mm_mul_epu32 ( data, a); temp = _mm_srli_epi64( product, 32 ); ctr1 = _mm_add_epi64 ( ctr1, temp );
temp = _mm_and_si128 ( mask_low, product );
ctr0 = _mm_add_epi64 ( ctr0, temp );
a = _mm_shuffle_epi32( a, 1*1+0*4+3*16+2*64 );
data = _mm_shuffle_epi32( data, 1*1+0*4+3*16+2*64 );
product = _mm_mul_epu32 ( data, a); temp = _mm_srli_epi64( product, 32 ); ctr1 = _mm_add_epi64 ( ctr1, temp );
temp = _mm_and_si128 ( mask_low, product );
ctr0 = _mm_add_epi64 ( ctr0, temp );
}
temp = _mm_unpackhi_epi64 ( ctr0, ctr1 ); data = _mm_unpacklo_epi64 ( ctr0, ctr1 ); ctr1 = _mm_add_epi64 ( data, temp );
#if (PMPML_CHUNK_OPTIMIZATION_TYPE== 1)
#if defined(_MSC_VER)
constTerm.QuadPart += ctr1.m128i_u32[0]; ctr.QuadPart += ctr1.m128i_u64[1] + ctr1.m128i_u32[1];
#elif defined( __SSE4_1__)
constTer.QuadPart += _mm_extract_epi32(ctr1,0);
ctr.QuadPart += _mm_extract_epi64(ctr1,0) + _mm_extract_epi32(ctr1,1);
#else
uint32_t b[4];
_mm_storeu_si128((__m128i *)b,ctr1);
constTerm.QuadPart += b[0];
ctr.QuadPart += b[1] + b[2] + ((uint64_t) b[3] <<32);
#endif
#elif (PMPML_CHUNK_OPTIMIZATION_TYPE== 2)
constTerm.QuadPart += *(uint64_t*)(&ctr1);
ctr += constTerm.QuadPart < *(uint64_t*)(&ctr1);
constTerm.HighPart += ((uint32_t*)(&ctr1))[2];
ctr += constTerm.HighPart < ((uint32_t*)(&ctr1))[2];
ctr += ((uint32_t*)(&ctr1))[3];
#else
#error unxpected PMPML_CHUNK_OPTIMIZATION_TYPE
#endif
#else
for ( uint32_t i=0; i<(size&0xFFFFFFF8); i+=8 )
{
PMPML_CHUNK_LOOP_BODY_ULI_T1( 0 + i )
PMPML_CHUNK_LOOP_BODY_ULI_T1( 1 + i )
PMPML_CHUNK_LOOP_BODY_ULI_T1( 2 + i )
PMPML_CHUNK_LOOP_BODY_ULI_T1( 3 + i )
#if ( PMPML_CHUNK_SIZE > 4 )
PMPML_CHUNK_LOOP_BODY_ULI_T1( 4 + i )
PMPML_CHUNK_LOOP_BODY_ULI_T1( 5 + i )
PMPML_CHUNK_LOOP_BODY_ULI_T1( 6 + i )
PMPML_CHUNK_LOOP_BODY_ULI_T1( 7 + i )
#endif
}
#endif
uint32_t offset = size & 0xFFFFFFF8;
switch( size & 0x7 )
{
case 0: { break; }
case 1: { PMPML_CHUNK_LOOP_BODY_ULI_T1( 0 + offset ) } break;
case 2: { PMPML_CHUNK_LOOP_BODY_ULI_T1( 0 + offset ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 1 + offset ) } break;
case 3: { PMPML_CHUNK_LOOP_BODY_ULI_T1( 0 + offset ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 1 + offset ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 2 + offset ) } break;
case 4: { PMPML_CHUNK_LOOP_BODY_ULI_T1( 0 + offset ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 1 + offset ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 2 + offset ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 3 + offset ) } break;
case 5: { PMPML_CHUNK_LOOP_BODY_ULI_T1( 0 + offset ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 1 + offset ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 2 + offset ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 3 + offset ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 4 + offset ) } break;
case 6: { PMPML_CHUNK_LOOP_BODY_ULI_T1( 0 + offset ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 1 + offset ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 2 + offset ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 3 + offset ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 4 + offset ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 5 + offset ) } break;
case 7: { PMPML_CHUNK_LOOP_BODY_ULI_T1( 0 + offset ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 1 + offset ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 2 + offset ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 3 + offset ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 4 + offset ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 5 + offset ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 6 + offset ) } break;
}
uint32_t xLast;
switch ( tail_size & ( PMPML_WORD_SIZE_BYTES - 1 ) )
{
case 0: { xLast = 0x1; break;}
case 1: { xLast = 0x100 | tail[tail_size-1]; break;}
case 2: { xLast = *((const unsigned short*)(tail + tail_size - 2 )) | 0x10000; break; }
case 3: { xLast = tail[ tail_size - 1 ]; xLast = ( xLast << 16 ) | *((const unsigned short*)(tail + tail_size - 3 )) | 0x1000000; break;}
}
PMPML_CHUNK_LOOP_BODY_ULI_T1_LAST
PMPML_CHUNK_LOOP_PRE_REDUCE_L0
PMPML_FULL_REDUCE_MOD_2_32_PLUS_15_AND_RETURN
}
#ifdef PMPML_STRICT_UNALIGNED_HANDLING
FORCE_INLINE
uint64_t hash_of_beginning_of_string_chunk_type2_un1( const uint32_t* coeff, ULARGE_INTEGER__XX constTerm, const unsigned char* tail, unsigned int tail_size ) const
{
PMPML_CHUNK_LOOP_INTRO_L0
uint32_t size = tail_size >> PMPML_WORD_SIZE_BYTES_LOG2;
const uint32_t* xx = (const uint32_t*)( tail + 3 );
uint32_t x = xx[ -1 ] >> 8;
for ( uint32_t i=0; i<(size&0xFFFFFFF8); i+=8 )
{
PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 8, 0 + i )
PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 8, 1 + i )
PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 8, 2 + i )
PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 8, 3 + i )
#if ( PMPML_CHUNK_SIZE > 4 )
PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 8, 4 + i )
PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 8, 5 + i )
PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 8, 6 + i )
PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 8, 7 + i )
#endif
}
uint32_t offset = size & 0xFFFFFFF8;
switch( size & 0x7 )
{
case 0: { break; }
case 1: { PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 8, 0 + offset ) } break;
case 2: { PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 8, 0 + offset ) PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 8, 1 + offset ) } break;
case 3: { PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 8, 0 + offset ) PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 8, 1 + offset ) PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 8, 2 + offset ) } break;
case 4: { PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 8, 0 + offset ) PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 8, 1 + offset ) PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 8, 2 + offset ) PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 8, 3 + offset ) } break;
case 5: { PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 8, 0 + offset ) PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 8, 1 + offset ) PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 8, 2 + offset ) PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 8, 3 + offset ) PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 8, 4 + offset ) } break;
case 6: { PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 8, 0 + offset ) PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 8, 1 + offset ) PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 8, 2 + offset ) PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 8, 3 + offset ) PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 8, 4 + offset ) PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 8, 5 + offset ) } break;
case 7: { PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 8, 0 + offset ) PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 8, 1 + offset ) PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 8, 2 + offset ) PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 8, 3 + offset ) PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 8, 4 + offset ) PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 8, 5 + offset ) PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 8, 6 + offset ) } break;
}
uint32_t xLast;
switch ( tail_size & ( PMPML_WORD_SIZE_BYTES - 1 ) )
{
case 0: { xLast = 0x1; break;}
case 1: { xLast = 0x100 | tail[tail_size-1]; break;}
case 2: { xLast = 0x100 | tail[tail_size-1]; xLast = ( xLast << 8 ) | tail[tail_size - 2]; break; }
case 3: { xLast = 0x100 | tail[tail_size-1]; xLast = ( xLast << 8 ) | tail[tail_size - 2]; xLast = ( xLast << 8 ) | tail[tail_size - 3]; break;}
}
PMPML_CHUNK_LOOP_BODY_ULI_T1_LAST
PMPML_CHUNK_LOOP_PRE_REDUCE_L0
PMPML_FULL_REDUCE_MOD_2_32_PLUS_15_AND_RETURN
}
FORCE_INLINE
uint64_t hash_of_beginning_of_string_chunk_type2_un2( const uint32_t* coeff, ULARGE_INTEGER__XX constTerm, const unsigned char* tail, unsigned int tail_size ) const
{
PMPML_CHUNK_LOOP_INTRO_L0
uint32_t size = tail_size >> PMPML_WORD_SIZE_BYTES_LOG2;
const uint32_t* xx = (const uint32_t*)( tail + 2 );
uint32_t x = xx[ -1 ] >> 16;
for ( uint32_t i=0; i<(size&0xFFFFFFF8); i+=8 )
{
PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 16, 0 + i )
PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 16, 1 + i )
PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 16, 2 + i )
PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 16, 3 + i )
#if ( PMPML_CHUNK_SIZE > 4 )
PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 16, 4 + i )
PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 16, 5 + i )
PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 16, 6 + i )
PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 16, 7 + i )
#endif
}
uint32_t offset = size & 0xFFFFFFF8;
switch( size & 0x7 )
{
case 0: { break; }
case 1: { PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 16, 0 + offset ) } break;
case 2: { PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 16, 0 + offset ) PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 16, 1 + offset ) } break;
case 3: { PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 16, 0 + offset ) PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 16, 1 + offset ) PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 16, 2 + offset ) } break;
case 4: { PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 16, 0 + offset ) PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 16, 1 + offset ) PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 16, 2 + offset ) PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 16, 3 + offset ) } break;
case 5: { PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 16, 0 + offset ) PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 16, 1 + offset ) PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 16, 2 + offset ) PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 16, 3 + offset ) PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 16, 4 + offset ) } break;
case 6: { PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 16, 0 + offset ) PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 16, 1 + offset ) PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 16, 2 + offset ) PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 16, 3 + offset ) PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 16, 4 + offset ) PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 16, 5 + offset ) } break;
case 7: { PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 16, 0 + offset ) PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 16, 1 + offset ) PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 16, 2 + offset ) PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 16, 3 + offset ) PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 16, 4 + offset ) PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 16, 5 + offset ) PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 16, 6 + offset ) } break;
}
uint32_t xLast;
switch ( tail_size & ( PMPML_WORD_SIZE_BYTES - 1 ) )
{
case 0: { xLast = 0x1; break;}
case 1: { xLast = 0x100 | tail[tail_size-1]; break;}
case 2: { xLast = 0x100 | tail[tail_size-1]; xLast = ( xLast << 8 ) | tail[tail_size - 2]; break; }
case 3: { xLast = 0x100 | tail[tail_size-1]; xLast = ( xLast << 8 ) | tail[tail_size - 2]; xLast = ( xLast << 8 ) | tail[tail_size - 3]; break;}
}
PMPML_CHUNK_LOOP_BODY_ULI_T1_LAST
PMPML_CHUNK_LOOP_PRE_REDUCE_L0
PMPML_FULL_REDUCE_MOD_2_32_PLUS_15_AND_RETURN
}
FORCE_INLINE
uint64_t hash_of_beginning_of_string_chunk_type2_un3( const uint32_t* coeff, ULARGE_INTEGER__XX constTerm, const unsigned char* tail, unsigned int tail_size ) const
{
PMPML_CHUNK_LOOP_INTRO_L0
uint32_t size = tail_size >> PMPML_WORD_SIZE_BYTES_LOG2;
const uint32_t* xx = (const uint32_t*)( tail + 1 );
uint32_t x = xx[ -1 ] >> 24;
for ( uint32_t i=0; i<(size&0xFFFFFFF8); i+=8 )
{
PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 24, 0 + i )
PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 24, 1 + i )
PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 24, 2 + i )
PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 24, 3 + i )
#if ( PMPML_CHUNK_SIZE > 4 )
PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 24, 4 + i )
PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 24, 5 + i )
PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 24, 6 + i )
PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 24, 7 + i )
#endif
}
uint32_t offset = size & 0xFFFFFFF8;
switch( size & 0x7 )
{
case 0: { break; }
case 1: { PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 24, 0 + offset ) } break;
case 2: { PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 24, 0 + offset ) PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 24, 1 + offset ) } break;
case 3: { PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 24, 0 + offset ) PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 24, 1 + offset ) PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 24, 2 + offset ) } break;
case 4: { PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 24, 0 + offset ) PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 24, 1 + offset ) PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 24, 2 + offset ) PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 24, 3 + offset ) } break;
case 5: { PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 24, 0 + offset ) PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 24, 1 + offset ) PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 24, 2 + offset ) PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 24, 3 + offset ) PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 24, 4 + offset ) } break;
case 6: { PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 24, 0 + offset ) PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 24, 1 + offset ) PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 24, 2 + offset ) PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 24, 3 + offset ) PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 24, 4 + offset ) PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 24, 5 + offset ) } break;
case 7: { PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 24, 0 + offset ) PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 24, 1 + offset ) PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 24, 2 + offset ) PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 24, 3 + offset ) PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 24, 4 + offset ) PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 24, 5 + offset ) PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL( 24, 6 + offset ) } break;
}
uint32_t xLast;
switch ( tail_size & ( PMPML_WORD_SIZE_BYTES - 1 ) )
{
case 0: { xLast = 0x1; break;}
case 1: { xLast = 0x100 | tail[tail_size-1]; break;}
case 2: { xLast = 0x100 | tail[tail_size-1]; xLast = ( xLast << 8 ) | tail[tail_size - 2]; break; }
case 3: { xLast = 0x100 | tail[tail_size-1]; xLast = ( xLast << 8 ) | tail[tail_size - 2]; xLast = ( xLast << 8 ) | tail[tail_size - 3]; break;}
}
PMPML_CHUNK_LOOP_BODY_ULI_T1_LAST
PMPML_CHUNK_LOOP_PRE_REDUCE_L0
PMPML_FULL_REDUCE_MOD_2_32_PLUS_15_AND_RETURN
}
#endif
FORCE_INLINE
uint64_t hash_of_num_chunk( const uint32_t* coeff, ULARGE_INTEGER__XX constTerm, const uint64_t* x ) const
{
PMPML_CHUNK_LOOP_INTRO_L0
for ( uint32_t i=0; i<PMPML_CHUNK_SIZE; i+=8 )
{
PMPML_CHUNK_LOOP_BODY_ULI_T1( 0 + i )
PMPML_CHUNK_LOOP_BODY_ULI_T1( 1 + i )
PMPML_CHUNK_LOOP_BODY_ULI_T1( 2 + i )
PMPML_CHUNK_LOOP_BODY_ULI_T1( 3 + i )
#if ( PMPML_CHUNK_SIZE > 4 )
PMPML_CHUNK_LOOP_BODY_ULI_T1( 4 + i )
PMPML_CHUNK_LOOP_BODY_ULI_T1( 5 + i )
PMPML_CHUNK_LOOP_BODY_ULI_T1( 6 + i )
PMPML_CHUNK_LOOP_BODY_ULI_T1( 7 + i )
#endif
}
PMPML_CHUNK_LOOP_PRE_REDUCE_L0
PMPML_FULL_REDUCE_MOD_2_32_PLUS_15_AND_RETURN
}
FORCE_INLINE
uint64_t hash_of_num_chunk_incomplete( const uint32_t* coeff, ULARGE_INTEGER__XX constTerm, ULARGE_INTEGER__XX prevConstTerm, ULARGE_INTEGER__XX coeffSum, const uint64_t* x, size_t count ) const
{
PMPML_CHUNK_LOOP_INTRO_L0
ULARGE_INTEGER__XX c_ctr;
c_ctr.QuadPart = 0;
uint32_t i;
if ( count < ( PMPML_CHUNK_SIZE >> 1 ) )
{
for ( i=0; i<count; i++ )
{
PMPML_CHUNK_LOOP_BODY_ULI_T1( 0 + i )
c_ctr.QuadPart += coeff[ i ];
}
c_ctr.QuadPart = coeffSum.QuadPart - c_ctr.QuadPart;
}
else
{
for ( i=0; i<count; i++ )
PMPML_CHUNK_LOOP_BODY_ULI_T1( 0 + i )
for ( ; i<PMPML_CHUNK_SIZE; i++ )
c_ctr.QuadPart += coeff[ i ];
}
ULARGE_INTEGER__XX lowProduct;
lowProduct.QuadPart = UInt32x32To64( c_ctr.LowPart, prevConstTerm.LowPart );
ULARGE_INTEGER__XX midProduct;
midProduct.QuadPart = UInt32x32To64( c_ctr.LowPart, prevConstTerm.HighPart ) + UInt32x32To64( c_ctr.HighPart, prevConstTerm.LowPart );
midProduct.QuadPart += lowProduct.HighPart;
lowProduct.HighPart = midProduct.LowPart;
uint32_t hiProduct = c_ctr.HighPart * prevConstTerm.HighPart + midProduct.HighPart;
constTerm.QuadPart += lowProduct.QuadPart;
ctr += hiProduct + ( constTerm.QuadPart < lowProduct.QuadPart );
PMPML_CHUNK_LOOP_PRE_REDUCE_L0
PMPML_FULL_REDUCE_MOD_2_32_PLUS_15_AND_RETURN
}
FORCE_INLINE
void procesNextValue( int level, uint64_t value, uint64_t * allValues, unsigned int * cnts, unsigned int& flag ) const
{
for ( int i=level;;i++ )
{
allValues[ ( i << PMPML_CHUNK_SIZE_LOG2 ) + cnts[ i ] ] = value;
(cnts[ i ]) ++;
if ( cnts[ i ] != PMPML_CHUNK_SIZE )
break;
cnts[ i ] = 0;
value = hash_of_num_chunk( curr_rd[ i ].random_coeff, *(ULARGE_INTEGER__XX*)(&(curr_rd[i].const_term)), allValues + ( i << PMPML_CHUNK_SIZE_LOG2 ) );
if ( ( flag & ( 1 << i ) ) == 0 )
{
cnts[ i + 1] = 0;
flag |= 1 << i;
}
}
}
FORCE_INLINE
uint64_t finalize( int level, uint64_t * allValues, unsigned int * cnts, unsigned int& flag ) const
{
for ( int i=level;;i++ )
{
if ( ( ( flag & ( 1 << i ) ) == 0 ) && cnts[ i ] == 1 )
{
return allValues[ i << PMPML_CHUNK_SIZE_LOG2 ];
}
if ( cnts[ i ] )
{
if ( ( flag & ( 1 << i ) ) == 0 )
{
cnts[ i + 1] = 0;
flag |= 1 << i;
}
procesNextValue( i + 1,
hash_of_num_chunk_incomplete( curr_rd[ i ].random_coeff,
*(ULARGE_INTEGER__XX*)(&(curr_rd[i].const_term)),
*(ULARGE_INTEGER__XX*)(&(curr_rd[i-1].const_term)),
*(ULARGE_INTEGER__XX*)(&(curr_rd[i].cachedSum)),
allValues + ( i << PMPML_CHUNK_SIZE_LOG2 ),
cnts[ i ]),
allValues, cnts, flag );
}
}
}
#ifdef PMPML_MSC_32_WORKAROUND
FORCE_INLINE uint32_t hash_size_0( const unsigned char* chars ) const
{
const uint32_t* coeff = curr_rd[0].random_coeff;
ULARGE_INTEGER__XX constTerm = *(ULARGE_INTEGER__XX*)(&(curr_rd[0].const_term));
constTerm.QuadPart += coeff[ 0 ]; PMPML_FULL_REDUCE_MOD_2_32_PLUS_15_AND_RETURN_RETURN_32x32_ONLY;
}
FORCE_INLINE uint32_t hash_size_1( const unsigned char* chars ) const
{
const uint32_t* coeff = curr_rd[0].random_coeff;
ULARGE_INTEGER__XX constTerm = *(ULARGE_INTEGER__XX*)(&(curr_rd[0].const_term));
uint32_t xLast;
xLast = 0x100 + chars[0]; constTerm.QuadPart += UInt32x32To64( coeff[ 0 ], xLast ); PMPML_FULL_REDUCE_MOD_2_32_PLUS_15_AND_RETURN_RETURN_32x32_ONLY;
}
FORCE_INLINE uint32_t hash_size_2( const unsigned char* chars ) const
{
const uint32_t* coeff = curr_rd[0].random_coeff;
ULARGE_INTEGER__XX constTerm = *(ULARGE_INTEGER__XX*)(&(curr_rd[0].const_term));
uint32_t xLast;
xLast = *((const unsigned short*)(chars )) + 0x10000; constTerm.QuadPart += UInt32x32To64( coeff[ 0 ], xLast ); PMPML_FULL_REDUCE_MOD_2_32_PLUS_15_AND_RETURN_RETURN_32x32_ONLY;
}
FORCE_INLINE uint32_t hash_size_3( const unsigned char* chars ) const
{
const uint32_t* coeff = curr_rd[0].random_coeff;
ULARGE_INTEGER__XX constTerm = *(ULARGE_INTEGER__XX*)(&(curr_rd[0].const_term));
uint32_t xLast;
xLast = chars[ 2 ]; xLast = ( xLast << 16 ) + *((const unsigned short*)(chars )) + 0x1000000; constTerm.QuadPart += UInt32x32To64( coeff[ 0 ], xLast ); PMPML_FULL_REDUCE_MOD_2_32_PLUS_15_AND_RETURN_RETURN_32x32_ONLY;
}
FORCE_INLINE uint32_t hash_size_4( const unsigned char* chars ) const
{
const uint32_t* coeff = curr_rd[0].random_coeff;
ULARGE_INTEGER__XX constTerm = *(ULARGE_INTEGER__XX*)(&(curr_rd[0].const_term));
uint32_t xLast;
constTerm.QuadPart += UInt32x32To64( coeff[ 0 ], *(uint32_t*)(chars) ) + coeff[ 1 ]; PMPML_FULL_REDUCE_MOD_2_32_PLUS_15_AND_RETURN_RETURN_32x32_ONLY;
}
#define HASH_SIZE_XXX_BEGIN( XXX ) \
FORCE_INLINE uint32_t hash_size_##XXX( const unsigned char* chars ) const \
{ \
const uint32_t* coeff = curr_rd[0].random_coeff; \
const uint32_t* x = (const uint32_t*)chars; \
ULARGE_INTEGER__XX constTerm = *(ULARGE_INTEGER__XX*)(&(curr_rd[0].const_term)); \
uint32_t xLast; \
PMPML_CHUNK_LOOP_INTRO_L0 \
uint32_t size = XXX >> PMPML_WORD_SIZE_BYTES_LOG2;
#define HASH_SIZE_XXX_END \
PMPML_CHUNK_LOOP_PRE_REDUCE_L0 \
PMPML_FULL_REDUCE_MOD_2_32_PLUS_15_AND_RETURN_RETURN \
}
HASH_SIZE_XXX_BEGIN(28 )
PMPML_CHUNK_LOOP_BODY_ULI_T1( 0 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 1 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 2 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 3 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 4 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 5 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 6 ) xLast = 0x1; PMPML_CHUNK_LOOP_BODY_ULI_T1_LAST_FOR_JUST_1;
HASH_SIZE_XXX_END
HASH_SIZE_XXX_BEGIN(29 )
PMPML_CHUNK_LOOP_BODY_ULI_T1( 0 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 1 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 2 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 3 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 4 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 5 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 6 ) xLast = 0x100 + chars[28]; PMPML_CHUNK_LOOP_BODY_ULI_T1_LAST;
HASH_SIZE_XXX_END
HASH_SIZE_XXX_BEGIN(30 )
PMPML_CHUNK_LOOP_BODY_ULI_T1( 0 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 1 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 2 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 3 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 4 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 5 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 6 ) xLast = *((const unsigned short*)(chars + 28 )) + 0x10000; PMPML_CHUNK_LOOP_BODY_ULI_T1_LAST
HASH_SIZE_XXX_END
HASH_SIZE_XXX_BEGIN(31 )
PMPML_CHUNK_LOOP_BODY_ULI_T1( 0 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 1 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 2 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 3 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 4 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 5 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 6 ) xLast = chars[ 30 ]; xLast = ( xLast << 16 ) + *((const unsigned short*)(chars + 28 )) + 0x1000000; PMPML_CHUNK_LOOP_BODY_ULI_T1_LAST;
HASH_SIZE_XXX_END
#endif
public:
FORCE_INLINE uint32_t hash( const unsigned char* chars, unsigned int cnt ) const
{
if ( _LIKELY_BRANCH_(cnt < 32) )
{
const uint32_t* coeff = curr_rd[0].random_coeff;
ULARGE_INTEGER__XX constTerm = *(ULARGE_INTEGER__XX*)(&(curr_rd[0].const_term));
PMPML_CHUNK_LOOP_INTRO_L0
uint32_t size = cnt >> PMPML_WORD_SIZE_BYTES_LOG2;
uint32_t xLast;
#if !defined PMPML_STRICT_UNALIGNED_HANDLING
const uint32_t* x = (const uint32_t*)chars;
#if !defined PMPML_MSC_32_WORKAROUND
switch( size )
{
case 0: { break; }
case 1: { PMPML_CHUNK_LOOP_BODY_ULI_T1( 0 ) } break;
case 2: { PMPML_CHUNK_LOOP_BODY_ULI_T1( 0 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 1 ) } break;
case 3: { PMPML_CHUNK_LOOP_BODY_ULI_T1( 0 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 1 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 2 ) } break;
case 4: { PMPML_CHUNK_LOOP_BODY_ULI_T1( 0 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 1 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 2 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 3 ) } break;
case 5: { PMPML_CHUNK_LOOP_BODY_ULI_T1( 0 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 1 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 2 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 3 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 4 ) } break;
case 6: { PMPML_CHUNK_LOOP_BODY_ULI_T1( 0 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 1 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 2 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 3 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 4 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 5 ) } break;
default: { PMPML_CHUNK_LOOP_BODY_ULI_T1( 0 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 1 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 2 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 3 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 4 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 5 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 6 ) } break;
}
switch ( cnt & ( PMPML_WORD_SIZE_BYTES - 1 ) )
{
case 0: { xLast = 0x1; break;}
case 1: { xLast = 0x100 + chars[cnt-1]; break;}
case 2: { xLast = *((const unsigned short*)(chars + cnt - 2 )) + 0x10000; break; }
default: { xLast = chars[ cnt - 1 ]; xLast = ( xLast << 16 ) + *((const unsigned short*)(chars + cnt - 3 )) + 0x1000000; break;}
}
#else
switch ( cnt )
{
case 0: { return hash_size_0( chars ); }
case 1: { return hash_size_1( chars ); }
case 2: { return hash_size_2( chars ); }
case 3: { return hash_size_3( chars ); }
case 4: { return hash_size_4( chars ); }
case 5: { PMPML_CHUNK_LOOP_BODY_ULI_T1( 0 ) xLast = 0x100 + chars[4]; PMPML_CHUNK_LOOP_BODY_ULI_T1_LAST; break; }
case 6: { PMPML_CHUNK_LOOP_BODY_ULI_T1( 0 ) xLast = *((const unsigned short*)(chars + 4 )) + 0x10000; PMPML_CHUNK_LOOP_BODY_ULI_T1_LAST; break; }
case 7: { PMPML_CHUNK_LOOP_BODY_ULI_T1( 0 ) xLast = chars[ 6 ]; xLast = ( xLast << 16 ) + *((const unsigned short*)(chars + 4 )) + 0x1000000; PMPML_CHUNK_LOOP_BODY_ULI_T1_LAST; break; }
case 8: { PMPML_CHUNK_LOOP_BODY_ULI_T1( 0 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 1 ) xLast = 0x1; PMPML_CHUNK_LOOP_BODY_ULI_T1_LAST_FOR_JUST_1; break; }
case 9: { PMPML_CHUNK_LOOP_BODY_ULI_T1( 0 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 1 ) xLast = 0x100 + chars[8]; PMPML_CHUNK_LOOP_BODY_ULI_T1_LAST; break; }
case 10: { PMPML_CHUNK_LOOP_BODY_ULI_T1( 0 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 1 ) xLast = *((const unsigned short*)(chars + 8 )) + 0x10000; PMPML_CHUNK_LOOP_BODY_ULI_T1_LAST; break; }
case 11: { PMPML_CHUNK_LOOP_BODY_ULI_T1( 0 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 1 ) xLast = chars[ 10 ]; xLast = ( xLast << 16 ) + *((const unsigned short*)(chars + 8 )) + 0x1000000; PMPML_CHUNK_LOOP_BODY_ULI_T1_LAST; break; }
case 12: { PMPML_CHUNK_LOOP_BODY_ULI_T1( 0 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 1 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 2 ) xLast = 0x1; PMPML_CHUNK_LOOP_BODY_ULI_T1_LAST_FOR_JUST_1; break; }
case 13: { PMPML_CHUNK_LOOP_BODY_ULI_T1( 0 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 1 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 2 ) xLast = 0x100 + chars[12]; PMPML_CHUNK_LOOP_BODY_ULI_T1_LAST; break; }
case 14: { PMPML_CHUNK_LOOP_BODY_ULI_T1( 0 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 1 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 2 ) xLast = *((const unsigned short*)(chars + 12 )) + 0x10000; PMPML_CHUNK_LOOP_BODY_ULI_T1_LAST; break; }
case 15: { PMPML_CHUNK_LOOP_BODY_ULI_T1( 0 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 1 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 2 ) xLast = chars[ 14 ]; xLast = ( xLast << 16 ) + *((const unsigned short*)(chars + 12 )) + 0x1000000; PMPML_CHUNK_LOOP_BODY_ULI_T1_LAST; break; }
case 16: { PMPML_CHUNK_LOOP_BODY_ULI_T1( 0 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 1 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 2 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 3 ) xLast = 0x1; PMPML_CHUNK_LOOP_BODY_ULI_T1_LAST_FOR_JUST_1; break; }
case 17: { PMPML_CHUNK_LOOP_BODY_ULI_T1( 0 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 1 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 2 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 3 ) xLast = 0x100 + chars[16]; PMPML_CHUNK_LOOP_BODY_ULI_T1_LAST; break; }
case 18: { PMPML_CHUNK_LOOP_BODY_ULI_T1( 0 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 1 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 2 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 3 ) xLast = *((const unsigned short*)(chars + 16 )) + 0x10000; PMPML_CHUNK_LOOP_BODY_ULI_T1_LAST; break; }
case 19: { PMPML_CHUNK_LOOP_BODY_ULI_T1( 0 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 1 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 2 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 3 ) xLast = chars[ 18 ]; xLast = ( xLast << 16 ) + *((const unsigned short*)(chars + 16 )) + 0x1000000; PMPML_CHUNK_LOOP_BODY_ULI_T1_LAST; break; }
case 20: { PMPML_CHUNK_LOOP_BODY_ULI_T1( 0 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 1 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 2 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 3 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 4 ) xLast = 0x1; PMPML_CHUNK_LOOP_BODY_ULI_T1_LAST_FOR_JUST_1; break; }
case 21: { PMPML_CHUNK_LOOP_BODY_ULI_T1( 0 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 1 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 2 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 3 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 4 ) xLast = 0x100 + chars[20]; PMPML_CHUNK_LOOP_BODY_ULI_T1_LAST; break; }
case 22: { PMPML_CHUNK_LOOP_BODY_ULI_T1( 0 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 1 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 2 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 3 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 4 ) xLast = *((const unsigned short*)(chars + 20 )) + 0x10000; PMPML_CHUNK_LOOP_BODY_ULI_T1_LAST; break; }
case 23: { PMPML_CHUNK_LOOP_BODY_ULI_T1( 0 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 1 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 2 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 3 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 4 ) xLast = chars[ 22 ]; xLast = ( xLast << 16 ) + *((const unsigned short*)(chars + 20 )) + 0x1000000; PMPML_CHUNK_LOOP_BODY_ULI_T1_LAST; break; }
case 24: { PMPML_CHUNK_LOOP_BODY_ULI_T1( 0 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 1 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 2 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 3 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 4 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 5 ) xLast = 0x1; PMPML_CHUNK_LOOP_BODY_ULI_T1_LAST_FOR_JUST_1; break; }
case 25: { PMPML_CHUNK_LOOP_BODY_ULI_T1( 0 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 1 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 2 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 3 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 4 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 5 ) xLast = 0x100 + chars[24]; PMPML_CHUNK_LOOP_BODY_ULI_T1_LAST; break; }
case 26: { PMPML_CHUNK_LOOP_BODY_ULI_T1( 0 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 1 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 2 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 3 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 4 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 5 ) xLast = *((const unsigned short*)(chars + 24 )) + 0x10000; PMPML_CHUNK_LOOP_BODY_ULI_T1_LAST; break; }
case 27: { PMPML_CHUNK_LOOP_BODY_ULI_T1( 0 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 1 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 2 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 3 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 4 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 5 ) xLast = chars[ 26 ]; xLast = ( xLast << 16 ) + *((const unsigned short*)(chars + 24 )) + 0x1000000; PMPML_CHUNK_LOOP_BODY_ULI_T1_LAST; break; }
case 28: { return hash_size_28( chars ); }
case 29: { return hash_size_29( chars ); }
case 30: { return hash_size_30( chars ); }
default: { return hash_size_31( chars ); }
}
#endif #else
if ( _LIKELY_BRANCH_( ( cnt & ( PMPML_WORD_SIZE_BYTES - 1 ) ) == 0 ) )
{
const uint32_t* x = (const uint32_t*)chars;
switch( size )
{
case 0: { break; }
case 1: { PMPML_CHUNK_LOOP_BODY_ULI_T1( 0 ) } break;
case 2: { PMPML_CHUNK_LOOP_BODY_ULI_T1( 0 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 1 ) } break;
case 3: { PMPML_CHUNK_LOOP_BODY_ULI_T1( 0 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 1 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 2 ) } break;
case 4: { PMPML_CHUNK_LOOP_BODY_ULI_T1( 0 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 1 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 2 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 3 ) } break;
case 5: { PMPML_CHUNK_LOOP_BODY_ULI_T1( 0 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 1 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 2 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 3 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 4 ) } break;
case 6: { PMPML_CHUNK_LOOP_BODY_ULI_T1( 0 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 1 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 2 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 3 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 4 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 5 ) } break;
default: { PMPML_CHUNK_LOOP_BODY_ULI_T1( 0 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 1 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 2 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 3 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 4 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 5 ) PMPML_CHUNK_LOOP_BODY_ULI_T1( 6 ) } break;
}
switch ( cnt & ( PMPML_WORD_SIZE_BYTES - 1 ) )
{
case 0: { xLast = 0x1; break;}
case 1: { xLast = 0x100 + chars[cnt-1]; break;}
case 2: { xLast = *((const unsigned short*)(chars + cnt - 2 )) + 0x10000; break; }
default: { xLast = chars[ cnt - 1 ]; xLast = ( xLast << 16 ) + *((const unsigned short*)(chars + cnt - 3 )) + 0x1000000; break;}
}
}
else
{
const unaligned_uint32* xun = (const unaligned_uint32*)chars;
switch( size )
{
case 0: { break; }
case 1: { PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL_PTR( 0 ) } break;
case 2: { PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL_PTR( 0 ) PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL_PTR( 1 ) } break;
case 3: { PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL_PTR( 0 ) PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL_PTR( 1 ) PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL_PTR( 2 ) } break;
case 4: { PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL_PTR( 0 ) PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL_PTR( 1 ) PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL_PTR( 2 ) PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL_PTR( 3 ) } break;
case 5: { PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL_PTR( 0 ) PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL_PTR( 1 ) PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL_PTR( 2 ) PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL_PTR( 3 ) PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL_PTR( 4 ) } break;
case 6: { PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL_PTR( 0 ) PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL_PTR( 1 ) PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL_PTR( 2 ) PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL_PTR( 3 ) PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL_PTR( 4 ) PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL_PTR( 5 ) } break;
default: { PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL_PTR( 0 ) PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL_PTR( 1 ) PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL_PTR( 2 ) PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL_PTR( 3 ) PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL_PTR( 4 ) PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL_PTR( 5 ) PMPML_CHUNK_LOOP_BODY_ULI_T1_UNL_PTR( 6 ) } break;
}
switch ( cnt & ( PMPML_WORD_SIZE_BYTES - 1 ) )
{
case 1: { xLast = 0x100 | chars[cnt-1]; break;}
case 2: { xLast = 0x100 | chars[cnt-1]; xLast = ( xLast << 8 ) | chars[cnt - 2]; break; }
case 3: { xLast = 0x100 | chars[cnt-1]; xLast = ( xLast << 8 ) | chars[cnt - 2]; xLast = ( xLast << 8 ) | chars[cnt - 3]; break;}
}
}
#endif
#if !defined PMPML_MSC_32_WORKAROUND
PMPML_CHUNK_LOOP_BODY_ULI_T1_LAST
#endif
PMPML_CHUNK_LOOP_PRE_REDUCE_L0
PMPML_FULL_REDUCE_MOD_2_32_PLUS_15_AND_RETURN_RETURN
}
else if ( cnt < PMPML_CHUNK_SIZE_BYTES )
{
return _hash_noRecursionNoInline_forLessThanChunk( chars, cnt );
}
else
{
return _hash_noRecursionNoInline_type2( chars, cnt );
}
}
NOINLINE uint32_t _hash_noRecursionNoInline_forLessThanChunk(const unsigned char* chars, unsigned int cnt) const
{
unsigned int i;
ULARGE_INTEGER__XX tmp_hash;
#if !defined PMPML_STRICT_UNALIGNED_HANDLING
tmp_hash.QuadPart = hash_of_beginning_of_string_chunk_type2( curr_rd[0].random_coeff, *(ULARGE_INTEGER__XX*)(&(curr_rd[0].const_term)), chars, cnt );
#else
switch (( ( (uint32_t)chars) & 3))
{
case 0: tmp_hash.QuadPart = hash_of_beginning_of_string_chunk_type2( curr_rd[0].random_coeff, *(ULARGE_INTEGER__XX*)(&(curr_rd[0].const_term)), chars, cnt ); break;
case 1: tmp_hash.QuadPart = hash_of_beginning_of_string_chunk_type2_un1( curr_rd[0].random_coeff, *(ULARGE_INTEGER__XX*)(&(curr_rd[0].const_term)), chars, cnt ); break;
case 2: tmp_hash.QuadPart = hash_of_beginning_of_string_chunk_type2_un2( curr_rd[0].random_coeff, *(ULARGE_INTEGER__XX*)(&(curr_rd[0].const_term)), chars, cnt ); break;
case 3: tmp_hash.QuadPart = hash_of_beginning_of_string_chunk_type2_un3( curr_rd[0].random_coeff, *(ULARGE_INTEGER__XX*)(&(curr_rd[0].const_term)), chars, cnt ); break;
}
#endif if ( tmp_hash.HighPart == 0 ) {
return fmix32_short( tmp_hash.LowPart );
}
return tmp_hash.LowPart;
}
NOINLINE uint32_t _hash_noRecursionNoInline_type2(const unsigned char* chars, unsigned int cnt) const
{
uint64_t allValues[ PMPML_LEVELS * PMPML_CHUNK_SIZE ];
unsigned int cnts[ PMPML_LEVELS ];
unsigned int flag;
cnts[ 1 ] = 0;
flag = 0;
unsigned int i;
ULARGE_INTEGER__XX tmp_hash;
#if !defined PMPML_STRICT_UNALIGNED_HANDLING
for ( i=0; i<(cnt>>PMPML_CHUNK_SIZE_BYTES_LOG2); i++ )
{
tmp_hash.QuadPart = hash_of_string_chunk_compact( curr_rd[0].random_coeff, *(ULARGE_INTEGER__XX*)(&(curr_rd[0].const_term)), ((const uint32_t*)(chars)) + ( i << PMPML_CHUNK_SIZE_LOG2 ) );
procesNextValue( 1, tmp_hash.QuadPart, allValues, cnts, flag );
}
#else
switch (( ( (uint32_t)chars) & 3))
{
case 0: for ( i=0; i<(cnt>>PMPML_CHUNK_SIZE_BYTES_LOG2); i++ ){ tmp_hash.QuadPart = hash_of_string_chunk_compact( curr_rd[0].random_coeff, *(ULARGE_INTEGER__XX*)(&(curr_rd[0].const_term)), ((const uint32_t*)(chars)) + ( i << PMPML_CHUNK_SIZE_LOG2 ) ); procesNextValue( 1, tmp_hash.QuadPart, allValues, cnts, flag );} break;
case 1: for ( i=0; i<(cnt>>PMPML_CHUNK_SIZE_BYTES_LOG2); i++ ){ tmp_hash.QuadPart = hash_of_string_chunk_compact_un_1( curr_rd[0].random_coeff, *(ULARGE_INTEGER__XX*)(&(curr_rd[0].const_term)), chars + ( i << PMPML_CHUNK_SIZE_BYTES_LOG2 ) ); procesNextValue( 1, tmp_hash.QuadPart, allValues, cnts, flag );} break;
case 2: for ( i=0; i<(cnt>>PMPML_CHUNK_SIZE_BYTES_LOG2); i++ ){ tmp_hash.QuadPart = hash_of_string_chunk_compact_un_2( curr_rd[0].random_coeff, *(ULARGE_INTEGER__XX*)(&(curr_rd[0].const_term)), chars + ( i << PMPML_CHUNK_SIZE_BYTES_LOG2 ) ); procesNextValue( 1, tmp_hash.QuadPart, allValues, cnts, flag );} break;
case 3: for ( i=0; i<(cnt>>PMPML_CHUNK_SIZE_BYTES_LOG2); i++ ){ tmp_hash.QuadPart = hash_of_string_chunk_compact_un_3( curr_rd[0].random_coeff, *(ULARGE_INTEGER__XX*)(&(curr_rd[0].const_term)), chars + ( i << PMPML_CHUNK_SIZE_BYTES_LOG2 ) ); procesNextValue( 1, tmp_hash.QuadPart, allValues, cnts, flag );} break;
}
#endif unsigned int tailCnt = cnt & ( PMPML_CHUNK_SIZE_BYTES - 1 );
const unsigned char* tail = chars + ( (cnt>>PMPML_CHUNK_SIZE_BYTES_LOG2) << PMPML_CHUNK_SIZE_BYTES_LOG2 );
#if !defined PMPML_STRICT_UNALIGNED_HANDLING
tmp_hash.QuadPart = hash_of_beginning_of_string_chunk_type2( curr_rd[0].random_coeff, *(ULARGE_INTEGER__XX*)(&(curr_rd[0].const_term)), tail, tailCnt );
#else
switch (( ( (uint32_t)chars) & 3))
{
case 0: tmp_hash.QuadPart = hash_of_beginning_of_string_chunk_type2( curr_rd[0].random_coeff, *(ULARGE_INTEGER__XX*)(&(curr_rd[0].const_term)), tail, tailCnt ); break;
case 1: tmp_hash.QuadPart = hash_of_beginning_of_string_chunk_type2_un1( curr_rd[0].random_coeff, *(ULARGE_INTEGER__XX*)(&(curr_rd[0].const_term)), tail, tailCnt ); break;
case 2: tmp_hash.QuadPart = hash_of_beginning_of_string_chunk_type2_un2( curr_rd[0].random_coeff, *(ULARGE_INTEGER__XX*)(&(curr_rd[0].const_term)), tail, tailCnt ); break;
case 3: tmp_hash.QuadPart = hash_of_beginning_of_string_chunk_type2_un3( curr_rd[0].random_coeff, *(ULARGE_INTEGER__XX*)(&(curr_rd[0].const_term)), tail, tailCnt ); break;
}
#endif procesNextValue( 1, tmp_hash.QuadPart, allValues, cnts, flag );
ULARGE_INTEGER__XX ret64;
ret64.QuadPart = finalize( 1, allValues, cnts, flag );
if ( ret64.HighPart == 0 ) {
return fmix32_short( ret64.LowPart );
}
return ret64.LowPart;
}
public:
PMP_Multilinear_Hasher()
{
#ifdef PMPML_USE_SSE
base_addr = NULL;
#endif
curr_rd = (random_data_for_MPSHF*)rd_for_MPSHF;
}
virtual ~PMP_Multilinear_Hasher()
{
#ifdef PMPML_USE_SSE
if ( base_addr != NULL )
delete [] base_addr;
#else
if ( curr_rd != NULL && curr_rd != rd_for_MPSHF )
delete [] curr_rd;
#endif
}
void randomize( UniformRandomNumberGenerator& rng )
{
#if !defined PMPML_USE_SSE
random_data_for_MPSHF * temp_curr_rd = new random_data_for_MPSHF[ PMPML_LEVELS ];
#else
if ( base_addr != NULL ) delete [] base_addr;
base_addr = new unsigned char [ sizeof( random_data_for_MPSHF ) * PMPML_LEVELS + 32 ];
random_data_for_MPSHF * temp_curr_rd = (random_data_for_MPSHF*)((((size_t)base_addr) + 15) & UINT64_C(0xFFFFFFFFFFFFFFF0));
#endif
int i, j;
for ( i=0; i<PMPML_LEVELS; i++ )
for ( j=0; j<PMPML_CHUNK_SIZE; j++ )
{
do
{
temp_curr_rd[ i ].random_coeff[ j ] = rng.rand();
}
while ( !IS_VALID_COEFFICIENT( temp_curr_rd[ i ].random_coeff[ j ], i ) );
}
for ( i=0; i<PMPML_LEVELS; i++ )
{
uint64_t rv;
do
{
rv = rng.rand();
rv <<= 32;
rv |= rng.rand();
}
while ( rv == 0 );
rv = rv % PMPML_MAIN_PRIME;
temp_curr_rd[ i ].const_term = rv;
}
#ifdef PMPML_USE_SSE
curr_rd = temp_curr_rd;
#else
if ( curr_rd == rd_for_MPSHF )
curr_rd = temp_curr_rd;
else
{
if ( curr_rd != NULL )
delete [] curr_rd;
curr_rd = temp_curr_rd;
}
#endif
}
void seed( uint32_t seed )
{
curr_rd[0].const_term ^= seed;
}
#if 0#endif };
#endif