///////////////////////////////////////////////////////////////////////////////////
/// OpenGL Mathematics (glm.g-truc.net)
///
/// Copyright (c) 2005 - 2015 G-Truc Creation (www.g-truc.net)
/// Permission is hereby granted, free of charge, to any person obtaining a copy
/// of this software and associated documentation files (the "Software"), to deal
/// in the Software without restriction, including without limitation the rights
/// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
/// copies of the Software, and to permit persons to whom the Software is
/// furnished to do so, subject to the following conditions:
/// 
/// The above copyright notice and this permission notice shall be included in
/// all copies or substantial portions of the Software.
/// 
/// Restrictions:
///		By making use of the Software for military purposes, you choose to make
///		a Bunny unhappy.
/// 
/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
/// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
/// THE SOFTWARE.
///
/// @file test/core/func_integer_bit_count.cpp
/// @date 2011-01-15 / 2014-11-25
/// @author Christophe Riccio
///////////////////////////////////////////////////////////////////////////////////

// This has the programs for computing the number of 1-bits
// in a word, or byte, etc.
// Max line length is 57, to fit in hacker.book.
#include <stdio.h>
#include <stdlib.h>     //To define "exit", req'd by XLC.
#include <ctime>

unsigned rotatel(unsigned x, int n)
{
	if ((unsigned)n > 63) {printf("rotatel, n out of range.\n"); exit(1);}
	return (x << n) | (x >> (32 - n));
}

int pop0(unsigned x)
{
	x = (x & 0x55555555) + ((x >> 1) & 0x55555555);
	x = (x & 0x33333333) + ((x >> 2) & 0x33333333);
	x = (x & 0x0F0F0F0F) + ((x >> 4) & 0x0F0F0F0F);
	x = (x & 0x00FF00FF) + ((x >> 8) & 0x00FF00FF);
	x = (x & 0x0000FFFF) + ((x >>16) & 0x0000FFFF);
	return x;
}

int pop1(unsigned x)
{
	x = x - ((x >> 1) & 0x55555555);
	x = (x & 0x33333333) + ((x >> 2) & 0x33333333);
	x = (x + (x >> 4)) & 0x0F0F0F0F;
	x = x + (x >> 8);
	x = x + (x >> 16);
	return x & 0x0000003F;
}
/* Note: an alternative to the last three executable lines above is:
   return x*0x01010101 >> 24;
if your machine has a fast multiplier (suggested by Jari Kirma). */

int pop2(unsigned x)
{
	unsigned n;

	n = (x >> 1) & 033333333333;       // Count bits in
	x = x - n;                         // each 3-bit
	n = (n >> 1) & 033333333333;       // field.
	x = x - n;
	x = (x + (x >> 3)) & 030707070707; // 6-bit sums.
	return x%63;                       // Add 6-bit sums.
}

/* An alternative to the "return" statement above is:
   return ((x * 0404040404) >> 26) +  // Add 6-bit sums.
           (x >> 30);
which runs faster on most machines (suggested by Norbert Juffa). */

int pop3(unsigned x)
{
	unsigned n;

	n = (x >> 1) & 0x77777777;        // Count bits in
	x = x - n;                        // each 4-bit
	n = (n >> 1) & 0x77777777;        // field.
	x = x - n;
	n = (n >> 1) & 0x77777777;
	x = x - n;
	x = (x + (x >> 4)) & 0x0F0F0F0F;  // Get byte sums.
	x = x*0x01010101;                 // Add the bytes.
	return x >> 24;
}

int pop4(unsigned x)
{
	int n;

	n = 0;
	while (x != 0) {
		n = n + 1;
		x = x & (x - 1);
	}
	return n;
}

int pop5(unsigned x)
{
	int i, sum;

	// Rotate and sum method        // Shift right & subtract

	sum = x;                     // sum = x;
	for (i = 1; i <= 31; i++) {  // while (x != 0) {
		x = rotatel(x, 1);        //    x = x >> 1;
		sum = sum + x;            //    sum = sum - x;
	}                            // }
	return -sum;                 // return sum;
}

int pop5a(unsigned x)
{
	int sum;

	// Shift right & subtract

	sum = x;
	while (x != 0) {
		x = x >> 1;
		sum = sum - x;
	}
	return sum;
}

int pop6(unsigned x)
{ // Table lookup.
	static char table[256] = {
		0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
		1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
		1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
		2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,

		1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
		2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
		2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
		3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,

		1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
		2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
		2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
		3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,

		2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
		3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
		3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
		4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8};

	return table[x         & 0xFF] +
			table[(x >>  8) & 0xFF] +
			table[(x >> 16) & 0xFF] +
			table[(x >> 24)];
}

// The following works only for 8-bit quantities.
int pop7(unsigned x)
{
	x = x*0x08040201;    // Make 4 copies.
	x = x >> 3;          // So next step hits proper bits.
	x = x & 0x11111111;  // Every 4th bit.
	x = x*0x11111111;    // Sum the digits (each 0 or 1).
	x = x >> 28;         // Position the result.
	return x;
}

// The following works only for 7-bit quantities.
int pop8(unsigned x)
{
	x = x*0x02040810;    // Make 4 copies, left-adjusted.
	x = x & 0x11111111;  // Every 4th bit.
	x = x*0x11111111;    // Sum the digits (each 0 or 1).
	x = x >> 28;         // Position the result.
	return x;
}

