1 #region Copyright notice and license 2 // Protocol Buffers - Google's data interchange format 3 // Copyright 2008 Google Inc. All rights reserved. 4 // 5 // Use of this source code is governed by a BSD-style 6 // license that can be found in the LICENSE file or at 7 // https://developers.google.com/open-source/licenses/bsd 8 #endregion 9 10 using System; 11 using System.Buffers; 12 using System.Collections.Generic; 13 14 namespace Google.Protobuf 15 { 16 internal static class ReadOnlySequenceFactory 17 { 18 /// <summary> 19 /// Create a sequence from the specified data. The data will be divided up into segments in the sequence. 20 /// </summary> CreateWithContent(byte[] data, int segmentSize = 1, bool addEmptySegmentDelimiters = true)21 public static ReadOnlySequence<byte> CreateWithContent(byte[] data, int segmentSize = 1, bool addEmptySegmentDelimiters = true) 22 { 23 var segments = new List<byte[]>(); 24 25 if (addEmptySegmentDelimiters) 26 { 27 segments.Add(Array.Empty<byte>()); 28 } 29 30 var currentIndex = 0; 31 while (currentIndex < data.Length) 32 { 33 var segment = new List<byte>(); 34 while (segment.Count < segmentSize && currentIndex < data.Length) 35 { 36 segment.Add(data[currentIndex++]); 37 } 38 segments.Add(segment.ToArray()); 39 40 if (addEmptySegmentDelimiters) 41 { 42 segments.Add(Array.Empty<byte>()); 43 } 44 } 45 46 return CreateSegments(segments.ToArray()); 47 } 48 49 /// <summary> 50 /// Originally from corefx, and has been contributed to Protobuf 51 /// https://github.com/dotnet/corefx/blob/e99ec129cfd594d53f4390bf97d1d736cff6f860/src/System.Memory/tests/ReadOnlyBuffer/ReadOnlySequenceFactory.byte.cs 52 /// </summary> CreateSegments(params byte[][] inputs)53 private static ReadOnlySequence<byte> CreateSegments(params byte[][] inputs) 54 { 55 if (inputs == null || inputs.Length == 0) 56 { 57 throw new InvalidOperationException(); 58 } 59 60 int i = 0; 61 62 BufferSegment last = null; 63 BufferSegment first = null; 64 65 do 66 { 67 byte[] s = inputs[i]; 68 int length = s.Length; 69 int dataOffset = length; 70 var chars = new byte[length * 2]; 71 72 for (int j = 0; j < length; j++) 73 { 74 chars[dataOffset + j] = s[j]; 75 } 76 77 // Create a segment that has offset relative to the OwnedMemory and OwnedMemory itself has offset relative to array 78 var memory = new Memory<byte>(chars).Slice(length, length); 79 80 if (first == null) 81 { 82 first = new BufferSegment(memory); 83 last = first; 84 } 85 else 86 { 87 last = last.Append(memory); 88 } 89 i++; 90 } while (i < inputs.Length); 91 92 return new ReadOnlySequence<byte>(first, 0, last, last.Memory.Length); 93 } 94 95 private class BufferSegment : ReadOnlySequenceSegment<byte> 96 { BufferSegment(Memory<byte> memory)97 public BufferSegment(Memory<byte> memory) 98 { 99 Memory = memory; 100 } 101 Append(Memory<byte> memory)102 public BufferSegment Append(Memory<byte> memory) 103 { 104 var segment = new BufferSegment(memory) 105 { 106 RunningIndex = RunningIndex + Memory.Length 107 }; 108 Next = segment; 109 return segment; 110 } 111 } 112 } 113 }