
uk.co.probablyfine.dirty.Store Maven / Gradle / Ivy
package uk.co.probablyfine.dirty;
import uk.co.probablyfine.dirty.utils.Classes;
import uk.co.probablyfine.dirty.utils.Nio;
import uk.co.probablyfine.dirty.utils.Types;
import java.lang.reflect.Field;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.BiConsumer;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static uk.co.probablyfine.dirty.utils.Exceptions.unchecked;
public class Store {
private final FileChannel fileChannel;
private final MappedByteBuffer memoryMappedFile;
private final int offSet;
private final List fields;
private final Class klass;
private final List> writeObservers = new ArrayList<>();
private int size;
public Store(String path, Class klass) {
this.klass = klass;
this.fields = Classes.primitiveFields(klass).collect(Collectors.toList());
this.fileChannel = Nio.fileChannel(path);
this.offSet = Types.offSetForClass(klass);
this.memoryMappedFile = Nio.mapFile(fileChannel, 1024 * 1024 * 2);
this.size = memoryMappedFile.getInt(0);
}
public void put(T t) {
AtomicInteger currentPosition = new AtomicInteger(Types.INT.getSize() + this.size*this.offSet);
fields.forEach(field -> {
Object unchecked = unchecked(() -> field.get(t));
Types fieldType = Types.of(field.getType());
fieldType.getWriteField().accept(memoryMappedFile, currentPosition.get(), unchecked);
currentPosition.addAndGet(fieldType.getSize());
});
this.writeObservers.forEach(x -> x.accept(t, this.size));
this.incrementSize();
}
private void incrementSize() {
this.size++;
this.memoryMappedFile.putInt(0, this.size);
}
public Stream all() throws IllegalAccessException {
Stream.Builder builder = Stream.builder();
for(int index = 0; index < this.size; index++) {
builder.add(extractEntry(index));
}
return builder.build();
}
public Stream reverse() throws IllegalAccessException {
Stream.Builder builder = Stream.builder();
for(int index = (this.size-1); index >= 0; index--) {
builder.add(extractEntry(index));
}
return builder.build();
}
private T extractEntry(int index) throws IllegalAccessException {
final AtomicInteger cursor = new AtomicInteger(Types.INT.getSize() + (index * this.offSet));
T t = unchecked(klass::newInstance);
fields.forEach(field -> {
final Types fieldType = Types.of(field.getType());
final Object apply = fieldType.getReadField().apply(memoryMappedFile, cursor.get());
unchecked(() -> field.set(t, apply));
cursor.addAndGet(fieldType.getSize());
});
return t;
}
public T get(int index) throws IllegalAccessException {
return extractEntry(index);
}
public void observeWrites(BiConsumer observeWriteFunction) {
this.writeObservers.add(observeWriteFunction);
}
public void reset() {
this.size = 0;
this.memoryMappedFile.putInt(0, 0);
}
public interface WithFile {
Store from(String path);
}
public static WithFile of(final Class fooClass) {
return path -> new Store<>(path, fooClass);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy