/* bitmap.c -- (C) Geoffrey Reynolds, April 2006.

   Bitmap functions set_bit(B,n), clear_bit(B,n), test_bit(B,n),
   first_bit(B), next_bit(B,n), fill_bits(B,first,last). B is a
   pointer to a bitmap, n is the bit number counting from zero.
   first_bit()/next_bit() require at least one bit to be set.

   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 of the License, or
   (at your option) any later version.
*/

#include <string.h>
#include "srsieve.h"
#include "bitmap.h"


/* Create a new bitmap of at least n clear bits.
*/
uint32_t *make_bitmap(uint32_t n)
{
  uint32_t size, *bitmap;

  size = ((n+UINT_BIT-1)/UINT_BIT+1);
  bitmap = xmalloc(size*sizeof(uint32_t));
  memset(bitmap,0,size*sizeof(uint32_t));
  bitmap[size-1] = ~0U; /* sentinel */

  return bitmap;
}

/* Resize a bitmap B of m bits to a bitmap of n bits. If the new bitmap is
   larger, clear the extra bits.
*/
#if 0
uint32_t *resize_bitmap(uint32_t *B, uint32_t m, uint32_t n)
{
  uint32_t old_size, new_size;

  old_size = ((m+UINT_BIT-1)/UINT_BIT+1);
  new_size = ((n+UINT_BIT-1)/UINT_BIT+1);
  if (old_size != new_size)
  {
    B = xrealloc(B,new_size*sizeof(uint32_t));
    if (old_size < new_size)
      memset(&B[old_size-1],0,(new_size-old_size)*sizeof(uint32_t));
    B[new_size-1] = ~0U; /* Sentinel */
  }

  return B;
}
#endif

#if defined(__MINGW32__)
#define ffs __builtin_ffs
#endif

/* Return first set bit in B counting from bit 0 (inclusive). At least one
   bit must be set for first_bit to find.
 */
uint32_t first_bit(const uint32_t *B)
{
  uint32_t i;

  for (i = 0; B[i] == 0; i++)
    ;

  return i*UINT_BIT + ffs(B[i]) - 1;
}

/* Return the next set bit in B counting from bit (inclusive). At least one
   bit must be set for next_bit to find.
 */
uint32_t next_bit(const uint32_t *B, uint32_t bit)
{
  uint32_t i, mask;

  i = bit / UINT_BIT;
  mask = ~0U << (bit % UINT_BIT);

  if (B[i] & mask)
    return i*UINT_BIT + ffs(B[i] & mask) - 1;

  for (i++; B[i] == 0; i++)
    ;

  return i*UINT_BIT + ffs(B[i]) - 1;
}

/* Set all bits from first to last inclusive.
 */
void fill_bits(uint32_t *B, uint32_t first, uint32_t last)
{
  uint32_t fmask, lmask, *ptr;

  fmask = ~0U << (first % UINT_BIT);
  lmask = ~0U >> (UINT_BIT - 1 - last % UINT_BIT);
  ptr = B + first / UINT_BIT;
  if (first / UINT_BIT == last / UINT_BIT)
    *ptr |= (fmask & lmask);
  else
  {
    *ptr |= fmask;
    while (++ptr < B + last / UINT_BIT)
      *ptr = ~0U;
    *ptr |= lmask;
  }
}
