File: Instance\ImmutableProjectCollections\ImmutableGlobalPropertiesCollectionConverter.cs
Web Access
Project: ..\..\..\src\Build\Microsoft.Build.csproj (Microsoft.Build)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System;
using System.CodeDom;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Build.Collections;
using Microsoft.Build.Execution;
using Microsoft.Build.Shared;
 
#nullable disable
 
namespace Microsoft.Build.Instance.ImmutableProjectCollections
{
    /// <summary>
    /// A collection representing the set of Global ProjectPropertyInstance objects.
    /// </summary>
    /// <remarks>This class is used only when the containing ProjectInstance originates from an
    /// immutable linked project source. It's specialized in order to reduce required allocations
    /// by instead relying on the linked project source's collection of global properties
    /// (the IDictionary _globalProperties) and the ProjectInstance's collection of all
    /// properties (the PropertyDictionary _allProperties). When a property is requested,
    /// _globalProperties is checked to determine whether the named property is actually
    /// a global property and, if it is, then instance is retrieved from _allProperties.
    /// </remarks>
    internal class ImmutableGlobalPropertiesCollectionConverter : IRetrievableEntryHashSet<ProjectPropertyInstance>
    {
        private readonly IDictionary<string, string> _globalProperties;
        private readonly PropertyDictionary<ProjectPropertyInstance> _allProperties;
        private readonly ValuesCollection _values;
 
        public ImmutableGlobalPropertiesCollectionConverter(
            IDictionary<string, string> globalProperties,
            PropertyDictionary<ProjectPropertyInstance> allProperties)
        {
            _globalProperties = globalProperties;
            _allProperties = allProperties;
            _values = new ValuesCollection(this);
        }
 
        public ProjectPropertyInstance this[string key]
        {
            set => throw new NotSupportedException();
            get
            {
                if (_globalProperties.ContainsKey(key))
                {
                    return _allProperties[key];
                }
 
                return null;
            }
        }
 
        public int Count => _globalProperties.Count;
 
        public bool IsReadOnly => true;
 
        public ICollection<string> Keys => _globalProperties.Keys;
 
        public ICollection<ProjectPropertyInstance> Values => _values;
 
        public void Add(ProjectPropertyInstance item) => throw new NotSupportedException();
 
        public void Add(string key, ProjectPropertyInstance value) => throw new NotSupportedException();
 
        public void Add(KeyValuePair<string, ProjectPropertyInstance> item) => throw new NotSupportedException();
 
        public void Clear() => throw new NotSupportedException();
 
        public bool Contains(ProjectPropertyInstance item) => _values.Contains(item);
 
        public bool Contains(KeyValuePair<string, ProjectPropertyInstance> itemKvp) => _values.Contains(itemKvp.Value);
 
        public bool ContainsKey(string key) => _globalProperties.ContainsKey(key);
 
        public void CopyTo(ProjectPropertyInstance[] array) => _values.CopyTo(array, arrayIndex: 0);
 
        public void CopyTo(ProjectPropertyInstance[] array, int arrayIndex) => _values.CopyTo(array, arrayIndex);
 
        public void CopyTo(ProjectPropertyInstance[] array, int arrayIndex, int count) => _values.CopyTo(array, arrayIndex, count);
 
        public void CopyTo(KeyValuePair<string, ProjectPropertyInstance>[] array, int arrayIndex)
        {
            ErrorUtilities.VerifyCollectionCopyToArguments(array, nameof(array), arrayIndex, nameof(arrayIndex), _globalProperties.Count);
 
            int currentIndex = arrayIndex;
            foreach (var itemKey in _globalProperties.Keys)
            {
                ProjectPropertyInstance instance = _allProperties[itemKey];
                if (instance != null)
                {
                    array[currentIndex] = new KeyValuePair<string, ProjectPropertyInstance>(itemKey, instance);
                    ++currentIndex;
                }
            }
        }
 
        public ProjectPropertyInstance Get(string key)
        {
            return this[key];
        }
 
        public ProjectPropertyInstance Get(string key, int index, int length)
        {
            // The PropertyDictionary containing all of the properties can efficiently
            // look up the requested property while honoring the specific index and length
            // constraints. We then just have to verify that it's one of the global properties.
            ProjectPropertyInstance actualProperty = _allProperties.Get(key, index, length);
            if (actualProperty != null && _globalProperties.ContainsKey(actualProperty.Name))
            {
                return actualProperty;
            }
 
            return null;
        }
 
