/*
 * Copyright (C) 2008 PathScale, LLC.  All Rights Reserved
 */

/*

  Copyright (C) 2000, 2001 Silicon Graphics, Inc.  All Rights Reserved.

   Path64 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.

   Path64 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 Path64; see the file COPYING.  If not, write to the Free
   Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
   02110-1301, USA.

   Special thanks goes to SGI for their continued support to open source

*/


/* ====================================================================
 * ====================================================================
 *
 * Module: bitset.c
 *
 * Revision history:
 *  05-03-93 - Original Version
 *
 * Description:
 *
 *      Bitset implementation.
 *
 * ====================================================================
 * ====================================================================
 */

#ifdef _KEEP_RCS_ID
static const char source_file[] = __FILE__;
#endif

#include "defs.h"
#include "mempool.h"
#include "errors.h"
#include "bitset.h"

/* A designated bad memory pool to support assertions that the sets
 * shouldn't have to grow:
 */
static MEM_POOL bad_pool_struct;
static MEM_POOL *bad_pool = &bad_pool_struct;

/* ====================================================================
 *
 *  bs_Malloc
 *
 *  Return a new BS*
 *
 *      length  is the number of words to allocate for members
 *      pool    is a pool in which to allocate it
 *
 *
 * ====================================================================
 */

static BS*
bs_Malloc(
  size_t    length,
  MEM_POOL *pool
)
{
    BS *new_set;

    Is_True(pool != bad_pool,("Shouldn't be allocating."));

    new_set = (BS *) TYPE_MEM_POOL_ALLOC_N(BS_WORD,pool,length + 1);

    BS_word_count(new_set) = length;
    return new_set;
}

/* ====================================================================
 *
 *  bs_Realloc
 *
 *  Grows the allocation of a BS, potentially returning a new pointer
 *  to it.
 *
 *      set     is the set to grow
 *      length  is the new number of words to allocate for members
 *      pool    is a pool to use for this
 *
 * ====================================================================
 */

static BS*
bs_Realloc(
  BS       *set,
  size_t    length,
  MEM_POOL *pool
)
{
  BS    *new_set;
  BS_ELT i;
  BS_ELT old_length = BS_word_count(set);
  size_t new_length;

  Is_True(pool != bad_pool,("Shouldn't be allocating."));

  if (length <= old_length) return set;

  // extend length to be a power of 2
  for (new_length = 2; new_length < length; new_length <<= 1);
  length = new_length;

  new_set = (BS *)TYPE_MEM_POOL_REALLOC_N(BS_WORD, pool, set, old_length+1,
					  length+1);

  if (!MEM_POOL_Zeroed(pool))
    for ( i = old_length; i < length; ++i )
      BS_word(new_set,i) = bs_ZEROS;

  BS_word_count(new_set) = length;

  return new_set;
}

/* ====================================================================
 *
 *  BS_Create
 *
 *  See interface description
 *
 * ====================================================================
 */

extern BS*
BS_Create(
  BS_ELT    size,
  MEM_POOL *pool
)
{
  Is_True(size >= 0,("BS_Create called with negative size."));

  return bs_Malloc(bs_QBPW(size + (BITS_PER_BS_WORD - 1)),pool);
}

/* ====================================================================
 *
 *  BS_Size_Alloc_Size
 *
 *  See interface description
 *
 * ====================================================================
 */

extern size_t
BS_Size_Alloc_Size(
  BS_ELT size
)
{
  return (1 + bs_QBPW(size + (BITS_PER_BS_WORD - 1) )) * sizeof(BS_WORD);
}

/* ====================================================================
 *
 *  BS_Alloc_Size
 *
 *  See interface description
 *
 * ====================================================================
 */

extern size_t
BS_Alloc_Size(
  BS *set
)
{
  return (BS_word_count(set) + 1) * sizeof(BS_WORD);
}

/* ====================================================================
 *
 *  BS_ClearD
 *
 *  See interface description
 *
 * ====================================================================
 */

extern BS*
BS_ClearD(
  BS *set
)
{
  BS_ELT i;

  for ( i = 0; i < BS_word_count(set); ++i )
    BS_word(set,i) = bs_ZEROS;

  return set;
}

/* ====================================================================
 *
 *  BS_Create_Empty
 *
 *  See interface description
 *
 * ====================================================================
 */

extern BS*
BS_Create_Empty(
  BS_ELT    size,
  MEM_POOL *pool
)
{
  BS *set = BS_Create(size, pool);
  if (!MEM_POOL_Zeroed(pool))
    BS_ClearD(set);
  return set;
}

/* ====================================================================
 *
 *  BS_Resize
 *
 *  See interface description
 *
 * ====================================================================
 */

extern BS*
BS_ResizeD(
  BS*	    set,
  BS_ELT    new_size,
  MEM_POOL *pool
)
{
  BS_ELT new_words = bs_QBPW(new_size + (BITS_PER_BS_WORD - 1));

  if ( new_words > BS_word_count(set) ) {
    set = bs_Realloc(set,new_words,pool);
  }
  return set;
}


/* ====================================================================
 *
 *  BS_Range
 *
 *  See interface description
 *
 * ====================================================================
 */

extern BS*
BS_Range(
  BS_ELT    low,
  BS_ELT    high,
  MEM_POOL *pool
)
{
  return BS_RangeD(BS_Create(high + 1,pool),low,high,bad_pool);
}


/* ====================================================================
 *
 *  BS_RangeD
 *
 *  See interface description
 *
 * ====================================================================
 */

extern BS*
BS_RangeD(
  BS*       set,
  BS_ELT    low,
  BS_ELT    high,
  MEM_POOL *pool
)
{
  BS_ELT  first_w, last_w, first_b, last_b;
  BS_ELT  i;

  Is_True(low >= 0,
            ("BS_RangeD called with negative low element."));

  Is_True(high - low + 1 >= 0,
            ("BS_RangeD called with negative range size."));

  if ( low > high )
    return BS_ClearD(set);

  first_w = bs_QBPW(low);     /* index of first non 0 word */
  last_w  = bs_QBPW(high);    /* index of last non 0 word  */
  first_b = bs_QBPB(low);
  last_b  = bs_QBPB(high);

  /* Reallocate if necessary.
   */
  if ( last_w >= BS_word_count(set) )
    set = bs_Realloc(set,last_w + 1,pool);

  set = BS_ClearD(set);

  /* Set every byte above the first up to and including the last to be
   * all ones.  This complexity is required in order to make the
   * representation endian independent.  We win back with a fast
   * endian independent ffo for machines with load byte instructions.
   */

  /* Set every word above the first and below the last to be all ones.
   */
  for ( i = first_w + 1; i < last_w; ++i )
    BS_word(set,i) = bs_ONES;

  /* Set every byte in the first word above the first byte to be all
   * ones.
   */
  /* for ( i = first_b; i < bs_PBPB(first_w + 1); ++i ) shin 03-29-95 */
  for ( i = first_b; i < bs_PBytesPW(first_w + 1) && i <= last_b; ++i )
    BS_byte(set,i) = (BS_BYTE)bs_ONES;

  /* Set every byte in the last word up to and including the last byte
   * to be all ones.
   */
  /* for ( i = bs_PBPB(last_w); i <= last_b; ++i ) fchow 04-11-95 */
  if (first_w != last_w)
    for ( i = bs_PBytesPW(last_w); i <= last_b; ++i )
      BS_byte(set,i) = (BS_BYTE)bs_ONES;

  /* Fix up the first and last bytes.  Order is important!  Remember
   * that we have already set all the bits in the last byte and that
   * the first and last bytes might be the same.
   */
  BS_byte(set,first_b) = bs_ONES << bs_RBPB(low);
  BS_byte(set,last_b) &=
    bs_ONES >> ((BITS_PER_BS_WORD - 1) - bs_RBPB(high));

  return set;
}

/* ====================================================================
 *
 *  BS_Singleton
 *
 *  See interface description
 *
 * ====================================================================
 */

extern BS*
BS_Singleton(
  BS_ELT element,
  MEM_POOL *pool
)
{
  return BS_SingletonD(BS_Create(element + 1,pool),
                       element,
                       bad_pool);
}

/* ====================================================================
 *
 *  BS_SingletonD
 *
 *  See interface description
 *
 * ====================================================================
 */

