Implement binary search for RandomAccessFileList, other API tweaks

This commit is contained in:
Travis Burtrum 2017-02-14 23:41:49 -05:00
parent 8a50a0c9e6
commit a8f5a83450
8 changed files with 113 additions and 87 deletions

View File

@ -4,7 +4,7 @@
<groupId>com.moparisthebest</groupId> <groupId>com.moparisthebest</groupId>
<artifactId>filelists</artifactId> <artifactId>filelists</artifactId>
<version>0.0.1</version> <version>0.1-SNAPSHOT</version>
<packaging>jar</packaging> <packaging>jar</packaging>
<name>filelists</name> <name>filelists</name>

View File

@ -5,6 +5,6 @@ package com.moparisthebest.filelist;
*/ */
public interface ByteArrayConverter<T> { public interface ByteArrayConverter<T> {
int numBytes(); int numBytes();
T fromBytes(final byte[] buff); T fromBytes(final byte[] buff, final int off);
void toBytes(final T o, final byte[] buff); void toBytes(final T o, final byte[] buff, final int off);
} }

View File

@ -16,20 +16,22 @@ public class LongConverter40Bit implements ByteArrayConverter<Long> {
} }
@Override @Override
public Long fromBytes(final byte[] buffer) { public Long fromBytes(final byte[] buffer, int off) {
return (((long) buffer[4] & 0xFFL) << 32) off += 5;
| (((long) buffer[3] & 0xFFL) << 24) return (((long) buffer[--off] & 0xFFL) << 32)
| (((long) buffer[2] & 0xFFL) << 16) | (((long) buffer[--off] & 0xFFL) << 24)
| (((long) buffer[1] & 0xFFL) << 8) | (((long) buffer[--off] & 0xFFL) << 16)
| ((long) buffer[0] & 0xFFL); | (((long) buffer[--off] & 0xFFL) << 8)
| ((long) buffer[--off] & 0xFFL);
} }
@Override @Override
public void toBytes(final Long l, final byte[] buffer) { public void toBytes(final Long l, final byte[] buffer, int off) {
buffer[0] = (byte) ((l) & 0xFF); --off;
buffer[1] = (byte) ((l >> 8) & 0xFF); buffer[++off] = (byte) ((l) & 0xFF);
buffer[2] = (byte) ((l >> 16) & 0xFF); buffer[++off] = (byte) ((l >> 8) & 0xFF);
buffer[3] = (byte) ((l >> 24) & 0xFF); buffer[++off] = (byte) ((l >> 16) & 0xFF);
buffer[4] = (byte) ((l >> 32) & 0xFF); buffer[++off] = (byte) ((l >> 24) & 0xFF);
buffer[++off] = (byte) ((l >> 32) & 0xFF);
} }
} }

View File

@ -1,53 +0,0 @@
package com.moparisthebest.filelist;
import java.io.IOException;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
/**
* Created by mopar on 2/9/17.
*/
public class Main {
public static void main(String[] args) throws IOException {
System.out.println("str " + new Date());
//final List<Long> list = new RandomAccessFileList<>("/home/mopar/raf2.list", new UnsignedLongConverter(5));
final List<Long> list = new RandomAccessFileList<>("/home/mopar/raf2.list", LongConverter40Bit.instance); list.clear();
/*
System.out.println(list.get(0));
System.out.println(((RandomAccessFileList)list).longSize());
System.out.println(((RandomAccessFileList)list).get(((RandomAccessFileList)list).longSize() - 1));
*/
//list.clear();
/*
long max = Integer.MAX_VALUE + 1000L;
for(long l = 0; l < max; ++l)
list.add(l);
System.out.println("yay " + new Date());
for(long l : list)
System.out.println(l);
*/
//if(true) return;
System.out.println(Integer.MAX_VALUE);
System.out.println(list);
list.add(5L);
System.out.println(list);
System.out.println(list.get(0));
list.add(99999999999L);
System.out.println(list.get(1));
list.add(6L);
list.add(4L);
System.out.println(list);
list.sort(Long::compareTo);
System.out.println(list);
System.out.println("------");
//if(true) return;
for(long l = 0; l < 1000; ++l)
//for(long l = 7; l < 11; ++l)
list.add(l);
System.out.println(list);
list.sort(Long::compareTo);
list.sort(Comparator.reverseOrder());
System.out.println(list);
}
}

