public void clear() {
   if (size != 0) {
     size = 0;
     zeroMask = CharOps.randomExcept((char) 0);
     Arrays.fill(set, (char) 0);
   }
 }
public class ZeroMaskingStatesLHashCharSet implements UnsafeConstants {

  public int size = 0;
  public char zeroMask = CharOps.randomExcept((char) 0);
  public char[] set;

  public ZeroMaskingStatesLHashCharSet(int capacity) {
    if ((capacity & (capacity - 1)) != 0) {
      throw new IllegalArgumentException();
    }
    set = new char[capacity];
  }

  public void clear() {
    if (size != 0) {
      size = 0;
      zeroMask = CharOps.randomExcept((char) 0);
      Arrays.fill(set, (char) 0);
    }
  }

  public int indexBinaryStateSimpleIndexing(char key) {
    if (key != 0 && key != zeroMask) {
      char[] keys = set;
      int capacityMask = keys.length - 1;
      int index = Primitives.hashCode(key) & capacityMask;
      char cur = keys[index];
      if (cur == key) {
        return index;
      } else {
        if (cur == 0) {
          return -1;
        } else {
          while (true) {
            index = (index + 1) & capacityMask;
            if ((cur = keys[index]) == key) {
              return index;
            } else if (cur == 0) {
              return -1;
            }
          }
        }
      }
    } else {
      return -1;
    }
  }

  public int indexBinaryStateUnsafeIndexing(char key) {
    if (key != 0 && key != zeroMask) {
      char[] keys = set;
      long capacityMask = (long) (keys.length - 1);
      long index = ((long) Primitives.hashCode(key)) & capacityMask;
      long offset = index << CHAR_SCALE_SHIFT;
      long CHAR_BASE = UnsafeConstants.CHAR_BASE;
      char cur = U.getChar(keys, CHAR_BASE + offset);
      if (cur == key) {
        return (int) index;
      } else {
        if (cur == 0) {
          return -1;
        } else {
          long capacityOffsetMask = capacityMask << CHAR_SCALE_SHIFT;
          while (true) {
            offset = (offset + CHAR_SCALE) & capacityOffsetMask;
            if ((cur = U.getChar(keys, CHAR_BASE + offset)) == key) {
              return (int) (offset >> CHAR_SCALE_SHIFT);
            } else if (cur == 0) {
              return -1;
            }
          }
        }
      }
    } else {
      return -1;
    }
  }

  public boolean addBinaryStateSimpleIndexing(char key) {
    if (key == 0 || key == zeroMask) {
      return false;
    }
    char[] keys = set;
    int capacityMask = keys.length - 1;
    int index = Primitives.hashCode(key) & capacityMask;
    char cur = keys[index];
    keyAbsent:
    if (cur != 0) {
      if (cur == key) {
        return false;
      } else {
        while (true) {
          index = (index + 1) & capacityMask;
          if ((cur = keys[index]) == 0) {
            break keyAbsent;
          } else if (cur == key) {
            return false;
          }
        }
      }
    }
    // key is absent
    keys[index] = key;
    size++;
    return true;
  }

  public boolean addBinaryStateUnsafeIndexing(char key) {
    if (key == 0 || key == zeroMask) {
      return false;
    }
    char[] keys = set;
    long capacityMask = (long) (keys.length - 1);
    long index = ((long) Primitives.hashCode(key)) & capacityMask;
    long offset = index << CHAR_SCALE_SHIFT;
    char cur = U.getChar(keys, CHAR_BASE + offset);
    keyAbsent:
    if (cur != 0) {
      if (cur == key) {
        return false;
      } else {
        long capacityOffsetMask = capacityMask << CHAR_SCALE_SHIFT;
        while (true) {
          offset = (offset + CHAR_SCALE) & capacityOffsetMask;
          if ((cur = U.getChar(keys, CHAR_BASE + offset)) == 0) {
            break keyAbsent;
          } else if (cur == key) {
            return false;
          }
        }
      }
    }
    // key is absent
    U.putChar(keys, CHAR_BASE + offset, key);
    size++;
    return true;
  }

  public boolean removeSimpleIndexing(char key) {
    if (key == 0 || key == zeroMask) {
      return false;
    }
    char[] keys = set;
    int capacity = set.length;
    int capacityMask = capacity - 1;
    int index = Primitives.hashCode(key) & capacityMask;
    char cur = keys[index];
    keyPresent:
    if (cur != key) {
      if (cur == 0) return false;
      while (true) {
        index = (index + 1) & capacityMask;
        if ((cur = keys[index]) == key) {
          break keyPresent;
        } else if (cur == 0) {
          return false;
        }
      }
    }
    // key is present
    int indexToRemove = index;
    int indexToShift = indexToRemove;
    int shiftDistance = 1;
    while (true) {
      indexToShift = (indexToShift + 1) & capacityMask;
      char keyToShift = keys[indexToShift];
      if (keyToShift == 0) {
        keys[indexToRemove] = (char) 0;
        return true;
      }
      int keyDistance = (indexToShift - Primitives.hashCode(keyToShift)) & capacityMask;
      if (keyDistance >= shiftDistance) {
        keys[indexToRemove] = keyToShift;
        indexToRemove = indexToShift;
        shiftDistance = 1;
      } else {
        shiftDistance++;
      }
    }
  }

  public boolean removeUnsafeIndexing(char key) {
    if (key == 0 || key == zeroMask) {
      return false;
    }
    char[] keys = set;
    int capacity = set.length;
    int capacityMask = capacity - 1;
    long capacityOffsetMask = ((long) capacityMask) << CHAR_SCALE_SHIFT;
    long index = (long) (Primitives.hashCode(key) & capacityMask);
    long offset = index << CHAR_SCALE_SHIFT;
    char cur = U.getChar(keys, CHAR_BASE + offset);
    keyPresent:
    if (cur != key) {
      if (cur == 0) return false;
      while (true) {
        offset = (offset + CHAR_SCALE) & capacityOffsetMask;
        if ((cur = U.getChar(keys, CHAR_BASE + offset)) == key) {
          break keyPresent;
        } else if (cur == 0) {
          return false;
        }
      }
    }
    // key is present
    long offsetToRemove = offset;
    long offsetToShift = offset;
    int shiftDistance = 1;
    while (true) {
      offsetToShift = (offsetToShift + CHAR_SCALE) & capacityOffsetMask;
      char keyToShift = U.getChar(keys, CHAR_BASE + offsetToShift);
      if (keyToShift == 0) break;
      int indexToShift = (int) (offsetToShift >> CHAR_SCALE_SHIFT);
      int keyDistance = (indexToShift - Primitives.hashCode(keyToShift)) & capacityMask;
      if (keyDistance >= shiftDistance) {
        U.putChar(keys, CHAR_BASE + offsetToRemove, keyToShift);
        offsetToRemove = offsetToShift;
        shiftDistance = 1;
      } else {
        shiftDistance++;
      }
    }
    U.putChar(keys, CHAR_BASE + offsetToRemove, (char) 0);
    return true;
  }

  public void forEachBinaryState(CharConsumer action) {
    char zeroMask = this.zeroMask;
    char[] keys = set;
    int i = keys.length - 1;
    for (; i >= 0; i--) {
      char k;
      if ((k = keys[i]) != 0) {
        action.accept(k != zeroMask ? k : (char) 0);
        if (k == zeroMask) break;
      } else {
        break;
      }
    }
    i--;
    for (; i >= 0; i--) {
      char k;
      if ((k = keys[i]) != 0) action.accept(k);
    }
  }
}