Skip to content

Commit 2c23d54

Browse files
authored
Merge pull request #43 from ra1028/v0.8.0
v0.8.0
2 parents dc186d7 + 77c05f2 commit 2c23d54

21 files changed

Lines changed: 116 additions & 83 deletions

DifferenceKit.podspec

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
Pod::Spec.new do |spec|
22
spec.name = 'DifferenceKit'
3-
spec.version = '0.7.2'
3+
spec.version = '0.8.0'
44
spec.author = { 'ra1028' => 'r.fe51028.r@gmail.com' }
55
spec.homepage = 'https://github.com/ra1028/DifferenceKit'
66
spec.documentation_url = 'https://ra1028.github.io/DifferenceKit'

Sources/Algorithm.swift

Lines changed: 87 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -67,32 +67,46 @@ public extension StagedChangeset where Collection: RangeReplaceableCollection, C
6767
}
6868

6969
var firstStageElements = ContiguousArray<Collection.Element>()
70+
var secondStageElements = ContiguousArray<Collection.Element>()
71+
72+
firstStageElements.reserveCapacity(sourceElements.count)
7073

7174
let result = differentiate(
7275
source: sourceElements,
7376
target: targetElements,
7477
trackTargetIndexAsUpdated: false,
7578
mapIndex: { ElementPath(element: $0, section: section) },
76-
remainedInTarget: { firstStageElements.append($0) }
79+
updatedElements: { firstStageElements.append($0) },
80+
undeletedElements: { secondStageElements.append($0) }
7781
)
7882

7983
var changesets = ContiguousArray<Changeset<Collection>>()
8084

