public static Builder<ByteBuffer> create() {
  return new Builder<>(PROXY_OPTIMAL);
} public static <T> KeyRange<T> all() {
  return (KeyRange<T>) FW;
} public static <T> KeyRange<T> allBackward() {
  return (KeyRange<T>) BK;
} public static <T> KeyRange<T> atLeast(final T start) {
  return new KeyRange<>(KeyRangeType.FORWARD_AT_LEAST, start, null);
} public static <T> KeyRange<T> atLeastBackward(final T start) {
  return new KeyRange<>(KeyRangeType.BACKWARD_AT_LEAST, start, null);
} public static <T> KeyRange<T> atMost(final T stop) {
  return new KeyRange<>(KeyRangeType.FORWARD_AT_MOST, null, stop);
} public static <T> KeyRange<T> atMostBackward(final T stop) {
  return new KeyRange<>(KeyRangeType.BACKWARD_AT_MOST, null, stop);
} public static <T> KeyRange<T> closed(final T start, final T stop) {
  return new KeyRange<>(KeyRangeType.FORWARD_CLOSED, start, stop);
} public static <T> KeyRange<T> closedBackward(final T start, final T stop) {
  return new KeyRange<>(KeyRangeType.BACKWARD_CLOSED, start, stop);
} public static <T> KeyRange<T> closedOpen(final T start, final T stop) {
  return new KeyRange<>(KeyRangeType.FORWARD_CLOSED_OPEN, start, stop);
} public static <T> KeyRange<T> closedOpenBackward(final T start, final T stop) {
  return new KeyRange<>(KeyRangeType.BACKWARD_CLOSED_OPEN, start, stop);
} public static <T> KeyRange<T> greaterThan(final T start) {
  return new KeyRange<>(KeyRangeType.FORWARD_GREATER_THAN, start, null);
} public static <T> KeyRange<T> greaterThanBackward(final T start) {
  return new KeyRange<>(KeyRangeType.BACKWARD_GREATER_THAN, start, null);
} public static <T> KeyRange<T> lessThan(final T stop) {
  return new KeyRange<>(KeyRangeType.FORWARD_LESS_THAN, null, stop);
} public static <T> KeyRange<T> lessThanBackward(final T stop) {
  return new KeyRange<>(KeyRangeType.BACKWARD_LESS_THAN, null, stop);
} public static <T> KeyRange<T> open(final T start, final T stop) {
  return new KeyRange<>(KeyRangeType.FORWARD_OPEN, start, stop);
} public static <T> KeyRange<T> openBackward(final T start, final T stop) {
  return new KeyRange<>(KeyRangeType.BACKWARD_OPEN, start, stop);
} public static <T> KeyRange<T> openClosed(final T start, final T stop) {
  return new KeyRange<>(KeyRangeType.FORWARD_OPEN_CLOSED, start, stop);
} public static <T> KeyRange<T> openClosedBackward(final T start, final T stop) {
  return new KeyRange<>(KeyRangeType.BACKWARD_OPEN_CLOSED, start, stop);
} public static final String DB_1 = "test-db-1"; @SuppressWarnings("PMD.AvoidUsingOctalValues")
public static final int POSIX_MODE = 0664; static ByteBuffer bb(final int value) {
  final ByteBuffer bb = allocateDirect(BYTES);
  bb.putInt(value).flip();
  return bb;
} public static final class KeyVal<T> {

  private T k;
  private T v;

  /**
   * The key.
   *
   * @return key
   */
  public T key() {
    return k;
  }

  /**
   * The value.
   *
   * @return value
   */
  public T val() {
    return v;
  }

  void setK(final T key) {
    this.k = key;
  }

  void setV(final T val) {
    this.v = val;
  }

}
import static com.jakewharton.byteunits.BinaryByteUnit.KIBIBYTES;
import static java.util.Arrays.asList;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.hasSize;
import static org.lmdbjava.DbiFlags.MDB_CREATE;
import static org.lmdbjava.Env.create;
import static org.lmdbjava.EnvFlags.MDB_NOSUBDIR;
import static org.lmdbjava.KeyRange.all;
import static org.lmdbjava.KeyRange.allBackward;
import static org.lmdbjava.KeyRange.atLeast;
import static org.lmdbjava.KeyRange.atLeastBackward;
import static org.lmdbjava.KeyRange.atMost;
import static org.lmdbjava.KeyRange.atMostBackward;
import static org.lmdbjava.KeyRange.closed;
import static org.lmdbjava.KeyRange.closedBackward;
import static org.lmdbjava.KeyRange.closedOpen;
import static org.lmdbjava.KeyRange.closedOpenBackward;
import static org.lmdbjava.KeyRange.greaterThan;
import static org.lmdbjava.KeyRange.greaterThanBackward;
import static org.lmdbjava.KeyRange.lessThan;
import static org.lmdbjava.KeyRange.lessThanBackward;
import static org.lmdbjava.KeyRange.open;
import static org.lmdbjava.KeyRange.openBackward;
import static org.lmdbjava.KeyRange.openClosed;
import static org.lmdbjava.KeyRange.openClosedBackward;
import static org.lmdbjava.PutFlags.MDB_NOOVERWRITE;
import static org.lmdbjava.TestUtils.DB_1;
import static org.lmdbjava.TestUtils.POSIX_MODE;
import static org.lmdbjava.TestUtils.bb;
import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Deque;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.NoSuchElementException;
import com.google.common.primitives.UnsignedBytes;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.lmdbjava.CursorIterable.KeyVal;
        .setMaxDbs(1)
        .open(path, POSIX_MODE, MDB_NOSUBDIR);
    db = env.openDbi(DB_1, MDB_CREATE);
    list = new LinkedList<>();
    list.addAll(asList(2, 3, 4, 5, 6, 7, 8, 9));
    try (Txn<ByteBuffer> txn = env.txnWrite()) {
      final Cursor<ByteBuffer> c = db.openCursor(txn);
      c.put(bb(2), bb(3), MDB_NOOVERWRITE);
      c.put(bb(4), bb(5));
      c.put(bb(6), bb(7));
      c.put(bb(8), bb(9));
      txn.commit();
    }
  }

  @Test
  public void closedBackwardTest() {
    verify(closedBackward(bb(7), bb(3)), 6, 4);
    verify(closedBackward(bb(6), bb(2)), 6, 4, 2);
    verify(closedBackward(bb(9), bb(3)), 8, 6, 4);
  }

  @Test
  public void closedOpenBackwardTest() {
    verify(closedOpenBackward(bb(8), bb(3)), 8, 6, 4);
    verify(closedOpenBackward(bb(7), bb(2)), 6, 4);
    verify(closedOpenBackward(bb(9), bb(3)), 8, 6, 4);
  }

  @Test
  public void closedOpenTest() {
    verify(closedOpen(bb(3), bb(8)), 4, 6);
    verify(closedOpen(bb(2), bb(6)), 2, 4);
  }

  @Test
  public void closedTest() {
    verify(closed(bb(3), bb(7)), 4, 6);
    verify(closed(bb(2), bb(6)), 2, 4, 6);
    verify(closed(bb(1), bb(7)), 2, 4, 6);
  }

  @Test
  public void greaterThanBackwardTest() {
    verify(greaterThanBackward(bb(6)), 4, 2);
    verify(greaterThanBackward(bb(7)), 6, 4, 2);
    verify(greaterThanBackward(bb(9)), 8, 6, 4, 2);
  }

  @Test
  public void greaterThanTest() {
    verify(greaterThan(bb(4)), 6, 8);
    verify(greaterThan(bb(3)), 4, 6, 8);
  }

  @Test(expected = IllegalStateException.class)
  public void iterableOnlyReturnedOnce() {
    try (Txn<ByteBuffer> txn = env.txnRead();
         CursorIterable<ByteBuffer> c = db.iterate(txn)) {
      c.iterator(); // ok
      c.iterator(); // fails
    }
  }

  @Test
  public void iterate() {
    try (Txn<ByteBuffer> txn = env.txnRead();
         CursorIterable<ByteBuffer> c = db.iterate(txn)) {
      for (final KeyVal<ByteBuffer> kv : c) {
        assertThat(kv.key().getInt(), is(list.pollFirst()));
        assertThat(kv.val().getInt(), is(list.pollFirst()));
      }
    }
  }

  @Test(expected = IllegalStateException.class)
  public void iteratorOnlyReturnedOnce() {
    try (Txn<ByteBuffer> txn = env.txnRead();
         CursorIterable<ByteBuffer> c = db.iterate(txn)) {
      c.iterator(); // ok
      c.iterator(); // fails
    }
  }

  @Test
  public void lessThanBackwardTest() {
    verify(lessThanBackward(bb(5)), 8, 6);
    verify(lessThanBackward(bb(2)), 8, 6, 4);
  }

  @Test
  public void lessThanTest() {
    verify(lessThan(bb(5)), 2, 4);
    verify(lessThan(bb(8)), 2, 4, 6);
  }

  @Test(expected = NoSuchElementException.class)
  public void nextThrowsNoSuchElementExceptionIfNoMoreElements() {
    try (Txn<ByteBuffer> txn = env.txnRead();
         CursorIterable<ByteBuffer> c = db.iterate(txn)) {
      final Iterator<KeyVal<ByteBuffer>> i = c.iterator();
      while (i.hasNext()) {
        final KeyVal<ByteBuffer> kv = i.next();
        assertThat(kv.key().getInt(), is(list.pollFirst()));
        assertThat(kv.val().getInt(), is(list.pollFirst()));
      }
      assertThat(i.hasNext(), is(false));
      i.next();
    }
  }

  @Test
  public void openBackwardTest() {
    verify(openBackward(bb(7), bb(2)), 6, 4);
    verify(openBackward(bb(8), bb(1)), 6, 4, 2);
    verify(openBackward(bb(9), bb(4)), 8, 6);
  }

  @Test
  public void openClosedBackwardTest() {
    verify(openClosedBackward(bb(7), bb(2)), 6, 4, 2);