/*-----------------------------------------------------------------
    SDCCbitv.c - contains support routines for bitvectors

    Written By - Sandeep Dutta . sandeep.dutta@usa.net (1998)

    This program is free software; you can redistribute it and/or modify it
    under the terms of the GNU General Public License as published by the
    Free Software Foundation; either version 2, or (at your option) any
    later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

    In other words, you are welcome to use, share and improve this program.
    You are forbidden to forbid anyone else to use, share and improve
    what you give them.   Help stamp out software-hoarding!
-------------------------------------------------------------------------*/

#include "common.h"

#include "newalloc.h"

int bitVectDefault = 1024;

/* genernal note about a bitvectors:
   bit vectors are stored from left to right i.e.
   bit position 0 is the MS bit of the first byte
   this also means that bit positions must start from 0 */
/*-----------------------------------------------------------------*/
/* newBitVect - returns a new bitvector of size                    */
/*-----------------------------------------------------------------*/
bitVect *
newBitVect (int size)
{
  bitVect *bvp;
  int byteSize;

  bvp = Safe_calloc (1, sizeof (bitVect));

  bvp->size = size;
  bvp->bSize = byteSize = (size / 8) + 1;
  bvp->vect = Safe_calloc (1, byteSize);
  return bvp;
}

/*-----------------------------------------------------------------*/
/* freeBitVect - frees the memory used by the bitVector            */
/*-----------------------------------------------------------------*/
void
freeBitVect (bitVect * bvp)
{
  if (!bvp)
    return;

  Safe_free (bvp->vect);
  Safe_free (bvp);
}

/*-----------------------------------------------------------------*/
/* bitVectResize - changes the size of a bit vector                */
/*-----------------------------------------------------------------*/
bitVect *
bitVectResize (bitVect * bvp, int size)
{
  int bSize = (size / 8) + 1;

  if (!bvp)
    return newBitVect (size);

  /* if we already have enough space */
  if (bvp->bSize >= bSize)
    {
      if (size > bvp->size)
	bvp->size = size;
      return bvp;
    }

  bvp->vect = Clear_realloc (bvp->vect, bvp->bSize, bSize);
  bvp->size = size;
  bvp->bSize = bSize;

  return bvp;
}

/*-----------------------------------------------------------------*/
/* bitVectSetBit - sets a given bit in the bit vector              */
/*-----------------------------------------------------------------*/
bitVect *
bitVectSetBit (bitVect * bvp, int pos)
{
  int byteSize;
  int offset;

  assert (pos>=0);
  /* if set is null then allocate it */
  if (!bvp)
    bvp = newBitVect (bitVectDefault);	/* allocate for twice the size */

  if (bvp->size <= pos)
    bvp = bitVectResize (bvp, pos + 2);		/* conservatively resize */

  byteSize = pos / 8;
  offset = pos % 8;
  bvp->vect[byteSize] |= (((unsigned char) 1) << (7 - offset));
  return bvp;
}

/*-----------------------------------------------------------------*/
/* bitVectUnSetBit - unsets the value of a bit in a bitvector      */
/*-----------------------------------------------------------------*/
void 
bitVectUnSetBit (const bitVect *bvp, int pos)
{
  int byteSize;
  int offset;

  assert (pos>=0);
  if (!bvp)
    return;

  byteSize = pos / 8;
  if (bvp->bSize <= byteSize)
    return;

  offset = pos % 8;

  bvp->vect[byteSize] &= ~(((unsigned char) 1) << (7 - offset));
}

/*-----------------------------------------------------------------*/
/* bitVectBitValue - returns value value at bit position           */
/*-----------------------------------------------------------------*/
int 
bitVectBitValue (const bitVect *bvp, int pos)
{
  int byteSize;
  int offset;

  assert (pos>=0);
  if (!bvp)
    return 0;

  byteSize = pos / 8;

  if (bvp->bSize <= byteSize)
    return 0;

  offset = pos % 8;

  return ((bvp->vect[byteSize] >> (7 - offset)) & ((unsigned char) 1));

}

