• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 }