#include <stdint.h> // uint8_t needed
//typedef unsigned char uint8_t;
//typedef unsigned short uint16_t;
//typedef unsigned int uint32_t;

#define _rotl_KAZE(x, n) (((x) << (n)) | ((x) >> (32-(n))))

uint32_t FNV1A_Hash_YoshimitsuTRIADii(const char *str, uint32_t wrdlen)
{
    const uint32_t PRIME = 709607;
    uint32_t hash32 = 2166136261;
    uint32_t hash32B = 2166136261;
    uint32_t hash32C = 2166136261;
    const char *p = str;
    uint32_t Loop_Counter;
    uint32_t Second_Line_Offset;

if (wrdlen >= 24) {
    Loop_Counter = (wrdlen/24);
    Loop_Counter++;
    Second_Line_Offset = wrdlen-(Loop_Counter)*(3*4);
    for(; Loop_Counter; Loop_Counter--, p += 3*sizeof(uint32_t)) {
		hash32 = (hash32 ^ (_rotl_KAZE(*(uint32_t *)(p+0),5) ^ *(uint32_t *)(p+0+Second_Line_Offset))) * PRIME;        
		hash32B = (hash32B ^ (_rotl_KAZE(*(uint32_t *)(p+4+Second_Line_Offset),5) ^ *(uint32_t *)(p+4))) * PRIME;        
		hash32C = (hash32C ^ (_rotl_KAZE(*(uint32_t *)(p+8),5) ^ *(uint32_t *)(p+8+Second_Line_Offset))) * PRIME;        
    }
		hash32 = (hash32 ^ _rotl_KAZE(hash32C,5) ) * PRIME;
} else {
    // 1111=15; 10111=23
    if (wrdlen & 4*sizeof(uint32_t)) {	
		hash32 = (hash32 ^ (_rotl_KAZE(*(uint32_t *)(p+0),5) ^ *(uint32_t *)(p+4))) * PRIME;        
		hash32B = (hash32B ^ (_rotl_KAZE(*(uint32_t *)(p+8),5) ^ *(uint32_t *)(p+12))) * PRIME;        
		p += 8*sizeof(uint16_t);
    }
    // Cases: 0,1,2,3,4,5,6,7,...,15
    if (wrdlen & 2*sizeof(uint32_t)) {
		hash32 = (hash32 ^ *(uint32_t*)(p+0)) * PRIME;
		hash32B = (hash32B ^ *(uint32_t*)(p+4)) * PRIME;
		p += 4*sizeof(uint16_t);
    }
    // Cases: 0,1,2,3,4,5,6,7
    if (wrdlen & sizeof(uint32_t)) {
		hash32 = (hash32 ^ *(uint16_t*)(p+0)) * PRIME;
		hash32B = (hash32B ^ *(uint16_t*)(p+2)) * PRIME;
		p += 2*sizeof(uint16_t);
    }
    if (wrdlen & sizeof(uint16_t)) {
        hash32 = (hash32 ^ *(uint16_t*)p) * PRIME;
        p += sizeof(uint16_t);
    }
    if (wrdlen & 1) 
        hash32 = (hash32 ^ *p) * PRIME;
}
    hash32 = (hash32 ^ _rotl_KAZE(hash32B,5) ) * PRIME;
    return hash32 ^ (hash32 >> 16);
}

