Skip to content

Commit e00b710

Browse files
Merge pull request #1030 from stebet/boundscheckremoval
Removing bounds checks when (de)serializing commands/frames.
2 parents 3299fcf + 2f407cd commit e00b710

File tree

81 files changed

+1204
-1260
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

81 files changed

+1204
-1260
lines changed

projects/Benchmarks/Program.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ public Config()
2121
{
2222
AddJob(Job.Default.WithRuntime(CoreRuntime.Core31));
2323
AddJob(Job.Default.WithRuntime(ClrRuntime.Net48));
24-
AddExporter(DefaultExporters.Markdown, DefaultExporters.Csv);
24+
AddExporter(DefaultExporters.Markdown, DefaultExporters.JsonFull).KeepBenchmarkFiles(true).DontOverwriteResults(true);
2525
AddDiagnoser(new DisassemblyDiagnoser(new DisassemblyDiagnoserConfig()), MemoryDiagnoser.Default);
2626
}
2727
}

projects/Benchmarks/WireFormatting/DataTypeSerialization.cs

Lines changed: 26 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -39,17 +39,17 @@ public class DataTypeFieldSerialization : DataTypeSerialization
3939
public override void SetUp()
4040
{
4141
_fieldNullBuffer = new byte[WireFormatting.GetFieldValueByteCount(null)];
42-
WireFormatting.WriteFieldValue(_fieldNullBuffer.Span, null);
42+
WireFormatting.WriteFieldValue(ref _fieldNullBuffer.Span.GetStart(), null);
4343
_fieldIntBuffer = new byte[WireFormatting.GetFieldValueByteCount(_intObject)];
44-
WireFormatting.WriteFieldValue(_fieldIntBuffer.Span, _intObject);
44+
WireFormatting.WriteFieldValue(ref _fieldIntBuffer.Span.GetStart(), _intObject);
4545
_fieldStringBuffer = new byte[WireFormatting.GetFieldValueByteCount(_shortString)];
46-
WireFormatting.WriteFieldValue(_fieldStringBuffer.Span, _shortString);
46+
WireFormatting.WriteFieldValue(ref _fieldStringBuffer.Span.GetStart(), _shortString);
4747
_fieldArrayBuffer = new byte[WireFormatting.GetFieldValueByteCount(_byteArray)];
48-
WireFormatting.WriteFieldValue(_fieldArrayBuffer.Span, _byteArray);
48+
WireFormatting.WriteFieldValue(ref _fieldArrayBuffer.Span.GetStart(), _byteArray);
4949
_fieldDictBuffer = new byte[WireFormatting.GetFieldValueByteCount(_emptyDictionary)];
50-
WireFormatting.WriteFieldValue(_fieldDictBuffer.Span, _emptyDictionary);
50+
WireFormatting.WriteFieldValue(ref _fieldDictBuffer.Span.GetStart(), _emptyDictionary);
5151
_fieldBinaryTableValueBuffer = new byte[WireFormatting.GetFieldValueByteCount(_binaryTableValue)];
52-
WireFormatting.WriteFieldValue(_fieldBinaryTableValueBuffer.Span, _binaryTableValue);
52+
WireFormatting.WriteFieldValue(ref _fieldBinaryTableValueBuffer.Span.GetStart(), _binaryTableValue);
5353
}
5454