extern BS*
BS_SingletonD(
  BS       *set,
  BS_ELT    element,
  MEM_POOL *pool
)
{
  BS_ELT word;

  Is_True(element >= 0,
            ("BS_SingletonD called with negative element."));

  word = bs_QBPW(element);

  /* Reallocate if necessary.
   */
  if ( word >= BS_word_count(set) )
    set = bs_Realloc(set,word + 1,pool);

  set = BS_ClearD(set);
  BS_byte(set,bs_QBPB(element)) = bs_ONE << bs_RBPB(element);

  return set;
}

/* ====================================================================
 *
 *  BS_Universe
 *
 *  See interface description
 *
 * ====================================================================
 */

extern BS*
BS_Universe(
  BS_ELT    size,
  MEM_POOL *pool
)
{
  return BS_UniverseD(BS_Create(size,pool),size,bad_pool);
}

/* ====================================================================
 *
 *  BS_UniverseD
 *
 *  See interface description
 *
 * ====================================================================
 */

extern BS*
BS_UniverseD(
  BS       *set,
  BS_ELT    size,
  MEM_POOL *pool
)
{
  return BS_RangeD(set,0,size - 1,bad_pool);
}

/* ====================================================================
 *
 *  BS_Copy
 *
 *  See interface description
 *
 * ====================================================================
 */

extern BS*
BS_Copy(
  BS       *set,
  MEM_POOL *pool
)
{
  size_t size;
  BS*    newset;
  BS_ELT i;

  size = BS_word_count(set);
  newset = bs_Malloc(size,pool);

  for ( i = 0; i < size; ++i )
    BS_word(newset,i) = BS_word(set,i);

  return newset;
}

/* ====================================================================
 *
 *  BS_CopyD
 *
 *  See interface description
 *
 * ====================================================================
 */

extern BS*
BS_CopyD(
  BS       *set1,
  BS       *set2,
  MEM_POOL *pool
)
{
  BS_ELT i;
  BS_ELT size1 = BS_word_count(set1);
  BS_ELT size2 = BS_word_count(set2);

  /* Reallocate if necessary.
   */
  if ( size1 < size2 )
    set1 = bs_Realloc(set1,size2,pool);
  else {
    /* Else zero out excess.
     */
    for ( i = size2; i < size1; ++i )
      BS_word(set1,i) = bs_ZEROS;
  }

  /* Copy in common part.
   */
  for ( i = 0; i < size2; ++i )
    BS_word(set1,i) = BS_word(set2,i);

  return set1;
}

/* Mapping from 8 bit unsigned integers to the index of the first one
 * bit:
 */
static const mUINT8 first_one [256] = {
  0, /*   0 */
  0, /*   1 */
  1, /*   2 */
  0, /*   3 */
  2, /*   4 */
  0, /*   5 */
  1, /*   6 */
  0, /*   7 */
  3, /*   8 */
  0, /*   9 */
  1, /*  10 */
  0, /*  11 */
  2, /*  12 */
  0, /*  13 */
  1, /*  14 */
  0, /*  15 */
  4, /*  16 */
  0, /*  17 */
  1, /*  18 */
  0, /*  19 */
  2, /*  20 */
  0, /*  21 */
  1, /*  22 */
  0, /*  23 */
  3, /*  24 */
  0, /*  25 */
  1, /*  26 */
  0, /*  27 */
  2, /*  28 */
  0, /*  29 */
  1, /*  30 */
  0, /*  31 */
  5, /*  32 */
  0, /*  33 */
  1, /*  34 */
  0, /*  35 */
  2, /*  36 */
  0, /*  37 */
  1, /*  38 */
  0, /*  39 */
  3, /*  40 */
  0, /*  41 */
  1, /*  42 */
  0, /*  43 */
  2, /*  44 */
  0, /*  45 */
  1, /*  46 */
  0, /*  47 */
  4, /*  48 */
  0, /*  49 */
  1, /*  50 */
  0, /*  51 */
  2, /*  52 */
  0, /*  53 */
  1, /*  54 */
  0, /*  55 */
  3, /*  56 */
  0, /*  57 */
  1, /*  58 */
  0, /*  59 */
  2, /*  60 */
  0, /*  61 */
  1, /*  62 */
  0, /*  63 */
  6, /*  64 */
  0, /*  65 */
  1, /*  66 */
  0, /*  67 */
  2, /*  68 */
  0, /*  69 */
  1, /*  70 */
  0, /*  71 */
  3, /*  72 */
  0, /*  73 */
  1, /*  74 */
  0, /*  75 */
  2, /*  76 */
  0, /*  77 */
  1, /*  78 */
  0, /*  79 */
  4, /*  80 */
  0, /*  81 */
  1, /*  82 */
  0, /*  83 */
  2, /*  84 */
  0, /*  85 */
  1, /*  86 */
  0, /*  87 */
  3, /*  88 */
  0, /*  89 */
  1, /*  90 */
  0, /*  91 */
  2, /*  92 */
  0, /*  93 */
  1, /*  94 */
  0, /*  95 */
  5, /*  96 */
  0, /*  97 */
  1, /*  98 */
  0, /*  99 */
  2, /* 100 */
  0, /* 101 */
  1, /* 102 */
  0, /* 103 */
  3, /* 104 */
  0, /* 105 */
  1, /* 106 */
  0, /* 107 */
  2, /* 108 */
  0, /* 109 */
  1, /* 110 */
  0, /* 111 */
  4, /* 112 */
  0, /* 113 */
  1, /* 114 */
  0, /* 115 */
  2, /* 116 */
  0, /* 117 */
  1, /* 118 */
  0, /* 119 */
  3, /* 120 */
  0, /* 121 */
  1, /* 122 */
  0, /* 123 */
  2, /* 124 */
  0, /* 125 */
  1, /* 126 */
  0, /* 127 */
  7, /* 128 */
  0, /* 129 */
  1, /* 130 */
  0, /* 131 */
  2, /* 132 */
  0, /* 133 */
  1, /* 134 */
  0, /* 135 */
  3, /* 136 */
  0, /* 137 */
  1, /* 138 */
  0, /* 139 */
  2, /* 140 */
  0, /* 141 */
  1, /* 142 */
  0, /* 143 */
  4, /* 144 */
  0, /* 145 */
  1, /* 146 */
  0, /* 147 */
  2, /* 148 */
  0, /* 149 */
  1, /* 150 */
  0, /* 151 */
  3, /* 152 */
  0, /* 153 */
  1, /* 154 */
  0, /* 155 */
  2, /* 156 */
  0, /* 157 */
  1, /* 158 */
  0, /* 159 */
  5, /* 160 */
  0, /* 161 */
  1, /* 162 */
  0, /* 163 */
  2, /* 164 */
  0, /* 165 */
  1, /* 166 */
  0, /* 167 */
  3, /* 168 */
  0, /* 169 */
  1, /* 170 */
  0, /* 171 */
  2, /* 172 */
  0, /* 173 */
  1, /* 174 */
  0, /* 175 */
  4, /* 176 */
  0, /* 177 */
  1, /* 178 */
  0, /* 179 */
  2, /* 180 */
  0, /* 181 */
  1, /* 182 */
  0, /* 183 */
  3, /* 184 */
  0, /* 185 */
  1, /* 186 */
  0, /* 187 */
  2, /* 188 */
  0, /* 189 */
  1, /* 190 */
  0, /* 191 */
  6, /* 192 */
  0, /* 193 */
  1, /* 194 */
  0, /* 195 */
  2, /* 196 */
  0, /* 197 */
  1, /* 198 */
  0, /* 199 */
  3, /* 200 */
  0, /* 201 */
  1, /* 202 */
  0, /* 203 */
  2, /* 204 */
  0, /* 205 */
  1, /* 206 */
  0, /* 207 */
  4, /* 208 */
  0, /* 209 */
  1, /* 210 */
  0, /* 211 */
  2, /* 212 */
  0, /* 213 */
  1, /* 214 */
  0, /* 215 */
  3, /* 216 */
  0, /* 217 */
  1, /* 218 */
  0, /* 219 */
  2, /* 220 */
  0, /* 221 */
  1, /* 222 */
  0, /* 223 */
  5, /* 224 */
  0, /* 225 */
  1, /* 226 */
  0, /* 227 */
  2, /* 228 */
  0, /* 229 */
  1, /* 230 */
  0, /* 231 */
  3, /* 232 */
  0, /* 233 */
  1, /* 234 */
  0, /* 235 */
  2, /* 236 */
  0, /* 237 */
  1, /* 238 */
  0, /* 239 */
  4, /* 240 */
  0, /* 241 */
  1, /* 242 */
  0, /* 243 */
  2, /* 244 */
  0, /* 245 */
  1, /* 246 */
  0, /* 247 */
  3, /* 248 */
  0, /* 249 */
  1, /* 250 */
  0, /* 251 */
  2, /* 252 */
  0, /* 253 */
  1, /* 254 */
  0, /* 255 */
};

