blob: d7337b27da0a13b7a5cf3c9ce4f1449181b53548 [file] [log] [blame]
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace DotPulsar.Internal
{
using System;
using System.Buffers;
using System.Collections.Generic;
using System.Linq;
public sealed class SequenceBuilder<T> where T : notnull
{
private readonly LinkedList<ReadOnlyMemory<T>> _elements;
public SequenceBuilder()
=> _elements = new LinkedList<ReadOnlyMemory<T>>();
public SequenceBuilder<T> Prepend(ReadOnlyMemory<T> memory)
{
_elements.AddFirst(memory);
return this;
}
public SequenceBuilder<T> Prepend(ReadOnlySequence<T> sequence)
{
LinkedListNode<ReadOnlyMemory<T>>? index = null;
foreach (var memory in sequence)
{
index = index is null
? _elements.AddFirst(memory)
: _elements.AddAfter(index, memory);
}
return this;
}
public SequenceBuilder<T> Append(ReadOnlyMemory<T> memory)
{
_elements.AddLast(memory);
return this;
}
public SequenceBuilder<T> Append(ReadOnlySequence<T> sequence)
{
foreach (var memory in sequence)
_elements.AddLast(memory);
return this;
}
public long Length => _elements.Sum(e => e.Length);
public ReadOnlySequence<T> Build()
{
var node = _elements.First;
if (node is null)
return ReadOnlySequence<T>.Empty;
var current = new Segment(node.Value);
var start = current;
while (true)
{
node = node.Next;
if (node is null)
break;
current = current.CreateNext(node.Value);
}
return new ReadOnlySequence<T>(start, 0, current, current.Memory.Length);
}
private sealed class Segment : ReadOnlySequenceSegment<T>
{
public Segment(ReadOnlyMemory<T> memory, long runningIndex = 0)
{
Memory = memory;
RunningIndex = runningIndex;
}
public Segment CreateNext(ReadOnlyMemory<T> memory)
{
var segment = new Segment(memory, RunningIndex + Memory.Length);
Next = segment;
return segment;
}
}
}
}