5555
[Benchmark]
@@ -64,20 +64,18 @@ public override void SetUp()
6464
public object DictRead() => WireFormatting.ReadFieldValue(_fieldDictBuffer.Span, out int _);
6565
[Benchmark]
6666
public object BinaryTableValueRead() => WireFormatting.ReadFieldValue(_fieldBinaryTableValueBuffer.Span, out int _);
67-
6867
[Benchmark]
69-
public int NullWrite() => WireFormatting.WriteFieldValue(_buffer.Span,null);
68+
public int NullWrite() => WireFormatting.WriteFieldValue(ref _buffer.Span.GetStart(), null);
7069
[Benchmark]
71-
public int IntWrite() => WireFormatting.WriteFieldValue(_buffer.Span, _intObject);
70+
public int IntWrite() => WireFormatting.WriteFieldValue(ref _buffer.Span.GetStart(), _intObject);
7271
[Benchmark]
73-
public int StringWrite() => WireFormatting.WriteFieldValue(_buffer.Span, _shortString);
72+
public int StringWrite() => WireFormatting.WriteFieldValue(ref _buffer.Span.GetStart(), _shortString);
7473
[Benchmark]
75-
public int ArrayWrite() => WireFormatting.WriteFieldValue(_buffer.Span, _byteArray);
74+
public int ArrayWrite() => WireFormatting.WriteFieldValue(ref _buffer.Span.GetStart(), _byteArray);
7675
[Benchmark]
77-
public int DictWrite() => WireFormatting.WriteFieldValue(_buffer.Span, _emptyDictionary);
76+
public int DictWrite() => WireFormatting.WriteFieldValue(ref _buffer.Span.GetStart(), _emptyDictionary);
7877
[Benchmark]
79-
public int BinaryTableValueWrite() => WireFormatting.WriteFieldValue(_buffer.Span, _binaryTableValue);
80-
78+
public int BinaryTableValueWrite() => WireFormatting.WriteFieldValue(ref _buffer.Span.GetStart(), _binaryTableValue);
8179
[Benchmark]
8280
public int NullGetSize() => WireFormatting.GetFieldValueByteCount(null);
8381
[Benchmark]
@@ -103,10 +101,10 @@ public override void SetUp()
103101
{
104102
_array = new List<object> { "longstring", 1234, 12.34m, _timestamp };
105103
_emptyArrayBuffer = new byte[WireFormatting.GetArrayByteCount(_emptyArray)];
106-
WireFormatting.WriteArray(_emptyArrayBuffer.Span, _emptyArray);
104+
WireFormatting.WriteArray(ref _emptyArrayBuffer.Span.GetStart(), _emptyArray);
107105

108106
_populatedArrayBuffer = new byte[WireFormatting.GetArrayByteCount(_array)];
109-
WireFormatting.WriteArray(_populatedArrayBuffer.Span, _array);
107+
WireFormatting.WriteArray(ref _populatedArrayBuffer.Span.GetStart(), _array);
110108
}
111109

112110
[Benchmark]
@@ -116,10 +114,10 @@ public override void SetUp()
116114
public IList ArrayReadPopulated() => WireFormatting.ReadArray(_populatedArrayBuffer.Span, out _);
117115

118116
[Benchmark]
119-
public int ArrayWriteEmpty() => WireFormatting.WriteArray(_buffer.Span, _emptyArray);
117+
public int ArrayWriteEmpty() => WireFormatting.WriteArray(ref _buffer.Span.GetStart(), _emptyArray);
120118

121119
[Benchmark]
122-
public int ArrayWritePopulated() => WireFormatting.WriteArray(_buffer.Span, _array);
120+
public int ArrayWritePopulated() => WireFormatting.WriteArray(ref _buffer.Span.GetStart(), _array);
123121

124122
[Benchmark]
125123
public int ArrayGetSizeEmpty() => WireFormatting.GetArrayByteCount(_emptyArray);
@@ -149,10 +147,10 @@ public override void SetUp()
149147
};
150148

151149
_emptyDictionaryBuffer = new byte[WireFormatting.GetTableByteCount(_emptyDict)];
152-
WireFormatting.WriteTable(_emptyDictionaryBuffer.Span, _emptyDict);
150+
WireFormatting.WriteTable(ref _emptyDictionaryBuffer.Span.GetStart(), _emptyDict);
153151

154152
_populatedDictionaryBuffer = new byte[WireFormatting.GetTableByteCount(_populatedDict)];
155-
WireFormatting.WriteTable(_populatedDictionaryBuffer.Span, _populatedDict);
153+
WireFormatting.WriteTable(ref _populatedDictionaryBuffer.Span.GetStart(), _populatedDict);
156154
}
157155

158156
[Benchmark]
@@ -162,10 +160,10 @@ public override void SetUp()
162160
public int TableReadPopulated() => WireFormatting.ReadDictionary(_populatedDictionaryBuffer.Span, out _);
163161