/* ====================================================================
 *
 *  BS_Choose
 *
 *  See interface description
 *
 * ====================================================================
 */

extern BS_ELT
BS_Choose(
  const BS* set
)
{
  BS_ELT i, j;

  for ( i = 0; i < BS_word_count(set); ++i ) {
    if ( BS_word(set,i) != bs_ZEROS ) {
      BS_ELT first_byte = bs_PBytesPW(i);

      for ( j = 0; j < BYTES_PER_BS_WORD; ++j ) {
        BS_BYTE byte = BS_byte(set,j + first_byte);

        if ( byte != bs_ZEROS )
          return first_one[byte] + bs_PBPB(j + first_byte);
      }

      Is_True(FALSE,("Word not zero, but no byte found"));
    }
  }

  return BS_CHOOSE_FAILURE;
}

/* ====================================================================
 *
 *  BS_Choose_Range
 *
 *  See interface description
 *
 * ====================================================================
 */

extern BS_ELT
BS_Choose_Range(
  BS    *set,
  BS_ELT low,
  BS_ELT high
)
{
  BS_BYTE byte;
  BS_ELT  last_first_word_full_byte, i, j;
  BS_ELT  first_word, last_word;
  BS_ELT  first_byte, last_byte;
  BS_ELT  last_elt_in_set;

  Is_True(low >= 0,
          ("BS_Choose_Range called with negative low element."));
  Is_True(high - low >= -1,
          ("BS_Choose_Range called with negative range size."));

  /* Adjust high to be within the set:
   */
  last_elt_in_set = bs_PBPW(BS_word_count(set)) - 1;
  if ( high > last_elt_in_set )
    high = last_elt_in_set;

  /* The following check is needed becaause we won't catch it if low is in
   * the next byte from high.
   */
  if ( low > high )
    return BS_CHOOSE_FAILURE;

  first_byte = bs_QBPB(low);
  last_byte  = bs_QBPB(high);

  /* Check first byte.  Since it also might be the last byte, we have
   * to be careful to mask out both ends of the range.  After this we
   * can assume the first byte and last byte are different, which
   * simplifies things quite a bit.
   */
  byte = BS_byte(set,first_byte) & (bs_ONES << bs_RBPB(low));
  if ( first_byte == last_byte )
    byte &= bs_ONES >> ((BITS_PER_BS_WORD - 1) - bs_RBPB(high));

  if ( byte != bs_ZEROS )
    return first_one[byte] + bs_PBPB(first_byte);
  else if (first_byte == last_byte)
    return BS_CHOOSE_FAILURE;

  /* Chack remaining full bytes in the first word.  Since the last
   * byte might be in the first word, we have to avoid checking it as
   * a full byte.
   */
  first_word = bs_QBPW(low);
  last_first_word_full_byte = (first_word + 1) * sizeof(BS_WORD) - 1;

  if ( last_first_word_full_byte >= last_byte )
    last_first_word_full_byte = last_byte - 1;

  for ( i = first_byte + 1; i <= last_first_word_full_byte;  ++i ) {
    byte = BS_byte(set,i);

    if ( byte != bs_ZEROS )
      return first_one[byte] + bs_PBPB(i);
  }

  /* Now we are either full word aligned or the last byte was in the
   * first word.  Check full words above the first word and below the
   * last word.  Notice that this loop won't trip if the last byte was
   * in the first word (or the next one for that matter.)
   */
  last_word = bs_QBPW(high);

  for ( i = first_word + 1; i < last_word; ++i ) {
    if ( BS_word(set,i) != bs_ZEROS ) {
      /* Found the word, now locate the byte in that word.
       */
      for ( j = 0; j < sizeof(BS_WORD); ++j ) {
        byte = BS_byte(set, j + i * BYTES_PER_BS_WORD);

        if ( byte != 0 )
          return first_one[byte] + bs_PBPB(j) + bs_PBPW(i);
      }
    }
  }

  /* Check any unchecked full bytes in the last word.  This loop will
   * only trip if the last word is greater than the first word, since
   * otherwise the loop above leaves i above the first word, no matter
   * what.  In fact, at this point i is the index of the first
   * unchecked word.
   */
  for ( i *= sizeof(BS_WORD); i < last_byte; ++i ) {
    byte = BS_byte(set,i);

    if ( byte != 0 )
      return first_one[byte] + 8 * i;
  }

  /* Now we'll check the final byte, which we have assumed is partial.
   * Even if it is full, the following will work.
   */
  byte =   BS_byte(set,last_byte)
         & (bs_ONES >> ((BITS_PER_BS_WORD - 1) - bs_RBPB(high)));

  if ( byte != 0 )
    return first_one[byte] + bs_PBPB(last_byte);

  return BS_CHOOSE_FAILURE;
}


/* =======================================================================
 *
 *  BS_Choose_Next
 *
 *  See interface description.
 *
 * =======================================================================
 */

extern BS_ELT
BS_Choose_Next(
  const BS*    set,
  BS_ELT bound 
)
{
  BS_ELT  i, j, inx_first_byte, inx_first_byte_second_word, word_count;
  BS_BYTE byte;

  ++bound;  /* Now bound is inclusive. */

  if ( bound >= bs_PBPW(BS_word_count(set)) )
    return BS_CHOOSE_FAILURE;

  /* Search first byte with stuff below bound masked out:
   */
  inx_first_byte = bs_QBPB(bound);
  byte = BS_byte(set,inx_first_byte) & (bs_ONES << bs_RBPB(bound));
  if ( byte != bs_ZEROS )
    return first_one[byte] + bs_PBPB(inx_first_byte);

  /* Search remaining bytes in first word:
   */
  inx_first_byte_second_word = (bs_QBPW(bound) + 1) * sizeof(BS_WORD);

  for ( i = inx_first_byte + 1; i < inx_first_byte_second_word; ++i ) {
    byte = BS_byte(set,i);

    if ( byte != bs_ZEROS )
      return first_one[byte] + bs_PBPB(i);
  }

  /* search remaining words:
   */
  word_count = BS_word_count(set);

  for ( i = bs_QBPW(bound) + 1; i < word_count; ++i ) {
    if ( BS_word(set,i) != bs_ZEROS ) {
      BS_ELT first_byte = bs_PBytesPW(i);

      /* There's something in this word, search each byte for it:
       */
      for ( j = 0; j < BYTES_PER_BS_WORD; ++j ) {
        BS_BYTE byte = BS_byte(set,j + first_byte);

        if ( byte != bs_ZEROS )
          return first_one[byte] + bs_PBPB(j + first_byte);
      }

      Is_True(FALSE,("Word not zero, but no byte found"));
    }
  }
    
  return BS_CHOOSE_FAILURE;
}


/* ====================================================================
 *
 *  BS_Intersection_Choose
 *
 *  See interface description
 *
 * ====================================================================
 */

extern BS_ELT
BS_Intersection_Choose(
  BS* set1,
  BS* set2
)
{
  BS_ELT i, j;
  BS_ELT last_word;

  if ( BS_word_count(set1) < BS_word_count(set2) )
    last_word = BS_word_count(set1);
  else
    last_word = BS_word_count(set2);

  for ( i = 0; i < last_word; ++i ) {
    if ( (BS_word(set1,i) & BS_word(set2,i)) != bs_ZEROS ) {
      BS_ELT first_byte = bs_PBytesPW(i);

      for ( j = 0; j < BYTES_PER_BS_WORD; ++j ) {
        BS_BYTE byte =   BS_byte(set1,j + first_byte)
                       & BS_byte(set2,j + first_byte);

        if ( byte != bs_ZEROS )
          return first_one[byte] + bs_PBPB(j + first_byte);
      }

      Is_True(FALSE,("Word not zero, but no byte found"));
    }
  }

  return BS_CHOOSE_FAILURE;
}



