Skip to content

Commit eb8db09

Browse files
committed
Lazily enumerate tree entry changes
1 parent f7222d2 commit eb8db09

File tree

2 files changed

+48
-50
lines changed

2 files changed

+48
-50
lines changed

LibGit2Sharp/TreeChanges.cs

Lines changed: 31 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -17,32 +17,8 @@ namespace LibGit2Sharp
1717
[DebuggerDisplay("{DebuggerDisplay,nq}")]
1818
public class TreeChanges : IEnumerable<TreeEntryChanges>, IDiffResult
1919
{
20-
private readonly List<TreeEntryChanges> changes = new List<TreeEntryChanges>();
21-
private readonly List<TreeEntryChanges> added = new List<TreeEntryChanges>();
22-
private readonly List<TreeEntryChanges> deleted = new List<TreeEntryChanges>();
23-
private readonly List<TreeEntryChanges> modified = new List<TreeEntryChanges>();
24-
private readonly List<TreeEntryChanges> typeChanged = new List<TreeEntryChanges>();
25-
private readonly List<TreeEntryChanges> unmodified = new List<TreeEntryChanges>();
26-
private readonly List<TreeEntryChanges> renamed = new List<TreeEntryChanges>();
27-
private readonly List<TreeEntryChanges> copied = new List<TreeEntryChanges>();
28-
private readonly List<TreeEntryChanges> conflicted = new List<TreeEntryChanges>();
29-
30-
private readonly IDictionary<ChangeKind, Action<TreeChanges, TreeEntryChanges>> fileDispatcher = Build();
31-
32-
private static IDictionary<ChangeKind, Action<TreeChanges, TreeEntryChanges>> Build()
33-
{
34-
return new Dictionary<ChangeKind, Action<TreeChanges, TreeEntryChanges>>
35-
{
36-
{ ChangeKind.Modified, (de, d) => de.modified.Add(d) },
37-
{ ChangeKind.Deleted, (de, d) => de.deleted.Add(d) },
38-
{ ChangeKind.Added, (de, d) => de.added.Add(d) },
39-
{ ChangeKind.TypeChanged, (de, d) => de.typeChanged.Add(d) },
40-
{ ChangeKind.Unmodified, (de, d) => de.unmodified.Add(d) },
41-
{ ChangeKind.Renamed, (de, d) => de.renamed.Add(d) },
42-
{ ChangeKind.Copied, (de, d) => de.copied.Add(d) },
43-
{ ChangeKind.Conflicted, (de, d) => de.conflicted.Add(d) },
44-
};
45-
}
20+
private readonly DiffSafeHandle diff;
21+
private readonly Lazy<int> count;
4622

4723
/// <summary>
4824
/// Needed for mocking purposes.
@@ -52,22 +28,28 @@ protected TreeChanges()
5228

5329
internal TreeChanges(DiffSafeHandle diff)
5430
{
55-
using(diff)
56-
Proxy.git_diff_foreach(diff, FileCallback, null, null);
31+
this.diff = diff;
32+
this.count = new Lazy<int>(() => Proxy.git_diff_num_deltas(diff));
5733
}
5834

59-
private int FileCallback(GitDiffDelta delta, float progress, IntPtr payload)
35+
/// <summary>
36+
/// Enumerates the diff and yields deltas with the specified change kind.
37+
/// </summary>
38+
/// <param name="changeKind">Change type to filter on.</param>
39+
private IEnumerable<TreeEntryChanges> GetChangesOfKind(ChangeKind changeKind)
6040
{
61-
AddFileChange(delta);
62-
return 0;
41+
for (int i = 0; i < count.Value; i++)
42+
{
43+
var delta = Proxy.git_diff_get_delta(diff, i);
44+
45+
if (TreeEntryChanges.GetStatusFromChangeKind(delta.Status) == changeKind)
46+
yield return new TreeEntryChanges(delta);
47+
}
6348
}
6449

65-
private void AddFileChange(GitDiffDelta delta)
50+
private static TreeEntryChanges ToTreeEntryChange(GitDiffDelta delta)
6651
{
67-
var treeEntryChanges = new TreeEntryChanges(delta);
68-
69-
fileDispatcher[treeEntryChanges.Status](this, treeEntryChanges);
70-
changes.Add(treeEntryChanges);
52+
return new TreeEntryChanges(delta);
7153
}
7254

7355
#region IEnumerable<TreeEntryChanges> Members
@@ -78,7 +60,10 @@ private void AddFileChange(GitDiffDelta delta)
7860
/// <returns>An <see cref="IEnumerator{T}"/> object that can be used to iterate through the collection.</returns>
7961
public virtual IEnumerator<TreeEntryChanges> GetEnumerator()
8062
{
81-
return changes.GetEnumerator();
63+
for (int i = 0; i < count.Value; i++)
64+
{
65+
yield return new TreeEntryChanges(Proxy.git_diff_get_delta(diff, i));
66+
}
8267
}
8368

8469
/// <summary>
@@ -97,63 +82,63 @@ IEnumerator IEnumerable.GetEnumerator()
9782
/// </summary>
9883
public virtual IEnumerable<TreeEntryChanges> Added
9984
{
100-
get { return added; }
85+
get { return GetChangesOfKind(ChangeKind.Added); }
10186
}
10287

10388
/// <summary>
10489
/// List of <see cref="TreeEntryChanges"/> that have been deleted.
10590
/// </summary>
10691
public virtual IEnumerable<TreeEntryChanges> Deleted
10792
{
108-
get { return deleted; }
93+
get { return GetChangesOfKind(ChangeKind.Deleted); }
10994
}
11095

11196
/// <summary>
11297
/// List of <see cref="TreeEntryChanges"/> that have been modified.
11398
/// </summary>
11499
public virtual IEnumerable<TreeEntryChanges> Modified
115100
{
116-
get { return modified; }
101+
get { return GetChangesOfKind(ChangeKind.Modified); }
117102
}
118103

119104
/// <summary>
120105
/// List of <see cref="TreeEntryChanges"/> which type have been changed.
121106
/// </summary>
122107
public virtual IEnumerable<TreeEntryChanges> TypeChanged
123108
{
124-
get { return typeChanged; }
109+
get { return GetChangesOfKind(ChangeKind.TypeChanged); }
125110
}
126111

127112
/// <summary>
128113
/// List of <see cref="TreeEntryChanges"/> which have been renamed
129114
/// </summary>
130115
public virtual IEnumerable<TreeEntryChanges> Renamed
131116
{
132-
get { return renamed; }
117+
get { return GetChangesOfKind(ChangeKind.Renamed); }
133118
}
134119

135120
/// <summary>
136121
/// List of <see cref="TreeEntryChanges"/> which have been copied
137122
/// </summary>
138123
public virtual IEnumerable<TreeEntryChanges> Copied
139124
{
140-
get { return copied; }
125+
get { return GetChangesOfKind(ChangeKind.Copied); }
141126
}
142127

143128
/// <summary>
144129
/// List of <see cref="TreeEntryChanges"/> which are unmodified
145130
/// </summary>
146131
public virtual IEnumerable<TreeEntryChanges> Unmodified
147132
{
148-
get { return unmodified; }
133+
get { return GetChangesOfKind(ChangeKind.Unmodified); }
149134
}
150135

151136
/// <summary>
152137
/// List of <see cref="TreeEntryChanges"/> which are conflicted
153138
/// </summary>
154139
public virtual IEnumerable<TreeEntryChanges> Conflicted
155140
{
156-
get { return conflicted; }
141+
get { return GetChangesOfKind(ChangeKind.Conflicted); }
157142
}
158143

159144
private string DebuggerDisplay
@@ -179,8 +164,7 @@ public void Dispose()
179164

180165
protected virtual void Dispose(bool disposing)
181166
{
182-
// This doesn't do anything yet because it loads everything
183-
// eagerly and disposes of the diff handle in the constructor.
167+
diff.SafeDispose();
184168
}
185169
}
186170
}

