text: //-----------------------------------------------------------------------------
  // MurmurHash3 was written by Austin Appleby, and is placed in the public
  // domain. The author hereby disclaims copyright to this source code.
  
  // Note - The x86 and x64 versions do _not_ produce the same results, as the
  // algorithms are optimized for their respective platforms. You can still
  // compile and run any of them on any platform, but your performance with the
  // non-native version will be less than optimal.
  
  // Platform-specific functions and macros
  
  // Microsoft Visual Studio
  
  #if defined(_MSC_VER)
  
  #define FORCE_INLINE __forceinline
  
  #define RotL32(x, y) _rotl(x, y)
  
  #define BIG_CONSTANT(x) (x)
  
  // Other compilers
  
  #else  // defined(_MSC_VER)
  
  #define FORCE_INLINE inline __attribute__((always_inline))
  
  inline u32 _rotl32(u32 x, i8 r) {
  	return (x << r) | (x >> (32 - r));
  }
  
  #define RotL32(x, y) _rotl32(x, y)
  
  #define BIG_CONSTANT(x) (x##LLU)
  
  #endif	// !defined(_MSC_VER)
  
  //-----------------------------------------------------------------------------
  // Block read - if your platform needs to do endian-swapping or can only
  // handle aligned reads, do the conversion here
  
  FORCE_INLINE u32 getblock32(const u32* p, i32 i) noexcept {
  	return p[i];
  }
  
  //-----------------------------------------------------------------------------
  // Finalization mix - force all bits of a hash block to avalanche
  
  FORCE_INLINE u32 fmix32(u32 h) noexcept {
  	h ^= h >> 16;
  	h *= 0x85ebca6b;
  	h ^= h >> 13;
  	h *= 0xc2b2ae35;
  	h ^= h >> 16;
  
  	return h;
  }
  
  //-----------------------------------------------------------------------------
  // objsize: 0x0-0x15f: 351
  
  u32 MurmurHash3_x86_32(const void* key, i32 len, u32 seed) noexcept {
  	const u8* data	  = (const u8*) key;
  	const i32 nblocks = len / 4;
  
  	u32 h1 = seed;
  
  	const u32 c1 = 0xcc9e2d51;
  	const u32 c2 = 0x1b873593;
  
  	//----------
  	// body
  
  	const u32* blocks = (const u32*) (data + nblocks * 4);
  
  	for (i32 i = -nblocks; i; i++) {
  		u32 k1 = getblock32(blocks, i);
  
  		k1 *= c1;
  		k1 = RotL32(k1, 15);
  		k1 *= c2;
  
  		h1 ^= k1;
  		h1 = RotL32(h1, 13);
  		h1 = h1 * 5 + 0xe6546b64;
  	}
  
  	//----------
  	// tail
  
  	const u8* tail = (const u8*) (data + nblocks * 4);
  
  	u32 k1 = 0;
  
  	switch (len & 3) {
  		case 3: k1 ^= tail[2] << 16;
  		case 2: k1 ^= tail[1] << 8;
  		case 1:
  			k1 ^= tail[0];
  			k1 *= c1;
  			k1 = RotL32(k1, 15);
  			k1 *= c2;
  			h1 ^= k1;
  	};
  
  	//----------
  	// finalization
  
  	h1 ^= len;
  
  	h1 = fmix32(h1);
  
  	return h1;
  }
  