/*-----------------------------------------------------------------*/
/* bitVectUnion - unions two bitvectors                            */
/*-----------------------------------------------------------------*/
bitVect *
bitVectUnion (bitVect * bvp1, bitVect * bvp2)
{
  int i;
  bitVect *newBvp;
  unsigned int *pn, *p1, *p2;
  int nbits;

  /* if both null */
  if (!bvp1 && !bvp2)
    return NULL;

  /* if one of them null then return the other */
  if (!bvp1 && bvp2)
    return bitVectCopy (bvp2);

  if (bvp1 && !bvp2)
    return bitVectCopy (bvp1);

  /* if they are not the same size */
  /* make them the same size */
  if (bvp1->bSize < bvp2->bSize)
    bvp1 = bitVectResize (bvp1, bvp2->size);
  else if (bvp2->bSize < bvp1->bSize)
    bvp2 = bitVectResize (bvp2, bvp1->size);

  newBvp = newBitVect (bvp1->size);
  nbits = bvp1->bSize;
  i = 0;

  pn = (unsigned int *)newBvp->vect; 
  p1 = (unsigned int *)bvp1->vect;
  p2 = (unsigned int *)bvp2->vect;

  while ((nbits - i) >= sizeof(*pn))
    {
      *pn++ = *p1++ | *p2++;
      i += sizeof(*pn);
    }

  for (; i < nbits; i++)
    newBvp->vect[i] = bvp1->vect[i] | bvp2->vect[i];

  return newBvp;
}

/*-----------------------------------------------------------------*/
/* bitVectIntersect - intersect  two bitvectors                    */
/*-----------------------------------------------------------------*/
bitVect *
bitVectIntersect (bitVect * bvp1, bitVect * bvp2)
{
  int i;
  bitVect *newBvp;
  unsigned int *pn, *p1, *p2;
  int nbits;

  if (!bvp2 || !bvp1)
    return NULL;

  /* if they are not the same size */
  /* make them the same size */
  if (bvp1->bSize < bvp2->bSize)
    bvp1 = bitVectResize (bvp1, bvp2->bSize);
  else if (bvp2->size < bvp1->size)
    bvp2 = bitVectResize (bvp2, bvp1->size);

  newBvp = newBitVect (bvp1->size);
  nbits = bvp1->bSize;
  i = 0;

  pn = (unsigned int *)newBvp->vect; 
  p1 = (unsigned int *)bvp1->vect;
  p2 = (unsigned int *)bvp2->vect;

  while ((nbits - i) >= sizeof(*pn))
    {
      *pn++ = *p1++ & *p2++;
      i += sizeof(*pn);
    }

  for (; i < nbits; i++)
    newBvp->vect[i] = bvp1->vect[i] & bvp2->vect[i];

  return newBvp;
}

/*-----------------------------------------------------------------*/
/* bitVectBitsInCommon - special case of intersection determines   */
/*                       if the vectors have any common bits set   */
/*-----------------------------------------------------------------*/
int 
bitVectBitsInCommon (const bitVect * bvp1, const bitVect * bvp2)
{
  int i;
  int nbits;
  unsigned int *p1, *p2;

  if (!bvp1 || !bvp2)
    return 0;

  nbits = min (bvp1->bSize, bvp2->bSize);
  i = 0;

  p1 = (unsigned int *)bvp1->vect;
  p2 = (unsigned int *)bvp2->vect;

  while ((nbits-i) >= sizeof(*p1))
    {
      if (*p1 & *p2)
        return 1;
      p1++; p2++;
      i += sizeof(*p1);
    }

  for (; i < nbits; i++)
    if (bvp1->vect[i] & bvp2->vect[i])
      return 1;

  return 0;
}

/*-----------------------------------------------------------------*/
/* bitVectCplAnd - complement the second & and it with the first   */
/*-----------------------------------------------------------------*/
bitVect *
bitVectCplAnd (bitVect * bvp1, bitVect * bvp2)
{
  int i;
  unsigned int *p1, *p2;
  int nbits;

  if (!bvp2)
    return bvp1;

  if (!bvp1)
    return bvp1;

  /* if they are not the same size */
  /* make them the same size */
  if (bvp1->bSize < bvp2->bSize)
    bvp1 = bitVectResize (bvp1, bvp2->bSize);
  else if (bvp2->size < bvp1->size)
    bvp2 = bitVectResize (bvp2, bvp1->size);

  nbits = bvp1->bSize;
  i = 0;

  p1 = (unsigned int *)bvp1->vect;
  p2 = (unsigned int *)bvp2->vect;

  while ((nbits - i) >= sizeof(*p1))
    {
      *p1 = *p1 & (~*p2);
      p2++; p1++;
      i += sizeof(*p1);
    }

  for (; i < nbits; i++)
    bvp1->vect[i] = bvp1->vect[i] & (~bvp2->vect[i]);

  return bvp1;
}

