#include <stdbool.h>
#include <stdint.h>

#define BITSET_BITS 12
#define BITSET_SIZE (1 << (BITSET_BITS - 6))

typedef uint64_t *bitset;

#define bitset_alloc(b) \
  do { \
    CALLOC (b, BITSET_SIZE); \
  } while (0)
#define bitset_release(b) \
  do { \
    DEALLOC (b, BITSET_SIZE); \
  } while (0)

bitset _dummy1 = 0, _dummy2 = 0, _dummy3 = 0, _dummy4 = 0, _dummy5 = 0,
       _dummy6 = 0;

#define define_iter(a) bitset a##_it = a;
#define define_iters(a, b, c, d, e, f, ...) \
  define_iter (a) define_iter (b) define_iter (c) define_iter (d) \
      define_iter (e) define_iter (f)

#define move_iter(a) , a##_it++
#define move_iters(a, b, c, d, e, f, ...) \
  move_iter (a) move_iter (b) move_iter (c) move_iter (d) move_iter (e) \
      move_iter (f)

#define bitset_wrapper_begin(...) \
  do { \
    define_iters (__VA_ARGS__, _dummy1, _dummy2, _dummy3, _dummy4, \
                  _dummy5, _dummy6); \
    for (int iter = 0; iter < BITSET_SIZE; \
         iter++ move_iters (__VA_ARGS__, _dummy1, _dummy2, _dummy3, \
                            _dummy4, _dummy5, _dummy6)) {

#define bitset_wrapper_end() \
  } \
  } \
  while (0)

#define bitset_fill_period(b, n) \
  do { \
    if ((n) < 6) { \
      uint64_t v = (~0llu) / ((1llu << (1 << (n))) + 1); \
      bitset iter = b; \
      for (int i = 0; i < BITSET_SIZE; i++, iter++) \
        *iter = v; \
    } else { \
      int v = (1llu << (n)) >> 6; \
      bitset iter = b; \
      for (int i = 0; i < BITSET_SIZE; i++, iter++) { \
        *iter = 0; \
        if (v & i) \
          *iter = ~(*iter); \
      } \
    } \
  } while (0)

#define bitset_fill_random(b) \
  do { \
    bitset iter = b; \
    for (int i = 0; i < BITSET_SIZE; i++, iter++) { \
      *iter = kissat_next_random64 (&solver->random); \
    } \
  } while (0)

#define bitset_fill_biased_0(b) \
  do { \
    bitset iter = b; \
    for (int i = 0; i < BITSET_SIZE; i++, iter++) { \
      *iter = kissat_next_random64 (&solver->random); \
      *iter &= kissat_next_random64 (&solver->random); \
      *iter &= kissat_next_random64 (&solver->random); \
    } \
  } while (0)

#define bitset_fill_biased_1(b) \
  do { \
    bitset iter = b; \
    for (int i = 0; i < BITSET_SIZE; i++, iter++) { \
      *iter = kissat_next_random64 (&solver->random); \
      *iter |= kissat_next_random64 (&solver->random); \
      *iter |= kissat_next_random64 (&solver->random); \
    } \
  } while (0)

#define bitset_fill(b) memset (b, 0xff, sizeof (uint64_t) * BITSET_SIZE)
#define bitset_clear(b) memset (b, 0, sizeof (uint64_t) * BITSET_SIZE)

#define bitset_find_zero(b, v) \
  do { \
    bitset iter = b; \
    v = -1; \
    for (int i = 0; i < BITSET_SIZE; i++, iter++) \
      if (~(*iter)) { \
        v = __builtin_ctzll (~(*iter)) + (i << 6); \
        break; \
      } \
  } while (0)

#define bitset_popcount(b, v) \
  do { \
    bitset iter = b; \
    v = 0; \
    for (int i = 0; i < BITSET_SIZE; i++, iter++) \
      v += __builtin_popcountll (*iter); \
  } while (0)

#define bitset_get(b, v) (((b)[v >> 6] >> (v & 0x3f)) & 1)
