kopia lustrzana https://github.com/onthegomap/planetiler
132 wiersze
3.5 KiB
Java
132 wiersze
3.5 KiB
Java
package com.onthegomap.planetiler.collection;
|
|
|
|
import com.onthegomap.planetiler.util.DiskBacked;
|
|
import com.onthegomap.planetiler.util.MemoryEstimator;
|
|
import java.io.Closeable;
|
|
import java.io.IOException;
|
|
import java.util.function.IntFunction;
|
|
import java.util.stream.Stream;
|
|
|
|
/**
|
|
* A large array of primitives. A single thread appends all elements then allows random access from multiple threads.
|
|
* <p>
|
|
* {@link AppendStoreRam} stores all data in {@link java.nio.ByteBuffer ByteBuffers} in RAM and {@link AppendStoreMmap}
|
|
* stores all data in a memory-mapped file.
|
|
*/
|
|
interface AppendStore extends Closeable, MemoryEstimator.HasEstimate, DiskBacked {
|
|
|
|
/** Returns the number of elements in the array */
|
|
long size();
|
|
|
|
default void checkIndexInBounds(long index) {
|
|
if (index >= size()) {
|
|
throw new IndexOutOfBoundsException("index: " + index + " size: " + size());
|
|
}
|
|
}
|
|
|
|
@Override
|
|
default long estimateMemoryUsageBytes() {
|
|
return 0;
|
|
}
|
|
|
|
@Override
|
|
default long diskUsageBytes() {
|
|
return 0;
|
|
}
|
|
|
|
/** An array of ints. */
|
|
interface Ints extends AppendStore {
|
|
|
|
static Ints create(Storage storage, Storage.Params params) {
|
|
return switch (storage) {
|
|
case DIRECT -> new AppendStoreRam.Ints(true, params);
|
|
case RAM -> new AppendStoreRam.Ints(false, params);
|
|
case MMAP -> new AppendStoreMmap.Ints(params);
|
|
};
|
|
}
|
|
|
|
void appendInt(int value);
|
|
|
|
int getInt(long index);
|
|
}
|
|
|
|
/** An array of longs. */
|
|
interface Longs extends AppendStore {
|
|
|
|
static Longs create(Storage storage, Storage.Params params) {
|
|
return switch (storage) {
|
|
case DIRECT -> new AppendStoreRam.Longs(true, params);
|
|
case RAM -> new AppendStoreRam.Longs(false, params);
|
|
case MMAP -> new AppendStoreMmap.Longs(params);
|
|
};
|
|
}
|
|
|
|
void appendLong(long value);
|
|
|
|
long getLong(long index);
|
|
}
|
|
|
|
/**
|
|
* An array longs that uses 4 bytes to represent each long by using a list of {@link Ints} arrays. Only suitable for
|
|
* values less than ~20 billion (i.e. OSM node IDs)
|
|
*/
|
|
final class SmallLongs implements Longs {
|
|
|
|
private static final int BITS = 31;
|
|
private static final long MASK = (1L << BITS) - 1L;
|
|
private final Ints[] ints = new Ints[10];
|
|
private long numWritten = 0;
|
|
|
|
SmallLongs(IntFunction<Ints> supplier) {
|
|
for (int i = 0; i < ints.length; i++) {
|
|
ints[i] = supplier.apply(i);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void appendLong(long value) {
|
|
int block = (int) (value >>> BITS);
|
|
int offset = (int) (value & MASK);
|
|
ints[block].appendInt(offset);
|
|
numWritten++;
|
|
}
|
|
|
|
@Override
|
|
public long getLong(long index) {
|
|
checkIndexInBounds(index);
|
|
for (int i = 0; i < ints.length; i++) {
|
|
Ints slab = ints[i];
|
|
long size = slab.size();
|
|
if (index < slab.size()) {
|
|
return slab.getInt(index) + (((long) i) << BITS);
|
|
}
|
|
index -= size;
|
|
}
|
|
throw new IndexOutOfBoundsException("index: " + index + " size: " + size());
|
|
}
|
|
|
|
@Override
|
|
public long size() {
|
|
return numWritten;
|
|
}
|
|
|
|
@Override
|
|
public void close() throws IOException {
|
|
for (var child : ints) {
|
|
child.close();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public long estimateMemoryUsageBytes() {
|
|
return Stream.of(ints).mapToLong(AppendStore::estimateMemoryUsageBytes).sum();
|
|
}
|
|
|
|
@Override
|
|
public long diskUsageBytes() {
|
|
return Stream.of(ints).mapToLong(AppendStore::diskUsageBytes).sum();
|
|
}
|
|
}
|
|
|
|
}
|