8185
// The 1st stage changeset.
8286
// - Includes:
83-
// - element deletes
8487
// - element updates
85-
if !result.deleted.isEmpty || !result.updated.isEmpty {
88+
if !result.updated.isEmpty {
8689
changesets.append(
8790
Changeset(
8891
data: Collection(firstStageElements),
89-
elementDeleted: result.deleted,
9092
elementUpdated: result.updated
9193
)
9294
)
9395
}
9496

95-
// The 2st stage changeset.
97+
// The 2nd stage changeset.
98+
// - Includes:
99+
// - element deletes
100+
if !result.deleted.isEmpty {
101+
changesets.append(
102+
Changeset(
103+
data: Collection(secondStageElements),
104+
elementDeleted: result.deleted
105+
)
106+
)
107+
}
108+
109+
// The 3rd stage changeset.
96110
// - Includes:
97111
// - element inserts
98112
// - element moves
@@ -149,9 +163,10 @@ public extension StagedChangeset where Collection: RangeReplaceableCollection, C
149163
let contiguousSourceSections = ContiguousArray(sourceSections.map { ContiguousArray($0.elements) })
150164
let contiguousTargetSections = ContiguousArray(targetSections.map { ContiguousArray($0.elements) })
151165

152-
var firstStageSections = ContiguousArray<Section>()
166+
var firstStageSections = sourceSections
153167
var secondStageSections = ContiguousArray<Section>()
154168
var thirdStageSections = ContiguousArray<Section>()
169+
var fourthStageSections = ContiguousArray<Section>()
155170

156171
var sourceElementTraces = contiguousSourceSections.map { section in
157172
ContiguousArray(repeating: Trace<ElementPath>(), count: section.count)
@@ -164,8 +179,8 @@ public extension StagedChangeset where Collection: RangeReplaceableCollection, C
164179
var flattenSourceIdentifiers = ContiguousArray<ElementIdentifier>()
165180
var flattenSourceElementPaths = ContiguousArray<ElementPath>()
166181

167-
secondStageSections.reserveCapacity(contiguousTargetSections.count)
168182
thirdStageSections.reserveCapacity(contiguousTargetSections.count)
183+
fourthStageSections.reserveCapacity(contiguousTargetSections.count)
169184

170185
flattenSourceIdentifiers.reserveCapacity(flattenSourceCount)
171186
flattenSourceElementPaths.reserveCapacity(flattenSourceCount)
@@ -252,43 +267,50 @@ public extension StagedChangeset where Collection: RangeReplaceableCollection, C
252267

253268
// Record the element deletions.
254269
for sourceSectionIndex in contiguousSourceSections.indices {
270+
let sourceSection = sourceSections[sourceSectionIndex]
271+
let sourceElements = contiguousSourceSections[sourceSectionIndex]
272+
var firstStageElements = sourceElements
273+
255274
// Should not calculate the element deletions in the deleted section.
256-
guard case .some = sectionResult.metadata.sourceTraces[sourceSectionIndex].reference else {
257-
continue
258-
}
275+
if case .some = sectionResult.metadata.sourceTraces[sourceSectionIndex].reference {
276+
var offsetByDelete = 0
259277

260-
var offsetByDelete = 0
261-
var firstStageElements = ContiguousArray<Element>()
262-
let sourceElements = contiguousSourceSections[sourceSectionIndex]
278+
var secondStageElements = ContiguousArray<Element>()
263279

264-
for sourceElementIndex in sourceElements.indices {
265-
let sourceElementPath = ElementPath(element: sourceElementIndex, section: sourceSectionIndex)
280+
for sourceElementIndex in sourceElements.indices {
281+
let sourceElementPath = ElementPath(element: sourceElementIndex, section: sourceSectionIndex)
282+
283+
sourceElementTraces[sourceElementPath].deleteOffset = offsetByDelete
266284

267-
sourceElementTraces[sourceElementPath].deleteOffset = offsetByDelete
285+
// If the element target section is recorded as insertion, record its element path as deletion.
286+
if let targetElementPath = sourceElementTraces[sourceElementPath].reference,
287+
case .some = sectionResult.metadata.targetReferences[targetElementPath.section] {
288+
let targetElement = contiguousTargetSections[targetElementPath]
289+
firstStageElements[sourceElementIndex] = targetElement
290+
secondStageElements.append(targetElement)
291+
continue
292+
}
268293

269-
// If the element target section is recorded as insertion, record its element path as deletion.
270-
if let targetElementPath = sourceElementTraces[sourceElementPath].reference,
271-
case .some = sectionResult.metadata.targetReferences[targetElementPath.section] {
272-
let targetElement = contiguousTargetSections[targetElementPath]
273-
firstStageElements.append(targetElement)
274-
continue
294+
elementDeleted.append(sourceElementPath)
295+
sourceElementTraces[sourceElementPath].isTracked = true
296+
offsetByDelete += 1
275297
}
276298

277-
elementDeleted.append(sourceElementPath)
278-
sourceElementTraces[sourceElementPath].isTracked = true
279-
offsetByDelete += 1
299+
let secondStageSection = Section(source: sourceSection, elements: secondStageElements)
300+
secondStageSections.append(secondStageSection)
301+
280302
}
281303

282-
let firstStageSection = Section(source: sourceSections[sourceSectionIndex], elements: firstStageElements)
283-
firstStageSections.append(firstStageSection)
304+
let firstStageSection = Section(source: sourceSection, elements: firstStageElements)
305+
firstStageSections[sourceSectionIndex] = firstStageSection
284306
}
285307

286308
// Record the element updates/moves/insertions.
287309
for targetSectionIndex in contiguousTargetSections.indices {
288310
// Should not calculate the element updates/moves/insertions in the inserted section.
289311
guard let sourceSectionIndex = sectionResult.metadata.targetReferences[targetSectionIndex] else {
290-
secondStageSections.append(targetSections[targetSectionIndex])
291312
thirdStageSections.append(targetSections[targetSectionIndex])
313+
fourthStageSections.append(targetSections[targetSectionIndex])
292314
continue
293315
}
294316

@@ -297,11 +319,11 @@ public extension StagedChangeset where Collection: RangeReplaceableCollection, C
297319

298320
let sectionDeleteOffset = sectionResult.metadata.sourceTraces[sourceSectionIndex].deleteOffset
299321

300-
let secondStageSection = firstStageSections[sourceSectionIndex - sectionDeleteOffset]
301-
secondStageSections.append(secondStageSection)
322+
let thirdStageSection = secondStageSections[sourceSectionIndex - sectionDeleteOffset]
323+
thirdStageSections.append(thirdStageSection)
302324

303-
var thirdStageElements = ContiguousArray<Element>()
304-
thirdStageElements.reserveCapacity(targetElements.count)
325+
var fourthStageElements = ContiguousArray<Element>()
326+
fourthStageElements.reserveCapacity(targetElements.count)
305327

306328
for targetElementIndex in targetElements.indices {
307329
untrackedSourceIndex = untrackedSourceIndex.flatMap { index in
@@ -314,15 +336,15 @@ public extension StagedChangeset where Collection: RangeReplaceableCollection, C
314336
// If the element source section is recorded as deletion, record its element path as insertion.
315337
guard let sourceElementPath = targetElementReferences[targetElementPath],
316338
let movedSourceSectionIndex = sectionResult.metadata.sourceTraces[sourceElementPath.section].reference else {
317-
thirdStageElements.append(targetElement)
339+
fourthStageElements.append(targetElement)
318340
elementInserted.append(targetElementPath)
319341
continue
320342
}
321343

322344
sourceElementTraces[sourceElementPath].isTracked = true
323345

324346
let sourceElement = contiguousSourceSections[sourceElementPath]
325-
thirdStageElements.append(targetElement)
347+
fourthStageElements.append(targetElement)
326348

327349
if !targetElement.isContentEqual(to: sourceElement) {
328350
elementUpdated.append(sourceElementPath)
@@ -335,57 +357,67 @@ public extension StagedChangeset where Collection: RangeReplaceableCollection, C
335357
}
336358
}
337359

338-
let thirdStageSection = Section(source: secondStageSection, elements: thirdStageElements)
339-
thirdStageSections.append(thirdStageSection)
360+
let fourthStageSection = Section(source: thirdStageSection, elements: fourthStageElements)
361+
fourthStageSections.append(fourthStageSection)
340362
}
341363

342364
var changesets = ContiguousArray<Changeset<Collection>>()
343365

344366
// The 1st stage changeset.
345367
// - Includes:
346-
// - section deletes
347-
// - element deletes
348368
// - element updates
349-
if !sectionResult.deleted.isEmpty || !elementDeleted.isEmpty || !elementUpdated.isEmpty {
369+
if !elementUpdated.isEmpty {
350370
changesets.append(
351371
Changeset(
352372
data: Collection(firstStageSections),
353-
sectionDeleted: sectionResult.deleted,
354-
elementDeleted: elementDeleted,
355373
elementUpdated: elementUpdated
356374
)
357375
)
358376
}
359377

360378
// The 2nd stage changeset.
361379
// - Includes:
380+
// - section deletes
381+
// - element deletes
382+
if !sectionResult.deleted.isEmpty || !elementDeleted.isEmpty {
383+
changesets.append(
384+
Changeset(
385+
data: Collection(secondStageSections),
386+
sectionDeleted: sectionResult.deleted,
387+
elementDeleted: elementDeleted
388+
)
389+
)
390+
}
391+
392+
// The 3rd stage changeset.
393+
// - Includes:
362394
// - section inserts
363395
// - section moves
364396
if !sectionResult.inserted.isEmpty || !sectionResult.moved.isEmpty {
365397
changesets.append(
366398
Changeset(
367-
data: Collection(secondStageSections),
399+
data: Collection(thirdStageSections),
368400
sectionInserted: sectionResult.inserted,
369401
sectionMoved: sectionResult.moved
370402
)
371403
)
372404
}
373405

374-
// The 3rd stage changeset.
406+
// The 4th stage changeset.
375407
// - Includes:
376408
// - element inserts
377409
// - element moves
378410
if !elementInserted.isEmpty || !elementMoved.isEmpty {
379411
changesets.append(
380412
Changeset(
381-
data: Collection(thirdStageSections),
413+
data: Collection(fourthStageSections),
382414
elementInserted: elementInserted,
383415
elementMoved: elementMoved
384416
)
385417
)
386418
}
387419

388-
// The 4th stage changeset.
420+
// The 5th stage changeset.
389421
// - Includes:
390422
// - section updates
391423
if !sectionResult.updated.isEmpty {
@@ -415,7 +447,8 @@ internal func differentiate<E: Differentiable, I>(
415447
target: ContiguousArray<E>,
416448
trackTargetIndexAsUpdated: Bool,
417449
mapIndex: (Int) -> I,
418-
remainedInTarget: ((E) -> Void)? = nil
450+
updatedElements: ((E) -> Void)? = nil,
451+
undeletedElements: ((E) -> Void)? = nil
419452
) -> DifferentiateResult<I> {
420453
var deleted = [I]()
421454
var inserted = [I]()
@@ -489,11 +522,15 @@ internal func differentiate<E: Differentiable, I>(
489522

490523
if let targetIndex = sourceTraces[sourceIndex].reference {
491524
let targetElement = target[targetIndex]
492-
remainedInTarget?(targetElement)
493-
} else {
525+
updatedElements?(targetElement)
526+
undeletedElements?(targetElement)
527+
}
528+
else {
529+
let sourceElement = source[sourceIndex]
494530
deleted.append(mapIndex(sourceIndex))
495531
sourceTraces[sourceIndex].isTracked = true
496532
offsetByDelete += 1
533+
updatedElements?(sourceElement)
497534
}
498535
}
499536

@@ -517,7 +554,8 @@ internal func differentiate<E: Differentiable, I>(
517554
let deleteOffset = sourceTraces[sourceIndex].deleteOffset
518555
moved.append((source: mapIndex(sourceIndex - deleteOffset), target: mapIndex(targetIndex)))
519556
}
520-
} else {
557+
}
558+
else {
521559
inserted.append(mapIndex(targetIndex))
522560
}
523561
}

Sources/ArraySection.swift

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -59,10 +59,6 @@ extension ArraySection: Equatable where Model: Equatable, Element: Equatable {
5959

6060
extension ArraySection: CustomDebugStringConvertible {
6161
public var debugDescription: String {
62-
guard !elements.isEmpty else {
63-
return "ArraySection(model: \(model), elements: [])"
64-
}
65-
6662
return """
6763
ArraySection(
6864
model: \(model),

Sources/Changeset.swift

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,11 @@ extension Changeset: Equatable where Collection: Equatable {
123123
extension Changeset: CustomDebugStringConvertible {
124124
public var debugDescription: String {
125125
guard !data.isEmpty || hasChanges else {
126-
return "Changeset(data: [])"
126+
return """
127+
Changeset(
128+
data: []
129+
)"
130+
"""
127131
}
128132

129133
var description = """

Sources/Extensions/UIKitExtension.swift

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -68,8 +68,6 @@ public extension UITableView {
6868
return reloadData()
6969
}
7070

71-
let contentOffset = self.contentOffset
72-
7371
for changeset in stagedChangeset {
7472
if let interrupt = interrupt, interrupt(changeset), let data = stagedChangeset.last?.data {
7573
setData(data)
@@ -112,10 +110,6 @@ public extension UITableView {
112110
}
113111
}
114112
}
115-
116-
if contentSize.height > bounds.size.height {
117-
setContentOffset(contentOffset, animated: false)
118-
}
119113
}
120114

121115
private func _performBatchUpdates(_ updates: () -> Void) {
@@ -152,8 +146,6 @@ public extension UICollectionView {
152146
return reloadData()
153147
}
154148

155-
let contentOffset = self.contentOffset
156-
157149
for changeset in stagedChangeset {
158150
if let interrupt = interrupt, interrupt(changeset), let data = stagedChangeset.last?.data {
159151
setData(data)
@@ -196,10 +188,6 @@ public extension UICollectionView {
196188
}
197189
})
198190
}
199-
200-
if contentSize.height > bounds.size.height {
201-
setContentOffset(contentOffset, animated: false)
202-
}
203191
}
204192
}
205193
#endif

Tests/AlgorithmTest.swift

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -199,11 +199,18 @@ extension AlgorithmTestCase {
199199
Changeset(
200200
data: [
201201
M(0, true),
202+
M(1, false),
202203
M(2, false)
203204
],
204-
elementDeleted: [ElementPath(element: 1, section: section)],
205205
elementUpdated: [ElementPath(element: 0, section: section)]
206206
),
207+
Changeset(
208+
data: [
209+
M(0, true),
210+
M(2, false)
211+
],
212+
elementDeleted: [ElementPath(element: 1, section: section)]
213+
),
207214
Changeset(
208215
data: target,
209216
elementInserted: [

docs/Extensions.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ <h4>Declaration</h4>
179179
</section>
180180
</section>
181181
<section id="footer">
182-
<p>&copy; 2018 <a class="link" href="https://github.com/ra1028" target="_blank" rel="external">Ryo Aoyama</a>. All rights reserved. (Last updated: 2018-10-09)</p>
182+
<p>&copy; 2018 <a class="link" href="https://github.com/ra1028" target="_blank" rel="external">Ryo Aoyama</a>. All rights reserved. (Last updated: 2018-11-11)</p>
183183
<p>Generated by <a class="link" href="https://github.com/realm/jazzy" target="_blank" rel="external">jazzy ♪♫ v0.9.3</a>, a <a class="link" href="https://realm.io" target="_blank" rel="external">Realm</a> project.</p>
184184
</section>
185185
</article>

0 commit comments

Comments
 (0)