/*-----------------------------------------------------------------
    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;

#define BYTE_SIZEOF_ELEMENT (sizeof(unsigned int))
#define BIT_SIZEOF_ELEMENT (BYTE_SIZEOF_ELEMENT*8)

/* genernal note about a bitvectors:
   bit positions must start from 0 */
/*-----------------------------------------------------------------*/
/* newBitVect - returns a new bitvector of size                    */
/*-----------------------------------------------------------------*/
bitVect *
newBitVect (int size)
{
  bitVect *bvp;

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

  bvp->size = size;
  bvp->allocSize = (size+BIT_SIZEOF_ELEMENT-1) / BIT_SIZEOF_ELEMENT;
  bvp->vect = Safe_calloc (BYTE_SIZEOF_ELEMENT, bvp->allocSize);
  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 allocSize;

  if (!bvp)
    return newBitVect (size);

  allocSize = (size+BIT_SIZEOF_ELEMENT-1) / BIT_SIZEOF_ELEMENT;

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

  bvp->vect = Clear_realloc (bvp->vect, bvp->allocSize*BYTE_SIZEOF_ELEMENT, allocSize*BYTE_SIZEOF_ELEMENT);
  bvp->size = size;
  bvp->allocSize = allocSize;

  return bvp;
}

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

  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 */

  index = pos / BIT_SIZEOF_ELEMENT;
  bitofs = pos % BIT_SIZEOF_ELEMENT;
  bvp->vect[index] |= 1u << bitofs;
  return bvp;
}

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

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

  if (bvp->size <= pos)
    return;

  index = pos / BIT_SIZEOF_ELEMENT;
  bitofs = pos % BIT_SIZEOF_ELEMENT;
  bvp->vect[index] &= ~(1u << bitofs);
}

/*-----------------------------------------------------------------*/
/* bitVectBitValue - returns value value at bit position           */
/*-----------------------------------------------------------------*/
int 
bitVectBitValue (const bitVect *bvp, int pos)
{
  unsigned int index;
  unsigned int bitofs;

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

  index = pos / BIT_SIZEOF_ELEMENT;
  bitofs = pos % BIT_SIZEOF_ELEMENT;

  if (bvp->size <= pos)
    return 0;


  return (bvp->vect[index] >> bitofs) & 1;
}

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

  /* 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->size < bvp2->size)
    bvp1 = bitVectResize (bvp1, bvp2->size);
  else if (bvp2->size < bvp1->size)
    bvp2 = bitVectResize (bvp2, bvp1->size);

  newBvp = newBitVect (bvp1->size);
  elements = bvp1->allocSize;

  pn = newBvp->vect; 
  p1 = bvp1->vect;
  p2 = bvp2->vect;

  while (elements--)
    {
      *pn++ = *p1++ | *p2++;
    }

  return newBvp;
}

/*-----------------------------------------------------------------*/
/* bitVectInplaceUnion - unions two bitvectors                     */
/*-----------------------------------------------------------------*/
bitVect *
bitVectInplaceUnion (bitVect * bvp1, bitVect * bvp2)
{
  unsigned int *p1, *p2;
  int elements;

  /* 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 bvp1;

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

  elements = bvp1->allocSize;

  p1 = bvp1->vect;
  p2 = bvp2->vect;

  while (elements--)
    {
      *p1 |= *p2;
      p1++; p2++;
    }

  return bvp1;
}


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

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

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

  newBvp = newBitVect (bvp1->size);
  elements = bvp1->allocSize;

  pn = newBvp->vect; 
  p1 = bvp1->vect;
  p2 = bvp2->vect;

  while (elements--)
    {
      *pn++ = *p1++ & *p2++;
    }

  return newBvp;
}

/*-----------------------------------------------------------------*/
/* bitVectInplaceIntersect - intersect  two bitvectors             */
/*-----------------------------------------------------------------*/
bitVect *
bitVectInplaceIntersect (bitVect * bvp1, bitVect * bvp2)
{
  unsigned int *p1, *p2;
  int elements;

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

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

  elements = bvp1->allocSize;

  p1 = bvp1->vect;
  p2 = bvp2->vect;

  while (elements--)
    {
      *p1 &= *p2;
      p1++; p2++;
    }

  return bvp1;
}

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

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

  elements = min (bvp1->allocSize, bvp2->allocSize);

  p1 = bvp1->vect;
  p2 = bvp2->vect;

  while (elements--)
    {
      if (*p1 & *p2)
        return 1;
      p1++; p2++;
    }

  return 0;
}

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

  if (!bvp1)
    return bvp1;

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

  elements = bvp1->allocSize;
  p1 = bvp1->vect;
  p2 = bvp2->vect;

  while (elements--)
    {
      *p1 = *p1 & ~ *p2;
      p2++; p1++;
    }

  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->allocSize; 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;
  int elements;
  
  if (!bvp1 || !bvp2)
    return 0;

  if (bvp1 == bvp2)
    return 1;

  /* elements common to both allocations must match */
  elements = min (bvp1->allocSize, bvp2->allocSize);
  for (i = 0; i < elements; i++)
    if (bvp1->vect[i] != bvp2->vect[i])
      return 0;

  /* any extra elements allocated must be 0 */
  if (bvp1->allocSize > elements)
    {
      for (i = elements; i < bvp1->allocSize; i++)
        if (bvp1->vect[i])
          return 0;
    }
  if (bvp2->allocSize > elements)
    {
      for (i = elements; i < bvp2->allocSize; i++)
        if (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->allocSize; i++)
    newBvp->vect[i] = bvp->vect[i];

  return newBvp;
}

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

  if (!bvp)
    return 0;

  p1 = bvp->vect;
  elements = bvp->allocSize;
  
  while (elements--)
    {
      unsigned int word = *p1++;
      while (word)
        {
          count++;
          word &= word-1;
        }
    }

  return count;
}

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

  if (!bvp)
    return -1;

  for (i = 0, index = 0; i < bvp->size; i+=BIT_SIZEOF_ELEMENT, index++)
    if (bvp->vect[index])
      break;

  for (; i < bvp->size; i++)
    if (bitVectBitValue (bvp, i))
      return i;

  return -1;
}

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

  if (!bvp)
    return;

  for (i = 0; i < bvp->allocSize; 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 allocSize = %d\n", bvp->size, bvp->allocSize);
  fprintf (of, "Bits on { ");
  for (i = 0; i < bvp->size; i++)
    {
      if (bitVectBitValue (bvp, i))
	fprintf (of, "(%d) ", i);
    }
  fprintf (of, "}\n");
}

