public void ProcessItemElement(string rootDirectory, ProjectItemElement itemElement, bool conditionResult) { LazyItemOperation operation = null; if (itemElement.IncludeLocation != null) { operation = BuildIncludeOperation(rootDirectory, itemElement, conditionResult); } else if (itemElement.RemoveLocation != null) { operation = BuildRemoveOperation(rootDirectory, itemElement); } else if (itemElement.UpdateLocation != null) { operation = BuildUpdateOperation(rootDirectory, itemElement); } else { throw new NotImplementedException(); } LazyItemList previousItemList = GetItemList(itemElement.ItemType); LazyItemList newList = new LazyItemList(previousItemList, operation); _itemLists[itemElement.ItemType] = newList; }
public void ProcessItemElement(string rootDirectory, ProjectItemElement itemElement, bool conditionResult) { LazyItemOperation operation = null; if (itemElement.IncludeLocation != null) { operation = BuildIncludeOperation(rootDirectory, itemElement, conditionResult); } else if (itemElement.RemoveLocation != null) { operation = BuildRemoveOperation(rootDirectory, itemElement, conditionResult); } else if (itemElement.UpdateLocation != null) { operation = BuildUpdateOperation(rootDirectory, itemElement, conditionResult); } else { ErrorUtilities.ThrowInternalErrorUnreachable(); } LazyItemList previousItemList = GetItemList(itemElement.ItemType); LazyItemList newList = new LazyItemList(previousItemList, operation); _itemLists[itemElement.ItemType] = newList; }
static ImmutableList <ItemData> .Builder GetItemsImplementation(LazyItemList lazyItemList, ImmutableHashSet <string> globsToIgnore) { Stack <LazyItemList> itemListStack = new Stack <LazyItemList>(); // Keep a separate stack of lists of globs to ignore that only gets modified for Remove operations Stack <ImmutableHashSet <string> > globsToIgnoreStack = null; for (var currentList = lazyItemList; currentList != null; currentList = currentList._previous) { // If this is a remove operation, then add any globs that will be removed // to a list of globs to ignore in previous operations var removeOperation = currentList._operation as RemoveOperation; if (removeOperation != null) { if (globsToIgnoreStack == null) { globsToIgnoreStack = new Stack <ImmutableHashSet <string> >(); } var globsToIgnoreFromFutureOperations = globsToIgnoreStack.Count > 0 ? globsToIgnoreStack.Peek() : globsToIgnore; var globsToIgnoreForPreviousOperations = removeOperation.GetRemovedGlobs(); foreach (var globToRemove in globsToIgnoreFromFutureOperations) { globsToIgnoreForPreviousOperations.Add(globToRemove); } globsToIgnoreStack.Push(globsToIgnoreForPreviousOperations.ToImmutable()); } itemListStack.Push(currentList); } ImmutableList <ItemData> .Builder items = ImmutableList.CreateBuilder <ItemData>(); ImmutableHashSet <string> currentGlobsToIgnore = globsToIgnoreStack == null ? globsToIgnore : globsToIgnoreStack.Peek(); // Walk back down the stack of item lists applying operations while (itemListStack.Count > 0) { var currentList = itemListStack.Pop(); // If this is a remove operation, then it could modify the globs to ignore, so pop the potentially // modified entry off the stack of globs to ignore var removeOperation = currentList._operation as RemoveOperation; if (removeOperation != null) { globsToIgnoreStack.Pop(); currentGlobsToIgnore = globsToIgnoreStack.Count == 0 ? globsToIgnore : globsToIgnoreStack.Peek(); } currentList._operation.Apply(items, currentGlobsToIgnore); // TODO: Cache result of operation (possibly only if it involved executing globs) } return(items); }
ICollection <ItemData> GetItems(string itemType) { LazyItemList itemList = GetItemList(itemType); if (itemList == null) { return(ImmutableList <ItemData> .Empty); } return(itemList.GetItems(ImmutableHashSet <string> .Empty).Where(itemData => itemData.ConditionResult).ToList()); }
private ImmutableList <I> GetItems(string itemType) { LazyItemList itemList = GetItemList(itemType); if (itemList == null) { return(ImmutableList <I> .Empty); } return(itemList.GetMatchedItems(ImmutableHashSet <string> .Empty)); }
internal static Item Create(LazyItemList list, int index, int height) { var id = list.ItemIdOffset + index; if (id % ItemTypeModulous == 0) { return(new Alternate(id, list.Id, height)); } return(new Normal(id, list.Id, height)); }
private static ImmutableList <ItemData> .Builder ComputeItems(LazyItemList lazyItemList, ImmutableHashSet <string> globsToIgnore) { // Stack of operations up to the first one that's cached (exclusive) Stack <LazyItemList> itemListStack = new Stack <LazyItemList>(); ImmutableList <ItemData> .Builder items = null; // Keep a separate stack of lists of globs to ignore that only gets modified for Remove operations Stack <ImmutableHashSet <string> > globsToIgnoreStack = null; for (var currentList = lazyItemList; currentList != null; currentList = currentList._previous) { var globsToIgnoreFromFutureOperations = globsToIgnoreStack?.Peek() ?? globsToIgnore; ImmutableList <ItemData> itemsFromCache; if (currentList._memoizedOperation.TryGetFromCache(globsToIgnoreFromFutureOperations, out itemsFromCache)) { // the base items on top of which to apply the uncached operations are the items of the first operation that is cached items = itemsFromCache.ToBuilder(); break; } // If this is a remove operation, then add any globs that will be removed // to a list of globs to ignore in previous operations var removeOperation = currentList._memoizedOperation.Operation as RemoveOperation; if (removeOperation != null) { if (globsToIgnoreStack == null) { globsToIgnoreStack = new Stack <ImmutableHashSet <string> >(); } var globsToIgnoreForPreviousOperations = removeOperation.GetRemovedGlobs(); foreach (var globToRemove in globsToIgnoreFromFutureOperations) { globsToIgnoreForPreviousOperations.Add(globToRemove); } globsToIgnoreStack.Push(globsToIgnoreForPreviousOperations.ToImmutable()); } itemListStack.Push(currentList); } if (items == null) { items = ImmutableList.CreateBuilder <ItemData>(); } ImmutableHashSet <string> currentGlobsToIgnore = globsToIgnoreStack == null ? globsToIgnore : globsToIgnoreStack.Peek(); // Walk back down the stack of item lists applying operations while (itemListStack.Count > 0) { var currentList = itemListStack.Pop(); // If this is a remove operation, then it could modify the globs to ignore, so pop the potentially // modified entry off the stack of globs to ignore var removeOperation = currentList._memoizedOperation.Operation as RemoveOperation; if (removeOperation != null) { globsToIgnoreStack.Pop(); currentGlobsToIgnore = globsToIgnoreStack.Count == 0 ? globsToIgnore : globsToIgnoreStack.Peek(); } currentList._memoizedOperation.Apply(items, currentGlobsToIgnore); } return(items); }
public LazyItemList(LazyItemList previous, LazyItemOperation operation) { _previous = previous; _memoizedOperation = new MemoizedOperation(operation); }
public LazyItemList(LazyItemList previous, LazyItemOperation operation) { _previous = previous; _operation = operation; }
private static OrderedItemDataCollection.Builder ComputeItems(LazyItemList lazyItemList, ImmutableHashSet <string> globsToIgnore) { // Stack of operations up to the first one that's cached (exclusive) Stack <LazyItemList> itemListStack = new Stack <LazyItemList>(); OrderedItemDataCollection.Builder items = null; // Keep a separate stack of lists of globs to ignore that only gets modified for Remove operations Stack <ImmutableHashSet <string> > globsToIgnoreStack = null; for (var currentList = lazyItemList; currentList != null; currentList = currentList._previous) { var globsToIgnoreFromFutureOperations = globsToIgnoreStack?.Peek() ?? globsToIgnore; OrderedItemDataCollection itemsFromCache; if (currentList._memoizedOperation.TryGetFromCache(globsToIgnoreFromFutureOperations, out itemsFromCache)) { // the base items on top of which to apply the uncached operations are the items of the first operation that is cached items = itemsFromCache.ToBuilder(); break; } // If this is a remove operation, then add any globs that will be removed // to a list of globs to ignore in previous operations if (currentList._memoizedOperation.Operation is RemoveOperation removeOperation) { globsToIgnoreStack ??= new Stack <ImmutableHashSet <string> >(); var globsToIgnoreForPreviousOperations = removeOperation.GetRemovedGlobs(); foreach (var globToRemove in globsToIgnoreFromFutureOperations) { globsToIgnoreForPreviousOperations.Add(globToRemove); } globsToIgnoreStack.Push(globsToIgnoreForPreviousOperations.ToImmutable()); } itemListStack.Push(currentList); } if (items == null) { items = OrderedItemDataCollection.CreateBuilder(); } ImmutableHashSet <string> currentGlobsToIgnore = globsToIgnoreStack == null ? globsToIgnore : globsToIgnoreStack.Peek(); Dictionary <string, UpdateOperation> itemsWithNoWildcards = new Dictionary <string, UpdateOperation>(StringComparer.OrdinalIgnoreCase); bool addedToBatch = false; // Walk back down the stack of item lists applying operations while (itemListStack.Count > 0) { var currentList = itemListStack.Pop(); if (currentList._memoizedOperation.Operation is UpdateOperation op) { bool addToBatch = true; int i; // The TextFragments are things like abc.def or x*y.*z. for (i = 0; i < op.Spec.Fragments.Count; i++) { ItemSpecFragment frag = op.Spec.Fragments[i]; if (MSBuildConstants.CharactersForExpansion.Any(frag.TextFragment.Contains)) { // Fragment contains wild cards, items, or properties. Cannot batch over it using a dictionary. addToBatch = false; break; } string fullPath = FileUtilities.GetFullPath(frag.TextFragment, frag.ProjectDirectory); if (itemsWithNoWildcards.ContainsKey(fullPath)) { // Another update will already happen on this path. Make that happen before evaluating this one. addToBatch = false; break; } else { itemsWithNoWildcards.Add(fullPath, op); } } if (!addToBatch) { // We found a wildcard. Remove any fragments associated with the current operation and process them later. for (int j = 0; j < i; j++) { itemsWithNoWildcards.Remove(currentList._memoizedOperation.Operation.Spec.Fragments[j].TextFragment); } } else { addedToBatch = true; continue; } } if (addedToBatch) { addedToBatch = false; ProcessNonWildCardItemUpdates(itemsWithNoWildcards, items); } // If this is a remove operation, then it could modify the globs to ignore, so pop the potentially // modified entry off the stack of globs to ignore if (currentList._memoizedOperation.Operation is RemoveOperation) { globsToIgnoreStack.Pop(); currentGlobsToIgnore = globsToIgnoreStack.Count == 0 ? globsToIgnore : globsToIgnoreStack.Peek(); } currentList._memoizedOperation.Apply(items, currentGlobsToIgnore); } // We finished looping through the operations. Now process the final batch if necessary. ProcessNonWildCardItemUpdates(itemsWithNoWildcards, items); return(items); }