164162
[Benchmark]
165-
public int TableWriteEmpty() => WireFormatting.WriteTable(_buffer.Span, _emptyDict);
163+
public int TableWriteEmpty() => WireFormatting.WriteTable(ref _buffer.Span.GetStart(), _emptyDict);
166164

167165
[Benchmark]
168-
public int TableWritePopulated() => WireFormatting.WriteTable(_buffer.Span, _populatedDict);
166+
public int TableWritePopulated() => WireFormatting.WriteTable(ref _buffer.Span.GetStart(), _populatedDict);
169167

170168
[Benchmark]
171169
public int TableGetSizeEmpty() => WireFormatting.GetTableByteCount(_emptyDict);
@@ -187,10 +185,10 @@ public class DataTypeLongStringSerialization : DataTypeSerialization
187185
public int LongstrReadPopulated() => WireFormatting.ReadLongstr(_populatedLongStringBuffer.Span, out _);
188186

189187
[Benchmark]
190-
public int LongstrWriteEmpty() => WireFormatting.WriteLongstr(_buffer.Span, string.Empty);
188+
public int LongstrWriteEmpty() => WireFormatting.WriteLongstr(ref _buffer.Span.GetStart(), string.Empty);
191189

192190
[Benchmark]
193-
public int LongstrWritePopulated() => WireFormatting.WriteLongstr(_buffer.Span, _longString);
191+
public int LongstrWritePopulated() => WireFormatting.WriteLongstr(ref _buffer.Span.GetStart(), _longString);
194192

195193
[Benchmark]
196194
public int LongstrGetSizeEmpty() => WireFormatting.GetFieldValueByteCount(string.Empty);
@@ -201,7 +199,7 @@ public class DataTypeLongStringSerialization : DataTypeSerialization
201199
private static byte[] GenerateLongStringBuffer(string val)
202200
{
203201
byte[] _buffer = new byte[5 + Encoding.UTF8.GetByteCount(val)];
204-
WireFormatting.WriteLongstr(_buffer, val);
202+
WireFormatting.WriteLongstr(ref _buffer.GetStart(), val);
205203
return _buffer;
206204
}
207205
}
@@ -219,10 +217,10 @@ public class DataTypeShortStringSerialization : DataTypeSerialization
219217
public int ShortstrReadPopulated() => WireFormatting.ReadShortstr(_populatedShortStringBuffer.Span, out _);
220218

221219
[Benchmark]
222-
public int ShortstrWriteEmpty() => WireFormatting.WriteShortstr(_buffer.Span, string.Empty);
220+
public int ShortstrWriteEmpty() => WireFormatting.WriteShortstr(ref _buffer.Span.GetStart(), string.Empty);
223221

224222
[Benchmark]
225-
public int ShortstrWritePopulated() => WireFormatting.WriteShortstr(_buffer.Span, _shortString);
223+
public int ShortstrWritePopulated() => WireFormatting.WriteShortstr(ref _buffer.Span.GetStart(), _shortString);
226224

227225
[Benchmark]
228226
public int ShortstrGetSizeEmpty() => WireFormatting.GetByteCount(string.Empty);
@@ -233,7 +231,7 @@ public class DataTypeShortStringSerialization : DataTypeSerialization
233231
private static byte[] GenerateStringBuffer(string val)
234232
{
235233
byte[] _buffer = new byte[2 + Encoding.UTF8.GetByteCount(val)];
236-
WireFormatting.WriteShortstr(_buffer, val);
234+
WireFormatting.WriteShortstr(ref _buffer.GetStart(), val);
237235
return _buffer;
238236
}
239237
}

projects/Benchmarks/WireFormatting/MethodSerialization.cs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System;
22
using System.Text;
3+
34
using BenchmarkDotNet.Attributes;
45

56
using RabbitMQ.Client.Framing;
@@ -37,11 +38,12 @@ public class MethodBasicDeliver : MethodSerializationBase
3738