/*-----------------------------------------------------------------*/
/* bitVectIsZero - bit vector has all bits turned off              */
/*-----------------------------------------------------------------*/
int 
bitVectIsZero (const bitVect * bvp)
{
  int i;

  if (!bvp)
    return 1;

  for (i = 0; i < bvp->bSize; i++)
    if (bvp->vect[i] != 0)
      return 0;

  return 1;
}

/*-----------------------------------------------------------------*/
/* bitVectsEqual - returns 1 if the two bit vectors are equal      */
/*-----------------------------------------------------------------*/
int 
bitVectEqual (bitVect * bvp1, bitVect * bvp2)
{
  int i;

  if (!bvp1 || !bvp2)
    return 0;

  if (bvp1 == bvp2)
    return 1;

  if (bvp1->bSize != bvp2->bSize)
    return 0;

  for (i = 0; i < bvp1->bSize; i++)
    if (bvp1->vect[i] != bvp2->vect[i])
      return 0;

  return 1;
}

/*-----------------------------------------------------------------*/
/* bitVectCopy - creates a bitvector from another bit Vector       */
/*-----------------------------------------------------------------*/
bitVect *
bitVectCopy (const bitVect * bvp)
{
  bitVect *newBvp;
  int i;

  if (!bvp)
    return NULL;

  newBvp = newBitVect (bvp->size);
  for (i = 0; i < bvp->bSize; i++)
    newBvp->vect[i] = bvp->vect[i];

  return newBvp;
}

/*-----------------------------------------------------------------*/
/* bitVectnBitsOn - returns the number of bits that are on         */
/*-----------------------------------------------------------------*/
int 
bitVectnBitsOn (const bitVect * bvp)
{
  int i, j;
  unsigned char byte;
  int count = 0;
  unsigned int *p1;

  /* The bit vector is highest to lowest.  Interesting. */
  const unsigned int mask[] = {
    0, 128, 128+64, 128+64+32, 128+64+32+16,
    128+64+32+16+8, 128+64+32+16+8+4, 128+64+32+16+8+4+2
  };

  if (!bvp)
    return 0;

  /* j is the number of bytes in the bitvect */
  j = (bvp->size+7) / 8;

  /* Fix up the highest bits in the top byte so that we can iterate over
     all of them. */
  if (bvp->size%8 != 0)
    {
      bvp->vect[j-1] &= mask[bvp->size&7];
    }

  /* Take care of things in machine word chunks if possible.  As we
     are only counting bits it does not matter which order they are
     counted in.
  */
  i = 0;
  p1 = (unsigned int *)bvp->vect;

  while ((j-i) >= sizeof(*p1))
    {
      unsigned int word = *p1++;
      while (word)
        {
          count++;
          word &= word-1;
        }
      i += sizeof(*p1);
    }

  /* Take care of the rest of the bitvect. */
  for (; i < j; i++)
    {
      byte = bvp->vect[i];
      while (byte)
        {
          count++;
          byte &= byte-1;
        }
    }
  return count;
}

/*-----------------------------------------------------------------*/
/* bitVectFirstBit - returns the key for the first bit that is on  */
/*-----------------------------------------------------------------*/
int 
bitVectFirstBit (const bitVect * bvp)
{
  int i;

  if (!bvp)
    return -1;
  for (i = 0; i < bvp->size; i++)
    if (bitVectBitValue (bvp, i))
      return i;

  return -1;
}

/*-----------------------------------------------------------------*/
/* bitVectIsZero - clear all bits                                  */
/*-----------------------------------------------------------------*/
void
bitVectClear (bitVect *bvp)
{
  int i;

  if (!bvp)
    return;

  for (i = 0; i < bvp->bSize; i++)
    bvp->vect[i] = 0;
}

/*-----------------------------------------------------------------*/
/* bitVectDebugOn - prints bits that are on                        */
/*-----------------------------------------------------------------*/
void 
bitVectDebugOn (bitVect * bvp, FILE * of)
{
  int i;

  if (of == NULL)
    of = stdout;
  if (!bvp)
    return;

  fprintf (of, "bitvector Size = %d bSize = %d\n", bvp->size, bvp->bSize);
  fprintf (of, "Bits on { ");
  for (i = 0; i < bvp->size; i++)
    {
      if (bitVectBitValue (bvp, i))
	fprintf (of, "(%d) ", i);
    }
  fprintf (of, "}\n");
}

