/* ,file-id archive://[lord]/380/vu/./bitset.c/1998-05-18
*/
/*	Copyright (C) 1997 Tom Lord
 * 
 * This program is provided to you under the terms of the Liberty Software
 * License.  You are NOT permitted to redistribute, modify, or use it
 * except in very specific ways described by that license.
 *
 * This software comes with NO WARRANTY.
 * 
 * You should have received a copy of the Liberty Software License
 * along with this software; see the file =LICENSE.  If not, write to
 * the Tom Lord, 1810 Francisco St. #2, Berkeley CA, 94703, USA.  
 */





#include "xmalloc.h"
#include "bitset.h"



bitset
bitset_xalloc (int size)
{
  bitset b;
  b = (bitset) xmalloc (sizeof_bitset (size));
  bitset_clear (size, b);
  return b;
}

bitset
bitset_dup (int size, bitset a)
{
  bitset cs;

  cs = bitset_xalloc (size);
  memcpy (cs, a, sizeof_bitset (size));
  return cs;
}

int
bitset_is_equal (int size, bitset a, bitset b)
{
  int x;
  subset s;

  x = bitset_numb_subsets(size);

  while (x--)
    {
      if (a[x] != b[x])
	return 0;
    }

  return 1;
}


int
bitset_is_subset (int size, bitset a, bitset b)
{
  int x;
  x = bitset_numb_subsets(size) - 1;
  while (x-- && ((a[x] & b[x]) == a[x]))
    ;
  return x == -1;
}


int
bitset_empty (int size, bitset a)
{
  int x;

  while (x-- && !a[x])
    ;

  return x == -1;
}

void
bitset_clear (int size, bitset b)
{
  memset ((char *)b, 0, sizeof_bitset(size));
}

void
bitset_fill (int size, bitset b)
{
  int x;

  x = bitset_numb_subsets (size);

  while (x--)
    *b++ = ~(subset)0;
}


void
bitset_complement (int size, bitset b)
{
  int x;

  x = bitset_numb_subsets (size);

  while (x--)
    {
      *b = ~*b;
      ++b;
    }
}


void
bitset_assign (int size, bitset a, bitset b)
{
  int x;
  x = bitset_numb_subsets (size);

  while (x--)
    {
      a[x] = b[x];
    }
}


void
bitset_union (int size, bitset a, bitset b)
{
  int x;
  x = bitset_numb_subsets (size);

  while (x--)
    {
      a[x] |= b[x];
    }
}


void
bitset_intersection (int size, bitset a, bitset b)
{
  int x;
  x = bitset_numb_subsets (size);

  while (x--)
    {
      a[x] &= b[x];
    }
}

void
bitset_difference (int size, bitset a, bitset b)
{
  int x;
  x = bitset_numb_subsets (size);

  while (x--)
    {
      a[x] &= ~ b[x];
    }
}

void
bitset_revdifference (int size, bitset a, bitset b)
{
  int x;
  x = bitset_numb_subsets (size);

  while (x--)
    {
      a[x] = ~a[x] & b[x];
    }
}

void
bitset_xor (int size, bitset a, bitset b)
{
  int x;
  x = bitset_numb_subsets (size);

  while (x--)
    {
      a[x] ^= b[x];
    }
}

/* 
 * (define l (let loop ((x 0) (l '())) (if (eq? x 256) l (loop (+ x 1) (cons x l)))))
 * (define lb (map (lambda (n) (number->string n 2)) l))
 * (define lc (map string->list lb))
 * (define ln (map (lambda (l) (map (lambda (c) (if (eq? c #\1) 1 0)) l)) lc))
 * (define lt (map (lambda (l) (apply + l)) ln))
 */

static int char_pops[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
};

int
bitset_population (int size, bitset a)
{
  int total;
  int x;
  unsigned char * bs;
  unsigned char s;

  total = 0;
  x = sizeof (subset) * bitset_numb_subsets (size);
  bs = (unsigned char *)a;
  while (x--)
    {
      total += char_pops [*bs];
      ++bs;
    }
  return total;
}     

int byte_ffs[256] =
{
  -1, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
  4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
  5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
  4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
  6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
  4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
  5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
  4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
  7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
  4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
  5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
  4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
  6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
  4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
  5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
  4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0
};

int
subset_ffs (subset a)
{
  int offset;
  int x;

  if (!a)
    return -1;

  offset = 0;
  x = sizeof (a);
  while (x--)
    {
      int q;
      q = byte_ffs [a & 0xff];
      if (q >= 0)
	return q + offset;
      offset += 8;
      a >>= 8;
    }

  return panic ("not reached");
}

int
bitset_ffs (int size, bitset b)
{
  int offset;
  int x;
  int bound;
  
  offset = 0;
  x = 0;
  bound = bitset_numb_subsets(size);

  while (x < bound)
    {
      int fs;

      fs = subset_ffs (b[x]);

      if (fs >= 0)
	return offset + fs;

      offset += bits_per_subset;
      ++x;
    }
  return -1;
}


unsigned long
bitset_hash (int size, bitset b)
{
  int x;
  unsigned long answer;

  /* This is just made up and should be checked out. */

  x = sizeof (subset) * bitset_numb_subsets (size);
  answer = 0;
  while (x--)
    {
      subset s;
      s = b[x];
      if (s & 0xff000000)
	answer = b[x] + (answer << 3) + (answer >> (8 * sizeof (answer) - 3));
      else if (s & 0xff0000)
	answer = b[x] + (answer << 9) + (answer >> (8 * sizeof (answer) - 9));
      else if (s & 0xff00)
	answer = b[x] + (answer << 9) + (answer >> (8 * sizeof (answer) - 9));
      else if (s & 0xff)
	answer = b[x] + (answer << 13) + (answer >> (8 * sizeof (answer) - 13));
    }
  return answer;
}
