#include <stdio.h>	/* printf, etc */
#include <string.h>	/* strlcpy, etc */

char *ultobstr(unsigned long u, int bitlen, char *str, size_t z)
{ /* convert value to binary string */
  int l = 0;
  char buf[z];

  strlcpy(buf, "", z);
  do {
    strlcpy(str, (u & 1UL) ? "1" : "0", z);
    strlcat(str, buf, z);
    strlcpy(buf, str, z);
    u >>= 1;
  } while ((bitlen < 0) ? u : (++l < bitlen));
  return str;
}

#define MASK_00 (1L<<0)
#define MASK_01 (1L<<1)
#define MASK_02 (1L<<2)
#define MASK_03 (1L<<3)
#define MASK_04 (1L<<4)
#define MASK_05 (1L<<5)
#define MASK_06 (1L<<6)
#define MASK_07 (1L<<7)

int main(void)
{
  static int bitlen = /*32*/8;
  int i;
  char buf[256];
  long mask;
  unsigned long umask;

  printf("\n/* bit mask - よく使うビット演算の紹介 */\n\n");

  mask = 0L;
  printf("zero mask:\t%s\n", ultobstr(mask, bitlen, buf, sizeof(buf)));

  mask = ~0L;
  printf("full mask:\t%s\n", ultobstr(mask, bitlen, buf, sizeof(buf)));

  mask = MASK_00 | MASK_02 | MASK_04 | MASK_06;
  printf("even mask:\t%s\n", ultobstr(mask, bitlen, buf, sizeof(buf)));

  printf("check mask_04:\t%s\n", (mask & MASK_04) ? "ON" : "OFF" );
  printf("check mask_05:\t%s\n", (mask & MASK_05) ? "ON" : "OFF" );

  mask |= MASK_05;
  printf("add mask_05:\t%s\n", ultobstr(mask, bitlen, buf, sizeof(buf)));
  printf("check mask_05:\t%s\n", (mask & MASK_05) ? "ON" : "OFF" );

  mask &= ~MASK_04;
  printf("del mask_04:\t%s\n", ultobstr(mask, bitlen, buf, sizeof(buf)));
  printf("check mask_04:\t%s\n", (mask & MASK_04) ? "ON" : "OFF" );

  mask |= MASK_03 | MASK_07;
  printf("add mask_03,07:\t%s\n", ultobstr(mask, bitlen, buf, sizeof(buf)));

  mask &= ~(MASK_02 | MASK_06);
  printf("del mask_02,06:\t%s\n", ultobstr(mask, bitlen, buf, sizeof(buf)));

  printf("\n/* bit shift and sign - 右シフトと符合 */\n\n");

  printf("(signed)mask<<24:\t%s\n", ultobstr(mask<<24, 32, buf, sizeof(buf)));
  printf("(signed)mask<<24>>24:\t%s\n", ultobstr(mask<<24>>24, 32, buf, sizeof(buf)));

  printf("(unsigned)mask<<24:\t%s\n", ultobstr((unsigned)mask<<24, 32, buf, sizeof(buf)));
  printf("(unsigned)mask<<24>>24:\t%s\n", ultobstr((unsigned)mask<<24>>24, 32, buf, sizeof(buf)));

  /*
   * References
   * [1] Henry S. Warren, Jr., ``Hacker's Delight,'' Addison Wesley, 2003.
   */
  printf("\n/* bit operator techniques - 知ってると得するビット演算 */\n\n");

  printf("\t/* m & (m-1) - 最右1ビットをオフにする\n"
	 "\t\t2^nなら零になる */\n");
  umask = mask;
  printf("orig mask:\t%s\n", ultobstr(umask, bitlen, buf, sizeof(buf)));
  for (i=0; i<5; i++) {
    umask = umask & (umask - 1); /* rightmost nonzero bit to zero */
    printf("m = m & (m-1):\t%s\n", ultobstr(umask, bitlen, buf, sizeof(buf)));
  }
  printf("\n");

  printf("\t/* m & (m+1) - 最右0ビットと連続する1ビットを0にする\n"
	 "\t\t2^n-1なら零になる */\n");
  for (i=0; i<2; i++) {
    switch (i) {
    case 0: umask = MASK_00 | MASK_01 | MASK_02; break;
    case 1: umask = MASK_00 | MASK_01 | MASK_03; break;
    }
    printf("orig mask:\t%s\n", ultobstr(umask, bitlen, buf, sizeof(buf)));
    umask = umask & (umask + 1); /* rightmost zero, trailing nonzero to zero */
    printf("m & (m+1):\t%s\n", ultobstr(umask, bitlen, buf, sizeof(buf)));
  }
  printf("\n");

  printf("\t/* m & (-m) - 最右1ビットを取り出す */\n");
  for (i=0; i<3; i++) {
    switch (i) {
    case 0: umask = MASK_03 | MASK_06 | MASK_07; break;
    case 1: umask = MASK_05 | MASK_06 | MASK_07; break;
    case 2: umask = 0UL; break;
    }
    printf("orig mask:\t%s\n", ultobstr(umask, bitlen, buf, sizeof(buf)));
    umask = umask & -umask; /* rightmost nonzero bit extraction */
    printf("m & (-m):\t%s\n", ultobstr(umask, bitlen, buf, sizeof(buf)));
  }
  printf("\n");

  printf("\t/* ~m & (m+1) - 最右0ビットを取り出す */\n");
  for (i=0; i<3; i++) {
    switch (i) {
    case 0: umask = MASK_03 | MASK_06 | MASK_07; break;
    case 1: umask = MASK_05 | MASK_06 | MASK_07; break;
    case 2: umask = 0UL; break;
    }
    umask = ~umask;
    printf("orig mask:\t%s\n", ultobstr(umask, bitlen, buf, sizeof(buf)));
    umask = ~umask & (umask + 1); /* rightmost zero bit extraction */
    printf("~m & (m+1):\t%s\n", ultobstr(umask, bitlen, buf, sizeof(buf)));
  }
  printf("\n");

  printf("\t/* ~m & (m-1) - 末尾まで続く0を1ビット列として取り出す */\n");
  for (i=0; i<3; i++) {
    switch (i) {
    case 0: umask = MASK_03 | MASK_06 | MASK_07; break;
    case 1: umask = MASK_05 | MASK_06 | MASK_07; break;
    case 2: umask = 0UL; break;
    }
    printf("orig mask:\t%s\n", ultobstr(umask, bitlen, buf, sizeof(buf)));
    umask = ~umask & (umask - 1); /* trailing zero to mask */
    printf("~m & (m-1):\t%s\n", ultobstr(umask, bitlen, buf, sizeof(buf)));
  }
  printf("\n");

  printf("\t/* m ^ (m-1) - 最右1ビットと末尾まで続く0を1ビット列として取り出す */\n");
  for (i=0; i<3; i++) {
    switch (i) {
    case 0: umask = MASK_03 | MASK_06 | MASK_07; break;
    case 1: umask = MASK_05 | MASK_06 | MASK_07; break;
    case 2: umask = 0UL; break;
    }
    printf("orig mask:\t%s\n", ultobstr(umask, bitlen, buf, sizeof(buf)));
    umask = umask ^ (umask - 1); /* rightmost nonzero, trailing zero to mask */
    printf("m ^ (m-1):\t%s\n", ultobstr(umask, bitlen, buf, sizeof(buf)));
  }
  printf("\n");

  printf("\t/* m | (m-1) - 最右1ビットを最右ビットまで満たす */\n");
  for (i=0; i<3; i++) {
    switch (i) {
    case 0: umask = MASK_03 | MASK_06 | MASK_07; break;
    case 1: umask = MASK_05 | MASK_06 | MASK_07; break;
    case 2: umask = 0UL; break;
    }
    printf("orig mask:\t%s\n", ultobstr(umask, bitlen, buf, sizeof(buf)));
    umask = umask | (umask - 1); /* rightmost nonzero fills to rightmost bit */
    printf("m | (m-1):\t%s\n", ultobstr(umask, bitlen, buf, sizeof(buf)));
  }
  printf("\n");

  printf("\t/* m | (m+1) - 最右0ビットを1とする */\n");
  for (i=0; i<3; i++) {
    switch (i) {
    case 0: umask = MASK_03 | MASK_06 | MASK_07; break;
    case 1: umask = MASK_05 | MASK_06 | MASK_07; break;
    case 2: umask = 0UL; break;
    }
    umask = ~umask;
    printf("orig mask:\t%s\n", ultobstr(umask, bitlen, buf, sizeof(buf)));
    umask = umask | (umask + 1); /* rightmost zero bit to nonzero */
    printf("m | (m+1):\t%s\n", ultobstr(umask, bitlen, buf, sizeof(buf)));
  }

  return 0;
}