        public IEnumerator<ProjectPropertyInstance> GetEnumerator() => _values.GetEnumerator();
 
        public void GetObjectData(SerializationInfo info, StreamingContext context) => throw new NotSupportedException();
 
        public void OnDeserialization(object sender) => throw new NotSupportedException();
 
        public bool Remove(ProjectPropertyInstance item) => throw new NotSupportedException();
 
        public bool Remove(string key) => throw new NotSupportedException();
 
        public bool Remove(KeyValuePair<string, ProjectPropertyInstance> item) => throw new NotSupportedException();
 
        public void TrimExcess()
        {
        }
 
        public bool TryGetValue(string key, out ProjectPropertyInstance value)
        {
            ProjectPropertyInstance instance = Get(key);
            value = instance;
            return instance != null;
        }
 
        public void UnionWith(IEnumerable<ProjectPropertyInstance> other) => throw new NotSupportedException();
 
        IEnumerator<KeyValuePair<string, ProjectPropertyInstance>> IEnumerable<KeyValuePair<string, ProjectPropertyInstance>>.GetEnumerator()
        {
            foreach (var itemKey in _globalProperties.Keys)
            {
                ProjectPropertyInstance instance = _allProperties[itemKey];
                if (instance != null)
                {
                    yield return new KeyValuePair<string, ProjectPropertyInstance>(itemKey, instance);
                }
            }
        }
 
        IEnumerator IEnumerable.GetEnumerator() => _values.GetEnumerator();
 
        private class ValuesCollection : ICollection<ProjectPropertyInstance>
        {
            private readonly ImmutableGlobalPropertiesCollectionConverter _parent;
 
            public ValuesCollection(ImmutableGlobalPropertiesCollectionConverter parent)
            {
                _parent = parent;
            }
 
            public int Count => _parent._globalProperties.Count;
 
            public bool IsReadOnly => true;
 
            public void Add(ProjectPropertyInstance item) => throw new NotSupportedException();
 
            public void Clear() => throw new NotSupportedException();
 
            public bool Remove(ProjectPropertyInstance item) => throw new NotSupportedException();
 
            public bool Contains(ProjectPropertyInstance item)
            {
                if (!_parent._globalProperties.ContainsKey(item.Name))
                {
                    return false;
                }
 
                ProjectPropertyInstance actualInstance = _parent._allProperties[item.Name];
 
                if (actualInstance == null)
                {
                    return false;
                }
 
                return actualInstance.Equals(item);
            }
 
            public void CopyTo(ProjectPropertyInstance[] array, int arrayIndex)
            {
                CopyTo(array, arrayIndex, _parent._globalProperties.Count);
            }
 
            public void CopyTo(ProjectPropertyInstance[] array, int arrayIndex, int count)
            {
                ErrorUtilities.VerifyCollectionCopyToArguments(array, nameof(array), arrayIndex, nameof(arrayIndex), _parent._globalProperties.Count);
 
                int currentIndex = arrayIndex;
                int currentCount = 0;
                foreach (var itemKey in _parent._globalProperties.Keys)
                {
                    if (currentCount >= count)
                    {
                        return;
                    }
 
                    ProjectPropertyInstance instance = _parent._allProperties[itemKey];
                    if (instance != null)
                    {
                        array[currentIndex] = instance;
                        ++currentIndex;
                        ++currentCount;
                    }
                }
            }
 
            public IEnumerator<ProjectPropertyInstance> GetEnumerator()
            {
                foreach (var itemKey in _parent._globalProperties.Keys)
                {
                    ProjectPropertyInstance instance = _parent._allProperties[itemKey];
                    if (instance != null)
                    {
                        yield return instance;
                    }
                }
            }
 
            IEnumerator IEnumerable.GetEnumerator()
            {
                foreach (var itemKey in _parent._globalProperties.Keys)
                {
                    ProjectPropertyInstance instance = _parent._allProperties[itemKey];
                    if (instance != null)
                    {
                        yield return instance;
                    }
                }
            }
        }
    }
}