View File

@ -9,13 +9,14 @@ import java.util.*;
/** /**
* Created by mopar on 2/9/17. * Created by mopar on 2/9/17.
*/ */
public class RandomAccessFileList<T> extends AbstractList<T> { public class RandomAccessFileList<T> extends AbstractList<T> implements AutoCloseable {
private final RandomAccessFile raf; private final RandomAccessFile raf;
private final byte[] buffer; private final byte[] buffer;
private final ByteArrayConverter<T> bac; private final ByteArrayConverter<T> bac;
private final boolean close;
public RandomAccessFileList(final RandomAccessFile raf, final ByteArrayConverter<T> bac) { private RandomAccessFileList(final RandomAccessFile raf, final boolean close, final ByteArrayConverter<T> bac) {
Objects.requireNonNull(raf); Objects.requireNonNull(raf);
Objects.requireNonNull(bac); Objects.requireNonNull(bac);
if (bac.numBytes() < 1) if (bac.numBytes() < 1)
@ -23,14 +24,25 @@ public class RandomAccessFileList<T> extends AbstractList<T> {
this.raf = raf; this.raf = raf;
this.buffer = new byte[bac.numBytes()]; this.buffer = new byte[bac.numBytes()];
this.bac = bac; this.bac = bac;
this.close = close;
}
public RandomAccessFileList(final RandomAccessFile raf, final ByteArrayConverter<T> bac) {
this(raf, false, bac);
} }
public RandomAccessFileList(final String name, final ByteArrayConverter<T> bac) throws FileNotFoundException { public RandomAccessFileList(final String name, final ByteArrayConverter<T> bac) throws FileNotFoundException {
this(new RandomAccessFile(name, "rw"), bac); this(new RandomAccessFile(name, "rw"), true, bac);
} }
public RandomAccessFileList(final File file, final ByteArrayConverter<T> bac) throws FileNotFoundException { public RandomAccessFileList(final File file, final ByteArrayConverter<T> bac) throws FileNotFoundException {
this(new RandomAccessFile(file, "rw"), bac); this(new RandomAccessFile(file, "rw"), true, bac);
}
@Override
public void close() throws IOException {
if(close)
raf.close();
} }
public T get(final int index) { public T get(final int index) {
@ -45,7 +57,7 @@ public class RandomAccessFileList<T> extends AbstractList<T> {
raf.seek(index * buffer.length); raf.seek(index * buffer.length);
if (raf.read(buffer) != buffer.length) if (raf.read(buffer) != buffer.length)
throw new IOException("no full buffer to read, corrupted file?"); throw new IOException("no full buffer to read, corrupted file?");
return bac.fromBytes(buffer); return bac.fromBytes(buffer, 0);
} }
public int size() { public int size() {
@ -64,7 +76,7 @@ public class RandomAccessFileList<T> extends AbstractList<T> {
public boolean add(final T o) { public boolean add(final T o) {
try { try {
raf.seek(raf.length()); raf.seek(raf.length());
bac.toBytes(o, buffer); bac.toBytes(o, buffer, 0);
raf.write(buffer); raf.write(buffer);
return true; return true;
} catch (IOException e) { } catch (IOException e) {
@ -84,7 +96,7 @@ public class RandomAccessFileList<T> extends AbstractList<T> {
public T set(final long index, final T o) throws IOException { public T set(final long index, final T o) throws IOException {
final T ret = get(index); final T ret = get(index);
raf.seek(index * buffer.length); raf.seek(index * buffer.length);
bac.toBytes(o, buffer); bac.toBytes(o, buffer, 0);
raf.write(buffer); raf.write(buffer);
return ret; return ret;
} }
@ -98,6 +110,60 @@ public class RandomAccessFileList<T> extends AbstractList<T> {
} }
} }
public <K> long indexedBinarySearch(final K key, final TransformComparator<K, ? super T> c) throws IOException {
long low = 0;
long high = this.longSize()-1;
while (low <= high) {
final long mid = (low + high) >>> 1;
final T midVal = this.get(mid);
final int cmp = c.compareTransform(key, midVal);
if (cmp > 0)
low = mid + 1;
else if (cmp < 0)
high = mid - 1;
else
return mid; // key found
}
return -(low + 1); // key not found
}
public <K> long iteratorBinarySearch(final K key, final TransformComparator<K, ? super T> c) throws IOException {
long low = 0;
long high = this.longSize()-1;
ListIterator<? extends T> i = this.listIterator();
while (low <= high) {
final long mid = (low + high) >>> 1;
final T midVal = get(i, mid);
final int cmp = c.compareTransform(key, midVal);
if (cmp > 0)
low = mid + 1;
else if (cmp < 0)
high = mid - 1;
else
return mid; // key found
}
return -(low + 1); // key not found
}
private T get(final ListIterator<? extends T> i, final long index) {
T obj = null;
int pos = i.nextIndex();
if (pos <= index) {
do {
obj = i.next();
} while (pos++ < index);
} else {
do {
obj = i.previous();
} while (--pos > index);
}
return obj;
}
@Override @Override
public void sort(final Comparator<? super T> c) { public void sort(final Comparator<? super T> c) {
try { try {

View File

@ -19,7 +19,7 @@ public class SignedLongConverter implements ByteArrayConverter<Long> {
} }
@Override @Override
public Long fromBytes(final byte[] buffer) { public Long fromBytes(final byte[] buffer, final int off) {
/* /*
if(true) if(true)
return (((long)buffer[0] << 56) + return (((long)buffer[0] << 56) +
@ -31,7 +31,7 @@ public class SignedLongConverter implements ByteArrayConverter<Long> {
((buffer[6] & 255) << 8) + ((buffer[6] & 255) << 8) +
((buffer[7] & 255) << 0)); ((buffer[7] & 255) << 0));
*/ */
int y = 0, x = (buffer.length * 8) - 8; int y = off, x = (this.numBytes * 8) - 8;
if(debug) System.out.printf("l = (long)(buffer[%d] << %d);%n", y, x); if(debug) System.out.printf("l = (long)(buffer[%d] << %d);%n", y, x);
long l = (long)(buffer[y] << x); long l = (long)(buffer[y] << x);
x = x - 8; x = x - 8;
@ -40,7 +40,7 @@ public class SignedLongConverter implements ByteArrayConverter<Long> {
if(debug) System.out.printf("l += ((long)(buffer[%d] & 255) << %d);%n", y, x); if(debug) System.out.printf("l += ((long)(buffer[%d] & 255) << %d);%n", y, x);
l += ((long)(buffer[y] & 255) << x); l += ((long)(buffer[y] & 255) << x);
} }
for (; y < buffer.length; x = x - 8, ++y) { for (; y < this.numBytes; x = x - 8, ++y) {
if(debug) System.out.printf("l += (buffer[%d] & 255) << %d;%n", y, x); if(debug) System.out.printf("l += (buffer[%d] & 255) << %d;%n", y, x);
l += (buffer[y] & 255) << x; l += (buffer[y] & 255) << x;
} }
@ -48,7 +48,7 @@ public class SignedLongConverter implements ByteArrayConverter<Long> {
} }
@Override @Override
public void toBytes(final Long l, final byte[] buffer) { public void toBytes(final Long l, final byte[] buffer, final int off) {
/* /*
writeBuffer[0] = (byte)(v >>> 56); writeBuffer[0] = (byte)(v >>> 56);
writeBuffer[1] = (byte)(v >>> 48); writeBuffer[1] = (byte)(v >>> 48);
@ -59,21 +59,21 @@ public class SignedLongConverter implements ByteArrayConverter<Long> {
writeBuffer[6] = (byte)(v >>> 8); writeBuffer[6] = (byte)(v >>> 8);
writeBuffer[7] = (byte)(v >>> 0); writeBuffer[7] = (byte)(v >>> 0);
*/ */
for(int y = 0, x = (buffer.length * 8) - 8; x > -1; x = x - 8, ++y) { for(int y = off, x = (this.numBytes * 8) - 8; x > -1; x = x - 8, ++y) {
if(debug) System.out.printf("buffer[%d] = (byte) (l >>> %d);%n", y, x); if(debug) System.out.printf("buffer[%d] = (byte) (l >>> %d);%n", y, x);
buffer[y] = (byte) (l >>> x); buffer[y] = (byte) (l >>> x);
} }
} }
public static void main(String[] args) { public static void main(String[] args) {
final ByteArrayConverter<Long> bac = new SignedLongConverter(5);
final byte[] buf = new byte[3]; // 5 99999999999L final byte[] buf = new byte[3]; // 5 99999999999L
final ByteArrayConverter<Long> bac = new SignedLongConverter(buf.length);
//System.out.println(4294967296L); System.out.println(Integer.MAX_VALUE * 2L); if(true)return; //System.out.println(4294967296L); System.out.println(Integer.MAX_VALUE * 2L); if(true)return;
//System.out.println(Long.MIN_VALUE + 500); //System.out.println(Long.MIN_VALUE + 500);
//bac.toBytes(99999999999L, buf); System.out.println(java.util.Arrays.toString(buf)); System.out.println(bac.fromBytes(buf)); if(true) return; //bac.toBytes(99999999999L, buf); System.out.println(java.util.Arrays.toString(buf)); System.out.println(bac.fromBytes(buf)); if(true) return;
for(long l = 0, c = 0; ; ++l) { for(long l = 0, c = 0; ; ++l) {
bac.toBytes(l, buf); bac.toBytes(l, buf, 0);
c = bac.fromBytes(buf); c = bac.fromBytes(buf, 0);
if(l != c) { if(l != c) {
System.out.printf("limit for %d bytes l = %d c = %d%n", buf.length, l, c); System.out.printf("limit for %d bytes l = %d c = %d%n", buf.length, l, c);
return; return;

View File

@ -0,0 +1,11 @@
package com.moparisthebest.filelist;
/**
* Created by mopar on 2/10/17.
*/
@FunctionalInterface
public interface TransformComparator<K, T> {
int compareTransform(K o1, T o2);
}

View File

@ -17,17 +17,17 @@ public class UnsignedLongConverter implements ByteArrayConverter<Long> {
} }
@Override @Override
public Long fromBytes(final byte[] buffer) { public Long fromBytes(final byte[] buffer, final int off) {
long l = 0; long l = 0;
for(int x = buffer.length - 1, y = (buffer.length * 8) - 8; x >= 0; --x, y = y - 8) { for(int x = this.numBytes - 1, y = (this.numBytes * 8) - 8; x >= off; --x, y = y - 8) {
l |= (((long) buffer[x] & 0xFFL) << y); l |= (((long) buffer[x] & 0xFFL) << y);
} }
return l; return l;
} }
@Override @Override
public void toBytes(final Long l, final byte[] buffer) { public void toBytes(final Long l, final byte[] buffer, final int off) {
for(int x = 0, y = 0; x < buffer.length; ++x, y = y + 8) { for(int x = off, y = 0; x < this.numBytes; ++x, y = y + 8) {
buffer[x] = (byte) ((l >> y) & 0xFF); buffer[x] = (byte) ((l >> y) & 0xFF);
} }
} }