org.jsimpledb.kv.util.KVNavigableSet Maven / Gradle / Ivy
/*
* Copyright (C) 2015 Archie L. Cobbs. All rights reserved.
*/
package org.jsimpledb.kv.util;
import com.google.common.base.Preconditions;
import java.util.Collections;
import java.util.Comparator;
import java.util.NavigableSet;
import org.jsimpledb.kv.KVStore;
import org.jsimpledb.kv.KeyFilter;
import org.jsimpledb.kv.KeyRange;
import org.jsimpledb.util.Bounds;
import org.jsimpledb.util.ByteReader;
import org.jsimpledb.util.ByteUtil;
import org.jsimpledb.util.ByteWriter;
/**
* A {@link java.util.NavigableSet} view of the keys in a {@link KVStore}.
*
*
* Instances are mutable, with these exceptions:
*
* - Adding new elements via {@link #add add()} is not supported
* - {@link #clear} is not supported when a {@link KeyFilter} is configured
*
*/
@SuppressWarnings("serial")
public class KVNavigableSet extends AbstractKVNavigableSet {
// Constructors
/**
* Constructor for when there are no range restrictions.
*
* @param kv underlying {@link KVStore}
*/
public KVNavigableSet(KVStore kv) {
this(kv, false, null, null);
}
/**
* Constructor for when the range of visible {@link KVStore} keys is all keys sharing a given {@code byte[]} prefix.
*
* @param kv underlying {@link KVStore}
* @param prefix prefix defining minimum and maximum keys
* @throws NullPointerException if {@code prefix} is null
*/
public KVNavigableSet(KVStore kv, byte[] prefix) {
this(kv, false, KeyRange.forPrefix(prefix), null);
}
/**
* Primary constructor.
*
* @param kv underlying {@link KVStore}
* @param reversed whether ordering is reversed
* @param keyRange key range restriction, or null for none
* @param keyFilter key filter, or null for none
* @throws IllegalArgumentException if {@code kv} is null
*/
protected KVNavigableSet(KVStore kv, boolean reversed, KeyRange keyRange, KeyFilter keyFilter) {
this(kv, reversed, keyRange, keyFilter, KVNavigableSet.createBounds(keyRange));
}
/**
* Internal constructor. Used for creating sub-sets and reversed views.
*
* @param kv underlying {@link KVStore}
* @param reversed whether ordering is reversed (implies {@code bounds} are also inverted)
* @param keyRange key range restriction, or null for none
* @param keyFilter key filter, or null for none
* @param bounds range restriction
* @throws IllegalArgumentException if {@code kv} or {@code bounds} is null
*/
private KVNavigableSet(KVStore kv, boolean reversed, KeyRange keyRange, KeyFilter keyFilter, Bounds bounds) {
super(kv, false, reversed, keyRange, keyFilter, bounds);
}
// Methods
@Override
public Comparator comparator() {
return this.reversed ? Collections.reverseOrder(ByteUtil.COMPARATOR) : ByteUtil.COMPARATOR;
}
@Override
public boolean remove(Object obj) {
if (!(obj instanceof byte[]))
return false;
final byte[] key = (byte[])obj;
if (!this.isVisible(key))
return false;
final byte[] value = this.kv.get(key);
if (value == null)
return false;
this.kv.remove(key);
return true;
}
@Override
public void clear() {
if (this.keyFilter != null)
throw new UnsupportedOperationException("clear() not supported when KeyFilter configured");
final byte[] minKey = this.keyRange != null ? this.keyRange.getMin() : null;
final byte[] maxKey = this.keyRange != null ? this.keyRange.getMax() : null;
this.kv.removeRange(minKey, maxKey);
return;
}
@Override
protected void encode(ByteWriter writer, Object obj) {
Preconditions.checkArgument(obj instanceof byte[], "value is not a byte[]");
writer.write((byte[])obj);
}
@Override
protected byte[] decode(ByteReader reader) {
return reader.getBytes();
}
@Override
protected NavigableSet createSubSet(boolean newReversed,
KeyRange newKeyRange, KeyFilter newKeyFilter, Bounds newBounds) {
return new KVNavigableSet(this.kv, newReversed, newKeyRange, newKeyFilter, newBounds);
}
static Bounds createBounds(KeyRange keyRange) {
return keyRange != null ? new Bounds(keyRange.getMin(), keyRange.getMax()) : new Bounds();
}
}