Skip to content

Avoid some smaller allocations in ItemGroupintrinsicTask #11779

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -482,23 +482,56 @@ private List<ProjectItemInstance> ExpandItemIntoItems(
}

// Filter the metadata as appropriate
List<string> metadataToRemove = null;
if (keepMetadata != null)
{
foreach (var item in items)
foreach (ProjectItemInstance item in items)
{
var metadataToRemove = item.MetadataNames.Where(name => !keepMetadata.Contains(name));
foreach (var metadataName in metadataToRemove)
if (metadataToRemove == null)
{
metadataToRemove = new List<string>();
}
else
{
metadataToRemove.Clear();
}

foreach (string metadataName in item.EnumerableMetadataNames)
{
if (!keepMetadata.Contains(metadataName))
{
metadataToRemove.Add(metadataName);
}
}

foreach(string metadataName in metadataToRemove)
{
item.RemoveMetadata(metadataName);
}
}
}
else if (removeMetadata != null)
{
foreach (var item in items)
foreach (ProjectItemInstance item in items)
{
var metadataToRemove = item.MetadataNames.Where(name => removeMetadata.Contains(name));
foreach (var metadataName in metadataToRemove)
if (metadataToRemove == null)
{
metadataToRemove = new List<string>();
}
else
{
metadataToRemove.Clear();
}

foreach (string metadataName in item.EnumerableMetadataNames)
{
if (removeMetadata.Contains(metadataName))
{
metadataToRemove.Add(metadataName);
}
}

foreach (string metadataName in metadataToRemove)
{
item.RemoveMetadata(metadataName);
}
Expand All @@ -517,7 +550,7 @@ private List<ProjectItemInstance> ExpandItemIntoItems(
/// <returns>A list of matching items</returns>
private HashSet<string> EvaluateExcludePaths(IReadOnlyList<string> excludes, ElementLocation excludeLocation)
{
HashSet<string> excludesUnescapedForComparison = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
HashSet<string> excludesUnescapedForComparison = new HashSet<string>(excludes.Count, StringComparer.OrdinalIgnoreCase);
foreach (string excludeSplit in excludes)
{
string[] excludeSplitFiles = EngineFileUtilities.GetFileListUnescaped(
Expand Down
2 changes: 1 addition & 1 deletion src/Build/Instance/ProjectInstance.cs
Original file line number Diff line number Diff line change
Expand Up @@ -827,7 +827,7 @@ private ProjectInstance(ProjectInstance that, bool isImmutable, RequestedProject
// any extant metadata.
// UNDONE: This could be achieved at lower GC cost by applying
// the metadata filter at DeepClone time above.
foreach (var metadataName in filteredItem.MetadataNames)
foreach (var metadataName in filteredItem.EnumerableMetadataNames)
{
if (!itemFilter.Value.Contains(metadataName, StringComparer.OrdinalIgnoreCase))
{
Expand Down
56 changes: 56 additions & 0 deletions src/Build/Instance/ProjectItemInstance.cs
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,8 @@
get { return new ReadOnlyCollection<string>(_taskItem.MetadataNames.Cast<string>()); }
}

internal TaskItem.MetadataNamesEnumerable EnumerableMetadataNames => _taskItem.EnumerableMetadatNames;

Check failure on line 288 in src/Build/Instance/ProjectItemInstance.cs

View check run for this annotation

Azure Pipelines / msbuild-pr (Linux Core)

src/Build/Instance/ProjectItemInstance.cs#L288

src/Build/Instance/ProjectItemInstance.cs(288,88): error CS1061: (NETCORE_ENGINEERING_TELEMETRY=Build) 'ProjectItemInstance.TaskItem' does not contain a definition for 'EnumerableMetadatNames' and no accessible extension method 'EnumerableMetadatNames' accepting a first argument of type 'ProjectItemInstance.TaskItem' could be found (are you missing a using directive or an assembly reference?)

Check failure on line 288 in src/Build/Instance/ProjectItemInstance.cs

View check run for this annotation

Azure Pipelines / msbuild-pr (Linux Core)

src/Build/Instance/ProjectItemInstance.cs#L288

src/Build/Instance/ProjectItemInstance.cs(288,88): error CS1061: (NETCORE_ENGINEERING_TELEMETRY=Build) 'ProjectItemInstance.TaskItem' does not contain a definition for 'EnumerableMetadatNames' and no accessible extension method 'EnumerableMetadatNames' accepting a first argument of type 'ProjectItemInstance.TaskItem' could be found (are you missing a using directive or an assembly reference?)

Check failure on line 288 in src/Build/Instance/ProjectItemInstance.cs

View check run for this annotation

Azure Pipelines / msbuild-pr (Linux Core)

src/Build/Instance/ProjectItemInstance.cs#L288

src/Build/Instance/ProjectItemInstance.cs(288,88): error CS1061: (NETCORE_ENGINEERING_TELEMETRY=Build) 'ProjectItemInstance.TaskItem' does not contain a definition for 'EnumerableMetadatNames' and no accessible extension method 'EnumerableMetadatNames' accepting a first argument of type 'ProjectItemInstance.TaskItem' could be found (are you missing a using directive or an assembly reference?)

Check failure on line 288 in src/Build/Instance/ProjectItemInstance.cs

View check run for this annotation

Azure Pipelines / msbuild-pr (Linux Core)

src/Build/Instance/ProjectItemInstance.cs#L288

src/Build/Instance/ProjectItemInstance.cs(288,88): error CS1061: (NETCORE_ENGINEERING_TELEMETRY=Build) 'ProjectItemInstance.TaskItem' does not contain a definition for 'EnumerableMetadatNames' and no accessible extension method 'EnumerableMetadatNames' accepting a first argument of type 'ProjectItemInstance.TaskItem' could be found (are you missing a using directive or an assembly reference?)

Check failure on line 288 in src/Build/Instance/ProjectItemInstance.cs

View check run for this annotation

Azure Pipelines / msbuild-pr (macOS Core)

src/Build/Instance/ProjectItemInstance.cs#L288

src/Build/Instance/ProjectItemInstance.cs(288,88): error CS1061: (NETCORE_ENGINEERING_TELEMETRY=Build) 'ProjectItemInstance.TaskItem' does not contain a definition for 'EnumerableMetadatNames' and no accessible extension method 'EnumerableMetadatNames' accepting a first argument of type 'ProjectItemInstance.TaskItem' could be found (are you missing a using directive or an assembly reference?)

Check failure on line 288 in src/Build/Instance/ProjectItemInstance.cs

View check run for this annotation

Azure Pipelines / msbuild-pr (macOS Core)

src/Build/Instance/ProjectItemInstance.cs#L288

src/Build/Instance/ProjectItemInstance.cs(288,88): error CS1061: (NETCORE_ENGINEERING_TELEMETRY=Build) 'ProjectItemInstance.TaskItem' does not contain a definition for 'EnumerableMetadatNames' and no accessible extension method 'EnumerableMetadatNames' accepting a first argument of type 'ProjectItemInstance.TaskItem' could be found (are you missing a using directive or an assembly reference?)

Check failure on line 288 in src/Build/Instance/ProjectItemInstance.cs

View check run for this annotation

Azure Pipelines / msbuild-pr (macOS Core)

src/Build/Instance/ProjectItemInstance.cs#L288

src/Build/Instance/ProjectItemInstance.cs(288,88): error CS1061: (NETCORE_ENGINEERING_TELEMETRY=Build) 'ProjectItemInstance.TaskItem' does not contain a definition for 'EnumerableMetadatNames' and no accessible extension method 'EnumerableMetadatNames' accepting a first argument of type 'ProjectItemInstance.TaskItem' could be found (are you missing a using directive or an assembly reference?)

Check failure on line 288 in src/Build/Instance/ProjectItemInstance.cs

View check run for this annotation

Azure Pipelines / msbuild-pr

src/Build/Instance/ProjectItemInstance.cs#L288

src/Build/Instance/ProjectItemInstance.cs(288,88): error CS1061: (NETCORE_ENGINEERING_TELEMETRY=Build) 'ProjectItemInstance.TaskItem' does not contain a definition for 'EnumerableMetadatNames' and no accessible extension method 'EnumerableMetadatNames' accepting a first argument of type 'ProjectItemInstance.TaskItem' could be found (are you missing a using directive or an assembly reference?)

/// <summary>
/// ITaskItem implementation
/// </summary>
Expand Down Expand Up @@ -957,6 +959,8 @@
}
}

public MetadataNamesEnumerable EnumerableMetadataNames => new MetadataNamesEnumerable(this);

/// <summary>
/// Gets the number of metadata set on the item.
/// Computed, not necessarily fast.
Expand Down Expand Up @@ -1961,6 +1965,58 @@
return null;
}

internal readonly struct MetadataNamesEnumerable
{
private readonly TaskItem _item;

public MetadataNamesEnumerable(TaskItem taskItem) => _item = taskItem;

public readonly MetadataNamesEnumerator GetEnumerator() => new MetadataNamesEnumerator(_item.MetadataCollection);
}

internal struct MetadataNamesEnumerator
{
private readonly IEnumerator<ProjectMetadataInstance> _metadataCollectionEnumerator;
private bool _metadataNamesEnumerated;
private int _itemSpecModifiersIndex;

internal MetadataNamesEnumerator(ICopyOnWritePropertyDictionary<ProjectMetadataInstance> metadataCollection)
{
_metadataCollectionEnumerator = ((IEnumerable<ProjectMetadataInstance>)metadataCollection).GetEnumerator();
_metadataNamesEnumerated = false;
_itemSpecModifiersIndex = 0;
}

public string Current { get; private set; }

public bool MoveNext()
{
if (!_metadataNamesEnumerated)
{
if (_metadataCollectionEnumerator.MoveNext())
{
Current = _metadataCollectionEnumerator.Current.Name;

return true;
}
else
{
_metadataNamesEnumerated = true;
}
}

if (_itemSpecModifiersIndex < FileUtilities.ItemSpecModifiers.All.Length)
{
Current = FileUtilities.ItemSpecModifiers.All[_itemSpecModifiersIndex];
++_itemSpecModifiersIndex;

return true;
}

return false;
}
}

/// <summary>
/// A class factory for instance model items.
/// </summary>
Expand Down
Loading