/* =======================================================================
 *
 *  BS_Intersection_Choose_Next
 *
 *  See interface description.
 *
 * =======================================================================
 */

extern BS_ELT
BS_Intersection_Choose_Next(
  BS*    set1,
  BS*    set2,
  BS_ELT bound 
)
{
  BS_ELT  i, j, inx_first_byte, inx_first_byte_second_word, word_count;
  BS_BYTE byte;

  if ( BS_word_count(set1) < BS_word_count(set2) )
    word_count = BS_word_count(set1);
  else
    word_count = BS_word_count(set2);

  ++bound;  /* Now bound is inclusive. */

  if ( bound >= bs_PBPW(word_count) )
    return BS_CHOOSE_FAILURE;

  /* Search first byte with stuff below bound masked out:
   */
  inx_first_byte = bs_QBPB(bound);
  byte =   BS_byte(set1,inx_first_byte)
         & BS_byte(set2,inx_first_byte)
         & (bs_ONES << bs_RBPB(bound));
  if ( byte != bs_ZEROS )
    return first_one[byte] + bs_PBPB(inx_first_byte);

  /* Search remaining bytes in first word:
   */
  inx_first_byte_second_word = (bs_QBPW(bound) + 1) * sizeof(BS_WORD);

  for ( i = inx_first_byte + 1; i < inx_first_byte_second_word; ++i ) {
    byte =   BS_byte(set1,i)
           & BS_byte(set2,i);

    if ( byte != bs_ZEROS )
      return first_one[byte] + bs_PBPB(i);
  }

  /* search remaining words:
   */
  for ( i = bs_QBPW(bound) + 1; i < word_count; ++i ) {
    if ( (BS_word(set1,i) & BS_word(set2,i)) != bs_ZEROS ) {
      BS_ELT first_byte = bs_PBytesPW(i);

      /* There's something in this word, search each byte for it:
       */
      for ( j = 0; j < BYTES_PER_BS_WORD; ++j ) {
        BS_BYTE byte =   BS_byte(set1,j + first_byte)
                       & BS_byte(set2,j + first_byte);

        if ( byte != bs_ZEROS )
          return first_one[byte] + bs_PBPB(j + first_byte);
      }

      Is_True(FALSE,("Word not zero, but no byte found"));
    }
  }
    
  return BS_CHOOSE_FAILURE;
}



/* ====================================================================
 *
 *  BS_Difference
 *
 *  See interface description
 *
 * ====================================================================
 */

extern BS*
BS_Difference(
  BS       *set1,
  BS       *set2,
  MEM_POOL *pool
)
{
  BS    *set;
  BS_ELT i;
  BS_ELT size1   = BS_word_count(set1);
  BS_ELT size2   = BS_word_count(set2);
  BS_ELT minsize = Min(size1,size2);

  set = bs_Malloc(size1,pool);

  /* Common part: copy in the difference.
   */
  for ( i = 0; i < minsize; ++i )
    BS_word(set,i) = BS_word(set1,i) & ~BS_word(set2,i);

  /* Excess of set1 over set2: just copy it in.
   */
  for ( i = minsize; i < size1; ++i )
    BS_word(set,i) = BS_word(set1,i);

  return set;
}

/* ====================================================================
 *
 *  BS_DifferenceD
 *
 *  See interface description
 *
 * ====================================================================
 */

extern BS*
BS_DifferenceD(
  BS* set1,
  BS* set2
)
{
  BS_ELT i;
  BS_ELT minsize = Min(BS_word_count(set1),BS_word_count(set2));

  for ( i = 0; i < minsize; ++i )
    BS_word(set1,i) &= ~BS_word(set2,i);

  return set1;
}

/* ====================================================================
 *
 *  BS_Difference1
 *
 *  See interface description
 *
 * ====================================================================
 */

extern BS*
BS_Difference1(
  BS       *set,
  BS_ELT    x,
  MEM_POOL *pool
)
{
  return BS_Difference1D(BS_Copy(set,pool),x);
}

/* ====================================================================
 *
 *  BS_Difference1D
 *
 *  See interface description
 *
 * ====================================================================
 */

extern BS*
BS_Difference1D(
  BS    *set,
  BS_ELT x
)
{
  Is_True(x >= 0,
            ("BS_Difference1D called with negative element."));

  if ( bs_QBPW(x) < BS_word_count(set) )
    BS_byte(set,bs_QBPB(x)) &= ~(bs_ONE << bs_RBPB(x));

  return set;
}

/* ====================================================================
 *
 *  BS_Intersection
 *
 *  See interface description
 *
 * ====================================================================
 */

extern BS*
BS_Intersection(
  const BS *set1,
  const BS *set2,
  MEM_POOL *pool
)
{
  BS_ELT i;
  BS_ELT size;
  BS    *newset;

  if ( BS_word_count(set1) < BS_word_count(set2) )
    size = BS_word_count(set1);
  else
    size = BS_word_count(set2);

  newset = bs_Malloc(size,pool);

  for ( i = 0; i < size; ++i )
    BS_word(newset,i) = BS_word(set1,i) & BS_word(set2,i);

  return newset;
}

/* ====================================================================
 *
 *  BS_IntersectionD
 *
 *  See interface description
 *
 * ====================================================================
 */

extern BS*
BS_IntersectionD(
  BS* set1,
  BS* set2
)
{
  BS_ELT i;
  BS_ELT minsize;

  minsize = MIN( BS_word_count(set1), BS_word_count(set2) );

  /* Form intersection of common part:
   */
  for ( i = 0; i < minsize; ++i )
    BS_word(set1,i) &= BS_word(set2,i);

  /* Zero surplus words in set1:
   */
  for ( i = i; i < BS_word_count(set1); ++i )
    BS_word(set1,i) = bs_ZEROS;

  return set1;
}


/* ====================================================================
 *
 *  BS_IntersectionR
 *
 *  See interface description
 *
 * ====================================================================
 */

extern BS*
BS_IntersectionR(
  BS* result,
  const BS* set1,
  const BS* set2
)
{
  BS_ELT i;
  BS_ELT minsize;

  minsize = MIN( BS_word_count(set1), BS_word_count(set2) );

  /* Form intersection of common part:
   */
  for ( i = 0; i < minsize; ++i )
    BS_word(result,i) = BS_word(set1,i) & BS_word(set2,i);

  /* Zero surplus words in result:
   */
  for ( i = i; i < BS_word_count(result); ++i )
    BS_word(result,i) = bs_ZEROS;

  return result;
}


/* Count of bits in all the one byte numbers.  Used to count members.
 */
