// Endianess
// http://bits.stephan-brumme.com

// references:
// unknown

// code:
bool isLittleEndian()
{
  // 16 bit value, represented as 0x0100 on Intel, and 0x0001 else
  short pattern = 0x0001;
  // access first byte, will be 1 on Intel, and 0 else
  return *(char*) &pattern == 0x01;
}

// restrictions:
// - none

// explanation:
// The memory layout of numbers depends on the CPU and has to be considered when designing a bit twiddler.
//
// Intel's x86 chips (and of cause compatible chips from AMD etc.) rely on "little endian":
// Numeric values consisting of multiple bytes have increasing numeric significance with increasing memory addresses.
//
// The opposite, called big endian, is true for Motorola chips, PowerPC and various other designs.
// A few CPUs can even switch at runtime like ARM or newer PowerPC or x64.
//
// The programming language C itself usually takes care of the endianness but whenever direct memory access is
// requires by the software, it might be important to know the endianness of the system.
//
// Here is the idea:
// A known number consisting of more than one byte is stored. The single bytes must not repeat.
// For simplicity, the number 0x0001 and data type short is chosen (line 4).
// Little endian stores it as 0x01, 0x00 whereas big endian stores 0x00, 0x01.
// Then the short's memory address is accessed via a char pointer, which refers to the first byte (line 6).
// If it points at 0x01, then we have a little endian architecture.
//
// This information can be gathered at compile time by smart compilers and thus often comes "for free" because the
// code is reduced to a simple assignment of true or false.

// validation:
#include <stdio.h>
#include <time.h>

int main(int argc, char* argv[])
{
  if (isLittleEndian())
    printf("Little Endian.\n");
  else
    printf("Big Endian.\n");

  const unsigned int repeatTest = 10*1000*1000*1000;

  printf("performance test ... ");
  clock_t start = clock();

  unsigned int x = 0;
  while (x < repeatTest)
  {
    // "volatile" is required to prevent optimizer from completely eliminating code
    volatile bool result;
    // unroll loop to reduce overhead
    result = isLittleEndian(); x++;
    result = isLittleEndian(); x++;
    result = isLittleEndian(); x++;
    result = isLittleEndian(); x++;
    result = isLittleEndian(); x++;
    result = isLittleEndian(); x++;
    result = isLittleEndian(); x++;
    result = isLittleEndian(); x++;
    result = isLittleEndian(); x++;
    result = isLittleEndian(); x++;
    result = isLittleEndian(); x++;
    result = isLittleEndian(); x++;
    result = isLittleEndian(); x++;
    result = isLittleEndian(); x++;
    result = isLittleEndian(); x++;
    result = isLittleEndian(); x++;
  }

  float seconds = (clock() - start) / float(CLOCKS_PER_SEC);
  printf("%.3f seconds, approx. %.3f million numbers per second.\n", seconds, (repeatTest/seconds)/1000000);

  return 0;
}