uint32_t FNV1A_Hash_YoshimitsuTRIAD(const char *str, uint32_t wrdlen)
{
    const uint32_t PRIME = 709607;
    uint32_t hash32 = 2166136261;
    uint32_t hash32B = 2166136261;
    uint32_t hash32C = 2166136261;
    //uint32_t hash32D = 2166136261;
    const char *p = str;

    for(; wrdlen >= 3*2*sizeof(uint32_t); wrdlen -= 3*2*sizeof(uint32_t), p += 3*2*sizeof(uint32_t)) {
		hash32 = (hash32 ^ (_rotl(*(uint32_t *)(p+0),5) ^ *(uint32_t *)(p+4))) * PRIME;        
		hash32B = (hash32B ^ (_rotl(*(uint32_t *)(p+8),5) ^ *(uint32_t *)(p+12))) * PRIME;        
		hash32C = (hash32C ^ (_rotl(*(uint32_t *)(p+16),5) ^ *(uint32_t *)(p+20))) * PRIME;        
		//hash32D = (hash32D ^ (_rotl(*(uint32_t *)(p+24),5) ^ *(uint32_t *)(p+28))) * PRIME;        

/*
// Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.30319.01 for 80x86 gave this:
// 12d-0f4+2= 59 bytes, No CARAMBA anymore.
$LL9@FNV1A_Hash@2:

; 160  : 		hash32 = (hash32 ^ (_rotl(*(uint32_t *)(p+0),5) ^ *(uint32_t *)(p+4))) * PRIME;        

  000f4	8b 01		 mov	 eax, DWORD PTR [ecx]
  000f6	c1 c0 05	 rol	 eax, 5
  000f9	33 41 04	 xor	 eax, DWORD PTR [ecx+4]
  000fc	83 eb 18	 sub	 ebx, 24			; 00000018H
  000ff	33 f0		 xor	 esi, eax

; 161  : 		hash32B = (hash32B ^ (_rotl(*(uint32_t *)(p+8),5) ^ *(uint32_t *)(p+12))) * PRIME;        

  00101	8b 41 08	 mov	 eax, DWORD PTR [ecx+8]
  00104	69 f6 e7 d3 0a
	00		 imul	 esi, 709607		; 000ad3e7H
  0010a	c1 c0 05	 rol	 eax, 5
  0010d	33 41 0c	 xor	 eax, DWORD PTR [ecx+12]
  00110	83 c1 18	 add	 ecx, 24			; 00000018H
  00113	33 f8		 xor	 edi, eax

; 162  : 		hash32C = (hash32C ^ (_rotl(*(uint32_t *)(p+16),5) ^ *(uint32_t *)(p+20))) * PRIME;        

  00115	8b 41 f8	 mov	 eax, DWORD PTR [ecx-8]
  00118	69 ff e7 d3 0a
	00		 imul	 edi, 709607		; 000ad3e7H
  0011e	c1 c0 05	 rol	 eax, 5
  00121	33 41 fc	 xor	 eax, DWORD PTR [ecx-4]
  00124	33 e8		 xor	 ebp, eax
  00126	69 ed e7 d3 0a
	00		 imul	 ebp, 709607		; 000ad3e7H
  0012c	4a		 dec	 edx
  0012d	75 c5		 jne	 SHORT $LL9@FNV1A_Hash@2
*/

/*
// Intel(R) C++ Compiler XE for applications running on IA-32, Version 12.1.1.258 Build 20111011 gave this:
// 216a-212f+2= 61 bytes, No CARAMBA anymore.
;;;     for(; wrdlen >= 3*2*sizeof(uint32_t); wrdlen -= 3*2*sizeof(uint32_t), p += 3*2*sizeof(uint32_t)) {

  02127 83 fa 18         cmp edx, 24                            
  0212a 72 43            jb .B4.5 ; Prob 10%                    
                                ; LOE eax edx ecx ebx ebp esi edi
.B4.2:                          ; Preds .B4.1
  0212c 89 34 24         mov DWORD PTR [esp], esi               ;
                                ; LOE eax edx ecx ebx ebp edi
.B4.3:                          ; Preds .B4.2 .B4.3

;;; 		hash32 = (hash32 ^ (_rotl(*(uint32_t *)(p+0),5) ^ *(uint32_t *)(p+4))) * PRIME;        

  0212f 8b 31            mov esi, DWORD PTR [ecx]               
  02131 83 c2 e8         add edx, -24                           
  02134 c1 c6 05         rol esi, 5                             
  02137 33 71 04         xor esi, DWORD PTR [4+ecx]             
  0213a 33 de            xor ebx, esi                           

;;; 		hash32B = (hash32B ^ (_rotl(*(uint32_t *)(p+8),5) ^ *(uint32_t *)(p+12))) * PRIME;        

  0213c 8b 71 08         mov esi, DWORD PTR [8+ecx]             
  0213f c1 c6 05         rol esi, 5                             
  02142 33 71 0c         xor esi, DWORD PTR [12+ecx]            
  02145 33 fe            xor edi, esi                           

;;; 		hash32C = (hash32C ^ (_rotl(*(uint32_t *)(p+16),5) ^ *(uint32_t *)(p+20))) * PRIME;        

  02147 8b 71 10         mov esi, DWORD PTR [16+ecx]            
  0214a c1 c6 05         rol esi, 5                             
  0214d 33 71 14         xor esi, DWORD PTR [20+ecx]            
  02150 83 c1 18         add ecx, 24                            
  02153 33 ee            xor ebp, esi                           
  02155 69 db e7 d3 0a 
        00               imul ebx, ebx, 709607                  
  0215b 69 ff e7 d3 0a 
        00               imul edi, edi, 709607                  
  02161 69 ed e7 d3 0a 
        00               imul ebp, ebp, 709607                  
  02167 83 fa 18         cmp edx, 24                            
  0216a 73 c3            jae .B4.3 ; Prob 82%                   
                                ; LOE eax edx ecx ebx ebp edi
.B4.4:                          ; Preds .B4.3
  0216c 8b 34 24         mov esi, DWORD PTR [esp]               ;
                                ; LOE eax edx ecx ebx ebp esi edi
.B4.5:                          ; Preds .B4.1 .B4.4
*/

    }
	if (p != str) {
		hash32 = (hash32 ^ _rotl(hash32C,5) ) * PRIME;
		//hash32B = (hash32B ^ _rotl(hash32D,5) ) * PRIME;
	}

    // 1111=15; 10111=23
    if (wrdlen & 4*sizeof(uint32_t)) {	
		hash32 = (hash32 ^ (_rotl(*(uint32_t *)(p+0),5) ^ *(uint32_t *)(p+4))) * PRIME;        
		hash32B = (hash32B ^ (_rotl(*(uint32_t *)(p+8),5) ^ *(uint32_t *)(p+12))) * PRIME;        
		p += 8*sizeof(uint16_t);
    }
    // Cases: 0,1,2,3,4,5,6,7,...,15
    if (wrdlen & 2*sizeof(uint32_t)) {
		hash32 = (hash32 ^ *(uint32_t*)(p+0)) * PRIME;
		hash32B = (hash32B ^ *(uint32_t*)(p+4)) * PRIME;
		p += 4*sizeof(uint16_t);
    }
    // Cases: 0,1,2,3,4,5,6,7
    if (wrdlen & sizeof(uint32_t)) {
		hash32 = (hash32 ^ *(uint16_t*)(p+0)) * PRIME;
		hash32B = (hash32B ^ *(uint16_t*)(p+2)) * PRIME;
		p += 2*sizeof(uint16_t);
    }
    if (wrdlen & sizeof(uint16_t)) {
        hash32 = (hash32 ^ *(uint16_t*)p) * PRIME;
        p += sizeof(uint16_t);
    }
    if (wrdlen & 1) 
        hash32 = (hash32 ^ *p) * PRIME;

    hash32 = (hash32 ^ _rotl(hash32B,5) ) * PRIME;
    return hash32 ^ (hash32 >> 16);
}

