#include <stdio.h>

#define U64 unsigned long long
#define C64(x) x##ULL 

U64 flipDiagA1H8(U64 x) {
   U64 t;
   const U64 k1 = C64(0x5500550055005500);
   const U64 k2 = C64(0x3333000033330000);
   const U64 k4 = C64(0x0f0f0f0f00000000);
   t  = k4 & (x ^ (x << 28));
   x ^=       t ^ (t >> 28) ;
   t  = k2 & (x ^ (x << 14));
   x ^=       t ^ (t >> 14) ;
   t  = k1 & (x ^ (x <<  7));
   x ^=       t ^ (t >>  7) ;
   return x;
}

U64 flipVertical(U64 x) {
    return  ( (x << 56)                           ) |
            ( (x << 40) & C64(0x00ff000000000000) ) |
            ( (x << 24) & C64(0x0000ff0000000000) ) |
            ( (x <<  8) & C64(0x000000ff00000000) ) |
            ( (x >>  8) & C64(0x00000000ff000000) ) |
            ( (x >> 24) & C64(0x0000000000ff0000) ) |
            ( (x >> 40) & C64(0x000000000000ff00) ) |
            ( (x >> 56) );
}

U64 hashword(U64 x)
{
   // Made up of four parts
   // Flip along antidiagonal
   U64 x1 = flipDiagA1H8(x);

   // Flip vertically
   x1 = flipVertical(x1);

   // XOR
   x1 = x ^ x1;

   // Add one

   x1++;

   return x1;
}

int main()
{
   U64 input = 0;
   U64 output = 0;
   int collisions = 0;
   
   printf("Small values:\n");
   for (input = 0; input < 16; input++) {
      printf("Input:  %016llx\n", input);
      output = hashword(input);
      printf("Output: %016llx\n\n", output);
   }

   printf("Large values:\n");
   for (input = 0xFFFFFFFFFF; input < 0xFFFFFFFFFF + 16; input++) {
      printf("Input:  %016llx\n", input);
      output = hashword(input);
      printf("Output: %016llx\n\n", output);
   }

   return 0;
}