3839
public override void SetUp()
3940
{
40-
int offset = RabbitMQ.Client.Impl.WireFormatting.WriteShortstr(_buffer.Span, string.Empty);
41-
offset += RabbitMQ.Client.Impl.WireFormatting.WriteLonglong(_buffer.Slice(offset).Span, 0);
42-
offset += RabbitMQ.Client.Impl.WireFormatting.WriteBits(_buffer.Slice(offset).Span, false);
43-
offset += RabbitMQ.Client.Impl.WireFormatting.WriteShortstr(_buffer.Slice(offset).Span, string.Empty);
44-
RabbitMQ.Client.Impl.WireFormatting.WriteShortstr(_buffer.Slice(offset).Span, string.Empty);
41+
int length = _buffer.Length;
42+
int offset = Client.Impl.WireFormatting.WriteShortstr(ref _buffer.Span.GetStart(), string.Empty);
43+
offset += Client.Impl.WireFormatting.WriteLonglong(ref _buffer.Span.GetOffset(offset), 0);
44+
offset += Client.Impl.WireFormatting.WriteBits(ref _buffer.Span.GetOffset(offset), false);
45+
offset += Client.Impl.WireFormatting.WriteShortstr(ref _buffer.Span.GetOffset(offset), string.Empty);
46+
Client.Impl.WireFormatting.WriteShortstr(ref _buffer.Span.GetOffset(offset), string.Empty);
4547
}
4648

4749
[Benchmark]

projects/Benchmarks/WireFormatting/PrimitivesSerialization.cs

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ public virtual void Setup() { }
1919

2020
public class PrimitivesBool : PrimitivesBase
2121
{
22-
public override void Setup() => WireFormatting.WriteBits(_buffer.Span, true, false, true, false, true);
22+
public override void Setup() => WireFormatting.WriteBits(ref _buffer.Span.GetStart(), true, false, true, false, true);
2323

2424
[Benchmark]
2525
public int BoolRead2() => WireFormatting.ReadBits(_buffer.Span, out bool _, out bool _);
@@ -29,70 +29,70 @@ public class PrimitivesBool : PrimitivesBase
2929

3030
[Benchmark]
3131
[Arguments(true, false)]
32-
public int BoolWrite2(bool param1, bool param2) => WireFormatting.WriteBits(_buffer.Span, param1, param2);
32+
public int BoolWrite2(bool param1, bool param2) => WireFormatting.WriteBits(ref _buffer.Span.GetStart(), param1, param2);
3333

3434
[Benchmark]
3535
[Arguments(true, false)]
36-
public int BoolWrite5(bool param1, bool param2) => WireFormatting.WriteBits(_buffer.Span, param1, param2, param1, param2, param1);
36+
public int BoolWrite5(bool param1, bool param2) => WireFormatting.WriteBits(ref _buffer.Span.GetStart(), param1, param2, param1, param2, param1);
3737
}
3838

3939
public class PrimitivesDecimal : PrimitivesBase
4040
{
41-
public override void Setup() => WireFormatting.WriteDecimal(_buffer.Span, 123.45m);
41+
public override void Setup() => WireFormatting.WriteDecimal(ref _buffer.Span.GetStart(), 123.45m);
4242

4343
[Benchmark]
4444
public decimal DecimalRead() => WireFormatting.ReadDecimal(_buffer.Span);
4545

4646
[Benchmark]
47-
public int DecimalWrite() => WireFormatting.WriteDecimal(_buffer.Span, 123.45m);
47+
public int DecimalWrite() => WireFormatting.WriteDecimal(ref _buffer.Span.GetStart(), 123.45m);
4848
}
4949

5050
public class PrimitivesLong : PrimitivesBase
5151
{
52-
public override void Setup() => WireFormatting.WriteLong(_buffer.Span, 12345u);
52+
public override void Setup() => WireFormatting.WriteLong(ref _buffer.Span.GetStart(), 12345u);
5353

5454
[Benchmark]
5555
public int LongRead() => WireFormatting.ReadLong(_buffer.Span, out _);
5656

5757
[Benchmark]
5858
[Arguments(12345u)]
59-
public int LongWrite(uint value) => WireFormatting.WriteLong(_buffer.Span, value);
59+
public int LongWrite(uint value) => WireFormatting.WriteLong(ref _buffer.Span.GetStart(), value);
6060
}
6161