LibGit2Sharp/TreeEntryChanges.cs

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,23 @@ internal TreeEntryChanges(GitDiffDelta delta)
2828
Exists = (delta.NewFile.Flags & GitDiffFlags.GIT_DIFF_FLAG_EXISTS) != 0;
2929
OldExists = (delta.OldFile.Flags & GitDiffFlags.GIT_DIFF_FLAG_EXISTS) != 0;
3030

31-
Status = (delta.Status == ChangeKind.Untracked || delta.Status == ChangeKind.Ignored)
32-
? ChangeKind.Added
33-
: delta.Status;
31+
Status = GetStatusFromChangeKind(delta.Status);
32+
}
33+
34+
// This treatment of change kind was apparently introduced in order to be able
35+
// to compare a tree against the index, see commit fdc972b. It's extracted
36+
// here so that TreeEntry can use the same rules without having to instantiate
37+
// a TreeEntryChanges object.
38+
internal static ChangeKind GetStatusFromChangeKind(ChangeKind changeKind)
39+
{
40+
switch (changeKind)
41+
{
42+
case ChangeKind.Untracked:
43+
case ChangeKind.Ignored:
44+
return ChangeKind.Added;
45+
default:
46+
return changeKind;
47+
}
3448
}
3549

3650
/// <summary>

0 commit comments

Comments
 (0)