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>
<artifactId>filelists</artifactId>
<version>0.0.1</version>
<version>0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>filelists</name>

View File

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

View File

@ -16,20 +16,22 @@ public class LongConverter40Bit implements ByteArrayConverter<Long> {
}
@Override
public Long fromBytes(final byte[] buffer) {
return (((long) buffer[4] & 0xFFL) << 32)
| (((long) buffer[3] & 0xFFL) << 24)
| (((long) buffer[2] & 0xFFL) << 16)
| (((long) buffer[1] & 0xFFL) << 8)
| ((long) buffer[0] & 0xFFL);
public Long fromBytes(final byte[] buffer, int off) {
off += 5;
return (((long) buffer[--off] & 0xFFL) << 32)
| (((long) buffer[--off] & 0xFFL) << 24)
| (((long) buffer[--off] & 0xFFL) << 16)
| (((long) buffer[--off] & 0xFFL) << 8)
| ((long) buffer[--off] & 0xFFL);
}
@Override
public void toBytes(final Long l, final byte[] buffer) {
buffer[0] = (byte) ((l) & 0xFF);
buffer[1] = (byte) ((l >> 8) & 0xFF);
buffer[2] = (byte) ((l >> 16) & 0xFF);
buffer[3] = (byte) ((l >> 24) & 0xFF);
buffer[4] = (byte) ((l >> 32) & 0xFF);
public void toBytes(final Long l, final byte[] buffer, int off) {
--off;
buffer[++off] = (byte) ((l) & 0xFF);
buffer[++off] = (byte) ((l >> 8) & 0xFF);
buffer[++off] = (byte) ((l >> 16) & 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.
*/
public class RandomAccessFileList<T> extends AbstractList<T> {
public class RandomAccessFileList<T> extends AbstractList<T> implements AutoCloseable {
private final RandomAccessFile raf;
private final byte[] buffer;
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(bac);
if (bac.numBytes() < 1)
@ -23,14 +24,25 @@ public class RandomAccessFileList<T> extends AbstractList<T> {
this.raf = raf;
this.buffer = new byte[bac.numBytes()];
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 {
this(new RandomAccessFile(name, "rw"), bac);
this(new RandomAccessFile(name, "rw"), true, bac);
}
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) {
@ -45,7 +57,7 @@ public class RandomAccessFileList<T> extends AbstractList<T> {
raf.seek(index * buffer.length);
if (raf.read(buffer) != buffer.length)
throw new IOException("no full buffer to read, corrupted file?");
return bac.fromBytes(buffer);
return bac.fromBytes(buffer, 0);
}
public int size() {
@ -64,7 +76,7 @@ public class RandomAccessFileList<T> extends AbstractList<T> {
public boolean add(final T o) {
try {
raf.seek(raf.length());
bac.toBytes(o, buffer);
bac.toBytes(o, buffer, 0);
raf.write(buffer);
return true;
} 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 {
final T ret = get(index);
raf.seek(index * buffer.length);
bac.toBytes(o, buffer);
bac.toBytes(o, buffer, 0);
raf.write(buffer);
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
public void sort(final Comparator<? super T> c) {
try {

View File

@ -19,7 +19,7 @@ public class SignedLongConverter implements ByteArrayConverter<Long> {
}
@Override
public Long fromBytes(final byte[] buffer) {
public Long fromBytes(final byte[] buffer, final int off) {
/*
if(true)
return (((long)buffer[0] << 56) +
@ -31,7 +31,7 @@ public class SignedLongConverter implements ByteArrayConverter<Long> {
((buffer[6] & 255) << 8) +
((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);
long l = (long)(buffer[y] << x);
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);
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);
l += (buffer[y] & 255) << x;
}
@ -48,7 +48,7 @@ public class SignedLongConverter implements ByteArrayConverter<Long> {
}
@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[1] = (byte)(v >>> 48);
@ -59,21 +59,21 @@ public class SignedLongConverter implements ByteArrayConverter<Long> {
writeBuffer[6] = (byte)(v >>> 8);
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);
buffer[y] = (byte) (l >>> x);
}
}
public static void main(String[] args) {
final ByteArrayConverter<Long> bac = new SignedLongConverter(5);
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(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;
for(long l = 0, c = 0; ; ++l) {
bac.toBytes(l, buf);
c = bac.fromBytes(buf);
bac.toBytes(l, buf, 0);
c = bac.fromBytes(buf, 0);
if(l != c) {
System.out.printf("limit for %d bytes l = %d c = %d%n", buf.length, l, c);
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
public Long fromBytes(final byte[] buffer) {
public Long fromBytes(final byte[] buffer, final int off) {
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);
}
return l;
}
@Override
public void toBytes(final Long l, final byte[] buffer) {
for(int x = 0, y = 0; x < buffer.length; ++x, y = y + 8) {
public void toBytes(final Long l, final byte[] buffer, final int off) {
for(int x = off, y = 0; x < this.numBytes; ++x, y = y + 8) {
buffer[x] = (byte) ((l >> y) & 0xFF);
}
}