File: Language\TagHelperCollection.Builder.cs
Web Access
Project: src\src\Razor\src\Compiler\Microsoft.CodeAnalysis.Razor.Compiler\src\Microsoft.CodeAnalysis.Razor.Compiler.csproj (Microsoft.CodeAnalysis.Razor.Compiler)
// 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.Collections;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Threading;
using Microsoft.AspNetCore.Razor.PooledObjects;
using Microsoft.AspNetCore.Razor.Utilities;
 
namespace Microsoft.AspNetCore.Razor.Language;
 
public abstract partial class TagHelperCollection
{
    public sealed partial class Builder : ICollection<TagHelperDescriptor>, IReadOnlyList<TagHelperDescriptor>, IDisposable
    {
        // Create new pooled builders and sets with a larger initial capacity to limit growth.
        private const int InitialCapacity = 256;
 
        // Builders and sets are typically large, so allow them to stay larger when returned to their pool.
        private const int MaximumObjectSize = 2048;
 
        private static readonly ArrayBuilderPool<TagHelperDescriptor> s_arrayBuilderPool =
            ArrayBuilderPool<TagHelperDescriptor>.Create(InitialCapacity, MaximumObjectSize);
 
        private ImmutableArray<TagHelperDescriptor>.Builder _items;
        private HashSet<Checksum> _set;
 
        public Builder()
        {
            _items = s_arrayBuilderPool.Get();
            _set = ChecksumSetPool.Default.Get();
        }
 
        public void Dispose()
        {
            var items = Interlocked.Exchange(ref _items, null!);
            if (items is not null)
            {
                s_arrayBuilderPool.Return(items);
            }
 
            var set = Interlocked.Exchange(ref _set, null!);
            if (set is not null)
            {
                ChecksumSetPool.Default.Return(set);
            }
        }
 
        public bool IsEmpty => Count == 0;
 
        public int Count => _items.Count;
 
        public bool IsReadOnly => false;
 
        public TagHelperDescriptor this[int index]
        {
            get
            {
                ArgHelper.ThrowIfNegative(index);
                ArgHelper.ThrowIfGreaterThanOrEqual(index, Count);
 
                return _items[index];
            }
        }
 
        public bool Add(TagHelperDescriptor item)
        {
            if (!_set.Add(item.Checksum))
            {
                return false;
            }
 
            _items.Add(item);
            return true;
        }
 
        void ICollection<TagHelperDescriptor>.Add(TagHelperDescriptor item)
            => Add(item);
 
        public void AddRange(TagHelperCollection items)
        {
            foreach (var item in items)
            {
                if (_set.Add(item.Checksum))
                {
                    _items.Add(item);
                }
            }
        }
 
        public void AddRange(ReadOnlySpan<TagHelperDescriptor> span)
        {
            foreach (var item in span)
            {
                if (_set.Add(item.Checksum))
                {
                    _items.Add(item);
                }
            }
        }
 
        public void AddRange(IEnumerable<TagHelperDescriptor> source)
        {
            foreach (var item in source)
            {
                if (_set.Add(item.Checksum))
                {
                    _items.Add(item);
                }
            }
        }
 
        public void Clear()
        {
            _items.Clear();
            _set.Clear();
        }
 
        public bool Contains(TagHelperDescriptor item)
            => _set.Contains(item.Checksum);
 
        public void CopyTo(TagHelperDescriptor[] array, int arrayIndex)
            => _items.CopyTo(array, arrayIndex);
 
        public bool Remove(TagHelperDescriptor item)
            => _set.Remove(item.Checksum) && _items.Remove(item);
 
        public TagHelperCollection ToCollection()
        {
            if (_items.Count == 0)
            {
                return Empty;
            }
 
            var array = _items.ToImmutable();
            return new SingleSegmentCollection(array.AsMemory());
        }
 
        public Enumerator GetEnumerator()
            => new(this);
 
        IEnumerator<TagHelperDescriptor> IEnumerable<TagHelperDescriptor>.GetEnumerator()
            => new EnumeratorImpl(this);
 
        IEnumerator IEnumerable.GetEnumerator()
            => new EnumeratorImpl(this);
    }
}