static unsigned const char bit_count[256] = {
  0, /*   0 */
  1, /*   1 */
  1, /*   2 */
  2, /*   3 */
  1, /*   4 */
  2, /*   5 */
  2, /*   6 */
  3, /*   7 */
  1, /*   8 */
  2, /*   9 */
  2, /*  10 */
  3, /*  11 */
  2, /*  12 */
  3, /*  13 */
  3, /*  14 */
  4, /*  15 */
  1, /*  16 */
  2, /*  17 */
  2, /*  18 */
  3, /*  19 */
  2, /*  20 */
  3, /*  21 */
  3, /*  22 */
  4, /*  23 */
  2, /*  24 */
  3, /*  25 */
  3, /*  26 */
  4, /*  27 */
  3, /*  28 */
  4, /*  29 */
  4, /*  30 */
  5, /*  31 */
  1, /*  32 */
  2, /*  33 */
  2, /*  34 */
  3, /*  35 */
  2, /*  36 */
  3, /*  37 */
  3, /*  38 */
  4, /*  39 */
  2, /*  40 */
  3, /*  41 */
  3, /*  42 */
  4, /*  43 */
  3, /*  44 */
  4, /*  45 */
  4, /*  46 */
  5, /*  47 */
  2, /*  48 */
  3, /*  49 */
  3, /*  50 */
  4, /*  51 */
  3, /*  52 */
  4, /*  53 */
  4, /*  54 */
  5, /*  55 */
  3, /*  56 */
  4, /*  57 */
  4, /*  58 */
  5, /*  59 */
  4, /*  60 */
  5, /*  61 */
  5, /*  62 */
  6, /*  63 */
  1, /*  64 */
  2, /*  65 */
  2, /*  66 */
  3, /*  67 */
  2, /*  68 */
  3, /*  69 */
  3, /*  70 */
  4, /*  71 */
  2, /*  72 */
  3, /*  73 */
  3, /*  74 */
  4, /*  75 */
  3, /*  76 */
  4, /*  77 */
  4, /*  78 */
  5, /*  79 */
  2, /*  80 */
  3, /*  81 */
  3, /*  82 */
  4, /*  83 */
  3, /*  84 */
  4, /*  85 */
  4, /*  86 */
  5, /*  87 */
  3, /*  88 */
  4, /*  89 */
  4, /*  90 */
  5, /*  91 */
  4, /*  92 */
  5, /*  93 */
  5, /*  94 */
  6, /*  95 */
  2, /*  96 */
  3, /*  97 */
  3, /*  98 */
  4, /*  99 */
  3, /* 100 */
  4, /* 101 */
  4, /* 102 */
  5, /* 103 */
  3, /* 104 */
  4, /* 105 */
  4, /* 106 */
  5, /* 107 */
  4, /* 108 */
  5, /* 109 */
  5, /* 110 */
  6, /* 111 */
  3, /* 112 */
  4, /* 113 */
  4, /* 114 */
  5, /* 115 */
  4, /* 116 */
  5, /* 117 */
  5, /* 118 */
  6, /* 119 */
  4, /* 120 */
  5, /* 121 */
  5, /* 122 */
  6, /* 123 */
  5, /* 124 */
  6, /* 125 */
  6, /* 126 */
  7, /* 127 */
  1, /* 128 */
  2, /* 129 */
  2, /* 130 */
  3, /* 131 */
  2, /* 132 */
  3, /* 133 */
  3, /* 134 */
  4, /* 135 */
  2, /* 136 */
  3, /* 137 */
  3, /* 138 */
  4, /* 139 */
  3, /* 140 */
  4, /* 141 */
  4, /* 142 */
  5, /* 143 */
  2, /* 144 */
  3, /* 145 */
  3, /* 146 */
  4, /* 147 */
  3, /* 148 */
  4, /* 149 */
  4, /* 150 */
  5, /* 151 */
  3, /* 152 */
  4, /* 153 */
  4, /* 154 */
  5, /* 155 */
  4, /* 156 */
  5, /* 157 */
  5, /* 158 */
  6, /* 159 */
  2, /* 160 */
  3, /* 161 */
  3, /* 162 */
  4, /* 163 */
  3, /* 164 */
  4, /* 165 */
  4, /* 166 */
  5, /* 167 */
  3, /* 168 */
  4, /* 169 */
  4, /* 170 */
  5, /* 171 */
  4, /* 172 */
  5, /* 173 */
  5, /* 174 */
  6, /* 175 */
  3, /* 176 */
  4, /* 177 */
  4, /* 178 */
  5, /* 179 */
  4, /* 180 */
  5, /* 181 */
  5, /* 182 */
  6, /* 183 */
  4, /* 184 */
  5, /* 185 */
  5, /* 186 */
  6, /* 187 */
  5, /* 188 */
  6, /* 189 */
  6, /* 190 */
  7, /* 191 */
  2, /* 192 */
  3, /* 193 */
  3, /* 194 */
  4, /* 195 */
  3, /* 196 */
  4, /* 197 */
  4, /* 198 */
  5, /* 199 */
  3, /* 200 */
  4, /* 201 */
  4, /* 202 */
  5, /* 203 */
  4, /* 204 */
  5, /* 205 */
  5, /* 206 */
  6, /* 207 */
  3, /* 208 */
  4, /* 209 */
  4, /* 210 */
  5, /* 211 */
  4, /* 212 */
  5, /* 213 */
  5, /* 214 */
  6, /* 215 */
  4, /* 216 */
  5, /* 217 */
  5, /* 218 */
  6, /* 219 */
  5, /* 220 */
  6, /* 221 */
  6, /* 222 */
  7, /* 223 */
  3, /* 224 */
  4, /* 225 */
  4, /* 226 */
  5, /* 227 */
  4, /* 228 */
  5, /* 229 */
  5, /* 230 */
  6, /* 231 */
  4, /* 232 */
  5, /* 233 */
  5, /* 234 */
  6, /* 235 */
  5, /* 236 */
  6, /* 237 */
  6, /* 238 */
  7, /* 239 */
  4, /* 240 */
  5, /* 241 */
  5, /* 242 */
  6, /* 243 */
  5, /* 244 */
  6, /* 245 */
  6, /* 246 */
  7, /* 247 */
  5, /* 248 */
  6, /* 249 */
  6, /* 250 */
  7, /* 251 */
  6, /* 252 */
  7, /* 253 */
  7, /* 254 */
  8  /* 255 */
};

/* ====================================================================
 *
 *  BS_Size
 *
 *  See interface description
 *
 * ====================================================================
 */

extern BS_ELT
BS_Size(
  BS* set
)
{
  /* Add up the population count of each byte in the set.  We get the
   * population counts from the table above.  Great for a machine with
   * effecient loadbyte instructions!
   */
  BS_ELT i;
  BS_ELT byte_count = BS_word_count(set) * sizeof(BS_WORD);
  size_t result = 0;

  for ( i = 0; i < byte_count; ++i )
    result += bit_count[BS_byte(set,i)];

  return result;
}

/* ====================================================================
 *
 *  BS_Union
 *
 *  See interface description
 *
 * ====================================================================
 */

extern BS*
BS_Union(
  BS       *set1,
  BS       *set2,
  MEM_POOL *pool
)
{
  BS    *set;
  BS_ELT i;
  BS_ELT size1 = BS_word_count(set1);
  BS_ELT size2 = BS_word_count(set2);

  if ( size1 < size2 ) {
    /* Normalize so set1 is at least as large:
     */
    BS    *tmps = set1;
    BS_ELT tmpe = size1;

    set1 = set2;
    set2 = tmps;
    size1 = size2;
    size2 = tmpe;
  }

  set = bs_Malloc(size1,pool);
  for ( i = 0; i < size2; ++i )
    BS_word(set,i) = BS_word(set1,i) | BS_word(set2,i);
  for ( i = size2; i < size1; ++i )
    BS_word(set,i) = BS_word(set1,i);

  return set;
}

/* ====================================================================
 *
 *  BS_UnionD
 *
 *  See interface description
 *
 * ====================================================================
 */

extern BS*
BS_UnionD(
  BS       *set1,
  BS       *set2,
  MEM_POOL *pool
)
{
  BS_ELT i;
  BS_ELT size1 = BS_word_count(set1);
  BS_ELT size2 = BS_word_count(set2);

  if ( size1 < size2 )
    set1 = bs_Realloc(set1,size2,pool);

  for ( i = 0; i < size2; ++i )
    BS_word(set1,i) |= BS_word(set2,i);

  return set1;
}

/* ====================================================================
 *
 *  BS_UnionR
 *
 *  See interface description
 *
 * ====================================================================
 */

extern BS*
BS_UnionR(
  BS       *result,
  BS       *set1,
  BS       *set2,
  MEM_POOL *pool
)
{
  BS_ELT i;
  BS_ELT size1 = BS_word_count(set1);
  BS_ELT size2 = BS_word_count(set2);
  BS_ELT maxsize = MAX( size1, size2 );
  BS_ELT rsize = BS_word_count(result);

  if ( rsize < maxsize )
    result = bs_Realloc(result,maxsize,pool);

  for ( i = 0; i < maxsize; ++i )
    BS_word(result,i) = BS_word(set1,i) | BS_word(set2,i);

  return result;
}

/* ====================================================================
 *
 *  BS_UnionD_Intersection
 *
 *  See interface description
 *
 * ====================================================================
 */

extern BS*
BS_UnionD_Intersection(
  BS       *set1,
  BS       *set2,
  BS       *set3,
  MEM_POOL *pool
)
{
  BS_ELT i;
  BS_ELT size1 = BS_word_count(set1);
  BS_ELT minsize = MIN( BS_word_count(set2), BS_word_count(set3) );

  if ( size1 < minsize )
    set1 = bs_Realloc(set1,minsize,pool);

  for ( i = 0; i < minsize; ++i )
    BS_word(set1,i) |= BS_word(set2,i) & BS_word(set3,i);

  return set1;
}

/* ====================================================================
 *
 *  BS_Union1
 *
 *  See interface description
 *
 * ====================================================================
 */

