diff --git a/pom.xml b/pom.xml
index aaa93ac..e60641d 100644
--- a/pom.xml
+++ b/pom.xml
@@ -9,11 +9,48 @@
maven-compiler-plugin
- 3.8.1
+ 3.11.0
17
+ UTF-8
+
+ org.apache.maven.plugins
+ maven-jar-plugin
+ 3.3.0
+
+
+ org.apache.maven.plugins
+ maven-javadoc-plugin
+ 3.6.2
+
+
+ UTF-8
+ src/main/java
+
+
+
+ attach-javadocs
+
+ jar
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-source-plugin
+ 3.3.0
+
+
+ attach-sources
+
+ jar
+
+
+
+
diff --git a/src/main/java/me/mrletsplay/shareclientcore/document/Util.java b/src/main/java/me/mrletsplay/shareclientcore/document/Util.java
index 01d8e5e..ea883a6 100644
--- a/src/main/java/me/mrletsplay/shareclientcore/document/Util.java
+++ b/src/main/java/me/mrletsplay/shareclientcore/document/Util.java
@@ -5,6 +5,8 @@ import java.util.List;
public class Util {
+ // Source for a lot of the code: https://digitalfreepen.com/2017/10/06/simple-real-time-collaborative-text-editor.html
+
public static final int BASE = 10;
public static int comparePositions(Identifier[] a, Identifier[] b) {
@@ -17,14 +19,17 @@ public class Util {
}
public static Identifier[] generatePositionBetween(Identifier[] before, Identifier[] after, int site) {
+ if(comparePositions(before, after) != -1) throw new IllegalArgumentException("before must be strictly less than after");
+
List newPosition = new ArrayList<>();
for(int i = 0; i < Math.min(before.length, after.length) + 1; i++) {
Identifier c1 = i >= before.length ? new Identifier(0, site) : before[i];
- Identifier c2 = i >= after.length ? new Identifier(BASE, site) : after[i];
+ Identifier c2 = i >= after.length ? new Identifier(BASE - 1, site) : after[i];
if(c1.digit() != c2.digit()) {
- // TODO: generate delta, then pick a value between
+ int[] incremented = getIncremented(before, after, i);
+ return constructPosition(incremented, before, after, site);
}
if(c1.site() == c2.site()) {
@@ -34,7 +39,8 @@ public class Util {
if(c1.site() < c2.site()) {
// Anything starting with before will be sorted before after
- newPosition.add(new Identifier(BASE, site));
+ newPosition.add(c1);
+ newPosition.add(new Identifier(1, site));
return newPosition.toArray(Identifier[]::new);
}
@@ -44,9 +50,9 @@ public class Util {
return null;
}
- public static int[] getIncremented(Identifier[] i1, Identifier[] i2, int offset) {
+ public static int[] getIncremented(Identifier[] before, Identifier[] after, int offset) {
// TODO: can potentially be optimized by just calculating the index of the first non-zero digit (e.g. don't return array and discard it -> just return the index)
- int[] delta = subtract(i2, i1, offset);
+ int[] delta = subtract(after, before, offset);
int firstNonZero = 0;
for(int i = 0; i < delta.length; i++) {
if(delta[i] != 0) {
@@ -57,16 +63,38 @@ public class Util {
// Because of math, (firstNonZero + 1) >= i1.length (I think)
// then make the array 1 longer so we have space for the increment (which is one order of magnitude smaller)
- int[] incremented = new int[firstNonZero + 2];
+ int[] incremented = new int[offset + firstNonZero + 2];
for(int i = 0; i < incremented.length; i++) {
- incremented[i] = i <= i1.length ? i1[i].digit() : 0;
+ incremented[i] = i < before.length ? before[i].digit() : 0;
}
- add1AtIndex(incremented, firstNonZero + 1); // last digit might be zero, which is ambigious, inc again
- if(incremented[incremented.length - 1] == 0) add1AtIndex(incremented, firstNonZero + 1);
+ add1AtIndex(incremented, offset + firstNonZero + 1); // last digit might be zero, which is ambigious, inc again
+ if(incremented[incremented.length - 1] == 0) add1AtIndex(incremented, offset + firstNonZero + 1);
return incremented;
}
+ public static Identifier[] constructPosition(int[] num, Identifier[] before, Identifier[] after, int site) {
+ // Implements rules according to constructPosition from https://inria.hal.science/inria-00432368/document
+
+ Identifier[] ident = new Identifier[num.length];
+
+ for(int i = 0; i < num.length; i++) {
+ int digit = num[i];
+
+ if(i == num.length - 1) {
+ ident[i] = new Identifier(digit, site);
+ }else if(i < before.length && digit == before[i].digit()) {
+ ident[i] = before[i];
+ }else if(i < after.length && digit == after[i].digit()) {
+ ident[i] = after[i];
+ }else {
+ ident[i] = new Identifier(digit, site);
+ }
+ }
+
+ return ident;
+ }
+
/**
* Subtract b from a, where a > b
*/
diff --git a/src/test/java/me/mrletsplay/shareclientcore/DecimalTest.java b/src/test/java/me/mrletsplay/shareclientcore/DecimalTest.java
index 4bcd748..99bf09f 100644
--- a/src/test/java/me/mrletsplay/shareclientcore/DecimalTest.java
+++ b/src/test/java/me/mrletsplay/shareclientcore/DecimalTest.java
@@ -12,58 +12,122 @@ public class DecimalTest {
@Test
public void testSimpleSubtraction() {
- Identifier[] a = new Identifier[] { new Identifier(1, 0), new Identifier(2, 0), new Identifier(3, 0) };
- Identifier[] b = new Identifier[] { new Identifier(1, 0), new Identifier(1, 0), new Identifier(3, 0) };
+ Identifier[] a = { new Identifier(1, 0), new Identifier(2, 0), new Identifier(3, 0) };
+ Identifier[] b = { new Identifier(1, 0), new Identifier(1, 0), new Identifier(3, 0) };
assertArrayEquals(new int[] { 0, 1, 0 }, Util.subtract(a, b, 0));
}
@Test
public void testCarrySubtraction() {
- Identifier[] a = new Identifier[] { new Identifier(2, 0), new Identifier(0, 0), new Identifier(4, 0) };
- Identifier[] b = new Identifier[] { new Identifier(1, 0), new Identifier(0, 0), new Identifier(5, 0) };
+ Identifier[] a = { new Identifier(2, 0), new Identifier(0, 0), new Identifier(4, 0) };
+ Identifier[] b = { new Identifier(1, 0), new Identifier(0, 0), new Identifier(5, 0) };
assertArrayEquals(new int[] { 0, Util.BASE - 1, Util.BASE - 1 }, Util.subtract(a, b, 0));
}
@Test
public void testOffsetSubtraction() {
- Identifier[] a = new Identifier[] { new Identifier(1, 0), new Identifier(0, 0), new Identifier(5, 0) };
- Identifier[] b = new Identifier[] { new Identifier(1, 0), new Identifier(0, 0), new Identifier(4, 0) };
+ Identifier[] a = { new Identifier(1, 0), new Identifier(0, 0), new Identifier(5, 0) };
+ Identifier[] b = { new Identifier(1, 0), new Identifier(0, 0), new Identifier(4, 0) };
assertArrayEquals(new int[] { 0, 1 }, Util.subtract(a, b, 1));
}
@Test
public void testReversedInputFails() {
- Identifier[] a = new Identifier[] { new Identifier(1, 0), new Identifier(1, 0), new Identifier(3, 0) };
- Identifier[] b = new Identifier[] { new Identifier(1, 0), new Identifier(2, 0), new Identifier(3, 0) };
+ Identifier[] a = { new Identifier(1, 0), new Identifier(1, 0), new Identifier(3, 0) };
+ Identifier[] b = { new Identifier(1, 0), new Identifier(2, 0), new Identifier(3, 0) };
assertThrows(RuntimeException.class, () -> Util.subtract(a, b, 0));
}
@Test
public void testSimpleAdd1() {
- int[] a = new int[] { 0, 0 };
+ int[] a = { 0, 0 };
Util.add1AtIndex(a, 1);
assertArrayEquals(new int[] { 0, 1 }, a);
}
@Test
public void testCarryAdd1() {
- int[] a = new int[] { 0, Util.BASE - 1 };
+ int[] a = { 0, Util.BASE - 1 };
Util.add1AtIndex(a, 1);
assertArrayEquals(new int[] { 1, 0 }, a);
}
@Test
public void testCarryAdd1_2() {
- int[] a = new int[] { 0, Util.BASE - 1, Util.BASE - 1 };
+ int[] a = { 0, Util.BASE - 1, Util.BASE - 1 };
Util.add1AtIndex(a, 2);
assertArrayEquals(new int[] { 1, 0, 0 }, a);
}
@Test
public void testCarryAdd1_3() {
- int[] a = new int[] { 0, Util.BASE - 1, Util.BASE - 1 };
+ int[] a = { 0, Util.BASE - 1, Util.BASE - 1 };
Util.add1AtIndex(a, 1);
assertArrayEquals(new int[] { 1, 0, Util.BASE - 1 }, a);
}
+ @Test
+ public void testIncrement_1() {
+ Identifier[] a = { new Identifier(1, 0), new Identifier(2, 0) };
+ Identifier[] b = { new Identifier(1, 0), new Identifier(3, 0) };
+ assertArrayEquals(new int[] { 1, 2, 1 }, Util.getIncremented(a, b, 1));
+ }
+
+ @Test
+ public void testIncrement_2() {
+ Identifier[] a = { new Identifier(1, 0), new Identifier(2, 0) };
+ Identifier[] b = { new Identifier(1, 0), new Identifier(2, 0), new Identifier(Util.BASE - 1, 0) };
+ assertArrayEquals(new int[] { 1, 2, 0, 1 }, Util.getIncremented(a, b, 1));
+ }
+
+ @Test
+ public void testCarryIncrement() {
+ Identifier[] a = { new Identifier(1, 0), new Identifier(2, 0), new Identifier(Util.BASE - 1, 0) };
+ Identifier[] b = { new Identifier(1, 0), new Identifier(4, 0) };
+ assertArrayEquals(new int[] { 1, 3, 1 }, Util.getIncremented(a, b, 1));
+ }
+
+ @Test
+ public void testConstructPosition_1() {
+ Identifier[] a = { new Identifier(1, 0), new Identifier(2, 0), new Identifier(Util.BASE - 1, 0) };
+ Identifier[] b = { new Identifier(1, 0), new Identifier(4, 0) };
+ int[] newIdent = Util.getIncremented(a, b, 1);
+ Identifier[] expected = { new Identifier(1, 0), new Identifier(3, 1), new Identifier(1, 1) };
+ assertArrayEquals(expected, Util.constructPosition(newIdent, a, b, 1));
+ }
+
+ @Test
+ public void testConstructPosition_2() {
+ Identifier[] a = { new Identifier(1, 0), new Identifier(2, 2), new Identifier(2, 2) };
+ Identifier[] b = { new Identifier(1, 0), new Identifier(4, 1), new Identifier(3, 1) };
+ int[] newIdent = Util.getIncremented(a, b, 1);
+ Identifier[] expected = { new Identifier(1, 0), new Identifier(2, 2), new Identifier(3, 3) };
+ assertArrayEquals(expected, Util.constructPosition(newIdent, a, b, 3));
+ }
+
+ @Test
+ public void testGeneratePosition_1() {
+ Identifier[] a = { new Identifier(1, 0), new Identifier(2, 1) };
+ Identifier[] b = { new Identifier(1, 0), new Identifier(3, 2) };
+ Identifier[] newIdent = Util.generatePositionBetween(a, b, 3);
+ Identifier[] expected = { new Identifier(1, 0), new Identifier(2, 1), new Identifier(1, 3) };
+ assertArrayEquals(expected, newIdent);
+ }
+
+ @Test
+ public void testGeneratePosition_2() {
+ Identifier[] a = { new Identifier(1, 0), new Identifier(2, 1) };
+ Identifier[] b = { new Identifier(1, 0), new Identifier(2, 2) };
+ Identifier[] newIdent = Util.generatePositionBetween(a, b, 3);
+ Identifier[] expected = { new Identifier(1, 0), new Identifier(2, 1), new Identifier(1, 3) };
+ assertArrayEquals(expected, newIdent);
+ }
+
+ @Test
+ public void testGeneratePositionInvalidInputFails() {
+ Identifier[] a = { new Identifier(1, 0), new Identifier(2, 2) };
+ Identifier[] b = { new Identifier(1, 0), new Identifier(2, 1) };
+ assertThrows(IllegalArgumentException.class, () -> Util.generatePositionBetween(a, b, 3));
+ }
+
}