6262
public class PrimitivesLonglong : PrimitivesBase
6363
{
64-
public override void Setup() => WireFormatting.WriteLonglong(_buffer.Span, 12345ul);
64+
public override void Setup() => WireFormatting.WriteLonglong(ref _buffer.Span.GetStart(), 12345ul);
6565

6666
[Benchmark]
6767
public int LonglongRead() => WireFormatting.ReadLonglong(_buffer.Span, out _);
6868

6969
[Benchmark]
7070
[Arguments(12345ul)]
71-
public int LonglongWrite(ulong value) => WireFormatting.WriteLonglong(_buffer.Span, value);
71+
public int LonglongWrite(ulong value) => WireFormatting.WriteLonglong(ref _buffer.Span.GetStart(), value);
7272
}
7373

7474
public class PrimitivesShort : PrimitivesBase
7575
{
76-
public override void Setup() => WireFormatting.WriteShort(_buffer.Span, 12345);
76+
public override void Setup() => WireFormatting.WriteShort(ref _buffer.Span.GetStart(), 12345);
7777

7878
[Benchmark]
7979
public int ShortRead() => WireFormatting.ReadShort(_buffer.Span, out _);
8080

8181
[Benchmark]
8282
[Arguments(12345)]
83-
public int ShortWrite(ushort value) => WireFormatting.WriteShort(_buffer.Span, value);
83+
public int ShortWrite(ushort value) => WireFormatting.WriteShort(ref _buffer.Span.GetStart(), value);
8484
}
8585

8686
public class PrimitivesTimestamp : PrimitivesBase
8787
{
8888
AmqpTimestamp _timestamp = new AmqpTimestamp(DateTimeOffset.UtcNow.ToUnixTimeSeconds());
8989

90-
public override void Setup() => WireFormatting.WriteTimestamp(_buffer.Span, _timestamp);
90+
public override void Setup() => WireFormatting.WriteTimestamp(ref _buffer.Span.GetStart(), _timestamp);
9191

9292
[Benchmark]
9393
public int TimestampRead() => WireFormatting.ReadTimestamp(_buffer.Span, out _);
9494

9595
[Benchmark]
96-
public int TimestampWrite() => WireFormatting.WriteTimestamp(_buffer.Span, _timestamp);
96+
public int TimestampWrite() => WireFormatting.WriteTimestamp(ref _buffer.Span.GetStart(), _timestamp);
9797
}
9898
}

projects/RabbitMQ.Client/client/framing/BasicAck.cs

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@
3030
//---------------------------------------------------------------------------
3131

3232
using System;
33+
using System.Runtime.CompilerServices;
34+
3335
using RabbitMQ.Client.client.framing;
3436
using RabbitMQ.Client.Impl;
3537

@@ -40,16 +42,13 @@ internal sealed class BasicAck : Client.Impl.MethodBase
4042
public ulong _deliveryTag;
4143
public bool _multiple;
4244

43-
public BasicAck()
44-
{
45-
}
46-
4745
public BasicAck(ulong DeliveryTag, bool Multiple)
4846
{
4947
_deliveryTag = DeliveryTag;
5048
_multiple = Multiple;
5149
}
5250

51+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
5352
public BasicAck(ReadOnlySpan<byte> span)
5453
{
5554
int offset = WireFormatting.ReadLonglong(span, out _deliveryTag);
@@ -58,17 +57,12 @@ public BasicAck(ReadOnlySpan<byte> span)
5857

5958
public override ProtocolCommandId ProtocolCommandId => ProtocolCommandId.BasicAck;
6059
public override string ProtocolMethodName => "basic.ack";
61-
public override bool HasContent => false;
62-
6360
public override int WriteArgumentsTo(Span<byte> span)
6461
{
65-
int offset = WireFormatting.WriteLonglong(span, _deliveryTag);
66-
return offset + WireFormatting.WriteBits(span.Slice(offset), _multiple);
67-
}
68-
69-
public override int GetRequiredBufferSize()
70-
{
71-
return 8 + 1;
62+
int offset = WireFormatting.WriteLonglong(ref span.GetStart(), _deliveryTag);
63+
offset += WireFormatting.WriteBits(ref span.GetOffset(offset), _multiple);
64+
return offset;
7265
}
66+
public override int GetRequiredBufferSize() => 9;
7367
}
7468
}