extern BS*
BS_Union1(
  BS       *set,
  BS_ELT    x,
  MEM_POOL *pool
)
{
  BS_ELT newsize;
  BS    *newset;

  if ( BS_word_count(set) > bs_QBPW(x) + 1 )
    newsize = bs_PBPW(BS_word_count(set));
  else
    newsize = x + 1;

  newset = BS_Create_Empty(newsize,pool);
  newset = BS_CopyD(newset,set,bad_pool);
  return BS_Union1D(newset,x,bad_pool);
}

/* ====================================================================
 *
 *  BS_Union1D
 *
 *  See interface description
 *
 * ====================================================================
 */

extern BS*
BS_Union1D(
  BS       *set,
  BS_ELT    x,
  MEM_POOL *pool
)
{
  BS_ELT minsize = bs_QBPW(x) + 1;

  Is_True(x >= 0,("BS_Union1D called with negative element."));

  if ( minsize > BS_word_count(set) )
    set = bs_Realloc(set,minsize,pool);

  BS_byte(set,bs_QBPB(x)) |= bs_ONE << bs_RBPB(x);

  return set;
}

/* ====================================================================
 *
 *  BS_2_1_Minus_3_Or_R
 *
 *  See interface description
 *
 * ====================================================================
 */

extern BS*
BS_2_1_Minus_3_Or_R(
  BS       *result,
  const BS *set1,
  const BS *set2,
  const BS *set3,
  MEM_POOL *pool
)
{
  BS_ELT i;
  BS_ELT rsize = BS_word_count(result);
  BS_ELT size3 = BS_word_count(set3);

  Is_True( BS_word_count(set1) == size3,
    ("BS_2_1_Minus_3_Or_R: set1 size (%d) < set3 size (%d)",
     (BS_ELT)BS_word_count(set1), size3) );
  Is_True( BS_word_count(set2) == size3,
    ("BS_2_1_Minus_3_Or_R: set2 size (%d) < set3 size (%d)",
     (BS_ELT)BS_word_count(set2), size3) );

  if ( rsize < size3 )
    result = bs_Realloc(result,size3,pool);

  for ( i = 0; i < size3; ++i )
    BS_word(result,i) = (~BS_word(set1,i) & BS_word(set2,i)) |
			  BS_word(set3,i);

  return result;
}

extern BS*
BS_3_2_Minus_1_Or_D(
  BS       *set1,
  const BS *set2,
  const BS *set3,
  MEM_POOL *pool
)
{
  BS_ELT i;
  BS_ELT size1 = BS_word_count(set1);
  BS_ELT size2 = BS_word_count(set2);
  BS_ELT size3 = BS_word_count(set3);

  Is_True( size2 == size3,
    ("BS_3_2_Minus_1_Or_D: set2 size (%d) != set3 size (%d)",
     size2, size3) );

  if ( size1 < size3 )
    set1 = bs_Realloc(set1,size3,pool);

  for ( i = 0; i < size3; ++i )
    BS_word(set1,i) |= (~BS_word(set2,i) & BS_word(set3,i));

  return set1;
}

/* ====================================================================
 * 
 * BS_3_2_Minus_4_Or_1_Or_D
 *
 * set1 += ((~set2) AND set3) OR set4
 * set1 += (set3 - set2) + set4
 * 
 * ====================================================================
 */

extern BS*
BS_3_2_Minus_4_Or_1_Or_D(
  BS       *set1,
  const BS *set2,
  const BS *set3,
  const BS *set4,
  MEM_POOL *pool )
{
  BS_ELT i;
  BS_ELT size1 = BS_word_count(set1);
  BS_ELT size2 = BS_word_count(set2);
  BS_ELT size3 = BS_word_count(set3);
  BS_ELT size4 = BS_word_count(set4);

  Is_True( size2 == size3 && size3 == size4,
    ("BS_3_2_Minus_4_Or_1_Or_D: sizes not equal %d, %d, %d",
     size2, size3, size4) );

  if ( size1 < size2 )
    set1 = bs_Realloc(set1,size2,pool);

  for ( i = 0; i < size2; ++i )
    BS_word(set1,i) |= (~BS_word(set2,i) & BS_word(set3,i)) |
		       BS_word(set4,i);

  return set1;
}


/* ====================================================================
 * 
 * BS_3_2_Minus_4_Or_5_Or_1_Or_D
 *
 * set1 += ((~set2) AND set3) OR set4 OR set5
 * set1 += (set3 - set2) + set4 + set5
 * 
 * ====================================================================
 */

extern BS*
BS_3_2_Minus_4_Or_5_Or_1_Or_D(
  BS       *set1,
  const BS *set2,
  const BS *set3,
  const BS *set4,
  const BS *set5,
  MEM_POOL *pool )
{
  BS_ELT i;
  BS_ELT size1 = BS_word_count(set1);
  BS_ELT size5  = BS_word_count(set5);

  Is_True( BS_word_count(set2) == size5,
    ("BS_3_2_Minus_4_Or_5_Or_1_Or_D: set2 size (%d) != set5 size (%d)",
     (BS_ELT)BS_word_count(set2), size5) );
  Is_True( BS_word_count(set3) == size5,
    ("BS_3_2_Minus_4_Or_5_Or_1_Or_D: set3 size (%d) != set5 size (%d)",
     (BS_ELT)BS_word_count(set3), size5) );
  Is_True( BS_word_count(set4) == size5,
    ("BS_3_2_Minus_4_Or_5_Or_1_Or_D: set4 size (%d) != set5 size (%d)",
     (BS_ELT)BS_word_count(set4), size5) );

  if ( size1 < size5 )
    set1 = bs_Realloc(set1,size5,pool);

  for ( i = 0; i < size5; ++i )
    BS_word(set1,i) |= (~BS_word(set2,i) & BS_word(set3,i)) |
			  BS_word(set4,i) | BS_word(set5,i);

  return set1;
}


/* ====================================================================
 *
 *  BS_2_1_Minus_3_Or_4_And_5_And_6_And_R
 *
 *  See interface description
 *
 * ====================================================================
 */

extern BS*
BS_2_1_Minus_3_Or_4_And_5_And_6_And_R(
  BS       *result,
  const BS *set1,
  const BS *set2,
  const BS *set3,
  const BS *set4,
  const BS *set5,
  const BS *set6,
  MEM_POOL *pool
)
{
  BS_ELT i;
  BS_ELT rsize = BS_word_count(result);
  BS_ELT size3 = BS_word_count(set3);

  Is_True( BS_word_count(set1) == size3,
    ("BS_2_1_Minus_3_Or_4_And_5_And_6_And_R: set1 size (%d) < set3 size (%d)",
     (BS_ELT)BS_word_count(set1), size3) );
  Is_True( BS_word_count(set2) == size3,
    ("BS_2_1_Minus_3_Or_4_And_5_And_6_And_R: set2 size (%d) < set3 size (%d)",
     (BS_ELT)BS_word_count(set2), size3) );
  Is_True( BS_word_count(set4) == size3,
    ("BS_2_1_Minus_3_Or_4_And_5_And_6_And_R: set4 size (%d) < set3 size (%d)",
     (BS_ELT)BS_word_count(set4), size3) );
  Is_True( BS_word_count(set5) == size3,
    ("BS_2_1_Minus_3_Or_4_And_5_And_6_And_R: set5 size (%d) < set3 size (%d)",
     (BS_ELT)BS_word_count(set4), size3) );
  Is_True( BS_word_count(set6) == size3,
    ("BS_2_1_Minus_3_Or_4_And_5_And_6_And_R: set6 size (%d) < set3 size (%d)",
     (BS_ELT)BS_word_count(set6), size3) );

  if ( rsize < size3 )
    result = bs_Realloc(result,size3,pool);

  for ( i = 0; i < size3; ++i )
    BS_word(result,i) = ((~BS_word(set1,i) & BS_word(set2,i)) |
			 BS_word(set3,i)) &
			BS_word(set4,i) &
			BS_word(set5,i) &
			BS_word(set6,i);

  return result;
}

/* ====================================================================
 *
 *  BS_2_1_Minus_3_Or_4_And_R
 *
 *  See interface description
 *
 * ====================================================================
 */

