// Copyright Epic Games, Inc. All Rights Reserved. using System; using System.Buffers; using System.Collections.Generic; namespace EpicGames.Core { /// /// Static utility methods /// public static class ReadOnlySequence { /// /// Create a sequence from a list of segments /// /// /// Sequence for the list of segments public static ReadOnlySequence Create(IReadOnlyList> segments) => ReadOnlySequenceBuilder.Create(segments); } /// /// Utility class to combine buffers into a /// /// Element type public class ReadOnlySequenceBuilder { class Segment : ReadOnlySequenceSegment { public Segment(long runningIndex, ReadOnlyMemory memory) { RunningIndex = runningIndex; Memory = memory; } public void SetNext(Segment next) { Next = next; } } readonly List> _segments = []; /// /// Current length of the sequence /// public long Length { get; private set; } /// /// Create a sequence from a list of segments /// /// /// Sequence for the list of segments internal static ReadOnlySequence Create(IReadOnlyList> segments) { if (segments.Count == 0) { return ReadOnlySequence.Empty; } Segment first = new Segment(0, segments[0]); Segment last = first; for (int idx = 1; idx < segments.Count; idx++) { Segment next = new Segment(last.RunningIndex + last.Memory.Length, segments[idx]); last.SetNext(next); last = next; } return new ReadOnlySequence(first, 0, last, last.Memory.Length); } /// /// Append a block of memory to the end of the sequence /// /// Memory to append public void Append(ReadOnlyMemory memory) { if (memory.Length > 0) { _segments.Add(memory); Length += memory.Length; } } /// /// Append another sequence to the end of this one /// /// Sequence to append public void Append(ReadOnlySequence sequence) { foreach (ReadOnlyMemory segment in sequence) { Append(segment); } } /// /// Construct a sequence from the added blocks /// /// Sequence for the added memory blocks public ReadOnlySequence Construct() => Create(_segments); } /// /// Extension methods for /// public static class ReadOnlySequenceExtensions { /// /// Gets the data from a sequence as a contiguous block of memory /// /// Sequence to return /// Data for the blob public static ReadOnlyMemory AsSingleSegment(this ReadOnlySequence sequence) { if (sequence.IsSingleSegment) { return sequence.First; } else { return sequence.ToArray(); } } } }