/*
   file phasing-in.c
   (C) 2003 Yann GUIDON <whygee@f-cpu.org>
   version Sat Dec 27 09:21:56 CET 2003

   Bitstream insertion/extraction with phasing-in
   codes, used by the Range Reduction and 3R algorithms.

   Modifications :
   - this file replaces bitstream.c
   - the "high" parameter is added
   - "nb_bits" is replaced by "range",
*/

#include <stdio.h>   /* for printf */

#include "bitstream.c"

/* The bit insertion routine */
void pi_put_bits(unsigned int data,   /* to be encoded */
                 unsigned int range,  /* number of bits */
                 unsigned int high) { /* maximal value of data + 1 */
  unsigned int t, nb_bits, range2;
  unsigned int pi_trig; /* phasing-in variables */
    signed int pi_var;

  printf("Encoding data=%d with high=%d and range=%d",
     data, high, range);

  if (range < 1) {
    printf(" [range < 1]\n");
    return;
  }

  range2 = range - 1;

  /* pi_trig = B = 2^k - b = 2^(k+1) - i */
  pi_trig = (1U << range) - high;
  pi_var = data - pi_trig; /* i - B */

  /* create the phasing-in code: */
  if (pi_var < 0) { /* short code */
    printf(" [-] ");
    nb_bits = range2;
    t = data;
  }
  else { /* long code */
    printf(" [+] ");
    nb_bits = range;
/* Here, the LSB is put in the MSB (rotated) because otherwise
 the decoder would hang when asking for the additional bit !! */
    t = ((pi_var >> 1) + pi_trig)
      | ((pi_var & 1) << range2);
  }

  /* this be inlined later */
  put_bits(nb_bits, t);
}


/* The bit extraction routine */
unsigned int pi_get_bits(
    unsigned int range,  /* number of bits */
    unsigned int high) { /* maximal value of data + 1 */

  unsigned int result;
  unsigned int pi_trig;  /* phasing-in variables */
    signed int pi_var;

  printf("Decoding with high=%d and range=%d, ", high, range);

  if (range < 1) {
    printf("[ range<1 -> result=0 ]\n");
    return 0; /* shortcut */
  }

  result = get_bits(range-1);

  /* pi_trig = B = 2^k - b = 2^(k+1) - i */
  pi_trig = (1U << range) - high;
  pi_var = result - pi_trig; /* i - B */

  if (pi_var < 0) { /* short code */
    printf(" [-]  ");
  }
  else { /* long code */
    printf(" [+] ");
    result = (pi_var << 1) + pi_trig + get_bits(1);
  }

  printf(" result=%u\n", result);

  return result;
}

