Browse Source

Remove dependency on the array view of structure and other minor improvements.

Timur Sağlam 5 years ago
parent
commit
8eb91c4f17

+ 13 - 5
jplag.frontend-utils/src/main/java/jplag/Structure.java

@@ -3,7 +3,9 @@ package jplag;
 import java.util.ArrayList;
 import java.util.List;
 
-/** The tokenlist */ // TODO PB: The name 'Structure' is very generic and should be changed to something more descriptive.
+/**
+ * List of tokens. Allows random access to individual tokens.
+ */ // TODO PB: The name 'Structure' is very generic and should be changed to something more descriptive.
 public class Structure implements TokenConstants { // TODO TS: How about renaming it to TokenList?
     private final List<Token> tokens;
     Table table = null;
@@ -30,10 +32,20 @@ public class Structure implements TokenConstants { // TODO TS: How about renamin
         tokens.add(token);
     }
 
+    /**
+     * Returns a view on all tokens.
+     * @return all tokens.
+     */
     public Iterable<Token> allTokens() {
         return new ArrayList<>(tokens);
     }
 
+    /**
+     * Grants access to a specific token.
+     * @param index is the token index.
+     * @return the desired token.
+     * @throws IllegalArgumentException if the index is out of bounds.
+     */
     public Token getToken(int index) {
         if (index < 0 || index >= tokens.size()) {
             throw new IllegalArgumentException("Cannot access token with index " + index + ", there are only " + tokens.size() + " tokens!");
@@ -41,10 +53,6 @@ public class Structure implements TokenConstants { // TODO TS: How about renamin
         return tokens.get(index);
     }
 
-    public Token[] getTokenArray() { // TODO TS: I added this to support the legacy code using arrays, however we should get rid of this.
-        return tokens.toArray(new Token[0]);
-    }
-
     @Override
     public final String toString() {
         StringBuffer buffer = new StringBuffer();

+ 10 - 9
jplag/src/main/java/jplag/GreedyStringTiling.java

@@ -4,7 +4,8 @@ import java.util.List;
 
 /**
  * This class implements the Greedy String Tiling algorithm as introduced by Michael Wise. However, it is very specific
- * to the classes {@link Structure}, {@link Token}, as well as {@link Matches} and {@link Match}.
+ * to the classes {@link Structure}, {@link Token}, as well as {@link Matches} and {@link Match}. While is class was
+ * reworked, it still contains some quirks from the initial version.
  * @see <a href=
  * "https://www.researchgate.net/publication/262763983_String_Similarity_via_Greedy_String_Tiling_and_Running_Karp-Rabin_Matching">
  * String Similarity via Greedy String Tiling and Running Karp−Rabin Matching </a>
@@ -42,9 +43,8 @@ public class GreedyStringTiling implements TokenConstants {
         int loops = tokenList.size() - hashLength;
         tokenList.table = (makeTable ? new Table(3 * loops) : null);
         int hash = 0;
-        int i;
         int hashedLength = 0;
-        for (i = 0; i < hashLength; i++) {
+        for (int i = 0; i < hashLength; i++) {
             hash = (2 * hash) + (tokenList.getToken(i).type & modulo);
             hashedLength++;
             if (tokenList.getToken(i).marked) {
@@ -54,7 +54,7 @@ public class GreedyStringTiling implements TokenConstants {
         int factor = (hashLength != 1 ? (2 << (hashLength - 2)) : 1);
 
         if (makeTable) {
-            for (i = 0; i < loops; i++) {
+            for (int i = 0; i < loops; i++) {
                 if (hashedLength >= hashLength) {
                     tokenList.getToken(i).hash = hash;
                     tokenList.table.add(hash, i);   // add into hashtable
@@ -70,7 +70,7 @@ public class GreedyStringTiling implements TokenConstants {
                 }
             }
         } else {
-            for (i = 0; i < loops; i++) {
+            for (int i = 0; i < loops; i++) {
                 tokenList.getToken(i).hash = (hashedLength >= hashLength) ? hash : -1;
                 hash -= factor * (tokenList.getToken(i).type & modulo);
                 hash = (2 * hash) + (tokenList.getToken(i + hashLength).type & modulo);
@@ -121,6 +121,7 @@ public class GreedyStringTiling implements TokenConstants {
      * @return the comparison results.
      */
     private final JPlagComparison compare(Submission firstSubmission, Submission secondSubmission, int minimalTokenMatch, boolean withBaseCode) {
+        // first and second refer to the list of tokens of the first and second submission:
         Structure first = firstSubmission.tokenList;
         Structure second = secondSubmission.tokenList;
 
@@ -145,7 +146,7 @@ public class GreedyStringTiling implements TokenConstants {
             createHashes(second, minimalTokenMatch, true);
         }
 
-        // start:
+        // start the black magic:
         int maxmatch;
         do {
             maxmatch = minimalTokenMatch;
@@ -183,12 +184,12 @@ public class GreedyStringTiling implements TokenConstants {
                 }
             }
             for (int i = matches.size() - 1; i >= 0; i--) {
-                int x = matches.matches[i].startA;  // begining of/in sequence A
-                int y = matches.matches[i].startB;  // begining of/in sequence B
+                int x = matches.matches[i].startA;  // Beginning of/in sequence A
+                int y = matches.matches[i].startB;  // Beginning of/in sequence B
                 comparison.addMatch(x, y, matches.matches[i].length);
                 // in order that "Match" will be newly build (because reusing)
                 for (int j = matches.matches[i].length; j > 0; j--) {
-                    first.getToken(x).marked = second.getToken(y).marked = true;   // mark all Token!
+                    first.getToken(x).marked = second.getToken(y).marked = true; // mark all Tokens!
                     if (withBaseCode) {
                         first.getToken(x).basecode = second.getToken(y).basecode = true;
                     }

+ 5 - 5
jplag/src/main/java/jplag/JPlagComparison.java

@@ -184,14 +184,14 @@ public class JPlagComparison implements Comparator<JPlagComparison> {
             return new String[] {};
         }
 
-        Token[] tokens = (j == 0 ? firstSubmission : secondSubmission).tokenList.getTokenArray();
+        Structure tokenList = (j == 0 ? firstSubmission : secondSubmission).tokenList;
         int i, h, starti, starth, count = 1;
 
         o1: for (i = 1; i < matches.size(); i++) {
             starti = (j == 0 ? matches.get(i).startA : matches.get(i).startB);
             for (h = 0; h < i; h++) {
                 starth = (j == 0 ? matches.get(h).startA : matches.get(h).startB);
-                if (tokens[starti].file.equals(tokens[starth].file)) {
+                if (tokenList.getToken(starti).file.equals(tokenList.getToken(starth).file)) {
                     continue o1;
                 }
             }
@@ -199,18 +199,18 @@ public class JPlagComparison implements Comparator<JPlagComparison> {
         }
 
         String[] res = new String[count];
-        res[0] = tokens[(j == 0 ? matches.get(0).startA : matches.get(0).startB)].file;
+        res[0] = tokenList.getToken((j == 0 ? matches.get(0).startA : matches.get(0).startB)).file;
         count = 1;
 
         o2: for (i = 1; i < matches.size(); i++) {
             starti = (j == 0 ? matches.get(i).startA : matches.get(i).startB);
             for (h = 0; h < i; h++) {
                 starth = (j == 0 ? matches.get(h).startA : matches.get(h).startB);
-                if (tokens[starti].file.equals(tokens[starth].file)) {
+                if (tokenList.getToken(starti).file.equals(tokenList.getToken(starth).file)) {
                     continue o2;
                 }
             }
-            res[count++] = tokens[starti].file;
+            res[count++] = tokenList.getToken(starti).file;
         }
 
         /*

+ 20 - 19
jplag/src/main/java/jplag/reporting/Report.java

@@ -20,6 +20,7 @@ import jplag.ExitException;
 import jplag.JPlagComparison;
 import jplag.JPlagResult;
 import jplag.Match;
+import jplag.Structure;
 import jplag.Submission;
 import jplag.Token;
 
@@ -388,8 +389,8 @@ public class Report {
      */
     private void reportComparison(HTMLFile htmlFile, JPlagComparison comparison, int index) {
         Match match;
-        Token[] tokensA = comparison.firstSubmission.tokenList.getTokenArray();
-        Token[] tokensB = comparison.secondSubmission.tokenList.getTokenArray();
+        Structure tokensA = comparison.firstSubmission.tokenList;
+        Structure tokensB = comparison.secondSubmission.tokenList;
         // sort();
 
         htmlFile.println("<TABLE BORDER=\"1\" CELLSPACING=\"0\" BGCOLOR=\"#d0d0d0\">");
@@ -399,10 +400,10 @@ public class Report {
         for (int i = 0; i < comparison.matches.size(); i++) {
             match = comparison.matches.get(i);
 
-            Token startA = tokensA[match.startA];
-            Token endA = tokensA[match.startA + match.length - 1];
-            Token startB = tokensB[match.startB];
-            Token endB = tokensB[match.startB + match.length - 1];
+            Token startA = tokensA.getToken(match.startA);
+            Token endA = tokensA.getToken(match.startA + match.length - 1);
+            Token startB = tokensB.getToken(match.startB);
+            Token endB = tokensB.getToken(match.startB + match.length - 1);
 
             String col = Color.getHexadecimalValue(i);
 
@@ -451,15 +452,15 @@ public class Report {
 
         String[][] text = sub.readFiles(files);
 
-        Token[] tokens = (j == 0 ? comparison.firstSubmission : comparison.secondSubmission).tokenList.getTokenArray();
+        Structure tokens = (j == 0 ? comparison.firstSubmission : comparison.secondSubmission).tokenList;
         Match currentMatch;
         String hilf;
         int h;
         for (int x = 0; x < comparison.matches.size(); x++) {
             currentMatch = comparison.matches.get(x);
 
-            Token start = tokens[(j == 0 ? currentMatch.startA : currentMatch.startB)];
-            Token ende = tokens[((j == 0 ? currentMatch.startA : currentMatch.startB) + currentMatch.length - 1)];
+            Token start = tokens.getToken(j == 0 ? currentMatch.startA : currentMatch.startB);
+            Token ende = tokens.getToken((j == 0 ? currentMatch.startA : currentMatch.startB) + currentMatch.length - 1);
 
             for (int y = 0; y < files.length; y++) {
                 if (start.file.equals(files[y]) && text[y] != null) {
@@ -492,8 +493,8 @@ public class Report {
 
             for (int x = 0; x < baseCodeComparison.matches.size(); x++) {
                 currentMatch = baseCodeComparison.matches.get(x);
-                Token start = tokens[currentMatch.startA];
-                Token ende = tokens[currentMatch.startA + currentMatch.length - 1];
+                Token start = tokens.getToken(currentMatch.startA);
+                Token ende = tokens.getToken(currentMatch.startA + currentMatch.length - 1);
 
                 for (int y = 0; y < files.length; y++) {
                     if (start.file.equals(files[y]) && text[y] != null) {
@@ -555,7 +556,7 @@ public class Report {
         Submission sub = (j == 0 ? comparison.firstSubmission : comparison.secondSubmission);
         String[] files = comparison.files(j);
         char[][] text = sub.readFilesChar(files);
-        Token[] tokens = (j == 0 ? comparison.firstSubmission : comparison.secondSubmission).tokenList.getTokenArray();
+        Structure tokens = (j == 0 ? comparison.firstSubmission : comparison.secondSubmission).tokenList;
 
         // get index array with matches sorted in ascending order.
         int[] perm = comparison.sort_permutation(j);
@@ -582,8 +583,8 @@ public class Report {
                 if (onematch == null) {
                     if (index < comparison.matches.size()) {
                         onematch = comparison.matches.get(perm[index]);
-                        start = tokens[(j == 0 ? onematch.startA : onematch.startB)];
-                        end = tokens[((j == 0 ? onematch.startA : onematch.startB) + onematch.length - 1)];
+                        start = tokens.getToken(j == 0 ? onematch.startA : onematch.startB);
+                        end = tokens.getToken((j == 0 ? onematch.startA : onematch.startB) + onematch.length - 1);
                         index++;
                     } else {
                         start = end = null;
@@ -628,7 +629,7 @@ public class Report {
         Submission sub = (j == 0 ? comparison.firstSubmission : comparison.secondSubmission);
         String[] files = comparison.files(j);
         String[][] text = sub.readFiles(files);
-        Token[] tokens = (j == 0 ? comparison.firstSubmission : comparison.secondSubmission).tokenList.getTokenArray();
+        Structure tokens = (j == 0 ? comparison.firstSubmission : comparison.secondSubmission).tokenList;
 
         // Markup list:
         Comparator<MarkupText> comp = (mo1, mo2) -> {
@@ -646,8 +647,8 @@ public class Report {
         for (int x = 0; x < comparison.matches.size(); x++) {
             Match onematch = comparison.matches.get(x);
 
-            Token start = tokens[(j == 0 ? onematch.startA : onematch.startB)];
-            Token end = tokens[((j == 0 ? onematch.startA : onematch.startB) + onematch.length - 1)];
+            Token start = tokens.getToken(j == 0 ? onematch.startA : onematch.startB);
+            Token end = tokens.getToken((j == 0 ? onematch.startA : onematch.startB) + onematch.length - 1);
             for (int fileIndex = 0; fileIndex < files.length; fileIndex++) {
                 if (start.file.equals(files[fileIndex]) && text[fileIndex] != null) {
                     String tmp = "<FONT color=\"" + Color.getHexadecimalValue(x) + "\">" + (j == 1 ? "<div style=\"position:absolute;left:0\">" : "")
@@ -671,8 +672,8 @@ public class Report {
 
             for (int x = 0; x < baseCodeComparison.matches.size(); x++) {
                 Match onematch = baseCodeComparison.matches.get(x);
-                Token start = tokens[onematch.startA];
-                Token end = tokens[onematch.startA + onematch.length - 1];
+                Token start = tokens.getToken(onematch.startA);
+                Token end = tokens.getToken(onematch.startA + onematch.length - 1);
 
                 for (int fileIndex = 0; fileIndex < files.length; fileIndex++) {
                     if (start.file.equals(files[fileIndex]) && text[fileIndex] != null) {