// The following works only for 15-bit quantities.
int pop9(unsigned x)
{
	unsigned long long y;
	y = x * 0x0002000400080010ULL;
	y = y & 0x1111111111111111ULL;
	y = y * 0x1111111111111111ULL;
	y = y >> 60;
	return y;
}

int errors;
void error(int x, int y)
{
	errors = errors + 1;
	printf("Error for x = %08x, got %08x\n", x, y);
}

int main()
{
#	ifdef NDEBUG

	int i, n;
	static unsigned test[] = {0,0, 1,1, 2,1, 3,2, 4,1, 5,2, 6,2, 7,3,
		8,1, 9,2, 10,2, 11,3, 12,2, 13,3, 14,3, 15,4, 16,1, 17,2,
		0x3F,6, 0x40,1, 0x41,2, 0x7f,7, 0x80,1, 0x81,2, 0xfe,7, 0xff,8,
		0x4000,1, 0x4001,2, 0x7000,3, 0x7fff,15,
		0x55555555,16, 0xAAAAAAAA, 16, 0xFF000000,8, 0xC0C0C0C0,8,
		0x0FFFFFF0,24, 0x80000000,1, 0xFFFFFFFF,32};

	std::size_t const Count = 1000000;

	n = sizeof(test)/4;

	std::clock_t TimestampBeg = 0;
	std::clock_t TimestampEnd = 0;

	TimestampBeg = std::clock();
	for (std::size_t k = 0; k < Count; ++k)
	for (i = 0; i < n; i += 2) {
		if (pop0(test[i]) != test[i+1]) error(test[i], pop0(test[i]));}
	TimestampEnd = std::clock();

	printf("pop0: %ld clocks\n", TimestampEnd - TimestampBeg);

	TimestampBeg = std::clock();
	for (std::size_t k = 0; k < Count; ++k)
	for (i = 0; i < n; i += 2) {
		if (pop1(test[i]) != test[i+1]) error(test[i], pop1(test[i]));}
	TimestampEnd = std::clock();

	printf("pop1: %ld clocks\n", TimestampEnd - TimestampBeg);

	TimestampBeg = std::clock();
	for (std::size_t k = 0; k < Count; ++k)
	for (i = 0; i < n; i += 2) {
		if (pop2(test[i]) != test[i+1]) error(test[i], pop2(test[i]));}
	TimestampEnd = std::clock();

	printf("pop2: %ld clocks\n", TimestampEnd - TimestampBeg);

	TimestampBeg = std::clock();
	for (std::size_t k = 0; k < Count; ++k)
	for (i = 0; i < n; i += 2) {
		if (pop3(test[i]) != test[i+1]) error(test[i], pop3(test[i]));}
	TimestampEnd = std::clock();

	printf("pop3: %ld clocks\n", TimestampEnd - TimestampBeg);

	TimestampBeg = std::clock();
	for (std::size_t k = 0; k < Count; ++k)
	for (i = 0; i < n; i += 2) {
		if (pop4(test[i]) != test[i+1]) error(test[i], pop4(test[i]));}
	TimestampEnd = std::clock();

	printf("pop4: %ld clocks\n", TimestampEnd - TimestampBeg);

	TimestampBeg = std::clock();
	for (std::size_t k = 0; k < Count; ++k)
	for (i = 0; i < n; i += 2) {
		if (pop5(test[i]) != test[i+1]) error(test[i], pop5(test[i]));}
	TimestampEnd = std::clock();

	printf("pop5: %ld clocks\n", TimestampEnd - TimestampBeg);

	TimestampBeg = std::clock();
	for (std::size_t k = 0; k < Count; ++k)
	for (i = 0; i < n; i += 2) {
		if (pop5a(test[i]) != test[i+1]) error(test[i], pop5a(test[i]));}
	TimestampEnd = std::clock();

	printf("pop5a: %ld clocks\n", TimestampEnd - TimestampBeg);

	TimestampBeg = std::clock();
	for (std::size_t k = 0; k < Count; ++k)
	for (i = 0; i < n; i += 2) {
		if (pop6(test[i]) != test[i+1]) error(test[i], pop6(test[i]));}
	TimestampEnd = std::clock();

	printf("pop6: %ld clocks\n", TimestampEnd - TimestampBeg);

	TimestampBeg = std::clock();
	for (std::size_t k = 0; k < Count; ++k)
	for (i = 0; i < n; i += 2) {
		if ((test[i] & 0xffffff00) == 0)
		if (pop7(test[i]) != test[i+1]) error(test[i], pop7(test[i]));}
	TimestampEnd = std::clock();

	printf("pop7: %ld clocks\n", TimestampEnd - TimestampBeg);

	TimestampBeg = std::clock();
	for (std::size_t k = 0; k < Count; ++k)
	for (i = 0; i < n; i += 2) {
		if ((test[i] & 0xffffff80) == 0)
		if (pop8(test[i]) != test[i+1]) error(test[i], pop8(test[i]));}
	TimestampEnd = std::clock();

	printf("pop8: %ld clocks\n", TimestampEnd - TimestampBeg);

	TimestampBeg = std::clock();
	for (std::size_t k = 0; k < Count; ++k)
	for (i = 0; i < n; i += 2) {
		if ((test[i] & 0xffff8000) == 0)
		if (pop9(test[i]) != test[i+1]) error(test[i], pop9(test[i]));}
	TimestampEnd = std::clock();

	printf("pop9: %ld clocks\n", TimestampEnd - TimestampBeg);

	if (errors == 0)
		printf("Passed all %d cases.\n", sizeof(test)/8);

#	endif//NDEBUG
}
