diff --git a/src/main/java/de/hechler/patrick/utils/cc/ModifiableString.java b/src/main/java/de/hechler/patrick/utils/cc/ModifiableString.java index c1db6b0de25f4b8979132ad8102cbd64ba79d399..c30e145d6641d32a9011b6cc8715a0532a6fd6f2 100644 --- a/src/main/java/de/hechler/patrick/utils/cc/ModifiableString.java +++ b/src/main/java/de/hechler/patrick/utils/cc/ModifiableString.java @@ -36,4 +36,10 @@ public interface ModifiableString extends CharSequence { return toString().getBytes(cs); } + @Override + int hashCode(); + + @Override + boolean equals(Object obj); + } diff --git a/src/main/java/de/hechler/patrick/utils/cc/file/CCPath.java b/src/main/java/de/hechler/patrick/utils/cc/file/CCPath.java index f54b3a5419fd6003b429655346b255698886194a..d2e4a0d3d3411060566d8c87beda51be5675a9c2 100644 --- a/src/main/java/de/hechler/patrick/utils/cc/file/CCPath.java +++ b/src/main/java/de/hechler/patrick/utils/cc/file/CCPath.java @@ -3,17 +3,12 @@ package de.hechler.patrick.utils.cc.file; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; +import java.util.Objects; -public class CCPath implements CCFile { +public record CCPath(Path path) implements CCFile { - private final Path path; - - public CCPath(Path path) { - this.path = path; - } - - public Path path() { - return path; + public CCPath { + Objects.requireNonNull(path, "path"); } @Override @@ -26,38 +21,9 @@ public class CCPath implements CCFile { return Files.readAllBytes(path); } - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((path == null) ? 0 : path.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - CCPath other = (CCPath) obj; - if (path == null) { - if (other.path != null) - return false; - } else if (!path.equals(other.path)) - return false; - return true; - } - @Override public String toString() { - StringBuilder builder = new StringBuilder(); - builder.append("CCPath [path="); - builder.append(path); - builder.append("]"); - return builder.toString(); + return path.toString(); } } diff --git a/src/main/java/de/hechler/patrick/utils/cc/file/CCSrcDstPath.java b/src/main/java/de/hechler/patrick/utils/cc/file/CCSrcDstPath.java index 6d08abaac83bb0ace5629ad5f7ae946875cd0290..df05775f2fc070113b5efe94eb1b356f63c60515 100644 --- a/src/main/java/de/hechler/patrick/utils/cc/file/CCSrcDstPath.java +++ b/src/main/java/de/hechler/patrick/utils/cc/file/CCSrcDstPath.java @@ -3,23 +3,13 @@ package de.hechler.patrick.utils.cc.file; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; +import java.util.Objects; -public class CCSrcDstPath implements CCFile { +public record CCSrcDstPath(Path src, Path dst) implements CCFile { - private final Path src; - private final Path dst; - - public CCSrcDstPath(Path src, Path dst) { - this.src = src; - this.dst = dst; - } - - public Path src() { - return src; - } - - public Path dst() { - return dst; + public CCSrcDstPath { + Objects.requireNonNull(src, "source path"); + Objects.requireNonNull(dst, "destination path"); } @Override @@ -33,46 +23,13 @@ public class CCSrcDstPath implements CCFile { Files.write(dst, content); } - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((dst == null) ? 0 : dst.hashCode()); - result = prime * result + ((src == null) ? 0 : src.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - CCSrcDstPath other = (CCSrcDstPath) obj; - if (dst == null) { - if (other.dst != null) - return false; - } else if (!dst.equals(other.dst)) - return false; - if (src == null) { - if (other.src != null) - return false; - } else if (!src.equals(other.src)) - return false; - return true; - } - @Override public String toString() { - StringBuilder builder = new StringBuilder(); - builder.append("CCSrcDstPath [src="); - builder.append(src); - builder.append(", dst="); - builder.append(dst); - builder.append("]"); - return builder.toString(); + StringBuilder b = new StringBuilder(); + b.append(src); + b.append(" ==> "); + b.append(dst); + return b.toString(); } } diff --git a/src/main/java/de/hechler/patrick/utils/cc/file/CCStream.java b/src/main/java/de/hechler/patrick/utils/cc/file/CCStream.java index 61a79c851ce59201fdd077f1cd2f2f56b8b37598..0b7d493eeab6fe3ce30fa9f5ba02aacd46b3e432 100644 --- a/src/main/java/de/hechler/patrick/utils/cc/file/CCStream.java +++ b/src/main/java/de/hechler/patrick/utils/cc/file/CCStream.java @@ -3,6 +3,7 @@ package de.hechler.patrick.utils.cc.file; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.util.Objects; public class CCStream implements CCFile { @@ -10,8 +11,8 @@ public class CCStream implements CCFile { private final OutputStream out; public CCStream(InputStream in, OutputStream out) { - this.in = in; - this.out = out; + this.in = Objects.requireNonNull(in, "input stream"); + this.out = Objects.requireNonNull(out, "output stream"); } @Override @@ -46,15 +47,9 @@ public class CCStream implements CCFile { if (getClass() != obj.getClass()) return false; CCStream other = (CCStream) obj; - if (in == null) { - if (other.in != null) - return false; - } else if (!in.equals(other.in)) + if (!in.equals(other.in)) return false; - if (out == null) { - if (other.out != null) - return false; - } else if (!out.equals(other.out)) + if (!out.equals(other.out)) return false; return true; } diff --git a/src/main/java/de/hechler/patrick/utils/cc/ms/DuplicateModifiableString.java b/src/main/java/de/hechler/patrick/utils/cc/ms/DuplicateModifiableString.java new file mode 100644 index 0000000000000000000000000000000000000000..2733c76f7c58a9e41b829de3c85dd5ebf9b38269 --- /dev/null +++ b/src/main/java/de/hechler/patrick/utils/cc/ms/DuplicateModifiableString.java @@ -0,0 +1,162 @@ +package de.hechler.patrick.utils.cc.ms; + +import java.nio.charset.Charset; +import java.util.Arrays; + +import de.hechler.patrick.utils.cc.ModifiableString; + +public class DuplicateModifiableString implements ModifiableString { + + private final ModifiableString a; + private final ModifiableString b; + + public DuplicateModifiableString() { + this(new ModStringBuilder(), new FastStringList()); + } + + public DuplicateModifiableString(ModifiableString b) { + this(new ModStringBuilder(), b); + } + + public DuplicateModifiableString(ModifiableString a, ModifiableString b) { + checkEquals(a, b); + checkEquals(a.hashCode(), b.hashCode()); + this.a = a; + this.b = b; + } + + private void checkEquals() { + checkEquals(a, b); + } + + private static int checkEquals(int a, int b) { + if (a != b) { + throw new AssertionError(); + } + return a; + } + + private static char checkEquals(char a, char b) { + if (a != b) { + throw new AssertionError(); + } + return a; + } + + private static boolean checkEquals(boolean a, boolean b) { + if (a != b) { + throw new AssertionError(); + } + return a; + } + + private static <T> T checkEquals(T a, T b) { + if (!a.equals(b) || a == b) { + throw new AssertionError(); + } + return a; + } + + private static byte[] checkEquals(byte[] a, byte[] b) { + if (!Arrays.equals(a, b) || a == b) { + throw new AssertionError(); + } + return a; + } + + @Override + public int length() { + return checkEquals(a.length(), b.length()); + } + + @Override + public char charAt(int index) { + char c = a.charAt(index); + char c2 = b.charAt(index); + return checkEquals(c, c2); + } + + @Override + public CharSequence subSequence(int start, int end) { + CharSequence cs = a.subSequence(start, end); + CharSequence cs2 = b.subSequence(start, end); + return checkEquals(cs, cs2); + } + + @Override + public int indexOf(char c, int off) { + int i = a.indexOf(c, off); + int i2 = b.indexOf(c, off); + return checkEquals(i, i2); + } + + @Override + public int lastIndexOf(char c, int off) { + int i = a.lastIndexOf(c, off); + int i2 = b.lastIndexOf(c, off); + return checkEquals(i, i2); + } + + @Override + public void replace(int start, int end, String str) { + a.replace(start, end, str); + b.replace(start, end, str); + checkEquals(); + } + + @Override + public void replace(int start, int end, char[] arr, int off, int len) { + a.replace(start, end, arr, off, len); + b.replace(start, end, arr, off, len); + checkEquals(); + } + + @Override + public void insert(int index, String str) { + a.insert(index, str); + b.insert(index, str); + checkEquals(); + } + + @Override + public void insert(int index, char[] arr, int off, int len) { + a.insert(index, arr, off, len); + b.insert(index, arr, off, len); + checkEquals(); + } + + @Override + public void append(String str) { + a.append(str); + b.append(str); + checkEquals(); + } + + @Override + public void append(char[] arr, int off, int len) { + a.append(arr, off, len); + b.append(arr, off, len); + checkEquals(); + } + + @Override + public String toString() { + return checkEquals(a.toString(), b.toString()); + } + + @Override + public byte[] getBytes(Charset cs) { + return checkEquals(a.getBytes(cs), b.getBytes(cs)); + } + + @Override + public int hashCode() { + return checkEquals(a.hashCode(), b.hashCode()); + } + + @Override + public boolean equals(Object obj) { + return checkEquals(a.equals(obj), b.equals(obj)); + } + +} diff --git a/src/main/java/de/hechler/patrick/utils/cc/ms/FastStringList.java b/src/main/java/de/hechler/patrick/utils/cc/ms/FastStringList.java index 02a2e6f500570e16fb8c596aa668f27a87b32125..267ac8c3d2d7d68bbe9f14682e0f8dce67e4b1dd 100644 --- a/src/main/java/de/hechler/patrick/utils/cc/ms/FastStringList.java +++ b/src/main/java/de/hechler/patrick/utils/cc/ms/FastStringList.java @@ -1,9 +1,5 @@ package de.hechler.patrick.utils.cc.ms; -import java.io.ByteArrayOutputStream; -import java.io.IOError; -import java.io.IOException; -import java.io.OutputStream; import java.nio.ByteBuffer; import java.nio.CharBuffer; import java.nio.charset.Charset; @@ -12,21 +8,27 @@ import java.util.Arrays; import de.hechler.patrick.utils.cc.ModifiableString; @SuppressWarnings("unused") -public final class FastStringList implements ModifiableString { +public class FastStringList implements ModifiableString { private static final int ARR_MAX_SIZE = 2048; - private static final int ARR_PREF_SIZE = ARR_MAX_SIZE - (ARR_MAX_SIZE / 8); private static final int ARR_MIN_SIZE = ARR_MAX_SIZE / 2; + private static final int ARR_PREF_SIZE = (ARR_MAX_SIZE + ARR_MIN_SIZE) / 2; // length/offset is only used/maintained in the user object - private int length; - private int offset; - private FastStringList prev; - private int dataSize; - private char[] data; - private FastStringList next; + protected int length; + protected int offset; + protected FastStringList prev; + protected int dataSize; + protected char[] data; + protected FastStringList next; // nextData is only used/maintained in the userObject - private char[] nextData; + protected char[] nextData; + + public FastStringList(boolean init) { + if (init) { + throw new AssertionError(); + } + } public FastStringList() { data = new char[ARR_MAX_SIZE]; @@ -107,7 +109,7 @@ public final class FastStringList implements ModifiableString { } } - private void dataSize(int nml) { + protected void dataSize(int nml) { if (nml > ARR_MAX_SIZE) { System.err.println("BREAK!"); // throw new AssertionError(nml); @@ -491,8 +493,8 @@ public final class FastStringList implements ModifiableString { off += ml; sl = sl.next; char[] nd = sl.data; + System.arraycopy(d, ml, nd, 0, ei); ml = sl.dataSize; - System.arraycopy(d, sl.dataSize, nd, 0, ei); d = nd; } // : insert the new data @@ -593,8 +595,13 @@ public final class FastStringList implements ModifiableString { System.arraycopy(sl.data, ei, rsd, offset + si, ml - ei); System.arraycopy(pd, npml, rsd, 0, offset); } else { - System.arraycopy(sl.data, ei, rsd, si, ml - ei); - System.arraycopy(pd, npml, rsd, 0, pml - npml); + int cpy = ml - ei; + System.arraycopy(sl.data, ei, rsd, si, cpy); + int pos = si + cpy; + cpy = ARR_MIN_SIZE - cpy - si; + System.arraycopy(pd, 0, rsd, pos, cpy); + System.arraycopy(pd, cpy, pd, 0, npml); + assert pml - cpy == npml; } removeStart.dataSize(ARR_MIN_SIZE); p.dataSize(npml); @@ -747,6 +754,90 @@ public final class FastStringList implements ModifiableString { } } + @Override + public int hashCode() { + FastStringList sl = this; + while (sl.prev != null) + sl = sl.prev; + int result = 0; + final int prime = 31; + for (; sl != null; sl = sl.next) { + int ml = sl.dataSize; + char[] d = sl.data; + for (int i = 0; i < ml; i++) { + result = result * prime + d[i]; + } + } + return result; + } + + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof ModifiableString ms)) { + return false; + } + if (!(obj instanceof FastStringList osl)) { + if (ms.length() != length) { + return false; + } + FastStringList sl = this; + while (sl.prev != null) + sl = sl.prev; + for (int off = 0, noff; sl != null; sl = sl.next, off = noff) { + int ml = sl.dataSize; + noff = off + ml; + CharSequence cs = ms.subSequence(off, noff); + if (!cs.toString().equals(new String(sl.data, 0, ml))) { + return false; + } + } + return true; + } + if (length != osl.length) { + return false; + } + FastStringList sl = this; + while (sl.prev != null) + sl = sl.prev; + while (osl.prev != null) + osl = osl.prev; + int i = 0, oi = 0; + int ml = sl.dataSize; + int oml = osl.dataSize; + while (true) { + if (i == ml) { + sl = sl.next; + if (sl != null) { + ml = sl.dataSize; + i = 0; + } + } + if (oi == oml) { + osl = osl.next; + if (osl != null) { + oml = osl.dataSize; + oi = 0; + } + } + if (sl == osl) { + if (sl != null) { + throw new AssertionError(); + } + return true; + } + int len = Math.min(ml - i, oml - oi); + int mm = Arrays.mismatch(sl.data, i, i + len, osl.data, oi, oi + len); + if (mm != -1) { + return false; + } + i += len; + oi += len; + } + } + @Override public String toString() { StringBuilder result = new StringBuilder(length); diff --git a/src/main/java/de/hechler/patrick/utils/cc/ms/ModStringBuilder.java b/src/main/java/de/hechler/patrick/utils/cc/ms/ModStringBuilder.java index b8f5ff164c7600445af54e2e5beb0fefa8c6b941..08e2b08ad1e32c890dc48d31d060e8aa56b549bb 100644 --- a/src/main/java/de/hechler/patrick/utils/cc/ms/ModStringBuilder.java +++ b/src/main/java/de/hechler/patrick/utils/cc/ms/ModStringBuilder.java @@ -27,7 +27,7 @@ public class ModStringBuilder implements ModifiableString { public char charAt(int index) { return this.sb.charAt(index); } - + @Override public CharSequence subSequence(int start, int end) { return this.sb.subSequence(start, end); @@ -37,12 +37,12 @@ public class ModStringBuilder implements ModifiableString { public int indexOf(char c, int off) { return this.sb.indexOf(String.valueOf(c), off); } - + @Override public int lastIndexOf(char c, int off) { return this.sb.lastIndexOf(String.valueOf(c), off); } - + @Override public void replace(int start, int end, String str) { this.sb.replace(start, end, str); @@ -88,9 +88,22 @@ public class ModStringBuilder implements ModifiableString { this.sb.append(arr, off, len); } + @Override + public int hashCode() { + return sb.toString().hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof ModifiableString)) { + return false; + } + return sb.toString().equals(obj.toString()); + } + @Override public String toString() { return this.sb.toString(); } - + } diff --git a/src/main/java/de/hechler/patrick/utils/cc/skip/SqlCorrector.java b/src/main/java/de/hechler/patrick/utils/cc/skip/SqlCorrector.java index e6302beb5340fdbced89f52c34f4abf9202593c5..8a5e5b40bd32e57876e13d36417d0afad2f69157 100644 --- a/src/main/java/de/hechler/patrick/utils/cc/skip/SqlCorrector.java +++ b/src/main/java/de/hechler/patrick/utils/cc/skip/SqlCorrector.java @@ -53,7 +53,7 @@ public class SqlCorrector extends MassCarCoder { cc.insert("ì\\n"); } if (change || !(p instanceof CCPath)) { - cc.save(p); +// cc.save(p); } if (!change) { System.out.println(" nothing changed");