diff --git a/core/java/src/net/i2p/client/naming/BlockfileNamingService.java b/core/java/src/net/i2p/client/naming/BlockfileNamingService.java index 6627a1be4125e944562f4d0ca1b74c65264acaae..067f4e0d726018d27509f6d043db5938b035226b 100644 --- a/core/java/src/net/i2p/client/naming/BlockfileNamingService.java +++ b/core/java/src/net/i2p/client/naming/BlockfileNamingService.java @@ -105,13 +105,13 @@ public class BlockfileNamingService extends DummyNamingService { private String _version = "0"; private boolean _needsUpgrade; - private static final Serializer _infoSerializer = new PropertiesSerializer(); - private static final Serializer _stringSerializer = new UTF8StringBytes(); - private static final Serializer _destSerializerV1 = new DestEntrySerializer(); - private static final Serializer _destSerializerV4 = new DestEntrySerializerV4(); + private static final Serializer<Properties> _infoSerializer = new PropertiesSerializer(); + private static final Serializer<String> _stringSerializer = new UTF8StringBytes(); + private static final Serializer<DestEntry> _destSerializerV1 = new DestEntrySerializer(); + private static final Serializer<DestEntry> _destSerializerV4 = new DestEntrySerializerV4(); // upgrade(), initExisting(), and initNew() will change this to _destSerializerV4 - private volatile Serializer _destSerializer = _destSerializerV1; - private static final Serializer _hashIndexSerializer = new IntBytes(); + private volatile Serializer<DestEntry> _destSerializer = _destSerializerV1; + private static final Serializer<Integer> _hashIndexSerializer = new IntBytes(); private static final String HOSTS_DB = "hostsdb.blockfile"; private static final String FALLBACK_LIST = "hosts.txt"; @@ -1402,14 +1402,13 @@ public class BlockfileNamingService extends DummyNamingService { * but if we threw a RuntimeException we would prevent access to entries later in * the SkipSpan. */ - private static class DestEntrySerializer implements Serializer { + private static class DestEntrySerializer implements Serializer<DestEntry> { /** * A format error on the properties is non-fatal (only the properties are lost) * A format error on the destination is fatal */ - public byte[] getBytes(Object o) { - DestEntry de = (DestEntry) o; + public byte[] getBytes(DestEntry de) { ByteArrayOutputStream baos = new ByteArrayOutputStream(1024); try { try { @@ -1429,7 +1428,7 @@ public class BlockfileNamingService extends DummyNamingService { } /** returns null on error */ - public Object construct(byte[] b) { + public DestEntry construct(byte[] b) { DestEntry rv = new DestEntry(); ByteArrayInputStream bais = new ByteArrayInputStream(b); try { @@ -1452,10 +1451,9 @@ public class BlockfileNamingService extends DummyNamingService { * For multiple destinations per hostname * @since 0.9.26 */ - private static class DestEntrySerializerV4 implements Serializer { + private static class DestEntrySerializerV4 implements Serializer<DestEntry> { - public byte[] getBytes(Object o) { - DestEntry de = (DestEntry) o; + public byte[] getBytes(DestEntry de) { ByteArrayOutputStream baos = new ByteArrayOutputStream(1024); int sz = de.destList != null ? de.destList.size() : 1; try { @@ -1487,7 +1485,7 @@ public class BlockfileNamingService extends DummyNamingService { } /** returns null on error */ - public Object construct(byte[] b) { + public DestEntry construct(byte[] b) { DestEntry rv = new DestEntry(); ByteArrayInputStream bais = new ByteArrayInputStream(b); try { diff --git a/core/java/src/net/metanotion/io/Serializer.java b/core/java/src/net/metanotion/io/Serializer.java index 40cab225524ed172b9d3ca55b00fb1aa30cbf011..44e3cf74a42a47c12fee765b1b01dd8aa9f7a607 100644 --- a/core/java/src/net/metanotion/io/Serializer.java +++ b/core/java/src/net/metanotion/io/Serializer.java @@ -28,7 +28,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package net.metanotion.io; -public interface Serializer { - public byte[] getBytes(Object o); - public Object construct(byte[] b); +public interface Serializer<T> { + public byte[] getBytes(T o); + public T construct(byte[] b); } diff --git a/core/java/src/net/metanotion/io/block/BlockFile.java b/core/java/src/net/metanotion/io/block/BlockFile.java index 5e1b4339953d953ca780241b33f6682b5e77e65c..b220a87f059c8276e8bf6f71d22845a655af4175 100644 --- a/core/java/src/net/metanotion/io/block/BlockFile.java +++ b/core/java/src/net/metanotion/io/block/BlockFile.java @@ -96,7 +96,7 @@ public class BlockFile implements Closeable { /** I2P was the file locked when we opened it? */ private final boolean _wasMounted; - private final BSkipList metaIndex; + private final BSkipList<String, Integer> metaIndex; private boolean _isClosed; /** cached list of free pages, only valid if freListStart > 0 */ private FreeListBlock flb; @@ -322,7 +322,7 @@ public class BlockFile implements Closeable { if (rai.canWrite()) mount(); - metaIndex = new BSkipList(spanSize, this, METAINDEX_PAGE, new StringBytes(), new IntBytes()); + metaIndex = new BSkipList<String, Integer>(spanSize, this, METAINDEX_PAGE, new StringBytes(), new IntBytes()); } /** @@ -442,15 +442,15 @@ public class BlockFile implements Closeable { * * @return null if not found */ - public BSkipList getIndex(String name, Serializer key, Serializer val) throws IOException { + public <K extends Comparable<? super K>, V> BSkipList<K, V> getIndex(String name, Serializer<K> key, Serializer<V> val) throws IOException { // added I2P - BSkipList bsl = openIndices.get(name); + BSkipList<K, V> bsl = (BSkipList<K, V>) openIndices.get(name); if (bsl != null) return bsl; - Integer page = (Integer) metaIndex.get(name); + Integer page = metaIndex.get(name); if (page == null) { return null; } - bsl = new BSkipList(spanSize, this, page.intValue(), key, val, true); + bsl = new BSkipList<K, V>(spanSize, this, page.intValue(), key, val, true); if (file.canWrite()) { log.info("Checking skiplist " + name + " in blockfile " + file); if (bsl.bslck(true, false)) @@ -468,12 +468,12 @@ public class BlockFile implements Closeable { * * @throws IOException if already exists or other errors */ - public BSkipList makeIndex(String name, Serializer key, Serializer val) throws IOException { + public <K extends Comparable<? super K>, V> BSkipList<K, V> makeIndex(String name, Serializer<K> key, Serializer<V> val) throws IOException { if(metaIndex.get(name) != null) { throw new IOException("Index already exists"); } int page = allocPage(); metaIndex.put(name, Integer.valueOf(page)); BSkipList.init(this, page, spanSize); - BSkipList bsl = new BSkipList(spanSize, this, page, key, val, true); + BSkipList<K, V> bsl = new BSkipList<K, V>(spanSize, this, page, key, val, true); openIndices.put(name, bsl); return bsl; } @@ -516,24 +516,24 @@ public class BlockFile implements Closeable { * @throws IOException if it is open or on errors * @since 0.9.26 */ - public void reformatIndex(String name, Serializer oldKey, Serializer oldVal, - Serializer newKey, Serializer newVal) throws IOException { + public <K extends Comparable<? super K>, V> void reformatIndex(String name, Serializer<K> oldKey, Serializer<V> oldVal, + Serializer<K> newKey, Serializer<V> newVal) throws IOException { if (openIndices.containsKey(name)) throw new IOException("Cannot reformat open skiplist " + name); - BSkipList old = getIndex(name, oldKey, oldVal); + BSkipList<K, V> old = getIndex(name, oldKey, oldVal); if (old == null) return; long start = System.currentTimeMillis(); String tmpName = "---tmp---" + name + "---tmp---"; - BSkipList tmp = makeIndex(tmpName, newKey, newVal); + BSkipList<K, V> tmp = makeIndex(tmpName, newKey, newVal); // It could be much more efficient to do this at the // SkipSpan layer but that's way too hard. final int loop = 32; - List<Comparable> keys = new ArrayList<Comparable>(loop); - List<Object> vals = new ArrayList<Object>(loop); + List<K> keys = new ArrayList<K>(loop); + List<V> vals = new ArrayList<V>(loop); while (true) { - SkipIterator iter = old.iterator(); + SkipIterator<K, V> iter = old.iterator(); for (int i = 0; iter.hasNext() && i < loop; i++) { keys.add(iter.nextKey()); vals.add(iter.next()); @@ -555,7 +555,7 @@ public class BlockFile implements Closeable { delIndex(name); closeIndex(name); closeIndex(tmpName); - Integer page = (Integer) metaIndex.get(tmpName); + Integer page = metaIndex.get(tmpName); metaIndex.put(name, page); metaIndex.remove(tmpName); if (log.shouldWarn()) @@ -623,9 +623,15 @@ public class BlockFile implements Closeable { try { // This uses IdentityBytes, so the value class won't be right, but at least // it won't fail the out-of-order check - Serializer keyser = slname.equals("%%__REVERSE__%%") ? new IntBytes() : new UTF8StringBytes(); - BSkipList bsl = getIndex(slname, keyser, new IdentityBytes()); - if (bsl == null) { + boolean fail; + if (slname.equals("%%__REVERSE__%%")) { + Serializer<Integer> keyser = new IntBytes(); + fail = getIndex(slname, keyser, new IdentityBytes()) == null; + } else { + Serializer<String> keyser = new UTF8StringBytes(); + fail = getIndex(slname, keyser, new IdentityBytes()) == null; + } + if (fail) { log.error("Can't find list? " + slname); continue; } diff --git a/core/java/src/net/metanotion/io/block/index/BSkipLevels.java b/core/java/src/net/metanotion/io/block/index/BSkipLevels.java index dcf5f38dd0ba7019c79a7d054c33256f6cffc90e..5785c2ddadd2e66ee2feca047e1c5712a2bf765d 100644 --- a/core/java/src/net/metanotion/io/block/index/BSkipLevels.java +++ b/core/java/src/net/metanotion/io/block/index/BSkipLevels.java @@ -55,13 +55,13 @@ import net.i2p.util.Log; * * Always fits on one page. */ -public class BSkipLevels extends SkipLevels { +public class BSkipLevels<K extends Comparable<? super K>, V> extends SkipLevels<K, V> { private static final long MAGIC = 0x42534c6576656c73l; // "BSLevels" static final int HEADER_LEN = 16; public final int levelPage; public final int spanPage; public final BlockFile bf; - private final BSkipList bsl; + private final BSkipList<K, V> bsl; private boolean isKilled; // the level pages, passed from the constructor to initializeLevels(), // NOT kept up to date @@ -73,7 +73,7 @@ public class BSkipLevels extends SkipLevels { * after the constructor, unless it's a new empty * level and init() was previously called. */ - public BSkipLevels(BlockFile bf, int levelPage, BSkipList bsl) throws IOException { + public BSkipLevels(BlockFile bf, int levelPage, BSkipList<K, V> bsl) throws IOException { this.levelPage = levelPage; this.bf = bf; this.bsl = bsl; @@ -97,7 +97,7 @@ public class BSkipLevels extends SkipLevels { throw new IOException("No span found in cache???"); } - this.levels = new BSkipLevels[maxLen]; + this.levels = (BSkipLevels<K, V>[]) new BSkipLevels[maxLen]; if (bf.log.shouldLog(Log.DEBUG)) bf.log.debug("Reading New BSkipLevels with " + nonNull + " / " + maxLen + " valid levels page " + levelPage + " in skiplist " + bsl); @@ -118,14 +118,14 @@ public class BSkipLevels extends SkipLevels { * @since 0.9.20 */ public void initializeLevels() { - List<BSkipLevels> toInit = new ArrayList<BSkipLevels>(32); - List<BSkipLevels> nextInit = new ArrayList<BSkipLevels>(32); + List<BSkipLevels<K, V>> toInit = new ArrayList<BSkipLevels<K, V>>(32); + List<BSkipLevels<K, V>> nextInit = new ArrayList<BSkipLevels<K, V>>(32); initializeLevels(toInit); while (!toInit.isEmpty()) { - for (BSkipLevels bsl : toInit) { + for (BSkipLevels<K, V> bsl : toInit) { bsl.initializeLevels(nextInit); } - List<BSkipLevels> tmp = toInit; + List<BSkipLevels<K, V>> tmp = toInit; toInit = nextInit; nextInit = tmp; nextInit.clear(); @@ -139,7 +139,7 @@ public class BSkipLevels extends SkipLevels { * @param nextInit out parameter, next levels to initialize * @since 0.9.20 */ - private void initializeLevels(List<BSkipLevels> nextInit) { + private void initializeLevels(List<BSkipLevels<K, V>> nextInit) { boolean fail = false; for(int i = 0; i < lps.length; i++) { int lp = lps[i]; @@ -147,7 +147,7 @@ public class BSkipLevels extends SkipLevels { levels[i] = bsl.levelHash.get(Integer.valueOf(lp)); if(levels[i] == null) { try { - BSkipLevels lev = new BSkipLevels(bf, lp, bsl); + BSkipLevels<K, V> lev = new BSkipLevels<K, V>(bf, lp, bsl); levels[i] = lev; nextInit.add(lev); } catch (IOException ioe) { @@ -158,8 +158,8 @@ public class BSkipLevels extends SkipLevels { continue; } } - Comparable ourKey = key(); - Comparable nextKey = levels[i].key(); + K ourKey = key(); + K nextKey = levels[i].key(); if (ourKey != null && nextKey != null && ourKey.compareTo(nextKey) >= 0) { bf.log.warn("Corrupt database, level out of order " + this + @@ -215,9 +215,9 @@ public class BSkipLevels extends SkipLevels { break; } bf.file.writeShort(i); - bf.file.writeInt(((BSkipSpan) bottom).page); + bf.file.writeInt(((BSkipSpan<K, V>) bottom).page); for(int j = 0; j < i; j++) { - bf.file.writeInt(((BSkipLevels) levels[j]).levelPage); + bf.file.writeInt(((BSkipLevels<K, V>) levels[j]).levelPage); } } catch (IOException ioe) { throw new RuntimeException("Error writing to database", ioe); } } @@ -236,15 +236,15 @@ public class BSkipLevels extends SkipLevels { } @Override - public SkipLevels newInstance(int levels, SkipSpan ss, SkipList sl) { + public SkipLevels<K, V> newInstance(int levels, SkipSpan<K, V> ss, SkipList<K, V> sl) { try { - BSkipSpan bss = (BSkipSpan) ss; - BSkipList bsl = (BSkipList) sl; + BSkipSpan<K, V> bss = (BSkipSpan<K, V>) ss; + BSkipList<K, V> bsl = (BSkipList<K, V>) sl; int page = bf.allocPage(); BSkipLevels.init(bf, page, bss.page, levels); if (bf.log.shouldLog(Log.DEBUG)) bf.log.debug("New BSkipLevels height " + levels + " page " + page); - return new BSkipLevels(bf, page, bsl); + return new BSkipLevels<K, V>(bf, page, bsl); // do not need to call initLevels() here } catch (IOException ioe) { throw new RuntimeException("Error creating database page", ioe); } } @@ -273,7 +273,7 @@ public class BSkipLevels extends SkipLevels { * @since 0.8.8 */ private boolean blvlfix() { - TreeSet<SkipLevels> lvls = new TreeSet<SkipLevels>(new LevelComparator()); + TreeSet<SkipLevels<K, V>> lvls = new TreeSet<SkipLevels<K, V>>(new LevelComparator<K, V>()); if (bf.log.shouldLog(Log.DEBUG)) bf.log.debug("Starting level search"); getAllLevels(this, lvls); @@ -285,15 +285,15 @@ public class BSkipLevels extends SkipLevels { } // traverse the levels, back-to-front boolean rv = false; - SkipLevels after = null; - for (SkipLevels lv : lvls) { + SkipLevels<K, V> after = null; + for (SkipLevels<K, V> lv : lvls) { boolean modified = false; if (bf.log.shouldLog(Log.DEBUG)) bf.log.debug("Checking " + lv.print()); if (after != null) { int min = Math.min(after.levels.length, lv.levels.length); for (int i = 0; i < min; i++) { - SkipLevels cur = lv.levels[i]; + SkipLevels<K, V> cur = lv.levels[i]; if (cur != after) { if (cur != null) bf.log.warn("Level " + i + " was wrong, fixing for " + lv.print()); @@ -331,12 +331,12 @@ public class BSkipLevels extends SkipLevels { * @param lvlSet out parameter, the result * @since 0.8.8 */ - private void getAllLevels(SkipLevels l, Set<SkipLevels> lvlSet) { + private void getAllLevels(SkipLevels<K, V> l, Set<SkipLevels<K, V>> lvlSet) { if (bf.log.shouldLog(Log.DEBUG)) bf.log.debug("GAL " + l.print()); // Do level 0 without recursion, on the assumption everything is findable // from the root - SkipLevels cur = l; + SkipLevels<K, V> cur = l; while (cur != null && lvlSet.add(cur)) { if (bf.log.shouldLog(Log.DEBUG)) bf.log.debug("Adding " + cur.print()); @@ -347,7 +347,7 @@ public class BSkipLevels extends SkipLevels { // If there were no nulls at level 0 in the middle, // i.e. there are no problems, this won't find anything for (int i = 1; i < l.levels.length; i++) { - SkipLevels lv = l.levels[i]; + SkipLevels<K, V> lv = l.levels[i]; if (lv != null && !lvlSet.contains(lv)) getAllLevels(lv, lvlSet); } @@ -358,10 +358,10 @@ public class BSkipLevels extends SkipLevels { * Sorts in REVERSE order. * @since 0.8.8 */ - private static class LevelComparator implements Comparator<SkipLevels>, Serializable { - public int compare(SkipLevels l, SkipLevels r) { - Comparable lk = l.key(); - Comparable rk = r.key(); + private static class LevelComparator<K extends Comparable<? super K>, V> implements Comparator<SkipLevels<K, V>>, Serializable { + public int compare(SkipLevels<K, V> l, SkipLevels<K, V> r) { + K lk = l.key(); + K rk = r.key(); if (lk == null && rk == null) return 0; if (lk == null) @@ -378,13 +378,13 @@ public class BSkipLevels extends SkipLevels { * This needs work. */ @Override - public boolean blvlck(boolean fix, int width, SkipLevels[] prevLevels) { + public boolean blvlck(boolean fix, int width, SkipLevels<K, V>[] prevLevels) { bf.log.warn(" Skip level at width " + width); bf.log.warn(" levels " + this.levels.length); bf.log.warn(" first key " + this.key()); bf.log.warn(" spanPage " + this.spanPage); bf.log.warn(" levelPage " + this.levelPage); - SkipLevels higher = null; + SkipLevels<K, V> higher = null; for (int i = levels.length - 1; i >= 0; i--) { if (levels[i] != null) { bf.log.info(" level " + i + " -> " + levels[i].key() + " "); @@ -418,7 +418,7 @@ public class BSkipLevels extends SkipLevels { } } } else { - prevLevels = new SkipLevels[levels.length]; + prevLevels = (SkipLevels<K, V>[]) new SkipLevels[levels.length]; System.arraycopy(levels, 0, prevLevels, 0, levels.length); } if (levels[0] != null) diff --git a/core/java/src/net/metanotion/io/block/index/BSkipList.java b/core/java/src/net/metanotion/io/block/index/BSkipList.java index 71bc805353be8ec8874f566fdf7393bca36ee67a..12c0a3dc6c1933b6e76c45347c5b799f64791aa0 100644 --- a/core/java/src/net/metanotion/io/block/index/BSkipList.java +++ b/core/java/src/net/metanotion/io/block/index/BSkipList.java @@ -51,7 +51,7 @@ import net.i2p.util.Log; * * Always fits on one page. */ -public class BSkipList extends SkipList implements Closeable { +public class BSkipList<K extends Comparable<? super K>, V> extends SkipList<K, V> implements Closeable { private static final long MAGIC = 0x536b69704c697374l; // "SkipList" public int firstSpanPage = 0; public int firstLevelPage = 0; @@ -59,16 +59,16 @@ public class BSkipList extends SkipList implements Closeable { public final BlockFile bf; private boolean isClosed; - final HashMap<Integer, BSkipSpan> spanHash = new HashMap<Integer, BSkipSpan>(); - final HashMap<Integer, SkipLevels> levelHash = new HashMap<Integer, SkipLevels>(); + final HashMap<Integer, BSkipSpan<K, V>> spanHash = new HashMap<Integer, BSkipSpan<K, V>>(); + final HashMap<Integer, SkipLevels<K, V>> levelHash = new HashMap<Integer, SkipLevels<K, V>>(); private final boolean fileOnly; - public BSkipList(int spanSize, BlockFile bf, int skipPage, Serializer key, Serializer val) throws IOException { + public BSkipList(int spanSize, BlockFile bf, int skipPage, Serializer<K> key, Serializer<V> val) throws IOException { this(spanSize, bf, skipPage, key, val, false); } - public BSkipList(int spanSize, BlockFile bf, int skipPage, Serializer key, Serializer val, boolean fileOnly) throws IOException { + public BSkipList(int spanSize, BlockFile bf, int skipPage, Serializer<K> key, Serializer<V> val, boolean fileOnly) throws IOException { if(spanSize < 1) { throw new RuntimeException("Span size too small"); } this.skipPage = skipPage; @@ -89,10 +89,10 @@ public class BSkipList extends SkipList implements Closeable { this.fileOnly = fileOnly; if (fileOnly) - first = new IBSkipSpan(bf, this, firstSpanPage, key, val); + first = new IBSkipSpan<K, V>(bf, this, firstSpanPage, key, val); else - first = new BSkipSpan(bf, this, firstSpanPage, key, val); - BSkipLevels bstack = new BSkipLevels(bf, firstLevelPage, this); + first = new BSkipSpan<K, V>(bf, this, firstSpanPage, key, val); + BSkipLevels<K, V> bstack = new BSkipLevels<K, V>(bf, firstLevelPage, this); bstack.initializeLevels(); stack = bstack; int total = 0; @@ -199,33 +199,33 @@ public class BSkipList extends SkipList implements Closeable { } @Override - public SkipIterator iterator() { + public SkipIterator<K, V> iterator() { if (!this.fileOnly) return super.iterator(); - return new IBSkipIterator(first, 0); + return new IBSkipIterator<K, V>(first, 0); } @Override - public SkipIterator min() { + public SkipIterator<K, V> min() { return iterator(); } @Override - public SkipIterator max() { + public SkipIterator<K, V> max() { if (!this.fileOnly) return super.max(); - SkipSpan ss = stack.getEnd(); - return new IBSkipIterator(ss, ss.nKeys - 1); + SkipSpan<K, V> ss = stack.getEnd(); + return new IBSkipIterator<K, V>(ss, ss.nKeys - 1); } @Override - public SkipIterator find(Comparable key) { + public SkipIterator<K, V> find(K key) { if (!this.fileOnly) return super.find(key); int[] search = new int[1]; - SkipSpan ss = stack.getSpan(stack.levels.length - 1, key, search); + SkipSpan<K, V> ss = stack.getSpan(stack.levels.length - 1, key, search); if(search[0] < 0) { search[0] = -1 * (search[0] + 1); } - return new IBSkipIterator(ss, search[0]); + return new IBSkipIterator<K, V>(ss, search[0]); } /** diff --git a/core/java/src/net/metanotion/io/block/index/BSkipSpan.java b/core/java/src/net/metanotion/io/block/index/BSkipSpan.java index 551bdca8864a39479a97037ad8ad6fdaa6470a3a..6b975e5d33e2109ebab58093027151d89b3de394 100644 --- a/core/java/src/net/metanotion/io/block/index/BSkipSpan.java +++ b/core/java/src/net/metanotion/io/block/index/BSkipSpan.java @@ -59,19 +59,19 @@ import net.i2p.util.Log; * next overflow page (unsigned int) *</pre> */ -public class BSkipSpan extends SkipSpan { +public class BSkipSpan<K extends Comparable<? super K>, V> extends SkipSpan<K, V> { protected static final int MAGIC = 0x5370616e; // "Span" protected static final int HEADER_LEN = 20; public static final int CONT_HEADER_LEN = 8; protected final BlockFile bf; - private final BSkipList bsl; + private final BSkipList<K, V> bsl; protected int page; protected int overflowPage; protected int prevPage; protected int nextPage = 0; - protected Serializer keySer; - protected Serializer valSer; + protected Serializer<K> keySer; + protected Serializer<V> valSer; // I2P protected int spanSize; @@ -88,11 +88,11 @@ public class BSkipSpan extends SkipSpan { } @Override - public SkipSpan newInstance(SkipList sl) { + public SkipSpan<K, V> newInstance(SkipList<K, V> sl) { try { int newPage = bf.allocPage(); init(bf, newPage, bf.spanSize); - return new BSkipSpan(bf, (BSkipList) sl, newPage, keySer, valSer); + return new BSkipSpan<K, V>(bf, (BSkipList<K, V>) sl, newPage, keySer, valSer); } catch (IOException ioe) { throw new RuntimeException("Error creating database page", ioe); } } @@ -237,7 +237,8 @@ public class BSkipSpan extends SkipSpan { //bsl.flush(); } - private static void load(BSkipSpan bss, BlockFile bf, BSkipList bsl, int spanPage, Serializer key, Serializer val) throws IOException { + private static <X extends Comparable<? super X>, Y> void load(BSkipSpan<X, Y> bss, BlockFile bf, BSkipList<X, Y> bsl, + int spanPage, Serializer<X> key, Serializer<Y> val) throws IOException { loadInit(bss, bf, bsl, spanPage, key, val); bss.loadData(); } @@ -246,7 +247,8 @@ public class BSkipSpan extends SkipSpan { * I2P - first half of load() * Only read the span headers */ - protected static void loadInit(BSkipSpan bss, BlockFile bf, BSkipList bsl, int spanPage, Serializer key, Serializer val) throws IOException { + protected static <X extends Comparable<? super X>, Y> void loadInit(BSkipSpan<X, Y> bss, BlockFile bf, BSkipList<X, Y> bsl, + int spanPage, Serializer<X> key, Serializer<Y> val) throws IOException { if (bss.isKilled) throw new IOException("Already killed!! " + bss); bss.page = spanPage; @@ -288,8 +290,8 @@ public class BSkipSpan extends SkipSpan { protected void loadData(boolean flushOnError) throws IOException { if (isKilled) throw new IOException("Already killed!! " + this); - this.keys = new Comparable[this.spanSize]; - this.vals = new Object[this.spanSize]; + this.keys = (K[]) new Comparable[this.spanSize]; + this.vals = (V[]) new Object[this.spanSize]; int ksz, vsz; int curPage = this.page; @@ -327,7 +329,7 @@ public class BSkipSpan extends SkipSpan { break; } // System.out.println("i=" + i + ", Page " + curPage + ", offset " + pageCounter[0] + " ksz " + ksz + " vsz " + vsz); - this.keys[i] = (Comparable) this.keySer.construct(k); + this.keys[i] = this.keySer.construct(k); this.vals[i] = this.valSer.construct(v); // Drop bad entry without throwing exception if (this.keys[i] == null || this.vals[i] == null) { @@ -377,31 +379,31 @@ public class BSkipSpan extends SkipSpan { } } - protected BSkipSpan(BlockFile bf, BSkipList bsl) { + protected BSkipSpan(BlockFile bf, BSkipList<K, V> bsl) { this.bf = bf; this.bsl = bsl; } - public BSkipSpan(BlockFile bf, BSkipList bsl, int spanPage, Serializer key, Serializer val) throws IOException { + public BSkipSpan(BlockFile bf, BSkipList<K, V> bsl, int spanPage, Serializer<K> key, Serializer<V> val) throws IOException { this.bf = bf; this.bsl = bsl; BSkipSpan.load(this, bf, bsl, spanPage, key, val); this.next = null; this.prev = null; - BSkipSpan bss = this; + BSkipSpan<K, V> bss = this; // findbugs ok (set in load() above) int np = nextPage; while(np != 0) { - BSkipSpan temp = bsl.spanHash.get(Integer.valueOf(np)); + BSkipSpan<K, V> temp = bsl.spanHash.get(Integer.valueOf(np)); if(temp != null) { bss.next = temp; break; } - bss.next = new BSkipSpan(bf, bsl); + bss.next = new BSkipSpan<K, V>(bf, bsl); bss.next.next = null; bss.next.prev = bss; - bss = (BSkipSpan) bss.next; + bss = (BSkipSpan<K, V>) bss.next; BSkipSpan.load(bss, bf, bsl, np, key, val); np = bss.nextPage; @@ -411,15 +413,15 @@ public class BSkipSpan extends SkipSpan { bss = this; np = prevPage; while(np != 0) { - BSkipSpan temp = bsl.spanHash.get(Integer.valueOf(np)); + BSkipSpan<K, V> temp = bsl.spanHash.get(Integer.valueOf(np)); if(temp != null) { bss.prev = temp; break; } - bss.prev = new BSkipSpan(bf, bsl); + bss.prev = new BSkipSpan<K, V>(bf, bsl); bss.prev.next = bss; bss.prev.prev = null; - bss = (BSkipSpan) bss.prev; + bss = (BSkipSpan<K, V>) bss.prev; BSkipSpan.load(bss, bf, bsl, np, key, val); np = bss.prevPage; diff --git a/core/java/src/net/metanotion/io/block/index/IBSkipIterator.java b/core/java/src/net/metanotion/io/block/index/IBSkipIterator.java index 732862e3b31f8758f89da37ab5f24c7972ad2087..1623b192acbffaab4fc8ff3866f5ca59ab478017 100644 --- a/core/java/src/net/metanotion/io/block/index/IBSkipIterator.java +++ b/core/java/src/net/metanotion/io/block/index/IBSkipIterator.java @@ -41,9 +41,9 @@ import net.metanotion.util.skiplist.SkipSpan; If the caller does not iterate all the way through, the last span will remain in memory. */ -public class IBSkipIterator extends SkipIterator { +public class IBSkipIterator<K extends Comparable<? super K>, V> extends SkipIterator<K, V> { - public IBSkipIterator(SkipSpan ss, int index) { + public IBSkipIterator(SkipSpan<K, V> ss, int index) { super(ss, index); } @@ -53,8 +53,8 @@ public class IBSkipIterator extends SkipIterator { * @throws RuntimeException on IOE */ @Override - public Object next() { - Object o; + public V next() { + V o; if(index < ss.nKeys) { if (ss.vals == null) { try { @@ -90,7 +90,7 @@ public class IBSkipIterator extends SkipIterator { * @throws RuntimeException on IOE */ @Override - public Comparable nextKey() { + public K nextKey() { if(index < ss.nKeys) { if (ss.keys == null) { try { @@ -110,7 +110,7 @@ public class IBSkipIterator extends SkipIterator { * @throws RuntimeException on IOE */ @Override - public Object previous() { + public V previous() { if(index > 0) { index--; } else if(ss.prev != null) { diff --git a/core/java/src/net/metanotion/io/block/index/IBSkipSpan.java b/core/java/src/net/metanotion/io/block/index/IBSkipSpan.java index d5d33cf9688ee32252021c80d5179f515fc160cb..d7cc26ba4efbbfbf943db0017ed6fa2884946fc8 100644 --- a/core/java/src/net/metanotion/io/block/index/IBSkipSpan.java +++ b/core/java/src/net/metanotion/io/block/index/IBSkipSpan.java @@ -54,21 +54,21 @@ import net.i2p.util.Log; * * @author zzz */ -public class IBSkipSpan extends BSkipSpan { +public class IBSkipSpan<K extends Comparable<? super K>, V> extends BSkipSpan<K, V> { - private Comparable firstKey; + private K firstKey; @Override - public SkipSpan newInstance(SkipList sl) { + public SkipSpan<K, V> newInstance(SkipList<K, V> sl) { if (bf.log.shouldLog(Log.DEBUG)) bf.log.debug("Splitting page " + this.page + " containing " + this.nKeys + '/' + this.spanSize); try { int newPage = bf.allocPage(); init(bf, newPage, bf.spanSize); - SkipSpan rv = new IBSkipSpan(bf, (BSkipList) sl, newPage, keySer, valSer); + SkipSpan<K, V> rv = new IBSkipSpan<K, V>(bf, (BSkipList<K, V>) sl, newPage, keySer, valSer); // this is called after a split, so we need the data arrays initialized - rv.keys = new Comparable[bf.spanSize]; - rv.vals = new Object[bf.spanSize]; + rv.keys = (K[]) new Comparable[bf.spanSize]; + rv.vals = (V[]) new Object[bf.spanSize]; return rv; } catch (IOException ioe) { throw new RuntimeException("Error creating database page", ioe); } } @@ -125,7 +125,7 @@ public class IBSkipSpan extends BSkipSpan { pageCounter[0] +=4; byte[] k = new byte[ksz]; curPage = this.bf.readMultiPageData(k, curPage, pageCounter, curNextPage); - this.firstKey = (Comparable) this.keySer.construct(k); + this.firstKey = this.keySer.construct(k); if (this.firstKey == null) { bf.log.error("Null deserialized first key in page " + curPage); repair(1); @@ -160,7 +160,7 @@ public class IBSkipSpan extends BSkipSpan { /** * Linear search through the span in the file for the value. */ - private Object getData(Comparable key) throws IOException { + private V getData(K key) throws IOException { seekData(); int curPage = this.page; int[] curNextPage = new int[1]; @@ -194,7 +194,7 @@ public class IBSkipSpan extends BSkipSpan { break; } //System.out.println("i=" + i + ", Page " + curPage + ", offset " + pageCounter[0] + " ksz " + ksz + " vsz " + vsz); - Comparable ckey = (Comparable) this.keySer.construct(k); + K ckey = this.keySer.construct(k); if (ckey == null) { // skip the value and keep going curPage = this.bf.skipMultiPageBytes(vsz, curPage, pageCounter, curNextPage); @@ -213,7 +213,7 @@ public class IBSkipSpan extends BSkipSpan { lostEntries(i, curPage); break; } - Object rv = this.valSer.construct(v); + V rv = this.valSer.construct(v); if (rv == null) { bf.log.error("Null deserialized value in entry " + i + " page " + curPage + " key=" + ckey); @@ -252,11 +252,11 @@ public class IBSkipSpan extends BSkipSpan { *****/ } - private IBSkipSpan(BlockFile bf, BSkipList bsl) { + private IBSkipSpan(BlockFile bf, BSkipList<K, V> bsl) { super(bf, bsl); } - public IBSkipSpan(BlockFile bf, BSkipList bsl, int spanPage, Serializer key, Serializer val) throws IOException { + public IBSkipSpan(BlockFile bf, BSkipList<K, V> bsl, int spanPage, Serializer<K> key, Serializer<V> val) throws IOException { super(bf, bsl); if (bf.log.shouldLog(Log.DEBUG)) bf.log.debug("New ibss page " + spanPage); @@ -265,24 +265,24 @@ public class IBSkipSpan extends BSkipSpan { this.next = null; this.prev = null; - IBSkipSpan bss = this; - IBSkipSpan temp; + IBSkipSpan<K, V> bss = this; + IBSkipSpan<K, V> temp; int np = nextPage; while(np != 0) { - temp = (IBSkipSpan) bsl.spanHash.get(Integer.valueOf(np)); + temp = (IBSkipSpan<K, V>) bsl.spanHash.get(Integer.valueOf(np)); if(temp != null) { bss.next = temp; break; } - bss.next = new IBSkipSpan(bf, bsl); + bss.next = new IBSkipSpan<K, V>(bf, bsl); bss.next.next = null; bss.next.prev = bss; - Comparable previousFirstKey = bss.firstKey; - bss = (IBSkipSpan) bss.next; + K previousFirstKey = bss.firstKey; + bss = (IBSkipSpan<K, V>) bss.next; BSkipSpan.loadInit(bss, bf, bsl, np, key, val); bss.loadFirstKey(); - Comparable nextFirstKey = bss.firstKey; + K nextFirstKey = bss.firstKey; if (previousFirstKey == null || nextFirstKey == null || previousFirstKey.compareTo(nextFirstKey) >= 0) { // TODO remove, but if we are at the bottom of a level @@ -299,20 +299,20 @@ public class IBSkipSpan extends BSkipSpan { bss = this; np = prevPage; while(np != 0) { - temp = (IBSkipSpan) bsl.spanHash.get(Integer.valueOf(np)); + temp = (IBSkipSpan<K, V>) bsl.spanHash.get(Integer.valueOf(np)); if(temp != null) { bss.prev = temp; break; } - bss.prev = new IBSkipSpan(bf, bsl); + bss.prev = new IBSkipSpan<K, V>(bf, bsl); bss.prev.next = bss; bss.prev.prev = null; - Comparable nextFirstKey = bss.firstKey; - bss = (IBSkipSpan) bss.prev; + K nextFirstKey = bss.firstKey; + bss = (IBSkipSpan<K, V>) bss.prev; BSkipSpan.loadInit(bss, bf, bsl, np, key, val); bss.loadFirstKey(); - Comparable previousFirstKey = bss.firstKey; + K previousFirstKey = bss.firstKey; if (previousFirstKey == null || nextFirstKey == null || previousFirstKey.compareTo(nextFirstKey) >= 0) { // TODO remove, but if we are at the bottom of a level @@ -330,7 +330,7 @@ public class IBSkipSpan extends BSkipSpan { * Does not call super, we always store first key here */ @Override - public Comparable firstKey() { + public K firstKey() { return this.firstKey; } @@ -339,13 +339,13 @@ public class IBSkipSpan extends BSkipSpan { * This is called only via SkipList.find() */ @Override - public SkipSpan getSpan(Comparable key, int[] search) { + public SkipSpan<K, V> getSpan(K key, int[] search) { try { seekAndLoadData(); } catch (IOException ioe) { throw new RuntimeException("Error reading database", ioe); } - SkipSpan rv = super.getSpan(key, search); + SkipSpan<K, V> rv = super.getSpan(key, search); this.keys = null; this.vals = null; return rv; @@ -355,7 +355,7 @@ public class IBSkipSpan extends BSkipSpan { * Linear search if in file, Binary search if in memory */ @Override - public Object get(Comparable key) { + public V get(K key) { try { if (nKeys == 0) { return null; } if (this.next != null && this.next.firstKey().compareTo(key) <= 0) @@ -370,13 +370,13 @@ public class IBSkipSpan extends BSkipSpan { * Load whole span from file, do the operation, flush out, then null out in-memory data again. */ @Override - public SkipSpan put(Comparable key, Object val, SkipList sl) { + public SkipSpan<K, V> put(K key, V val, SkipList<K, V> sl) { try { seekAndLoadData(); } catch (IOException ioe) { throw new RuntimeException("Error reading database", ioe); } - SkipSpan rv = super.put(key, val, sl); + SkipSpan<K, V> rv = super.put(key, val, sl); // flush() nulls out the data return rv; } @@ -385,7 +385,7 @@ public class IBSkipSpan extends BSkipSpan { * Load whole span from file, do the operation, flush out, then null out in-memory data again. */ @Override - public Object[] remove(Comparable key, SkipList sl) { + public Object[] remove(K key, SkipList<K, V> sl) { if (bf.log.shouldLog(Log.DEBUG)) bf.log.debug("Remove " + key + " in " + this); if (nKeys <= 0) diff --git a/core/java/src/net/metanotion/io/data/IdentityBytes.java b/core/java/src/net/metanotion/io/data/IdentityBytes.java index 6e83c9b285c5f87d40e4d9ec4a37db38437f3fc1..9a6ef9a0edd6fce16fd81620ca78f1dca9c85046 100644 --- a/core/java/src/net/metanotion/io/data/IdentityBytes.java +++ b/core/java/src/net/metanotion/io/data/IdentityBytes.java @@ -35,11 +35,11 @@ import net.metanotion.io.Serializer; * Will never return null. * Added by I2P. */ -public class IdentityBytes implements Serializer { +public class IdentityBytes implements Serializer<byte[]> { /** @return byte[] */ - public byte[] getBytes(Object o) { return (byte[])o; } + public byte[] getBytes(byte[] o) { return o; } /** @return b */ - public Object construct(byte[] b) { return b; } + public byte[] construct(byte[] b) { return b; } } diff --git a/core/java/src/net/metanotion/io/data/IntBytes.java b/core/java/src/net/metanotion/io/data/IntBytes.java index 89845040c2a20c17d6f486cd52fe6c673a79b0ff..28abf27145a0f60c58f77e70f655ce60d71e1780 100644 --- a/core/java/src/net/metanotion/io/data/IntBytes.java +++ b/core/java/src/net/metanotion/io/data/IntBytes.java @@ -30,10 +30,10 @@ package net.metanotion.io.data; import net.metanotion.io.Serializer; -public class IntBytes implements Serializer { - public byte[] getBytes(Object o) { +public class IntBytes implements Serializer<Integer> { + public byte[] getBytes(Integer o) { byte[] b = new byte[4]; - int v = ((Integer) o).intValue(); + int v = o.intValue(); b[0] = (byte)(0xff & (v >> 24)); b[1] = (byte)(0xff & (v >> 16)); b[2] = (byte)(0xff & (v >> 8)); @@ -41,7 +41,7 @@ public class IntBytes implements Serializer { return b; } - public Object construct(byte[] b) { + public Integer construct(byte[] b) { int v = (((b[0] & 0xff) << 24) | ((b[1] & 0xff) << 16) | ((b[2] & 0xff) << 8) | diff --git a/core/java/src/net/metanotion/io/data/LongBytes.java b/core/java/src/net/metanotion/io/data/LongBytes.java index fe06e5120450ac8abb34ca7f379ea13437482cd6..cc1ed3c5826aeb3e341c58623bf2066c2cfa5b98 100644 --- a/core/java/src/net/metanotion/io/data/LongBytes.java +++ b/core/java/src/net/metanotion/io/data/LongBytes.java @@ -30,10 +30,10 @@ package net.metanotion.io.data; import net.metanotion.io.Serializer; -public class LongBytes implements Serializer { - public byte[] getBytes(Object o) { +public class LongBytes implements Serializer<Long> { + public byte[] getBytes(Long o) { byte[] b = new byte[8]; - long v = ((Long) o).longValue(); + long v = o.longValue(); b[0] = (byte)(0xff & (v >> 56)); b[1] = (byte)(0xff & (v >> 48)); b[2] = (byte)(0xff & (v >> 40)); @@ -45,7 +45,7 @@ public class LongBytes implements Serializer { return b; } - public Object construct(byte[] b) { + public Long construct(byte[] b) { long v =(((long)(b[0] & 0xff) << 56) | ((long)(b[1] & 0xff) << 48) | ((long)(b[2] & 0xff) << 40) | diff --git a/core/java/src/net/metanotion/io/data/NullBytes.java b/core/java/src/net/metanotion/io/data/NullBytes.java index c3849b0ed588bbf9d31c25efa4f93ce2135a387c..fb51a124112a9770f57577030492e1d253521f57 100644 --- a/core/java/src/net/metanotion/io/data/NullBytes.java +++ b/core/java/src/net/metanotion/io/data/NullBytes.java @@ -30,7 +30,7 @@ package net.metanotion.io.data; import net.metanotion.io.Serializer; -public class NullBytes implements Serializer { +public class NullBytes implements Serializer<Object> { public byte[] getBytes(Object o) { return null; } public Object construct(byte[] b) { return null; } } diff --git a/core/java/src/net/metanotion/io/data/StringBytes.java b/core/java/src/net/metanotion/io/data/StringBytes.java index 18740b7b5a942c677de3e96fe29e86f4ed6a0a5a..8237783489d800c7156ad636f43a23d3b559db3e 100644 --- a/core/java/src/net/metanotion/io/data/StringBytes.java +++ b/core/java/src/net/metanotion/io/data/StringBytes.java @@ -32,14 +32,14 @@ import java.io.UnsupportedEncodingException; import net.metanotion.io.Serializer; -public class StringBytes implements Serializer { - public byte[] getBytes(Object o) { +public class StringBytes implements Serializer<String> { + public byte[] getBytes(String o) { try { - return ((String) o).getBytes("US-ASCII"); + return o.getBytes("US-ASCII"); } catch (UnsupportedEncodingException uee) { throw new Error("Unsupported Encoding"); } } - public Object construct(byte[] b) { + public String construct(byte[] b) { try { return new String(b, "US-ASCII"); } catch (UnsupportedEncodingException uee) { throw new Error("Unsupported Encoding"); } diff --git a/core/java/src/net/metanotion/io/data/UTF8StringBytes.java b/core/java/src/net/metanotion/io/data/UTF8StringBytes.java index 3924aee941e258555e82eaa9dc3d9c0d5e18e9b0..44876c82032b0d21fdb6fa7bfa48220e737bfc53 100644 --- a/core/java/src/net/metanotion/io/data/UTF8StringBytes.java +++ b/core/java/src/net/metanotion/io/data/UTF8StringBytes.java @@ -35,14 +35,14 @@ import net.metanotion.io.Serializer; /** * Added by I2P */ -public class UTF8StringBytes implements Serializer { - public byte[] getBytes(Object o) { +public class UTF8StringBytes implements Serializer<String> { + public byte[] getBytes(String o) { try { - return ((String) o).getBytes("UTF-8"); + return o.getBytes("UTF-8"); } catch (UnsupportedEncodingException uee) { throw new Error("Unsupported Encoding"); } } - public Object construct(byte[] b) { + public String construct(byte[] b) { try { return new String(b, "UTF-8"); } catch (UnsupportedEncodingException uee) { throw new Error("Unsupported Encoding"); } diff --git a/core/java/src/net/metanotion/util/skiplist/SkipIterator.java b/core/java/src/net/metanotion/util/skiplist/SkipIterator.java index b0793d638baf9df6ea64742cd196d577fc88b480..9bbeb0bd8415351380af7dc5dd8e1357b31385d2 100644 --- a/core/java/src/net/metanotion/util/skiplist/SkipIterator.java +++ b/core/java/src/net/metanotion/util/skiplist/SkipIterator.java @@ -39,12 +39,13 @@ import java.util.NoSuchElementException; To be clear, this is an iterator through the values. To get the key, call nextKey() BEFORE calling next(). */ -public class SkipIterator implements ListIterator { - protected SkipSpan ss; +public class SkipIterator<K extends Comparable<? super K>, V> implements ListIterator<V> { + protected SkipSpan<K, V> ss; protected int index; protected SkipIterator() { } - public SkipIterator(SkipSpan ss, int index) { + + public SkipIterator(SkipSpan<K, V> ss, int index) { if(ss==null) { throw new NullPointerException(); } this.ss = ss; this.index = index; @@ -59,8 +60,8 @@ public class SkipIterator implements ListIterator { * @return the next value, and advances the index * @throws NoSuchElementException */ - public Object next() { - Object o; + public V next() { + V o; if(index < ss.nKeys) { o = ss.vals[index]; } else { @@ -83,7 +84,7 @@ public class SkipIterator implements ListIterator { * @return the key for which the value will be returned in the subsequent call to next() * @throws NoSuchElementException */ - public Comparable nextKey() { + public K nextKey() { if(index < ss.nKeys) { return ss.keys[index]; } throw new NoSuchElementException(); } @@ -98,7 +99,7 @@ public class SkipIterator implements ListIterator { * @return the previous value, and decrements the index * @throws NoSuchElementException */ - public Object previous() { + public V previous() { if(index > 0) { index--; } else if(ss.prev != null) { @@ -111,9 +112,9 @@ public class SkipIterator implements ListIterator { // Optional methods - public void add(Object o) { throw new UnsupportedOperationException(); } + public void add(V o) { throw new UnsupportedOperationException(); } public void remove() { throw new UnsupportedOperationException(); } - public void set(Object o) { throw new UnsupportedOperationException(); } + public void set(V o) { throw new UnsupportedOperationException(); } public int nextIndex() { throw new UnsupportedOperationException(); } public int previousIndex() { throw new UnsupportedOperationException(); } diff --git a/core/java/src/net/metanotion/util/skiplist/SkipLevels.java b/core/java/src/net/metanotion/util/skiplist/SkipLevels.java index bd9da7ba16b1f821b3da6caeb943a4948d29df12..226660193b86c2797e8ea55d78dd7136b774c134 100644 --- a/core/java/src/net/metanotion/util/skiplist/SkipLevels.java +++ b/core/java/src/net/metanotion/util/skiplist/SkipLevels.java @@ -35,7 +35,7 @@ import net.metanotion.io.block.BlockFile; import net.i2p.I2PAppContext; import net.i2p.util.Log; -public class SkipLevels implements Flushable { +public class SkipLevels<K extends Comparable<? super K>, V> implements Flushable { /** We can't have more than 2**32 pages */ public static final int MAX_SIZE = 32; @@ -45,12 +45,15 @@ public class SkipLevels implements Flushable { * The "bottom" level is the direct pointer to a SkipSpan. */ // levels is almost final - public SkipLevels[] levels; + public SkipLevels<K, V>[] levels; // bottom is final - public SkipSpan bottom; + public SkipSpan<K, V> bottom; private final Log _log = I2PAppContext.getGlobalContext().logManager().getLog(BlockFile.class); - public SkipLevels newInstance(int levels, SkipSpan ss, SkipList sl) { return new SkipLevels(levels, ss); } + public SkipLevels<K, V> newInstance(int levels, SkipSpan<K, V> ss, SkipList<K, V> sl) { + return new SkipLevels<K, V>(levels, ss); + } + public void killInstance() { } public void flush() { } @@ -59,10 +62,10 @@ public class SkipLevels implements Flushable { /* * @throws IllegalArgumentException if size too big or too small */ - public SkipLevels(int size, SkipSpan span) { + public SkipLevels(int size, SkipSpan<K, V> span) { if(size < 1 || size > MAX_SIZE) throw new IllegalArgumentException("Invalid Level Skip size"); - levels = new SkipLevels[size]; + levels = (SkipLevels<K, V>[]) new SkipLevels[size]; bottom = span; } @@ -92,14 +95,14 @@ public class SkipLevels implements Flushable { return buf.toString(); } - public SkipSpan getEnd() { + public SkipSpan<K, V> getEnd() { for(int i=(levels.length - 1);i>=0;i--) { if(levels[i] != null) { return levels[i].getEnd(); } } return bottom.getEnd(); } - public SkipSpan getSpan(int start, Comparable key, int[] search) { + public SkipSpan<K, V> getSpan(int start, K key, int[] search) { for(int i=Math.min(start, levels.length - 1);i>=0;i--) { if((levels[i] != null) && (levels[i].key().compareTo(key) <= 0)) { return levels[i].getSpan(i,key,search); @@ -108,9 +111,9 @@ public class SkipLevels implements Flushable { return bottom.getSpan(key, search); } - public Comparable key() { return bottom.firstKey(); } + public K key() { return bottom.firstKey(); } - public Object get(int start, Comparable key) { + public V get(int start, K key) { for(int i=Math.min(start, levels.length - 1);i>=0;i--) { if((levels[i] != null) && (levels[i].key().compareTo(key) <= 0)) { return levels[i].get(i,key); @@ -126,16 +129,16 @@ public class SkipLevels implements Flushable { * and the deleted SkipLevels is taller than this SkipLevels. * rv is null if no object was removed. */ - public Object[] remove(int start, Comparable key, SkipList sl) { + public Object[] remove(int start, K key, SkipList<K, V> sl) { Object[] res = null; - SkipLevels slvls = null; + SkipLevels<K, V> slvls = null; for(int i = Math.min(start, levels.length - 1); i >= 0; i--) { if(levels[i] != null) { int cmp = levels[i].key().compareTo(key); if((cmp < 0) || ((i==0) && (cmp <= 0))) { res = levels[i].remove(i, key, sl); if((res != null) && (res[1] != null)) { - slvls = (SkipLevels) res[1]; + slvls = (SkipLevels<K, V>) res[1]; if(levels.length >= slvls.levels.length) { res[1] = null; } @@ -159,7 +162,7 @@ public class SkipLevels implements Flushable { // if the returned SkipSpan was already copied to us boolean isFirst = sl.first == bottom; if (isFirst && levels[0] != null) { - SkipSpan ssres = (SkipSpan)res[1]; + SkipSpan<K, V> ssres = (SkipSpan<K, V>)res[1]; if (bottom.firstKey().equals(ssres.firstKey())) { // bottom copied the next span to itself if (_log.shouldLog(Log.INFO)) { @@ -171,7 +174,7 @@ public class SkipLevels implements Flushable { _log.info("FIXUP TIME"); } - SkipLevels replace = levels[0]; + SkipLevels<K, V> replace = levels[0]; for (int i = 0; i < levels.length; i++) { if (levels[i] == null) break; @@ -213,12 +216,12 @@ public class SkipLevels implements Flushable { * and the new level is taller than our level; * else null if it went in an existing level or the new level is our height or less. */ - public SkipLevels put(int start, Comparable key, Object val, SkipList sl) { + public SkipLevels<K, V> put(int start, K key, V val, SkipList<K, V> sl) { boolean modified = false; for(int i = Math.min(start, levels.length - 1); i >= 0; i--) { // is key equal to or after the start of the level? if((levels[i] != null) && (levels[i].key().compareTo(key) <= 0)) { - SkipLevels slvls = levels[i].put(i, key, val, sl); + SkipLevels<K, V> slvls = levels[i].put(i, key, val, sl); if(slvls != null) { for (int j = i + 1; j < Math.min(slvls.levels.length, levels.length); j++) { // he points to where we used to point @@ -243,11 +246,11 @@ public class SkipLevels implements Flushable { return null; } } - SkipSpan ss = bottom.put(key,val,sl); + SkipSpan<K, V> ss = bottom.put(key,val,sl); if(ss!=null) { int height = sl.generateColHeight(); if(height != 0) { - SkipLevels slvls = this.newInstance(height, ss, sl); + SkipLevels<K, V> slvls = this.newInstance(height, ss, sl); for(int i=0;i<(Math.min(height,levels.length));i++) { // he points to where we used to point // and we now point to him @@ -267,6 +270,6 @@ public class SkipLevels implements Flushable { } public boolean blvlck(boolean fix) { return false; } - public boolean blvlck(boolean fix, int width, SkipLevels[] prevLevels) { return false; } + public boolean blvlck(boolean fix, int width, SkipLevels<K, V>[] prevLevels) { return false; } } diff --git a/core/java/src/net/metanotion/util/skiplist/SkipList.java b/core/java/src/net/metanotion/util/skiplist/SkipList.java index 6619485f223117112acf8e982cd409bff827924f..32c3e7231387318b05658dd21647a13e3e94edbe 100644 --- a/core/java/src/net/metanotion/util/skiplist/SkipList.java +++ b/core/java/src/net/metanotion/util/skiplist/SkipList.java @@ -35,13 +35,13 @@ import net.i2p.util.RandomSource; //import net.metanotion.io.block.BlockFile; -public class SkipList implements Flushable { +public class SkipList<K extends Comparable<? super K>, V> implements Flushable { /** the probability of each next higher level */ protected static final int P = 2; private static final int MIN_SLOTS = 4; // these two are really final - protected SkipSpan first; - protected SkipLevels stack; + protected SkipSpan<K, V> first; + protected SkipLevels<K, V> stack; // I2P mod public static final Random rng = RandomSource.getInstance(); @@ -57,8 +57,8 @@ public class SkipList implements Flushable { public SkipList(int span) { if(span < 1 || span > SkipSpan.MAX_SIZE) throw new IllegalArgumentException("Invalid span size"); - first = new SkipSpan(span); - stack = new SkipLevels(1, first); + first = new SkipSpan<K, V>(span); + stack = new SkipLevels<K, V>(1, first); //rng = new Random(System.currentTimeMillis()); } @@ -95,14 +95,14 @@ public class SkipList implements Flushable { return max; } - public void put(Comparable key, Object val) { + public void put(K key, V val) { if(key == null) { throw new NullPointerException(); } if(val == null) { throw new NullPointerException(); } - SkipLevels slvls = stack.put(stack.levels.length - 1, key, val, this); + SkipLevels<K, V> slvls = stack.put(stack.levels.length - 1, key, val, this); if(slvls != null) { // grow our stack //BlockFile.log.info("Top level old hgt " + stack.levels.length + " new hgt " + slvls.levels.length); - SkipLevels[] levels = new SkipLevels[slvls.levels.length]; + SkipLevels<K, V>[] levels = (SkipLevels<K, V>[]) new SkipLevels[slvls.levels.length]; for(int i=0;i < slvls.levels.length; i++) { if(i < stack.levels.length) { levels[i] = stack.levels[i]; @@ -116,12 +116,12 @@ public class SkipList implements Flushable { } } - public Object remove(Comparable key) { + public Object remove(K key) { if(key == null) { throw new NullPointerException(); } Object[] res = stack.remove(stack.levels.length - 1, key, this); if(res != null) { if(res[1] != null) { - SkipLevels slvls = (SkipLevels) res[1]; + SkipLevels<K, V> slvls = (SkipLevels<K, V>) res[1]; for(int i=0;i < slvls.levels.length; i++) { if(stack.levels[i] == slvls) { stack.levels[i] = slvls.levels[i]; @@ -154,26 +154,26 @@ public class SkipList implements Flushable { System.out.println(first.print()); } - public Object get(Comparable key) { + public V get(K key) { if(key == null) { throw new NullPointerException(); } return stack.get(stack.levels.length - 1, key); } - public SkipIterator iterator() { return new SkipIterator(first, 0); } + public SkipIterator<K, V> iterator() { return new SkipIterator<K, V>(first, 0); } - public SkipIterator min() { return new SkipIterator(first, 0); } + public SkipIterator<K, V> min() { return new SkipIterator<K, V>(first, 0); } - public SkipIterator max() { - SkipSpan ss = stack.getEnd(); - return new SkipIterator(ss, ss.nKeys - 1); + public SkipIterator<K, V> max() { + SkipSpan<K, V> ss = stack.getEnd(); + return new SkipIterator<K, V>(ss, ss.nKeys - 1); } /** @return an iterator where nextKey() is the first one greater than or equal to 'key' */ - public SkipIterator find(Comparable key) { + public SkipIterator<K, V> find(K key) { int[] search = new int[1]; - SkipSpan ss = stack.getSpan(stack.levels.length - 1, key, search); + SkipSpan<K, V> ss = stack.getSpan(stack.levels.length - 1, key, search); if(search[0] < 0) { search[0] = -1 * (search[0] + 1); } - return new SkipIterator(ss, search[0]); + return new SkipIterator<K, V>(ss, search[0]); } diff --git a/core/java/src/net/metanotion/util/skiplist/SkipSpan.java b/core/java/src/net/metanotion/util/skiplist/SkipSpan.java index 94210ebd4bc6d727b51322471761bb72cdacf588..71e9eb689f2d2df756a280a5705294df2b166f73 100644 --- a/core/java/src/net/metanotion/util/skiplist/SkipSpan.java +++ b/core/java/src/net/metanotion/util/skiplist/SkipSpan.java @@ -32,16 +32,16 @@ import java.io.Flushable; //import net.metanotion.io.block.BlockFile; -public class SkipSpan implements Flushable { +public class SkipSpan<K extends Comparable<? super K>, V> implements Flushable { /** This is actually limited by BlockFile.spanSize which is much smaller */ public static final int MAX_SIZE = 256; public int nKeys = 0; - public Comparable[] keys; - public Object[] vals; - public SkipSpan next, prev; + public K[] keys; + public V[] vals; + public SkipSpan<K, V> next, prev; - public SkipSpan newInstance(SkipList sl) { return new SkipSpan(keys.length); } + public SkipSpan<K, V> newInstance(SkipList<K, V> sl) { return new SkipSpan<K, V>(keys.length); } public void killInstance() { } public void flush() { } @@ -53,8 +53,8 @@ public class SkipSpan implements Flushable { public SkipSpan(int size) { if(size < 1 || size > MAX_SIZE) throw new IllegalArgumentException("Invalid span size " + size); - keys = new Comparable[size]; - vals = new Object[size]; + keys = (K[]) new Comparable[size]; + vals = (V[]) new Object[size]; } /** dumps all the data from here to the end */ @@ -70,7 +70,7 @@ public class SkipSpan implements Flushable { return buf.toString(); } - private int binarySearch(Comparable key) { + private int binarySearch(K key) { int high = nKeys - 1; int low = 0; int cur; @@ -89,12 +89,12 @@ public class SkipSpan implements Flushable { return (-1 * (low + 1)); } - public SkipSpan getEnd() { + public SkipSpan<K, V> getEnd() { if(next == null) { return this; } return next.getEnd(); } - public SkipSpan getSpan(Comparable key, int[] search) { + public SkipSpan<K, V> getSpan(K key, int[] search) { if(nKeys == 0) { search[0] = -1; return this; @@ -111,7 +111,7 @@ public class SkipSpan implements Flushable { return this; } - public Object get(Comparable key) { + public V get(K key) { if(nKeys == 0) { return null; } if(keys[nKeys - 1].compareTo(key) < 0) { if(next == null) { return null; } @@ -138,8 +138,8 @@ public class SkipSpan implements Flushable { nKeys++; } - private void split(int loc, Comparable key, Object val, SkipList sl) { - SkipSpan right = newInstance(sl); + private void split(int loc, K key, V val, SkipList<K, V> sl) { + SkipSpan<K, V> right = newInstance(sl); if(this.next != null) { this.next.prev = right; } right.next = this.next; @@ -175,7 +175,7 @@ public class SkipSpan implements Flushable { /** * @return the new span if it caused a split, else null if it went in this span */ - private SkipSpan insert(int loc, Comparable key, Object val, SkipList sl) { + private SkipSpan<K, V> insert(int loc, K key, V val, SkipList<K, V> sl) { sl.addItem(); if(nKeys == keys.length) { // split. @@ -193,7 +193,7 @@ public class SkipSpan implements Flushable { /** * @return the new span if it caused a split, else null if it went in an existing span */ - public SkipSpan put(Comparable key, Object val, SkipList sl) { + public SkipSpan<K, V> put(K key, V val, SkipList<K, V> sl) { if(nKeys == 0) { sl.addItem(); keys[0] = key; @@ -246,7 +246,7 @@ public class SkipSpan implements Flushable { * rv[1] is the deleted SkipSpan if the removed object was the last in the SkipSpan. * rv is null if no object was removed. */ - public Object[] remove(Comparable key, SkipList sl) { + public Object[] remove(K key, SkipList<K, V> sl) { if(nKeys == 0) { return null; } if(keys[nKeys - 1].compareTo(key) < 0) { if(next == null) { return null; } @@ -270,7 +270,7 @@ public class SkipSpan implements Flushable { nKeys = next.nKeys; //BlockFile.log.error("Killing next span " + next + ") and copying to this span " + this + " in remove of " + key); // Make us point to next.next and him point back to us - SkipSpan nn = next.next; + SkipSpan<K, V> nn = next.next; next.killInstance(); if (nn != null) { nn.prev = this; @@ -311,7 +311,7 @@ public class SkipSpan implements Flushable { } /** I2P */ - public Comparable firstKey() { + public K firstKey() { return keys[0]; } }