package com.github.kratorius.jefs;

import sun.misc.Unsafe;

public class LFBitSet extends NotSafe {
  private static Unsafe unsafe = getUnsafe();
  private static final int base = unsafe.arrayBaseOffset(int[].class);
  private static final int shift;

  static {
    int scale = Integer.numberOfLeadingZeros(unsafe.arrayIndexScale(int[].class));
    shift = 31 - scale;
  }

   // The volatile is needed because clear() creates a whole new array
  private volatile int[] bitset;
  private final int nbits;

  public LFBitSet(int nbits) {
    if (nbits < 0) {
      throw new IllegalArgumentException();
    }

    this.nbits = nbits;
    this.bitset = new int[getBucket(nbits) + 1];
  }

  private long byteOffset(int idx) {
    return ((long) idx << shift) + base;
  }

  private int getBucket(int bit) {
    //noinspection NumericOverflow
    return ((bit - 1) >> 5) + 1;
  }

  public void clear() {
    this.bitset = new int[getBucket(nbits) + 1];
  }

  public void clear(int bitIndex) {
    int bucket = getBucket(bitIndex);
    if (bucket >= bitset.length) {
      throw new IndexOutOfBoundsException();
    }

    int v1, v2;
    for (;;) {
      v1 = bitset[bucket];
      v2 = v1 & ~(1 << bitIndex);
      if (unsafe.compareAndSwapInt(bitset, byteOffset(bucket), v1, v2)) {
        return;
      }
    }
  }

  public void flip(int bitIndex) {
    int bucket = getBucket(bitIndex);
    if (bucket >= bitset.length) {
      throw new IndexOutOfBoundsException();
    }

    int v1, v2;
    for (;;) {
      v1 = bitset[bucket];
      v2 = v1 ^ (1 << bitIndex);
      if (unsafe.compareAndSwapInt(bitset, byteOffset(bucket), v1, v2)) {
        return;
      }
    }
  }

  public void set(int bitIndex) {
    int bucket = getBucket(bitIndex);
    if (bucket >= bitset.length) {
      throw new IndexOutOfBoundsException();
    }

    int v1, v2;
    for (;;) {
      v1 = bitset[bucket];
      v2 = v1 | (1 << bitIndex);
      if (unsafe.compareAndSwapInt(bitset, byteOffset(bucket), v1, v2)) {
        return;
      }
    }
  }

  public boolean get(int bitIndex) {
    int bucket = getBucket(bitIndex);
    if (bucket >= bitset.length) {
      throw new IndexOutOfBoundsException();
    }

    int v = unsafe.getIntVolatile(bitset, byteOffset(bucket));
    return (v & (1 << bitIndex)) != 0;
  }
}

@@ -197,19 +197,20 @@
 eOffset(
-int
+long
 %5B%5D.class
@@ -326,19 +326,20 @@
 exScale(
-int
+long
 %5B%5D.class
@@ -371,17 +371,16 @@
 e;%0A  %7D%0A%0A
- 
   // The
@@ -460,19 +460,20 @@
 olatile 
-int
+long
 %5B%5D bitse
@@ -644,35 +644,36 @@
 is.bitset = new 
-int
+long
 %5BgetBucket(nbits
@@ -867,9 +867,9 @@
  %3E%3E 
-5
+6
 ) + 
@@ -922,19 +922,20 @@
 t = new 
-int
+long
 %5BgetBuck
@@ -1112,35 +1112,36 @@
 n();%0A    %7D%0A%0A    
-int
+long
  v1, v2;%0A    for
@@ -1194,16 +1194,17 @@
 v1 & ~(1
+L
  %3C%3C bitI
@@ -1233,35 +1233,36 @@
 e.compareAndSwap
-Int
+Long
 (bitset, byteOff
@@ -1476,35 +1476,36 @@
 n();%0A    %7D%0A%0A    
-int
+long
  v1, v2;%0A    for
@@ -1557,16 +1557,17 @@
  v1 %5E (1
+L
  %3C%3C bitI
@@ -1596,35 +1596,36 @@
 e.compareAndSwap
-Int
+Long
 (bitset, byteOff
@@ -1846,19 +1846,20 @@
  %7D%0A%0A    
-int
+long
  v1, v2;
@@ -1919,16 +1919,17 @@
  v1 %7C (1
+L
  %3C%3C bitI
@@ -1966,19 +1966,20 @@
 eAndSwap
-Int
+Long
 (bitset,
@@ -2211,19 +2211,20 @@
  %7D%0A%0A    
-int
+long
  v = uns
@@ -2230,19 +2230,20 @@
 safe.get
-Int
+Long
 Volatile
@@ -2290,16 +2290,17 @@
  (v & (1
+L
  %3C%3C bitI

Use an array of longs rather than an array of ints