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(long[].class);
  private static final int shift;

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

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

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

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

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

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

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

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

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

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

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

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

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

  public void set(int bitIndex, boolean value) {
    if (value) {
      set(bitIndex);
    } else {
      clear(bitIndex);
    }
  }

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

    long v = unsafe.getLongVolatile(bitset, byteOffset(bucket));
    return (v & (1L << bitIndex)) != 0;
  }
}

@@ -54,16 +54,192 @@
 nsafe;%0A%0A
+/**%0A * Represents a vector of a fixed number of bits.%0A * This class differs from the normal %7B@link java.util.BitSet%7D class in that we only allow%0A * a fixed number of bits.%0A */%0A
 public c
@@ -679,16 +679,230 @@
 nbits;%0A%0A
+  /**%0A   * Creates a new bit set whose size is large enough to explicitely represent bits%0A   * with indices in the range %7B@code 0%7D through %7B@code nbits - 1%7D.%0A   * @param nbits the initial size of the bit set%0A   */%0A
   public
@@ -1262,24 +1262,93 @@
 ) + 1;%0A  %7D%0A%0A
+  /**%0A   * Sets all the bits in this bit set to %7B@code false%7D.%0A   */%0A
   public voi
@@ -1410,24 +1410,143 @@
  + 1%5D;%0A  %7D%0A%0A
+  /**%0A   * Sets the bit specified by the index to false.%0A   * @param bitIndex the index of the bit to be cleared%0A   */%0A
   public voi
@@ -1904,32 +1904,175 @@
    %7D%0A    %7D%0A  %7D%0A%0A
+  /**%0A   * Sets the bit at the specified index to the complement of its current value.%0A   * @param bitIndex the index of the bit to flip%0A   */%0A
   public void fl
@@ -2424,32 +2424,127 @@
    %7D%0A    %7D%0A  %7D%0A%0A
+  /**%0A   * Sets the bit at the specified index to true.%0A   * @param bitIndex a bit index%0A   */%0A
   public void se
@@ -2909,139 +2909,728 @@
 %0A%0A  
-public void set(int bitIndex, boolean value) %7B%0A    if (value) %7B%0A      set(bitIndex);%0A    %7D else %7B%0A      clear(bitIndex);%0A    %7D%0A  %7D%0A
+/**%0A   * Sets the bit at the specified index to the specified value.%0A   * @param bitIndex a bit index%0A   * @param value    a boolean value to set%0A   */%0A  public void set(int bitIndex, boolean value) %7B%0A    if (value) %7B%0A      set(bitIndex);%0A    %7D else %7B%0A      clear(bitIndex);%0A    %7D%0A  %7D%0A%0A  /**%0A   * Returns the value of the bit with the specified index.%0A   * The value is true if the bit with the index %7B@code bitIndex%7D is currently set%0A   * in this BitSet; otherwise, the result is %7B@code false%7D.%0A   * @param bitIndex a bit index%0A   * @return the value of the bit with the specified index%0A   * @throws java.lang.IndexOutOfBoundsException if the specified index is negative or%0A   *         exceeds the bit set length%0A   */
 %0A  p

Include javadoc on LFBitSet