diff --git a/src/main/java/ru/windcorp/optica/common/util/BinUtil.java b/src/main/java/ru/windcorp/optica/common/util/BinUtil.java
index 43b8424..10193fd 100644
--- a/src/main/java/ru/windcorp/optica/common/util/BinUtil.java
+++ b/src/main/java/ru/windcorp/optica/common/util/BinUtil.java
@@ -31,5 +31,9 @@ public class BinUtil {
public static int roundToGreaterPowerOf2(int x) {
return closestGreaterPowerOf2(x - 1);
}
+
+ public static boolean isPowerOf2(int x) {
+ return (x > 0) && ((x & (x - 1)) == 0);
+ }
}
diff --git a/src/main/java/ru/windcorp/optica/common/util/CoordinatePacker.java b/src/main/java/ru/windcorp/optica/common/util/CoordinatePacker.java
index 5d2f297..d54e6e2 100644
--- a/src/main/java/ru/windcorp/optica/common/util/CoordinatePacker.java
+++ b/src/main/java/ru/windcorp/optica/common/util/CoordinatePacker.java
@@ -22,6 +22,9 @@ public class CoordinatePacker {
private static final int BITS_3_INTS_INTO_LONG;
private static final long MASK_3_INTS_INTO_LONG;
+ private static final int BITS_2_INTS_INTO_LONG;
+ private static final long MASK_2_INTS_INTO_LONG;
+
static {
BITS_3_INTS_INTO_LONG = 64 / 3;
@@ -37,7 +40,10 @@ public class CoordinatePacker {
* \_________/ - BITS_3_INTS_INTO_LONG ones - WIN
*/
- MASK_3_INTS_INTO_LONG = (1 << BITS_3_INTS_INTO_LONG) - 1;
+ MASK_3_INTS_INTO_LONG = (1l << BITS_3_INTS_INTO_LONG) - 1;
+
+ BITS_2_INTS_INTO_LONG = 64 / 2;
+ MASK_2_INTS_INTO_LONG = (1l << BITS_2_INTS_INTO_LONG) - 1;
}
public static long pack3IntsIntoLong(int a, int b, int c) {
@@ -65,5 +71,24 @@ public class CoordinatePacker {
return result;
}
+
+ public static long pack2IntsIntoLong(int a, int b) {
+ return
+ ((a & MASK_2_INTS_INTO_LONG) << (1 * BITS_2_INTS_INTO_LONG)) |
+ ((b & MASK_2_INTS_INTO_LONG) << (0 * BITS_2_INTS_INTO_LONG));
+ }
+
+ public static int unpack2IntsFromLong(long packed, int index) {
+ if (index < 0 || index >= 2) {
+ throw new IllegalArgumentException("Invalid index " + index);
+ }
+
+ int result = (int) (
+ (packed >>> ((1 - index) * BITS_2_INTS_INTO_LONG))
+ & MASK_2_INTS_INTO_LONG
+ );
+
+ return result;
+ }
}
diff --git a/src/test/java/ru/windcorp/optica/util/BinUtilIsPowerOf2Test.java b/src/test/java/ru/windcorp/optica/util/BinUtilIsPowerOf2Test.java
new file mode 100644
index 0000000..8db1b18
--- /dev/null
+++ b/src/test/java/ru/windcorp/optica/util/BinUtilIsPowerOf2Test.java
@@ -0,0 +1,72 @@
+/*******************************************************************************
+ * Optica
+ * Copyright (C) 2020 Wind Corporation
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *******************************************************************************/
+package ru.windcorp.optica.util;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.Random;
+
+import org.junit.Test;
+
+import ru.windcorp.optica.common.util.BinUtil;
+
+public class BinUtilIsPowerOf2Test {
+
+ @Test
+ public void cornerCases() {
+ test(-1);
+ test(0);
+ test(1);
+
+ test(15);
+ test(16);
+ test(17);
+
+ test(1 << 30);
+ test(Integer.MAX_VALUE);
+ test(Integer.MIN_VALUE);
+ }
+
+ @Test
+ public void random() {
+ Random random = new Random(0);
+
+ for (int x = 0; x < 10000; ++x) {
+ test(x);
+ }
+
+ for (int i = 0; i < 10000; ++i) {
+ test(random.nextInt());
+ }
+ }
+
+ void test(int x) {
+ assertEquals("Round, x = " + x, referenceIsPowerOf2(x), BinUtil.isPowerOf2(x));
+ }
+
+ boolean referenceIsPowerOf2(int x) {
+ for (int power = 1; power > 0; power *= 2) {
+ if (x == power) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+}
diff --git a/src/test/java/ru/windcorp/optica/util/BinUtilTest.java b/src/test/java/ru/windcorp/optica/util/BinUtilRoundTest.java
similarity index 94%
rename from src/test/java/ru/windcorp/optica/util/BinUtilTest.java
rename to src/test/java/ru/windcorp/optica/util/BinUtilRoundTest.java
index 0588084..b959a81 100644
--- a/src/test/java/ru/windcorp/optica/util/BinUtilTest.java
+++ b/src/test/java/ru/windcorp/optica/util/BinUtilRoundTest.java
@@ -25,7 +25,7 @@ import org.junit.Test;
import ru.windcorp.optica.common.util.BinUtil;
-public class BinUtilTest {
+public class BinUtilRoundTest {
@Test
public void cornerCases() {
diff --git a/src/test/java/ru/windcorp/optica/util/CoordinatePacker2Test.java b/src/test/java/ru/windcorp/optica/util/CoordinatePacker2Test.java
new file mode 100644
index 0000000..b7b667f
--- /dev/null
+++ b/src/test/java/ru/windcorp/optica/util/CoordinatePacker2Test.java
@@ -0,0 +1,69 @@
+/*******************************************************************************
+ * Optica
+ * Copyright (C) 2020 Wind Corporation
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *******************************************************************************/
+package ru.windcorp.optica.util;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.Random;
+
+import org.junit.Test;
+
+import ru.windcorp.optica.common.util.CoordinatePacker;
+
+public class CoordinatePacker2Test {
+
+ @Test
+ public void cornerCases() {
+ check(0, 0);
+ check(0, 42);
+ check(42, 0);
+ check(1, 1);
+ check(-1, -1);
+
+ for (int a : new int[] {Integer.MAX_VALUE, Integer.MIN_VALUE, 0}) {
+ for (int b : new int[] {Integer.MAX_VALUE, Integer.MIN_VALUE, 0}) {
+ check(a, b);
+ }
+ }
+ }
+
+ @Test
+ public void randomValues() {
+ Random random = new Random(0);;
+
+ for (int i = 0; i < 1000000; ++i) {
+ check(
+ random.nextInt(),
+ random.nextInt()
+ );
+ }
+ }
+
+ private void check(int a, int b) {
+
+ long packed = CoordinatePacker.pack2IntsIntoLong(a, b);
+
+ int unpackedA = CoordinatePacker.unpack2IntsFromLong(packed, 0);
+ int unpackedB = CoordinatePacker.unpack2IntsFromLong(packed, 1);
+
+ assertEquals(a, unpackedA);
+ assertEquals(b, unpackedB);
+
+ }
+
+}
diff --git a/src/test/java/ru/windcorp/optica/util/CoordinatePackerTest.java b/src/test/java/ru/windcorp/optica/util/CoordinatePacker3Test.java
similarity index 95%
rename from src/test/java/ru/windcorp/optica/util/CoordinatePackerTest.java
rename to src/test/java/ru/windcorp/optica/util/CoordinatePacker3Test.java
index 9768c45..06fcb46 100644
--- a/src/test/java/ru/windcorp/optica/util/CoordinatePackerTest.java
+++ b/src/test/java/ru/windcorp/optica/util/CoordinatePacker3Test.java
@@ -25,7 +25,7 @@ import org.junit.Test;
import ru.windcorp.optica.common.util.CoordinatePacker;
-public class CoordinatePackerTest {
+public class CoordinatePacker3Test {
@Test
public void cornerCases() {