package puzzle; import com.google.gson.Gson; import puzzle.SwedishGenerator.Lemma; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.MappedByteBuffer; import java.nio.channels.FileChannel; import java.nio.charset.StandardCharsets; import java.nio.file.Path; import java.nio.file.StandardOpenOption; import java.util.Arrays; import java.util.Locale; public class Meta { static final Gson GSON = new Gson(); static final int VERSION = 1; static final int SHARD_MAGIC = 0x49445831; // "IDX1" static final int MAP_MAGIC = 0x4D415031; // "MAP1" static final ByteOrder ORDER = ByteOrder.BIG_ENDIAN; static record ShardRec(String word, long w, int simpel, String[] clues) { } static final Path projectRoot = Path.of("").toAbsolutePath().normalize(); // current working dir //static final Path dir = projectRoot.resolve("src/main/resources/shards"); //static final Path shardData = dir.resolve("shard0.data"); //static final Path shardMap = dir.resolve("shard0.map"); static final Path dir = detectShardDir(); static final Path shardData = dir.resolve("shard0.data"); static final Path shardMap = dir.resolve("shard0.map"); private static Path detectShardDir() { // 1) optioneel override String p = System.getProperty("puzzle.shards.dir"); if (p != null && !p.isBlank()) return Path.of(p).toAbsolutePath().normalize(); // 2) default: naast classes output (CLASS_OUTPUT/shards) try { var url = Meta.class.getProtectionDomain().getCodeSource().getLocation(); // classes dir (niet jar) Path classes = Path.of(url.toURI()); return classes.resolve("shards"); } catch (Exception e) { // 3) fallback: oude dev-locatie return Path.of("").toAbsolutePath().normalize().resolve("src/main/resources/shards"); } } // --- Lookup: w -> i using mmap --- static int findIndexInMapMmap(long target) throws IOException { try (var ch = FileChannel.open(Meta.shardMap, StandardOpenOption.READ)) { var mbb = (MappedByteBuffer) ch.map(FileChannel.MapMode.READ_ONLY, 0, ch.size()).order(ORDER); var magic = mbb.getInt(0); var ver = mbb.getInt(4); var n = mbb.getInt(8); if (magic != MAP_MAGIC || ver != VERSION) throw new IOException("Bad map file"); int lo = 0, hi = n - 1; while (lo <= hi) { var mid = (lo + hi) >>> 1; var off = 12 + mid * 8; var key = mbb.getLong(off); if (key < target) lo = mid + 1; else if (key > target) hi = mid - 1; else return mid; } return -1; } } // --- Read record i from shard.data (your format) --- static ShardLem readRecord(long w, int i) throws IOException { try (var ch = FileChannel.open(Meta.shardData, StandardOpenOption.READ)) { var hdr = ByteBuffer.allocate(12).order(ORDER); ch.read(hdr); hdr.flip(); var magic = hdr.getInt(); var ver = hdr.getInt(); var n = hdr.getInt(); if (magic != SHARD_MAGIC || ver != VERSION) throw new IOException("Bad shard file"); if (i < 0 || i >= n) throw new IndexOutOfBoundsException(); var tableStart = 12L; var dataStart = 12L + (long) n * 4L; var offI = readIntAt(ch, tableStart + (long) i * 4L); var offIp = (i + 1 < n) ? readIntAt(ch, tableStart + (long) (i + 1) * 4L) : (int) (ch.size() - dataStart); var len = offIp - offI; var buf = ByteBuffer.allocate(len); ch.position(dataStart + offI); ch.read(buf); buf.flip(); var s = StandardCharsets.UTF_8.decode(buf).toString(); var parts = s.split("\t", 3); var simpel = Integer.parseInt(parts[1]); var clues = GSON.fromJson(parts[2], String[].class); return new ShardLem(w, simpel, clues); } } static int readIntAt(FileChannel ch, long pos) throws IOException { var b = ByteBuffer.allocate(4).order(ORDER); ch.position(pos); ch.read(b); b.flip(); return b.getInt(); } // --- Demo main --- public static ShardLem lookup(long w) { try { var i = findIndexInMapMmap(Lemma.pack43(w)); System.out.println("\nQuery: w=" + w + " -> i=" + i); if (i >= 0) { var rec = readRecord(w, i); System.out.println(" simpel=" + rec.simpel()); System.out.println(" clues=" + Arrays.toString(rec.clues())); return rec; } else { System.out.println(" NOT FOUND"); throw new RuntimeException("NOT FOUND"); } } catch (Exception e) { throw new RuntimeException(e); } } public record ShardLem(long w, int simpel, String[] clues) { } }