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
+ #if NETCOREAPP2_1
34
+ using System ;
35
+ using System . Buffers ;
36
+ using System . Collections . Generic ;
37
+ using System . Runtime . CompilerServices ;
38
+ using System . Text ;
39
+
40
+ namespace Google . Protobuf
41
+ {
42
+ internal class ArrayBufferWriter : IBufferWriter < byte > , IDisposable
43
+ {
44
+ private ResizableArray < byte > _buffer ;
45
+ private readonly int _maximumSizeHint ;
46
+
47
+ public ArrayBufferWriter ( int capacity , int ? maximumSizeHint = null )
48
+ {
49
+ _buffer = new ResizableArray < byte > ( ArrayPool < byte > . Shared . Rent ( capacity ) ) ;
50
+ _maximumSizeHint = maximumSizeHint ?? int . MaxValue ;
51
+ }
52
+
53
+ public int CommitedByteCount => _buffer . Count ;
54
+
55
+ public void Clear ( )
56
+ {
57
+ _buffer . Count = 0 ;
58
+ }
59
+
60
+ public ArraySegment < byte > Free => _buffer . Free ;
61
+
62
+ public ArraySegment < byte > Formatted => _buffer . Full ;
63
+
64
+ public Memory < byte > GetMemory ( int minimumLength = 0 )
65
+ {
66
+ minimumLength = Math . Min ( minimumLength , _maximumSizeHint ) ;
67
+
68
+ if ( minimumLength < 1 )
69
+ {
70
+ minimumLength = 1 ;
71
+ }
72
+
73
+ if ( minimumLength > _buffer . FreeCount )
74
+ {
75
+ int doubleCount = _buffer . FreeCount * 2 ;
76
+ int newSize = minimumLength > doubleCount ? minimumLength : doubleCount ;
77
+ byte [ ] newArray = ArrayPool < byte > . Shared . Rent ( newSize + _buffer . Count ) ;
78
+ byte [ ] oldArray = _buffer . Resize ( newArray ) ;
79
+ ArrayPool < byte > . Shared . Return ( oldArray ) ;
80
+ }
81
+
82
+ return _buffer . FreeMemory ;
83
+ }
84
+
85
+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
86
+ public Span < byte > GetSpan ( int minimumLength = 0 )
87
+ {
88
+ minimumLength = Math . Min ( minimumLength , _maximumSizeHint ) ;
89
+
90
+ if ( minimumLength < 1 )
91
+ {
92
+ minimumLength = 1 ;
93
+ }
94
+
95
+ if ( minimumLength > _buffer . FreeCount )
96
+ {
97
+ int doubleCount = _buffer . FreeCount * 2 ;
98
+ int newSize = minimumLength > doubleCount ? minimumLength : doubleCount ;
99
+ byte [ ] newArray = ArrayPool < byte > . Shared . Rent ( newSize + _buffer . Count ) ;
100
+ byte [ ] oldArray = _buffer . Resize ( newArray ) ;
101
+ ArrayPool < byte > . Shared . Return ( oldArray ) ;
102
+ }
103
+
104
+ return _buffer . FreeSpan ;
105
+ }
106
+
107
+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
108
+ public void Advance ( int bytes )
109
+ {
110
+ _buffer . Count += bytes ;
111
+ if ( _buffer . Count > _buffer . Capacity )
112
+ {
113
+ throw new InvalidOperationException ( "More bytes commited than returned from FreeBuffer" ) ;
114
+ }
115
+ }
116
+
117
+ public void Dispose ( )
118
+ {
119
+ byte [ ] array = _buffer . Array ;
120
+ _buffer . Array = null ;
121
+ ArrayPool < byte > . Shared . Return ( array ) ;
122
+ }
123
+
124
+ private struct ResizableArray < T >
125
+ {
126
+ public ResizableArray ( T [ ] array , int count = 0 )
127
+ {
128
+ Array = array ;
129
+ Count = count ;
130
+ }
131
+
132
+ public T [ ] Array { get ; set ; }
133
+
134
+ public int Count { get ; set ; }
135
+
136
+ public int Capacity => Array . Length ;
137
+
138
+ public T [ ] Resize ( T [ ] newArray )
139
+ {
140
+ T [ ] oldArray = Array ;
141
+ Array . AsSpan ( 0 , Count ) . CopyTo ( newArray ) ; // CopyTo will throw if newArray.Length < _count
142
+ Array = newArray ;
143
+ return oldArray ;
144
+ }
145
+
146
+ public ArraySegment < T > Full => new ArraySegment < T > ( Array , 0 , Count ) ;
147
+
148
+ public ArraySegment < T > Free => new ArraySegment < T > ( Array , Count , Array . Length - Count ) ;
149
+
150
+ public Span < T > FreeSpan => new Span < T > ( Array , Count , Array . Length - Count ) ;
151
+
152
+ public Memory < T > FreeMemory => new Memory < T > ( Array , Count , Array . Length - Count ) ;
153
+
154
+ public int FreeCount => Array . Length - Count ;
155
+ }
156
+ }
157
+ }
158
+ #endif
0 commit comments