extern BS*
BS_2_1_Minus_3_Or_4_And_R(
  BS       *result,
  const BS *set1,
  const BS *set2,
  const BS *set3,
  const BS *set4,
  MEM_POOL *pool
)
{
  BS_ELT i;
  BS_ELT rsize = BS_word_count(result);
  BS_ELT size3 = BS_word_count(set3);

  Is_True( BS_word_count(set1) == size3,
    ("BS_2_1_Minus_3_Or_4_And_R: set1 size (%d) < set3 size (%d)",
     (BS_ELT)BS_word_count(set1), size3) );
  Is_True( BS_word_count(set2) == size3,
    ("BS_2_1_Minus_3_Or_4_And_R: set2 size (%d) < set3 size (%d)",
     (BS_ELT)BS_word_count(set2), size3) );
  Is_True( BS_word_count(set4) == size3,
    ("BS_2_1_Minus_3_Or_4_And_R: set4 size (%d) < set3 size (%d)",
     (BS_ELT)BS_word_count(set4), size3) );

  if ( rsize < size3 )
    result = bs_Realloc(result,size3,pool);

  for ( i = 0; i < size3; ++i )
    BS_word(result,i) = ((~BS_word(set1,i) & BS_word(set2,i)) |
			 BS_word(set3,i)) &
			BS_word(set4,i);

  return result;
}

/* ====================================================================
 *
 *  BS_1_Not_2_Or_3_Minus_4_And_R
 *
 *  See interface description
 *
 * ====================================================================
 */

extern BS*
BS_1_Not_2_Or_3_Minus_4_And_R(
  BS       *result,
  const BS *set1,
  const BS *set2,
  const BS *set3,
  const BS *set4,
  MEM_POOL *pool
)
{
  BS_ELT i;
  BS_ELT rsize = BS_word_count(result);
  BS_ELT size2 = BS_word_count(set2);

  Is_True( BS_word_count(set1) == size2,
    ("BS_1_Not_2_Or_3_Minus_4_And_R: set1 size (%d) < set2 size (%d)",
     (BS_ELT)BS_word_count(set1), size2) );
  Is_True( BS_word_count(set3) == size2,
    ("BS_1_Not_2_Or_3_Minus_4_And_R: set3 size (%d) < set2 size (%d)",
     (BS_ELT)BS_word_count(set3), size2) );
  Is_True( BS_word_count(set4) == size2,
    ("BS_1_Not_2_Or_3_Minus_4_And_R: set4 size (%d) < set2 size (%d)",
     (BS_ELT)BS_word_count(set4), size2) );

  if ( rsize < size2 )
    result = bs_Realloc(result,size2,pool);

  for ( i = 0; i < size2; ++i )
    BS_word(result,i) = (~BS_word(set1,i) | BS_word(set2,i)) &
			(~BS_word(set3,i)) &
			BS_word(set4,i);
  return result;
}

/* ====================================================================
 * 
 * BS_2_3_Or_1_Or_D
 *
 * set1 += (set2 OR set3)
 * set1 += (set2 + set3)
 * 
 * ====================================================================
 */

extern BS*
BS_2_3_Or_1_Or_D(
  BS       *set1,
  const BS *set2,
  const BS *set3,
  MEM_POOL *pool )
{
  BS_ELT i;
  BS_ELT size1 = BS_word_count(set1);
  BS_ELT size2  = BS_word_count(set2);
  BS_ELT size3  = BS_word_count(set3);

  Is_True( size2 == size3,
    ("BS_2_3_Or_1_Or_D: sizes not equal %d, %d",
     size2, size3) );

  if ( size1 < size2 )
    set1 = bs_Realloc(set1,size2,pool);

  for ( i = 0; i < size2; ++i )
    BS_word(set1,i) |= (BS_word(set2,i) | BS_word(set3,i));

  return set1;
}

/* ====================================================================
 *
 *  BS_1_2_Or_3_And_R
 *
 *  See interface description
 *
 * ====================================================================
 */

extern BS*
BS_1_2_Or_3_And_R(
  BS       *result,
  const BS *set1,
  const BS *set2,
  const BS *set3,
  MEM_POOL *pool
)
{
  BS_ELT i;
  BS_ELT rsize = BS_word_count(result);
  BS_ELT size1 = BS_word_count(set1);

  Is_True( BS_word_count(set2) == size1,
    ("BS_1_2_Or_3_And_R: set2 size (%d) < set1 size (%d)",
     (BS_ELT)BS_word_count(set2), size1) );
  Is_True( BS_word_count(set3) == size1,
    ("BS_1_2_Or_3_And_R: set3 size (%d) < set1 size (%d)",
     (BS_ELT)BS_word_count(set3), size1) );

  if ( rsize < size1 )
    result = bs_Realloc(result,size1,pool);

  for ( i = 0; i < size1; ++i )
    BS_word(result,i) = (BS_word(set1,i) | BS_word(set2,i)) &
			BS_word(set3,i);

  return result;
}

/* ====================================================================
 *
 *  BS_2_3_And_1_Or_D
 *
 *  See interface description
 *
 * ====================================================================
 */

extern BS*
BS_2_3_And_1_Or_D(
  BS *set1,
  const BS *set2,
  const BS *set3,
  MEM_POOL *pool
)
{
  BS_ELT i;
  BS_ELT size1 = BS_word_count(set1);
  BS_ELT size = MIN(BS_word_count(set2),BS_word_count(set3));

  if ( size1 < size )
    set1 = bs_Realloc(set1,size,pool);

  for ( i = 0; i < size; ++i )
    BS_word(set1,i) |= BS_word(set2,i) & BS_word(set3,i);

  return set1;
}

/* ====================================================================
 *
 *  BS_3_Not_4_Or_2_And_1_Or_D
 *
 *  See interface description
 *
 * ====================================================================
 */

extern BS*
BS_3_Not_4_Or_2_And_1_Or_D(
  BS       *set1,
  const BS *set2,
  const BS *set3,
  const BS *set4,
  MEM_POOL *pool
)
{
  BS_ELT i;
  BS_ELT size1 = BS_word_count(set1);
  BS_ELT size2 = BS_word_count(set2);

  Is_True( BS_word_count(set3) == size2,
    ("BS_3_Not_4_Or_2_And_1_Or_D: set3 size (%d) < set2 size (%d)",
     (BS_ELT)BS_word_count(set3), size2) );
  Is_True( BS_word_count(set4) == size2,
    ("BS_3_Not_4_Or_2_And_1_Or_D: set4 size (%d) < set2 size (%d)",
     (BS_ELT)BS_word_count(set4), size2) );

  if ( size1 < size2 )
    set1 = bs_Realloc(set1,size2,pool);

  for ( i = 0; i < size2; ++i )
    BS_word(set1,i) |= BS_word(set2,i) &
                       (~BS_word(set3,i) | BS_word(set4,i));

  return set1;
}

/* ====================================================================
 *
 *  BS_4_3_Minus_2_Not_Or_1_And_D
 *
 *  See interface description
 *
 * ====================================================================
 */

extern BS*
BS_4_3_Minus_2_Not_Or_1_And_D(
  BS       *set1,
  const BS *set2,
  const BS *set3,
  const BS *set4,
  MEM_POOL *pool
)
{
  BS_ELT i;
  BS_ELT size1 = BS_word_count(set1);
  BS_ELT size2 = BS_word_count(set2);

  Is_True( BS_word_count(set3) == size2,
    ("BS_4_3_Minus_2_Not_Or_1_And_D: set3 size (%d) < set2 size (%d)",
     (BS_ELT)BS_word_count(set3), size2) );
  Is_True( BS_word_count(set4) == size2,
    ("BS_4_3_Minus_2_Not_Or_1_And_D: set4 size (%d) < set2 size (%d)",
     (BS_ELT)BS_word_count(set4), size2) );

  if ( size1 < size2 )
    set1 = bs_Realloc(set1,size2,pool);

  for ( i = 0; i < size2; ++i )
    BS_word(set1,i) &= ~BS_word(set2,i) |
                       (BS_word(set4,i) & ~BS_word(set3,i));

  return set1;
}

/* ====================================================================
 *
 *  BS_2_3_Minus_1_Or_D
 *
 *  See interface description
 *
 * ====================================================================
 */

extern BS*
BS_2_3_Minus_1_Or_D(
  BS       *set1,
  const BS *set2,
  const BS *set3,
  MEM_POOL *pool
)
{
  BS_ELT i;
  BS_ELT size1 = BS_word_count(set1);
  BS_ELT size2 = BS_word_count(set2);
  BS_ELT size3 = BS_word_count(set3);

  Is_True( size2 == size3,
    ("BS_2_3_Minus_1_Or_D: sizes not equal %d, %d",
     size2, size3) );

  if ( size1 < size2 )
    set1 = bs_Realloc(set1,size2,pool);

  for ( i = 0; i < size2; ++i )
    BS_word(set1,i) |= BS_word(set2,i) & ~BS_word(set3,i);

  return set1;
}

