diff --git a/src/main/java/net/woggioni/jwo/Leb128.java b/src/main/java/net/woggioni/jwo/Leb128.java new file mode 100644 index 0000000..cdabf61 --- /dev/null +++ b/src/main/java/net/woggioni/jwo/Leb128.java @@ -0,0 +1,76 @@ +package net.woggioni.jwo; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import lombok.SneakyThrows; + +import java.io.InputStream; +import java.io.OutputStream; + +public class Leb128 { + + public static long reverse(long n) { + long res = 0; + for(int i = 0; i < 8; i++) { + long b = (n & (0xFFL << (i * 8))) >>> (i * 8); + res |= b << ((7 - i) * 8); + } + return res; + } + + public static int encode(OutputStream os, double input) { + return encode(os, reverse(Double.doubleToLongBits(input))); + } + + @SneakyThrows + public static int encode(OutputStream os, long input) { + int bytes_written = 0; + long number = input >= 0 ? (input << 1) : (-(input + 1)) << 1 | 1; + while((number & 127L) != number) { + os.write((int) (number & 127) | 128); + bytes_written++; + number >>>= 7; + } + os.write((int) number); + return ++bytes_written; + } + + @RequiredArgsConstructor + public static class Leb128Decoder { + @Getter + private int bytesRead = 0; + + private final InputStream is; + + public byte decodeByte() { + return (byte) decode(); + } + + public short decodeShort() { + return (short) decode(); + } + + public int decodeInt() { + return (int) decode(); + } + + public double decodeDouble() { + return Double.longBitsToDouble(reverse(decode())); + } + + @SneakyThrows + public long decode() { + long res = 0; + for(int i = 0; i < (8 * 8 + 6) / 7; i++) { + int c = is.read(); + bytesRead++; + if(c < 0) { + throw new IllegalArgumentException("Unexpected end of file"); + } + res |= ((long)(c & 127)) << (i * 7); + if((byte) c >= 0) break; + } + return (res & 1) != 0 ? - (res >>> 1) - 1 : (res >>> 1); + } + } +} diff --git a/src/main/java/net/woggioni/jwo/tuple/MutableTuple2.java b/src/main/java/net/woggioni/jwo/tuple/MutableTuple2.java index 840a0a2..65f3444 100644 --- a/src/main/java/net/woggioni/jwo/tuple/MutableTuple2.java +++ b/src/main/java/net/woggioni/jwo/tuple/MutableTuple2.java @@ -13,7 +13,15 @@ public class MutableTuple2 { public T _1; public U _2; - public static , Y extends Comparable> Comparator> getComparator(Class cls1, Class cls2) { + public static , Y extends Comparable> + Comparator> getComparator(Class cls1, Class cls2) { + return Comparator + .comparing((MutableTuple2 t) -> t._1) + .thenComparing((MutableTuple2 t) -> t._2); + } + + public static , Y extends Comparable> + Comparator> getComparator(MutableTuple2 tuple) { return Comparator .comparing((MutableTuple2 t) -> t._1) .thenComparing((MutableTuple2 t) -> t._2); diff --git a/src/main/java/net/woggioni/jwo/tuple/MutableTuple3.java b/src/main/java/net/woggioni/jwo/tuple/MutableTuple3.java index a78e1c0..6e9e6cc 100644 --- a/src/main/java/net/woggioni/jwo/tuple/MutableTuple3.java +++ b/src/main/java/net/woggioni/jwo/tuple/MutableTuple3.java @@ -14,7 +14,16 @@ public class MutableTuple3 { public U _2; public V _3; - public static , Y extends Comparable, Z extends Comparable> Comparator> getComparator(Class cls1, Class cls2, Class cls3) { + public static , Y extends Comparable, Z extends Comparable> + Comparator> getComparator(Class cls1, Class cls2, Class cls3) { + return Comparator + .comparing((MutableTuple3 t) -> t._1) + .thenComparing((MutableTuple3 t) -> t._2) + .thenComparing((MutableTuple3 t) -> t._3); + } + + public static , Y extends Comparable, Z extends Comparable> + Comparator> getComparator(MutableTuple3 tuple) { return Comparator .comparing((MutableTuple3 t) -> t._1) .thenComparing((MutableTuple3 t) -> t._2) diff --git a/src/main/java/net/woggioni/jwo/tuple/Tuple2.java b/src/main/java/net/woggioni/jwo/tuple/Tuple2.java index 2852663..f4071e2 100644 --- a/src/main/java/net/woggioni/jwo/tuple/Tuple2.java +++ b/src/main/java/net/woggioni/jwo/tuple/Tuple2.java @@ -16,4 +16,10 @@ public class Tuple2 { .comparing((Tuple2 t) -> t._1) .thenComparing((Tuple2 t) -> t._2); } + + public static , Y extends Comparable> Comparator> getComparator(Tuple2 tuple) { + return Comparator + .comparing((Tuple2 t) -> t._1) + .thenComparing((Tuple2 t) -> t._2); + } } diff --git a/src/main/java/net/woggioni/jwo/tuple/Tuple3.java b/src/main/java/net/woggioni/jwo/tuple/Tuple3.java index 3658f4d..dab37c2 100644 --- a/src/main/java/net/woggioni/jwo/tuple/Tuple3.java +++ b/src/main/java/net/woggioni/jwo/tuple/Tuple3.java @@ -12,10 +12,19 @@ public class Tuple3 { public final U _2; public final V _3; - public static , Y extends Comparable, Z extends Comparable> Comparator> getComparator(Class cls1, Class cls2, Class cls3) { + public static , Y extends Comparable, Z extends Comparable> + Comparator> getComparator(Class cls1, Class cls2, Class cls3) { return Comparator .comparing((Tuple3 t) -> t._1) .thenComparing((Tuple3 t) -> t._2) .thenComparing((Tuple3 t) -> t._3); } + + public static , Y extends Comparable, Z extends Comparable> + Comparator> getComparator(Tuple3 tuple) { + return Comparator + .comparing((Tuple3 t) -> t._1) + .thenComparing((Tuple3 t) -> t._2) + .thenComparing((Tuple3 t) -> t._3); + } } diff --git a/src/test/java/net/woggioni/jwo/utils/JWOTest.java b/src/test/java/net/woggioni/jwo/JWOTest.java similarity index 94% rename from src/test/java/net/woggioni/jwo/utils/JWOTest.java rename to src/test/java/net/woggioni/jwo/JWOTest.java index 82892ab..287cceb 100644 --- a/src/test/java/net/woggioni/jwo/utils/JWOTest.java +++ b/src/test/java/net/woggioni/jwo/JWOTest.java @@ -1,14 +1,10 @@ -package net.woggioni.jwo.utils; +package net.woggioni.jwo; -import lombok.RequiredArgsConstructor; import lombok.SneakyThrows; -import net.woggioni.jwo.Chronometer; -import net.woggioni.jwo.JWO; import org.junit.Assert; import org.junit.Test; import java.io.*; -import java.net.URI; import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; diff --git a/src/test/java/net/woggioni/jwo/Leb128Test.java b/src/test/java/net/woggioni/jwo/Leb128Test.java new file mode 100644 index 0000000..4f70042 --- /dev/null +++ b/src/test/java/net/woggioni/jwo/Leb128Test.java @@ -0,0 +1,61 @@ +package net.woggioni.jwo; + +import lombok.SneakyThrows; +import org.junit.Assert; +import org.junit.Test; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.util.Arrays; +import java.util.List; + +public class Leb128Test { + + @Test + public void testLong() { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + List numbers = Arrays.asList(0L, 1L, -3L, 5L, 7L, 8L, 125L, 255L, 10325L, -2000L, 1024L * 1024L * 1024L * 12L); + + numbers.forEach(n -> Leb128.encode(baos, n)); + + byte[] bytes = baos.toByteArray(); + + Leb128.Leb128Decoder decoder = new Leb128.Leb128Decoder(new ByteArrayInputStream(bytes)); + numbers.forEach(n -> Assert.assertEquals((long) n, decoder.decode())); + } + + @Test + public void testDouble() { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + List numbers = Arrays.asList( + 0.0, 1.5, -3.0, 0.5, 2.5, 8.25, -125.0, 255.0, 10325.0, -2000.0, 1024.0 * 1024 * 1024 * 12, + -122.42200352825247, 37.80848009696725); + + numbers.forEach(n -> Leb128.encode(baos, n)); + + byte[] bytes = baos.toByteArray(); + + Leb128.Leb128Decoder decoder = new Leb128.Leb128Decoder(new ByteArrayInputStream(bytes)); + numbers.forEach(n -> Assert.assertEquals(n, decoder.decodeDouble(), 0.0)); + } + + + @Test + public void reverseTest() { + long n = 101325; + Assert.assertEquals(n, Leb128.reverse(Leb128.reverse(n))); + } + + @Test + @SneakyThrows + public void reverseTestDouble() { + double n = 0.25; + long doubleLong = Double.doubleToLongBits(n); + long reverse = Leb128.reverse(doubleLong); + try(ByteArrayOutputStream os = new ByteArrayOutputStream()) { + Leb128.encode(os, reverse); + byte[] bytes = os.toByteArray(); + Assert.assertEquals(3, bytes.length); + } + } +} diff --git a/src/test/java/net/woggioni/jwo/utils/io/CircularBufferTest.java b/src/test/java/net/woggioni/jwo/io/CircularBufferTest.java similarity index 97% rename from src/test/java/net/woggioni/jwo/utils/io/CircularBufferTest.java rename to src/test/java/net/woggioni/jwo/io/CircularBufferTest.java index 4a6f9df..278d70a 100644 --- a/src/test/java/net/woggioni/jwo/utils/io/CircularBufferTest.java +++ b/src/test/java/net/woggioni/jwo/io/CircularBufferTest.java @@ -1,4 +1,4 @@ -package net.woggioni.jwo.utils.io; +package net.woggioni.jwo.io; import lombok.SneakyThrows; import net.woggioni.jwo.io.CircularBuffer; diff --git a/src/test/java/net/woggioni/jwo/utils/tree/TreeWalkerTest.java b/src/test/java/net/woggioni/jwo/tree/TreeWalkerTest.java similarity index 95% rename from src/test/java/net/woggioni/jwo/utils/tree/TreeWalkerTest.java rename to src/test/java/net/woggioni/jwo/tree/TreeWalkerTest.java index 99cec23..7a70f0c 100644 --- a/src/test/java/net/woggioni/jwo/utils/tree/TreeWalkerTest.java +++ b/src/test/java/net/woggioni/jwo/tree/TreeWalkerTest.java @@ -1,11 +1,7 @@ -package net.woggioni.jwo.utils.tree; +package net.woggioni.jwo.tree; import lombok.Getter; import lombok.RequiredArgsConstructor; -import net.woggioni.jwo.tree.StackContext; -import net.woggioni.jwo.tree.TreeNode; -import net.woggioni.jwo.tree.TreeNodeVisitor; -import net.woggioni.jwo.tree.TreeWalker; import net.woggioni.jwo.tuple.Tuple2; import org.junit.Assert; import org.junit.Test;