Skip to content

Commit 483e653

Browse files
committed
Merge branch 'refactor'
2 parents 51db1f4 + f865e4e commit 483e653

1 file changed

Lines changed: 156 additions & 128 deletions

File tree

Diff/DiffArray.swift

Lines changed: 156 additions & 128 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
// swiftlint:disable line_length
22
// swiftlint:disable file_length
3-
// swiftlint:disable cyclomatic_complexity
43
//
54
// DiffArray.swift
65
// DBDB
@@ -233,162 +232,191 @@ private func diff_computeDiffsBetweenArrays<T: Equatable>(arrayA: [T], arrayB: [
233232
return diff_bisectOfArrays(arrayA: arrayA, arrayB: arrayB)
234233
}
235234

236-
// yes this method is way too long. Pull requests welcome!
235+
private class Kay {
236+
var start: Int = 0
237+
var end: Int = 0
238+
var index: Int = 0
239+
}
237240

238-
// swiftlint:disable function_body_length
239-
func diff_bisectOfArrays<T: Equatable>(arrayA inArrayA: [T], arrayB inArrayB: [T]) -> [Diff<T>] {
240-
let arrayALength = inArrayA.count
241-
let arrayBLength = inArrayB.count
242-
var haveFoundDiffs = false
243-
var diffs: [Diff<T>] = []
241+
private struct CommonPathParameters<T: Equatable> {
242+
let vOffset: Int
243+
let inArrayA: [T]
244+
let inArrayB: [T]
245+
let front: Bool
246+
let delta: Int
247+
let vLength: Int
248+
}
244249

245-
let maxD = (arrayALength + arrayBLength + 1) / 2
246-
let vOffset = maxD
247-
var vLength = 2 * maxD
250+
private func walkFrontPath<T: Equatable>(
251+
commonParameters: CommonPathParameters<T>,
252+
currentD: Int,
253+
kay1: Kay,
254+
vectors1: inout [Int],
255+
vectors2: inout [Int]) -> [Diff<T>] {
248256

249-
if vLength <= vOffset + 2 {
250-
vLength = vOffset + 2
251-
}
252-
253-
var v1: [Int] = []
254-
var v2: [Int] = []
257+
while kay1.index <= currentD - kay1.end {
258+
defer {
259+
kay1.index += 2
260+
}
261+
let k1Offset = commonParameters.vOffset + kay1.index
262+
var x1 = 0
255263

256-
for _ in 0..<vLength {
257-
v1.append(-1)
258-
v2.append(-1)
259-
}
264+
if kay1.index == -currentD || (kay1.index != currentD && vectors1[k1Offset - 1] < vectors1[k1Offset + 1]) {
265+
x1 = vectors1[k1Offset + 1]
266+
} else {
267+
x1 = vectors1[k1Offset - 1] + 1
268+
}
260269

261-
v1[vOffset + 1] = 0
262-
v2[vOffset + 1] = 0
270+
var y1 = x1 - kay1.index
263271

264-
let delta = arrayALength - arrayBLength
272+
// follow the snake!
273+
while x1 < commonParameters.inArrayA.count && y1 < commonParameters.inArrayB.count && commonParameters.inArrayA[x1] == commonParameters.inArrayB[y1] {
274+
x1 += 1
275+
y1 += 1
276+
}
265277

266-
// If the total number of characters is odd, then the front path will collide with the reverse path.
267-
let front = delta % 2 != 0
268-
// BOOL front = (delta % 2 != 0);
278+
vectors1[k1Offset] = x1
279+
280+
if x1 > commonParameters.inArrayA.count {
281+
// Ran off the right of the graph.
282+
kay1.end += 2
283+
} else if y1 > commonParameters.inArrayB.count {
284+
// Ran off the bottom of the graph.
285+
kay1.start += 2
286+
} else if commonParameters.front {
287+
let k2Offset = commonParameters.vOffset + commonParameters.delta - kay1.index
288+
289+
if k2Offset >= 0 && k2Offset < commonParameters.vLength && vectors2[k2Offset] != -1 {
290+
// Mirror x2 onto top-left coordinate system.
291+
let x2 = commonParameters.inArrayA.count - vectors2[k2Offset]
292+
if x1 >= x2 {
293+
// diffs = diff_bisectSplitOfStrings(text1, text2, x1, y1, properties);
294+
return diff_bisectSplitOfArrays(arrayA: commonParameters.inArrayA, arrayB: commonParameters.inArrayB, x: x1, y: y1)
295+
}
296+
}
297+
}
298+
}
299+
return []
300+
}
269301

270-
// Offsets for start and end of k loop. Prevents mapping of space beyond the grid.
271-
var k1start = 0
272-
var k1end = 0
273-
var k2start = 0
274-
var k2end = 0
302+
private func walkReversePath<T: Equatable>(
303+
commonParameters: CommonPathParameters<T>,
304+
currentD: Int,
305+
kay2: Kay,
306+
vectors1: inout [Int],
307+
vectors2: inout [Int]) -> [Diff<T>] {
275308

276-
//
277-
for currentD in 0..<maxD {
309+
while kay2.index <= currentD - kay2.end {
278310

279-
// Walk the front path one step.
280-
var k1 = -currentD + k1start
281-
while k1 <= currentD - k1end {
282-
defer {
283-
k1 += 2
284-
}
285-
let k1Offset = vOffset + k1
286-
var x1 = 0
311+
defer {
312+
kay2.index += 2
313+
}
314+
let k2Offset = commonParameters.vOffset + kay2.index
315+
var x2 = 0
287316

288-
if k1 == -currentD || (k1 != currentD && v1[k1Offset - 1] < v1[k1Offset + 1]) {
289-
x1 = v1[k1Offset + 1]
290-
} else {
291-
x1 = v1[k1Offset - 1] + 1
292-
}
317+
if kay2.index == -currentD || (kay2.index != currentD && vectors2[k2Offset - 1] < vectors2[k2Offset + 1]) {
318+
x2 = vectors2[k2Offset + 1]
319+
} else {
320+
x2 = vectors2[k2Offset - 1] + 1
321+
}
293322

294-
var y1 = x1 - k1
323+
var y2 = x2 - kay2.index
295324

296-
// follow the snake!
297-
while x1 < arrayALength && y1 < arrayBLength && inArrayA[x1] == inArrayB[y1] {
298-
x1 += 1
299-
y1 += 1
300-
}
325+
while x2 < commonParameters.inArrayA.count && y2 < commonParameters.inArrayB.count && (commonParameters.inArrayA[commonParameters.inArrayA.count - x2 - 1] == commonParameters.inArrayB[commonParameters.inArrayB.count - y2 - 1]) {
326+
x2 += 1
327+
y2 += 1
328+
}
301329

302-
v1[k1Offset] = x1
303-
304-
if x1 > arrayALength {
305-
// Ran off the right of the graph.
306-
k1end += 2
307-
} else if y1 > arrayBLength {
308-
// Ran off the bottom of the graph.
309-
k1start += 2
310-
} else if front {
311-
let k2Offset = vOffset + delta - k1
312-
313-
if k2Offset >= 0 && k2Offset < vLength && v2[k2Offset] != -1 {
314-
// Mirror x2 onto top-left coordinate system.
315-
let x2 = arrayALength - v2[k2Offset]
316-
if x1 >= x2 {
317-
// diffs = diff_bisectSplitOfStrings(text1, text2, x1, y1, properties);
318-
diffs = diff_bisectSplitOfArrays(arrayA: inArrayA, arrayB: inArrayB, x: x1, y: y1)
319-
haveFoundDiffs = true
320-
break
321-
}
330+
vectors2[k2Offset] = x2
331+
332+
if x2 > commonParameters.inArrayA.count {
333+
// Ran off the left of the graph.
334+
kay2.end += 2
335+
} else if y2 > commonParameters.inArrayB.count {
336+
// Ran off the top of the graph.
337+
kay2.start += 2
338+
} else if !commonParameters.front {
339+
let k1Offset = commonParameters.vOffset + commonParameters.delta - kay2.index
340+
341+
if k1Offset >= 0 && k1Offset < commonParameters.vLength && vectors1[k1Offset] != -1 {
342+
let x1 = vectors1[k1Offset]
343+
let y1 = commonParameters.vOffset + x1 - k1Offset
344+
// Mirror x2 onto top-left coordinate system.
345+
x2 = commonParameters.inArrayA.count - x2
346+
347+
if x1 >= x2 {
348+
// Overlap detected.
349+
return diff_bisectSplitOfArrays(arrayA: commonParameters.inArrayA, arrayB: commonParameters.inArrayB, x: x1, y: y1)
322350
}
323351
}
324352
}
353+
}
354+
return []
355+
}
325356

326-
if haveFoundDiffs {
327-
break
328-
}
357+
// yes this method is way too long. Pull requests welcome!
358+
func diff_bisectOfArrays<T: Equatable>(arrayA inArrayA: [T], arrayB inArrayB: [T]) -> [Diff<T>] {
359+
let maxD = (inArrayA.count + inArrayB.count + 1) / 2
360+
let vOffset = maxD
361+
var vLength = 2 * maxD
329362

330-
// Walk the reverse path one step.
331-
var k2 = -currentD + k2start
332-
while k2 <= currentD - k2end {
363+
if vLength <= vOffset + 2 {
364+
vLength = vOffset + 2
365+
}
333366

334-
defer {
335-
k2 += 2
336-
}
337-
let k2Offset = vOffset + k2
338-
var x2 = 0
367+
var vectors1: [Int] = []
368+
var vectors2: [Int] = []
339369

340-
if k2 == -currentD || (k2 != currentD && v2[k2Offset - 1] < v2[k2Offset + 1]) {
341-
x2 = v2[k2Offset + 1]
342-
} else {
343-
x2 = v2[k2Offset - 1] + 1
344-
}
370+
for _ in 0..<vLength {
371+
vectors1.append(-1)
372+
vectors2.append(-1)
373+
}
374+
vectors1[vOffset + 1] = 0
375+
vectors2[vOffset + 1] = 0
345376

346-
var y2 = x2 - k2
377+
let delta = inArrayA.count - inArrayB.count
347378

348-
while x2 < arrayALength && y2 < arrayBLength && (inArrayA[arrayALength - x2 - 1] == inArrayB[arrayBLength - y2 - 1]) {
349-
x2 += 1
350-
y2 += 1
351-
}
379+
// If the total number of characters is odd, then the front path will collide with the reverse path.
380+
let front = delta % 2 != 0
352381

353-
v2[k2Offset] = x2
354-
355-
if x2 > arrayALength {
356-
// Ran off the left of the graph.
357-
k2end += 2
358-
} else if y2 > arrayBLength {
359-
// Ran off the top of the graph.
360-
k2start += 2
361-
} else if !front {
362-
let k1Offset = vOffset + delta - k2
363-
364-
if k1Offset >= 0 && k1Offset < vLength && v1[k1Offset] != -1 {
365-
let x1 = v1[k1Offset]
366-
let y1 = vOffset + x1 - k1Offset
367-
// Mirror x2 onto top-left coordinate system.
368-
x2 = arrayALength - x2
369-
370-
if x1 >= x2 {
371-
// Overlap detected.
372-
diffs = diff_bisectSplitOfArrays(arrayA: inArrayA, arrayB: inArrayB, x: x1, y: y1)
373-
haveFoundDiffs = true
374-
break
375-
}
376-
}
377-
}
378-
}
382+
// Offsets for start and end of k loop. Prevents mapping of space beyond the grid.
383+
let kay1 = Kay()
384+
let kay2 = Kay()
379385

380-
if haveFoundDiffs {
381-
break
386+
let commonParameters = CommonPathParameters(vOffset: vOffset, inArrayA: inArrayA, inArrayB: inArrayB, front: front, delta: delta, vLength: vLength)
387+
388+
for currentD in 0..<maxD {
389+
390+
// Walk the front path one step.
391+
kay1.index = -currentD + kay1.start
392+
let frontDiffs = walkFrontPath(
393+
commonParameters: commonParameters,
394+
currentD: currentD,
395+
kay1: kay1,
396+
vectors1: &vectors1,
397+
vectors2: &vectors2)
398+
399+
if !frontDiffs.isEmpty {
400+
return frontDiffs
382401
}
383-
}
384402

385-
if !haveFoundDiffs {
386-
// we haven't found a snake at all so we couldn't cut the problem in half.
387-
// This means we have no common element. Just add the diffs straight away.
388-
diffs = [Diff(operation: .delete, array: inArrayA), Diff(operation: .insert, array: inArrayB)]
403+
// Walk the reverse path one step.
404+
kay2.index = -currentD + kay2.start
405+
let reverseDiffs = walkReversePath(
406+
commonParameters: commonParameters,
407+
currentD: currentD,
408+
kay2: kay2,
409+
vectors1: &vectors1,
410+
vectors2: &vectors2)
411+
412+
if !reverseDiffs.isEmpty {
413+
return reverseDiffs
414+
}
389415
}
390416

391-
return diffs
417+
// we haven't found a snake at all so we couldn't cut the problem in half.
418+
// This means we have no common element. Just add the diffs straight away.
419+
return [Diff(operation: .delete, array: inArrayA), Diff(operation: .insert, array: inArrayB)]
392420
}
393421
// swiftlint:enable function_body_length
394422

0 commit comments

Comments
 (0)