/* ====================================================================
 *
 *  BS_2_3_Minus_4_Minus_1_Or_D
 *
 *  See interface description
 *
 * ====================================================================
 */

extern BS*
BS_2_3_Minus_4_Minus_1_Or_D(
  BS       *set1,
  const BS *set2,
  const BS *set3,
  const BS *set4,
  MEM_POOL *pool
)
{
  BS_ELT i;
  BS_ELT size1 = BS_word_count(set1);
  BS_ELT size2 = BS_word_count(set2);
  BS_ELT size3 = BS_word_count(set3);
  BS_ELT size4 = BS_word_count(set4);

  Is_True( size2 == size3 && size3 == size4,
    ("BS_2_3_Minus_4_Minus_1_Or_D: sizes not equal %d, %d, %d",
     size2, size3, size4) );

  if ( size1 < size2 )
    set1 = bs_Realloc(set1,size2,pool);

  for ( i = 0; i < size2; ++i )
    BS_word(set1,i) |= BS_word(set2,i) & ~BS_word(set3,i)
			 & ~BS_word(set4,i);

  return set1;
}

/* ====================================================================
 *
 *  BS_ContainsP
 *
 *  See interface description
 *
 * ====================================================================
 */

extern BOOL
BS_ContainsP(
  BS *set1,
  BS *set2
)
{
  BS_ELT minsize;
  BS_ELT i;

  if ( BS_word_count(set1) < BS_word_count(set2) )
    minsize = BS_word_count(set1);
  else
    minsize = BS_word_count(set2);

  /* Check common part.
   */
  for ( i = 0; i < minsize; ++i ) {
    if ( BS_word(set1,i) != (BS_word(set1,i) | BS_word(set2,i)) )
      return FALSE;
  }

  /* Check excess in set2.
   */
  for ( ; i < BS_word_count(set2); ++i ) {
    if ( BS_word(set2,i) != bs_ZEROS )
      return FALSE;
  }

  return TRUE;
}

/* ====================================================================
 *
 *  BS_EmptyP
 *
 *  See interface description
 *
 * ====================================================================
 */

extern BOOL
BS_EmptyP(
  BS *set
)
{
  BS_ELT i;

  for ( i = 0; i < BS_word_count(set); ++i ) {
    if ( BS_word(set,i) != bs_ZEROS )
      return FALSE;
  }

  return TRUE;
}

/* ====================================================================
 *
 *  BS_EqualP
 *
 *  See interface description
 *
 * ====================================================================
 */

extern BOOL
BS_EqualP(
  BS *set1,
  BS *set2
)
{
  BS_ELT i;

  /* Normalize so set1 is smaller:
   */
  if ( BS_word_count(set1) > BS_word_count(set2) ) {
    BS *tmp = set1;
    set1 = set2;
    set2 = tmp;
  }

  for ( i = 0; i < BS_word_count(set1); ++i ) {
    if ( BS_word(set1,i) != BS_word(set2,i) )
      return FALSE;
  }

  for ( ; i < BS_word_count(set2); ++i ) {
    if ( BS_word(set2,i) != bs_ZEROS )
      return FALSE;
  }

  return TRUE;
}

/* ====================================================================
 *
 *  BS_IntersectsP
 *
 *  See interface description
 *
 * ====================================================================
 */

extern BOOL
BS_IntersectsP(
  BS *set1,
  BS *set2
)
{
  BS_ELT minsize, i;

  if ( BS_word_count(set1) < BS_word_count(set2) )
    minsize = BS_word_count(set1);
  else
    minsize = BS_word_count(set2);

  for ( i = 0; i < minsize; ++i ) {
    if ( (BS_word(set1,i) & BS_word(set2,i)) != bs_ZEROS )
      return TRUE;
  }

  return FALSE;
}

/* ====================================================================
 *
 *  BS_MemberP
 *
 *  See interface description
 *
 * ====================================================================
 */

extern BOOL
BS_MemberP(
  BS    *set,
  BS_ELT x
)
{
  Is_True(x >= 0,("BS_Member called with negative element."));

  if ( bs_QBPW(x) >= BS_word_count(set) )
    return FALSE;
  else
    return    (BS_byte(set,bs_QBPB(x)) & (bs_ONE << bs_RBPB(x)))
           != bs_ZEROS;
}

/* ====================================================================
 *
 *  BS_Intersection_MemberP
 *
 *  See interface description
 *
 * ====================================================================
 */

extern BOOL
BS_Intersection_MemberP(
  BS    *set1,
  BS    *set2,
  BS_ELT x
)
{
  Is_True(x >= 0,("BS_Member called with negative element."));

  if (    bs_QBPW(x) >= BS_word_count(set1)
       || bs_QBPW(x) >= BS_word_count(set2)
  ) {
    return FALSE;
  }
  else {
    return    (   BS_byte(set1,bs_QBPB(x))
                & BS_byte(set2,bs_QBPB(x))
                & (bs_ONE << bs_RBPB(x)))
           != bs_ZEROS;
  }
}

/* ====================================================================
 *
 *  PrintRange
 *
 *  Subroutine for BS_Print to print a range within the set.
 *
 *  f       - The file to print to
 *  low     - First elemnt of range
 *  high    - Last element of range
 *  first   - First range to be printed.  (Reference argument)
 *
 * ====================================================================
 */

static void
PrintRange(
  FILE  *f,
  BS_ELT low,
  BS_ELT high,
  BOOL  *first
)
{
  if ( *first )
    *first = FALSE;
  else
    fprintf(f,",");

  if ( low == high )
    fprintf(f,"%d",low);
  else
    fprintf(f,"%d-%d",low,high);
}

/* ====================================================================
 *
 *  BS_Print
 *
 *  See interface description
 *
 * ====================================================================
 */

extern void
BS_Print(
  const BS *set,
  FILE *f
)
{
  BS_ELT range_first, last_elt, elt;
  BOOL   first = TRUE;

  if ( set == NULL ) {
    fprintf ( f, "<NULL>" );
    return;
  }

  fprintf(f,"{");

  elt = BS_Choose(set);
  if ( elt == BS_CHOOSE_FAILURE ) {
    fprintf(f,"}");
    return;
  }
  range_first = elt;
  last_elt = range_first;

  while ( (elt = BS_Choose_Next(set,elt)) != BS_CHOOSE_FAILURE ) {
    if ( elt != last_elt + 1 ) {
      /* renge_first .. last_elt was a range
       */

      PrintRange(f,range_first,last_elt,&first);
      range_first = elt;
    }
    last_elt = elt;
  }

  PrintRange(f,range_first,last_elt,&first);
  fprintf(f,"}");
}

/* ====================================================================
 *
 *  BS_Print_dbg - same as BS_Print, but to stderr, to be called from
 *  dbx
 *
 * ====================================================================
 */

extern void
BS_Print_dbg(BS   *set)
{
  BS_Print(set, stderr);
  fprintf(stderr, "\n");
}


/* ====================================================================
 *
 *  FBS_MemberP
 *
 *  See interface description
 *
 * ====================================================================
 */

extern BOOL
FBS_MemberP_Validate(
  BS    *set,
  BS_ELT x
)
{
  Is_True(x >= 0,("FBS_Member called with negative element."));
  Is_True( bs_QBPW(x) < BS_word_count(set), ("FBS_Member called with out of bound element."));
  return  (BS_byte(set,bs_QBPB(x)) & (bs_ONE << bs_RBPB(x))) != bs_ZEROS;
}


/* ====================================================================
 *
 *  FBS_Union1D
 *
 *  See interface description
 *
 * ====================================================================
 */

void
FBS_Union1D_Validate(
  BS       *set,
  BS_ELT    x
)
{
  BS_ELT minsize = bs_QBPW(x) + 1;
  Is_True(x >= 0,("FBS_Union1D called with negative element."));
  Is_True( minsize <= BS_word_count(set), ("FBS_Union1D called with out of bound element."));
  BS_byte(set,bs_QBPB(x)) |= bs_ONE << bs_RBPB(x);
}



