1 #region Copyright notice and license 2 // Protocol Buffers - Google's data interchange format 3 // Copyright 2008 Google Inc. All rights reserved. 4 // https://developers.google.com/protocol-buffers/ 5 // 6 // Redistribution and use in source and binary forms, with or without 7 // modification, are permitted provided that the following conditions are 8 // met: 9 // 10 // * Redistributions of source code must retain the above copyright 11 // notice, this list of conditions and the following disclaimer. 12 // * Redistributions in binary form must reproduce the above 13 // copyright notice, this list of conditions and the following disclaimer 14 // in the documentation and/or other materials provided with the 15 // distribution. 16 // * Neither the name of Google Inc. nor the names of its 17 // contributors may be used to endorse or promote products derived from 18 // this software without specific prior written permission. 19 // 20 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 #endregion 32 33 using System; 34 using System.Buffers; 35 using System.Collections.Generic; 36 using System.Linq; 37 using System.Text; 38 using System.Threading.Tasks; 39 40 namespace Google.Protobuf 41 { 42 internal static class ReadOnlySequenceFactory 43 { 44 /// <summary> 45 /// Create a sequence from the specified data. The data will be divided up into segments in the sequence. 46 /// </summary> CreateWithContent(byte[] data, int segmentSize = 1, bool addEmptySegmentDelimiters = true)47 public static ReadOnlySequence<byte> CreateWithContent(byte[] data, int segmentSize = 1, bool addEmptySegmentDelimiters = true) 48 { 49 var segments = new List<byte[]>(); 50 51 if (addEmptySegmentDelimiters) 52 { 53 segments.Add(new byte[0]); 54 } 55 56 var currentIndex = 0; 57 while (currentIndex < data.Length) 58 { 59 var segment = new List<byte>(); 60 while (segment.Count < segmentSize && currentIndex < data.Length) 61 { 62 segment.Add(data[currentIndex++]); 63 } 64 segments.Add(segment.ToArray()); 65 66 if (addEmptySegmentDelimiters) 67 { 68 segments.Add(new byte[0]); 69 } 70 } 71 72 return CreateSegments(segments.ToArray()); 73 } 74 75 /// <summary> 76 /// Originally from corefx, and has been contributed to Protobuf 77 /// https://github.com/dotnet/corefx/blob/e99ec129cfd594d53f4390bf97d1d736cff6f860/src/System.Memory/tests/ReadOnlyBuffer/ReadOnlySequenceFactory.byte.cs 78 /// </summary> CreateSegments(params byte[][] inputs)79 private static ReadOnlySequence<byte> CreateSegments(params byte[][] inputs) 80 { 81 if (inputs == null || inputs.Length == 0) 82 { 83 throw new InvalidOperationException(); 84 } 85 86 int i = 0; 87 88 BufferSegment last = null; 89 BufferSegment first = null; 90 91 do 92 { 93 byte[] s = inputs[i]; 94 int length = s.Length; 95 int dataOffset = length; 96 var chars = new byte[length * 2]; 97 98 for (int j = 0; j < length; j++) 99 { 100 chars[dataOffset + j] = s[j]; 101 } 102 103 // Create a segment that has offset relative to the OwnedMemory and OwnedMemory itself has offset relative to array 104 var memory = new Memory<byte>(chars).Slice(length, length); 105 106 if (first == null) 107 { 108 first = new BufferSegment(memory); 109 last = first; 110 } 111 else 112 { 113 last = last.Append(memory); 114 } 115 i++; 116 } while (i < inputs.Length); 117 118 return new ReadOnlySequence<byte>(first, 0, last, last.Memory.Length); 119 } 120 121 private class BufferSegment : ReadOnlySequenceSegment<byte> 122 { BufferSegment(Memory<byte> memory)123 public BufferSegment(Memory<byte> memory) 124 { 125 Memory = memory; 126 } 127 Append(Memory<byte> memory)128 public BufferSegment Append(Memory<byte> memory) 129 { 130 var segment = new BufferSegment(memory) 131 { 132 RunningIndex = RunningIndex + Memory.Length 133 }; 134 Next = segment; 135 return segment; 136 } 137 } 138 } 139 }