| File: Language\TagHelperCollection.MultiSegmentCollection.cs | Web Access |
| Project: src\roslyn\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.Immutable; using System.Diagnostics; using System.Linq; namespace Microsoft.AspNetCore.Razor.Language; public abstract partial class TagHelperCollection { /// <summary> /// Represents a read-only collection of <see cref="TagHelperDescriptor"/> objects composed /// from multiple contiguous memory segments, providing efficient indexed access across all segments. /// </summary> /// <remarks> /// This collection is optimized for scenarios where <see cref="TagHelperDescriptor"/> items /// are distributed across several memory segments, allowing for efficient access without merging /// the segments into a single array. The collection is immutable and thread-safe for concurrent /// read operations. /// </remarks> private sealed class MultiSegmentCollection : SegmentCollectionBase { private readonly ImmutableArray<ReadOnlyMemory<TagHelperDescriptor>> _segments; private readonly int[] _segmentStartIndices; private readonly int _count; public MultiSegmentCollection(ImmutableArray<ReadOnlyMemory<TagHelperDescriptor>> segments) { Debug.Assert(segments.Length > 0, "Segments cannot be empty."); _segments = segments; // Pre-calculate segment boundaries for efficient indexing _segmentStartIndices = new int[segments.Length]; var count = 0; for (var i = 0; i < segments.Length; i++) { Debug.Assert(segments[i].Length > 0, "Segments cannot be empty."); _segmentStartIndices[i] = count; count += segments[i].Length; } _count = count; } protected override int SegmentCount => _segments.Length; protected override ReadOnlyMemory<TagHelperDescriptor> GetSegment(int index) { Debug.Assert(index >= 0 && index < _segments.Length); return _segments[index]; } public override int Count => _count; public override TagHelperDescriptor this[int index] { get { ArgHelper.ThrowIfNegative(index); ArgHelper.ThrowIfGreaterThanOrEqual(index, Count); // Binary search to find the segment containing this index var segmentIndex = FindSegmentIndex(index); var localIndex = index - _segmentStartIndices[segmentIndex]; return _segments[segmentIndex].Span[localIndex]; } } private int FindSegmentIndex(int index) { var searchResult = _segmentStartIndices.BinarySearch(index); if (searchResult >= 0) { return searchResult; } var insertionPoint = ~searchResult; return insertionPoint - 1; } } }