projects/RabbitMQ.Client/client/framing/BasicCancel.cs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
//---------------------------------------------------------------------------
3131

3232
using System;
33-
using System.Text;
33+
3434
using RabbitMQ.Client.client.framing;
3535
using RabbitMQ.Client.Impl;
3636

@@ -59,12 +59,11 @@ public BasicCancel(ReadOnlySpan<byte> span)
5959

6060
public override ProtocolCommandId ProtocolCommandId => ProtocolCommandId.BasicCancel;
6161
public override string ProtocolMethodName => "basic.cancel";
62-
public override bool HasContent => false;
6362

6463
public override int WriteArgumentsTo(Span<byte> span)
6564
{
66-
int offset = WireFormatting.WriteShortstr(span, _consumerTag);
67-
return offset + WireFormatting.WriteBits(span.Slice(offset), _nowait);
65+
int offset = WireFormatting.WriteShortstr(ref span.GetStart(), _consumerTag);
66+
return offset + WireFormatting.WriteBits(ref span.GetOffset(offset), _nowait);
6867
}
6968

7069
public override int GetRequiredBufferSize()

projects/RabbitMQ.Client/client/framing/BasicCancelOk.cs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
//---------------------------------------------------------------------------
3131

3232
using System;
33-
using System.Text;
33+
3434
using RabbitMQ.Client.client.framing;
3535
using RabbitMQ.Client.Impl;
3636

@@ -56,11 +56,10 @@ public BasicCancelOk(ReadOnlySpan<byte> span)
5656

5757
public override ProtocolCommandId ProtocolCommandId => ProtocolCommandId.BasicCancelOk;
5858
public override string ProtocolMethodName => "basic.cancel-ok";
59-
public override bool HasContent => false;
6059

6160
public override int WriteArgumentsTo(Span<byte> span)
6261
{
63-
return WireFormatting.WriteShortstr(span, _consumerTag);
62+
return WireFormatting.WriteShortstr(ref span.GetStart(), _consumerTag);
6463
}
6564

6665
public override int GetRequiredBufferSize()

projects/RabbitMQ.Client/client/framing/BasicConsume.cs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131

3232
using System;
3333
using System.Collections.Generic;
34+
3435
using RabbitMQ.Client.client.framing;
3536
using RabbitMQ.Client.Impl;
3637

@@ -75,15 +76,14 @@ public BasicConsume(ReadOnlySpan<byte> span)
7576

7677
public override ProtocolCommandId ProtocolCommandId => ProtocolCommandId.BasicConsume;
7778
public override string ProtocolMethodName => "basic.consume";
78-
public override bool HasContent => false;
7979

8080
public override int WriteArgumentsTo(Span<byte> span)
8181
{
82-
int offset = WireFormatting.WriteShort(span, default);
83-
offset += WireFormatting.WriteShortstr(span.Slice(offset), _queue);
84-
offset += WireFormatting.WriteShortstr(span.Slice(offset), _consumerTag);
85-
offset += WireFormatting.WriteBits(span.Slice(offset), _noLocal, _noAck, _exclusive, _nowait);
86-
return offset + WireFormatting.WriteTable(span.Slice(offset), _arguments);
82+
int offset = WireFormatting.WriteShort(ref span.GetStart(), default);
83+
offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), _queue);
84+
offset += WireFormatting.WriteShortstr(ref span.GetOffset(offset), _consumerTag);
85+
offset += WireFormatting.WriteBits(ref span.GetOffset(offset), _noLocal, _noAck, _exclusive, _nowait);
86+
return offset + WireFormatting.WriteTable(ref span.GetOffset(offset), _arguments);
8787
}
8888

8989
public override int GetRequiredBufferSize()

0 commit comments

Comments
 (0)