| File: Syntax\SyntaxListBuilder.cs | Web Access |
| Project: src\roslyn\src\Compilers\Core\Portable\Microsoft.CodeAnalysis.csproj (Microsoft.CodeAnalysis) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. using System; using System.Diagnostics; namespace Microsoft.CodeAnalysis.Syntax { internal class SyntaxListBuilder { private ArrayElement<GreenNode?>[] _nodes; public int Count { get; private set; } public SyntaxListBuilder(int size) { _nodes = new ArrayElement<GreenNode?>[size]; } public void Clear() { this.Count = 0; } public void Add(SyntaxNode item) { AddInternal(item.Green); } internal void AddInternal(GreenNode item) { if (item == null) { throw new ArgumentNullException(); } if (Count >= _nodes.Length) { this.Grow(Count == 0 ? 8 : _nodes.Length * 2); } _nodes[Count++].Value = item; } public void AddRange(SyntaxNode[] items) { this.AddRange(items, 0, items.Length); } public void AddRange(SyntaxNode[] items, int offset, int length) { if (Count + length > _nodes.Length) { this.Grow(Count + length); } for (int i = offset, j = Count; i < offset + length; ++i, ++j) { _nodes[j].Value = items[i].Green; } int start = Count; Count += length; Validate(start, Count); } [Conditional("DEBUG")] private void Validate(int start, int end) { for (int i = start; i < end; i++) { if (_nodes[i].Value == null) { throw new ArgumentException("Cannot add a null node."); } } } public void AddRange(SyntaxList<SyntaxNode> list) { this.AddRange(list, 0, list.Count); } public void AddRange(SyntaxList<SyntaxNode> list, int offset, int count) { if (this.Count + count > _nodes.Length) { this.Grow(Count + count); } var dst = this.Count; for (int i = offset, limit = offset + count; i < limit; i++) { _nodes[dst].Value = list.ItemInternal(i)!.Green; dst++; } int start = Count; Count += count; Validate(start, Count); } public void AddRange<TNode>(SyntaxList<TNode> list) where TNode : SyntaxNode { this.AddRange(list, 0, list.Count); } public void AddRange<TNode>(SyntaxList<TNode> list, int offset, int count) where TNode : SyntaxNode { this.AddRange(new SyntaxList<SyntaxNode>(list.Node), offset, count); } public void AddRange(SyntaxNodeOrTokenList list) { this.AddRange(list, 0, list.Count); } public void AddRange(SyntaxNodeOrTokenList list, int offset, int count) { if (this.Count + count > _nodes.Length) { this.Grow(Count + count); } var dst = this.Count; for (int i = offset, limit = offset + count; i < limit; i++) { _nodes[dst].Value = list[i].UnderlyingNode; dst++; } int start = Count; Count += count; Validate(start, Count); } public void AddRange(SyntaxTokenList list) { this.AddRange(list, 0, list.Count); } public void AddRange(SyntaxTokenList list, int offset, int length) { Debug.Assert(list.Node is object); this.AddRange(new SyntaxList<SyntaxNode>(list.Node.CreateRed()), offset, length); } private void Grow(int size) { var tmp = new ArrayElement<GreenNode?>[size]; Array.Copy(_nodes, tmp, _nodes.Length); _nodes = tmp; } public bool Any(int kind) { for (int i = 0; i < Count; i++) { if (_nodes[i].Value!.RawKind == kind) { return true; } } return false; } internal GreenNode? ToListNode() { switch (this.Count) { case 0: return null; case 1: return _nodes[0].Value; case 2: return InternalSyntax.SyntaxList.List(_nodes[0].Value!, _nodes[1].Value!); case 3: return InternalSyntax.SyntaxList.List(_nodes[0].Value!, _nodes[1].Value!, _nodes[2].Value!); default: var tmp = new ArrayElement<GreenNode>[this.Count]; for (int i = 0; i < this.Count; i++) { tmp[i].Value = _nodes[i].Value!; } return InternalSyntax.SyntaxList.List(tmp); } } public static implicit operator SyntaxList<SyntaxNode>(SyntaxListBuilder builder) { if (builder == null) { return default(SyntaxList<SyntaxNode>); } return builder.ToList(); } internal void RemoveLast() { this.Count -= 1; this._nodes[Count] = default; } } }