uint32_t FNV1A_Hash_Yoshimura(const char *str, SIZE_T wrdlen)
{
    const uint32_t PRIME = 709607;
    uint32_t hash32 = 2166136261;
    uint32_t hash32B = 2166136261;
    const char *p = str;
    uint32_t Loop_Counter;
    uint32_t Second_Line_Offset;

if (wrdlen >= 2*2*sizeof(uint32_t)) {
    Second_Line_Offset = wrdlen-((wrdlen>>4)+1)*(2*4); // ((wrdlen>>1)>>3)
    Loop_Counter = (wrdlen>>4);
    //if (wrdlen%16) Loop_Counter++;
    Loop_Counter++;
    for(; Loop_Counter; Loop_Counter--, p += 2*sizeof(uint32_t)) {
		// revision 1:
		//hash32 = (hash32 ^ (_rotl(*(uint32_t *)(p+0),5) ^ *(uint32_t *)(p+4))) * PRIME;        
		//hash32B = (hash32B ^ (_rotl(*(uint32_t *)(p+0+Second_Line_Offset),5) ^ *(uint32_t *)(p+4+Second_Line_Offset))) * PRIME;        
		// revision 2:
		hash32 = (hash32 ^ (_rotl(*(uint32_t *)(p+0),5) ^ *(uint32_t *)(p+0+Second_Line_Offset))) * PRIME;        
		hash32B = (hash32B ^ (_rotl(*(uint32_t *)(p+4+Second_Line_Offset),5) ^ *(uint32_t *)(p+4))) * PRIME;        
    }
} else {
    // Cases: 0,1,2,3,4,5,6,7,...,15
    if (wrdlen & 2*sizeof(uint32_t)) {
		hash32 = (hash32 ^ *(uint32_t*)(p+0)) * PRIME;
		hash32B = (hash32B ^ *(uint32_t*)(p+4)) * PRIME;
		p += 4*sizeof(uint16_t);
    }
    // Cases: 0,1,2,3,4,5,6,7
    if (wrdlen & sizeof(uint32_t)) {
		hash32 = (hash32 ^ *(uint16_t*)(p+0)) * PRIME;
		hash32B = (hash32B ^ *(uint16_t*)(p+2)) * PRIME;
		p += 2*sizeof(uint16_t);
    }
    if (wrdlen & sizeof(uint16_t)) {
        hash32 = (hash32 ^ *(uint16_t*)p) * PRIME;
        p += sizeof(uint16_t);
    }
    if (wrdlen & 1) 
        hash32 = (hash32 ^ *p) * PRIME;
}
    hash32 = (hash32 ^ _rotl(hash32B,5) ) * PRIME;
    return hash32 ^ (hash32 >> 16);
}

