protected void compactBucket(Bucket bucket) {
    LongsArray singles = bucket.singles;
    Long2ObjectOpenHashMap<LongsArray> dupes = bucket.dupes;
    long[] a = singles.a;
    int n = singles.n;

    Long2ObjectOpenHashMap<LongsArray> dupesNew = new Long2ObjectOpenHashMap<LongsArray>();
    dupesNew.defaultReturnValue(null);
    for (int i = 0; i < n; i += 2) {
      long v1 = a[i];
      long v2 = a[i + 1];
      long xyKey = xyToKey(x(v1, v2), y(v1, v2));

      LongsArray vs = dupesNew.get(xyKey);
      if (vs == null) {
        vs = new LongsArray(new long[16], 0);
        dupesNew.put(xyKey, vs);
      }
      vs.append(a, i, i + 2);
    }

    singles.n = 0;
    int dupeThreshold = 2 * max(2, (int) (0.1 * maxBucketSize));
    for (Entry<LongsArray> en : dupesNew.long2ObjectEntrySet()) {
      LongsArray vs = en.getValue();
      if (vs.n >= dupeThreshold) {
        long xyKey = en.getLongKey();
        dupes.put(xyKey, vs);
      } else {
        singles.append(vs);
      }
    }
  }
  protected static void remove2(LongsArray longs, long v1, long v2) {
    long[] a = longs.a;
    int n = longs.n;

    for (int i = 0; i < n; i += 2) {
      if (a[i] == v1 && a[i + 1] == v2) {
        System.arraycopy(a, i + 2, a, i, n - (i + 2));
        longs.n -= 2;
        return;
      }
    }
  }