Replace switch table with data-based slicing.
[string-lerp.git] / string-lerp.js
index cff0bf7..1aa89b0 100644 (file)
         return d;
     }
 
+    // First, note that deletion is just substition with nothing, so
+    // any DEL operation can be replaced by a SUB. Second, the
+    // operation code *is* the necessary slice offset for applying the
+    // diff.
+    var INS = 0, SUB = 1;
+
     function editPath(costs, target) {
         /** Given a cost matrix and a target, create an edit list */
         var path = [];
             var ins = j ? costs[n * i + j - 1] : Infinity;
             if (sub <= ins && sub <= del) {
                 if (costs[n * i + j] !== costs[n * (i - 1) + j - 1])
-                    path.push(["sub", i - 1, target[j - 1]]);
+                    path.push([SUB, i - 1, target[j - 1]]);
                 --i; --j;
             } else if (ins <= del) {
-                path.push(["ins", i, target[j - 1]]);
+                path.push([INS, i, target[j - 1]]);
                 --j;
             } else {
-                path.push(["del", i - 1]);
+                path.push([SUB, i - 1, ""]);
                 --i;
             }
         }
         return editPath(costMatrix(source, target, ins, del, sub), target);
     }
 
-    function patch(edits, s) {
+    function patch(diff, source) {
         /** Apply the list of edits to s */
         var edit;
         var i;
 
-        if (Array.isArray(s)) {
-            for (i = 0; i < edits.length; ++i) {
-                edit = edits[i];
-                switch (edit[0]) {
-                case "sub":
-                    s[edit[1]] = edit[2];
-                    break;
-                case "ins":
-                    s.splice(edit[1], 0, edit[2]);
-                    break;
-                case "del":
-                    s.splice(edit[1], 1);
-                    break;
-                }
+        if (Array.isArray(source)) {
+            for (i = 0; i < diff.length; ++i) {
+                edit = diff[i];
+                source.splice(edit[1], edit[0], edit[2]);
             }
         } else {
-            for (i = 0; i < edits.length; ++i) {
-                edit = edits[i];
-                switch (edit[0]) {
-                case "sub":
-                    s = s.slice(0, edit[1]) + edit[2] + s.slice(edit[1] + 1);
-                    break;
-                case "ins":
-                    s = s.slice(0, edit[1]) + edit[2] + s.slice(edit[1]);
-                    break;
-                case "del":
-                    s = s.slice(0, edit[1]) + s.slice(edit[1] + 1);
-                    break;
-                }
+            for (i = 0; i < diff.length; ++i) {
+                edit = diff[i];
+                var head = source.slice(0, edit[1]);
+                var tail = source.slice(edit[1] + edit[0]);
+                source = head + edit[2] + tail;
             }
         }
-        return s;
+        return source;
     }
 
     var MULTI = /[\uD800-\uDBFF][\uDC00-\uDFFF]|[\u0300-\u036F\u1DC0-\u1DFF\u20D0-\u20FF\uFE20-\uFE2F]/;