Skip to content

Commit 2d6ab4d

Browse files
author
Dan Shechter
committed
In/outgoing Span<byte> support, linux net45 build
- Closes #587 - Add netfx.props and tweak sbxee-dll csproj to allow building sbe.dll for net45 on Linux using dotnet sdk following: https://andrewlock.net/building-net-framework-asp-net-core-apps-on-linux-using-mono-and-the-net-cli/ - Remove packages.config files from projects already converted to SDK style project since those files serve no purpose other than confusing potential contributors... - Intoroduce minimal Span<byte> GetBytes/SetBytes implementation for copying to/from Span<byte> to sbe.dll itself. - Change code generation for array types to use Span<byte> internally keeping the original functionality intact with no (hopefully!) visible user facing changes except for the addtitional Get/Set methods accepting Span<byte> being added to the mix.
1 parent 1e0e929 commit 2d6ab4d

File tree

6 files changed

+132
-62
lines changed

6 files changed

+132
-62
lines changed

csharp/netfx.props

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
2+
<PropertyGroup>
3+
<!-- When compiling .NET SDK 2.0 projects targeting .NET 4.x on Mono using 'dotnet build' you -->
4+
<!-- have to teach MSBuild where the Mono copy of the reference asssemblies is -->
5+
<TargetIsMono Condition="$(TargetFramework.StartsWith('net4')) and '$(OS)' == 'Unix'">true</TargetIsMono>
6+
7+
<!-- Look in the standard install locations -->
8+
<MonoBasePath Condition="'$(MonoBasePath)' == '' AND '$(TargetIsMono)' == 'true' AND EXISTS('/Library/Frameworks/Mono.framework/Versions/Current/lib/mono')">/Library/Frameworks/Mono.framework/Versions/Current/lib/mono</MonoBasePath>
9+
<MonoBasePath Condition="'$(MonoBasePath)' == '' AND '$(TargetIsMono)' == 'true' AND EXISTS('/usr/lib/mono')">/usr/lib/mono</MonoBasePath>
10+
<MonoBasePath Condition="'$(MonoBasePath)' == '' AND '$(TargetIsMono)' == 'true' AND EXISTS('/usr/local/lib/mono')">/usr/local/lib/mono</MonoBasePath>
11+
12+
<!-- If we found Mono reference assemblies, then use them -->
13+
<FrameworkPathOverride Condition="'$(MonoBasePath)' != '' AND '$(TargetFramework)' == 'net45'">$(MonoBasePath)/4.5-api</FrameworkPathOverride>
14+
<FrameworkPathOverride Condition="'$(MonoBasePath)' != '' AND '$(TargetFramework)' == 'net451'">$(MonoBasePath)/4.5.1-api</FrameworkPathOverride>
15+
<FrameworkPathOverride Condition="'$(MonoBasePath)' != '' AND '$(TargetFramework)' == 'net452'">$(MonoBasePath)/4.5.2-api</FrameworkPathOverride>
16+
<FrameworkPathOverride Condition="'$(MonoBasePath)' != '' AND '$(TargetFramework)' == 'net46'">$(MonoBasePath)/4.6-api</FrameworkPathOverride>
17+
<FrameworkPathOverride Condition="'$(MonoBasePath)' != '' AND '$(TargetFramework)' == 'net461'">$(MonoBasePath)/4.6.1-api</FrameworkPathOverride>
18+
<FrameworkPathOverride Condition="'$(MonoBasePath)' != '' AND '$(TargetFramework)' == 'net462'">$(MonoBasePath)/4.6.2-api</FrameworkPathOverride>
19+
<FrameworkPathOverride Condition="'$(MonoBasePath)' != '' AND '$(TargetFramework)' == 'net47'">$(MonoBasePath)/4.7-api</FrameworkPathOverride>
20+
<FrameworkPathOverride Condition="'$(MonoBasePath)' != '' AND '$(TargetFramework)' == 'net471'">$(MonoBasePath)/4.7.1-api</FrameworkPathOverride>
21+
<EnableFrameworkPathOverride Condition="'$(MonoBasePath)' != ''">true</EnableFrameworkPathOverride>
22+
23+
<!-- Add the Facades directory. Not sure how else to do this. Necessary at least for .NET 4.5 -->
24+
<AssemblySearchPaths Condition="'$(MonoBasePath)' != ''">$(FrameworkPathOverride)/Facades;$(AssemblySearchPaths)</AssemblySearchPaths>
25+
</PropertyGroup>
26+
</Project>

csharp/sbe-dll/DirectBuffer.cs

Lines changed: 47 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ namespace Org.SbeTool.Sbe.Dll
99
public sealed unsafe class DirectBuffer : IDisposable
1010
{
1111
/// <summary>
12-
/// Delegate invoked if buffer size is too small.
12+
/// Delegate invoked if buffer size is too small.
1313
/// </summary>
1414
/// <param name="existingBufferSize"></param>
1515
/// <param name="requestedBufferSize"></param>
@@ -66,7 +66,7 @@ public DirectBuffer(byte* pBuffer, int bufferLength, BufferOverflowDelegate buff
6666
/// <summary>
6767
/// Creates a DirectBuffer that can later be wrapped
6868
/// </summary>
69-
public DirectBuffer()
69+
public DirectBuffer()
7070
{
7171
}
7272

@@ -569,6 +569,22 @@ public void DoublePutLittleEndian(int index, double value)
569569

570570
#endregion
571571

572+
/// <summary>
573+
/// Creates a <see cref="Span{T}" /> on top of the underlying buffer
574+
/// </summary>
575+
/// <param name="index">index in the underlying buffer to start from.</param>
576+
/// <param name="length">length of the supplied buffer to use.</param>
577+
/// <returns>The new <see cref="Span{T}" /> wrapping the requested memory</returns>
578+
public Span<T> AsSpan<T>(int index, int length) => new Span<T>(_pBuffer + index, length);
579+
580+
/// <summary>
581+
/// Creates a <see cref="ReadOnlySpan{T}" /> on top of the underlying buffer
582+
/// </summary>
583+
/// <param name="index">index in the underlying buffer to start from.</param>
584+
/// <param name="length">length of the supplied buffer to use.</param>
585+
/// <returns>The new <see cref="ReadOnlySpan{T}" /> wrapping the requested memory</returns>
586+
public ReadOnlySpan<T> AsReadOnlySpan<T>(int index, int length) => new ReadOnlySpan<T>(_pBuffer + index, length);
587+
572588
/// <summary>
573589
/// Copies a range of bytes from the underlying into a supplied byte array.
574590
/// </summary>
@@ -585,6 +601,20 @@ public int GetBytes(int index, byte[] destination, int offsetDestination, int le
585601
return count;
586602
}
587603

604+
/// <summary>
605+
/// Copies a range of bytes from the underlying into a supplied <see cref="Span{T}" />.
606+
/// </summary>
607+
/// <param name="index">index in the underlying buffer to start from.</param>
608+
/// <param name="destination"><see cref="Span{T}" /> into which the bytes will be copied.</param>
609+
/// <returns>count of bytes copied.</returns>
610+
public int GetBytes(int index, Span<byte> destination)
611+
{
612+
int count = Math.Min(destination.Length, _capacity - index);
613+
AsReadOnlySpan<byte>(index, count).CopyTo(destination);
614+
615+
return count;
616+
}
617+
588618
/// <summary>
589619
/// Writes a byte array into the underlying buffer.
590620
/// </summary>
@@ -601,6 +631,20 @@ public int SetBytes(int index, byte[] src, int offset, int length)
601631
return count;
602632
}
603633

634+
/// <summary>
635+
/// Writes a <see cref="Span{T}" /> into the underlying buffer.
636+
/// </summary>
637+
/// <param name="index">index in the underlying buffer to start from.</param>
638+
/// <param name="src">source <see cref="Span{T}" /> to be copied to the underlying buffer.</param>
639+
/// <returns>count of bytes copied.</returns>
640+
public int SetBytes(int index, ReadOnlySpan<byte> src)
641+
{
642+
int count = Math.Min(src.Length, _capacity - index);
643+
src.CopyTo(AsSpan<byte>(index, count));
644+
645+
return count;
646+
}
647+
604648
/// <summary>
605649
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
606650
/// </summary>
@@ -638,4 +682,4 @@ private void FreeGCHandle()
638682
}
639683
}
640684
}
641-
}
685+
}

csharp/sbe-dll/packages.config

Lines changed: 0 additions & 4 deletions
This file was deleted.

csharp/sbe-dll/sbe-dll.csproj

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
<Project Sdk="Microsoft.NET.Sdk">
2+
<Import Project="..\netfx.props" />
23

34
<PropertyGroup>
45
<TargetFrameworks>net45;netstandard2.0</TargetFrameworks>
@@ -10,11 +11,19 @@
1011
</PropertyGroup>
1112

1213
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|net45|AnyCPU'">
13-
<DocumentationFile>bin\Release\net45\SBE.xml</DocumentationFile>
14+
<DocumentationFile>bin\release\net45\SBE.xml</DocumentationFile>
1415
</PropertyGroup>
1516

1617
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|netstandard2.0|AnyCPU'">
17-
<DocumentationFile>bin\Release\netstandard2.0\SBE.xml</DocumentationFile>
18+
<DocumentationFile>bin\release\netstandard2.0\SBE.xml</DocumentationFile>
1819
</PropertyGroup>
20+
21+
<ItemGroup Condition=" '$(TargetFramework)' == 'net45' ">
22+
<Reference Include="System.Runtime" />
23+
</ItemGroup>
24+
25+
<ItemGroup>
26+
<PackageReference Include="System.Memory" Version="4.5.1" />
27+
</ItemGroup>
1928

2029
</Project>

csharp/sbe-tests/packages.config

Lines changed: 0 additions & 5 deletions
This file was deleted.

sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpGenerator.java

Lines changed: 48 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -358,16 +358,21 @@ private CharSequence generateVarData(final List<Token> tokens, final String inde
358358
sizeOfLengthField));
359359

360360
sb.append(String.format("\n" +
361-
indent + "public int Get%1$s(byte[] dst, int dstOffset, int length)\n" +
361+
indent + "public int Get%1$s(byte[] dst, int dstOffset, int length) =>\n" +
362+
indent + INDENT + "Get%1$s(new Span<byte>(dst, dstOffset, length));\n",
363+
propertyName));
364+
365+
sb.append(String.format("\n" +
366+
indent + "public int Get%1$s(Span<byte> dst)\n" +
362367
indent + "{\n" +
363368
"%2$s" +
364369
indent + INDENT + "const int sizeOfLengthField = %3$d;\n" +
365370
indent + INDENT + "int limit = _parentMessage.Limit;\n" +
366371
indent + INDENT + "_buffer.CheckLimit(limit + sizeOfLengthField);\n" +
367372
indent + INDENT + "int dataLength = (int)_buffer.%4$sGet%5$s(limit);\n" +
368-
indent + INDENT + "int bytesCopied = Math.Min(length, dataLength);\n" +
373+
indent + INDENT + "int bytesCopied = Math.Min(dst.Length, dataLength);\n" +
369374
indent + INDENT + "_parentMessage.Limit = limit + sizeOfLengthField + dataLength;\n" +
370-
indent + INDENT + "_buffer.GetBytes(limit + sizeOfLengthField, dst, dstOffset, bytesCopied);\n\n" +
375+
indent + INDENT + "_buffer.GetBytes(limit + sizeOfLengthField, dst.Slice(0, bytesCopied));\n\n" +
371376
indent + INDENT + "return bytesCopied;\n" +
372377
indent + "}\n",
373378
propertyName,
@@ -377,14 +382,19 @@ private CharSequence generateVarData(final List<Token> tokens, final String inde
377382
byteOrderStr));
378383

379384
sb.append(String.format("\n" +
380-
indent + "public int Set%1$s(byte[] src, int srcOffset, int length)\n" +
385+
indent + "public int Set%1$s(byte[] src, int srcOffset, int length) =>\n" +
386+
indent + INDENT + "Set%1$s(new ReadOnlySpan<byte>(src, srcOffset, length));\n",
387+
propertyName));
388+
389+
sb.append(String.format("\n" +
390+
indent + "public int Set%1$s(ReadOnlySpan<byte> src)\n" +
381391
indent + "{\n" +
382392
indent + INDENT + "const int sizeOfLengthField = %2$d;\n" +
383393
indent + INDENT + "int limit = _parentMessage.Limit;\n" +
384-
indent + INDENT + "_parentMessage.Limit = limit + sizeOfLengthField + length;\n" +
385-
indent + INDENT + "_buffer.%3$sPut%5$s(limit, (%4$s)length);\n" +
386-
indent + INDENT + "_buffer.SetBytes(limit + sizeOfLengthField, src, srcOffset, length);\n\n" +
387-
indent + INDENT + "return length;\n" +
394+
indent + INDENT + "_parentMessage.Limit = limit + sizeOfLengthField + src.Length;\n" +
395+
indent + INDENT + "_buffer.%3$sPut%5$s(limit, (%4$s)src.Length);\n" +
396+
indent + INDENT + "_buffer.SetBytes(limit + sizeOfLengthField, src);\n\n" +
397+
indent + INDENT + "return src.Length;\n" +
388398
indent + "}\n",
389399
propertyName,
390400
sizeOfLengthField,
@@ -756,44 +766,30 @@ private CharSequence generateArrayProperty(
756766

757767
sb.append(String.format("\n" +
758768
indent + "public const int %sLength = %d;\n",
759-
propName,
760-
fieldLength));
769+
propName, fieldLength));
761770

762771
sb.append(String.format("\n" +
763772
indent + "public %1$s Get%2$s(int index)\n" +
764773
indent + "{\n" +
765-
indent + INDENT + "if (index < 0 || index >= %3$d)\n" +
766-
indent + INDENT + "{\n" +
774+
indent + INDENT + "if (index < 0 || index >= %3$d) {\n" +
767775
indent + INDENT + INDENT + "throw new IndexOutOfRangeException(\"index out of range: index=\" + index);\n" +
768776
indent + INDENT + "}\n\n" +
769777
"%4$s" +
770778
indent + INDENT + "return _buffer.%5$sGet%8$s(_offset + %6$d + (index * %7$d));\n" +
771779
indent + "}\n",
772-
typeName,
773-
propName,
774-
fieldLength,
780+
typeName, propName, fieldLength,
775781
generateFieldNotPresentCondition(token.version(), token.encoding(), indent),
776-
typePrefix,
777-
offset,
778-
typeSize,
779-
byteOrderStr));
782+
typePrefix, offset, typeSize, byteOrderStr));
780783

781784
sb.append(String.format("\n" +
782785
indent + "public void Set%1$s(int index, %2$s value)\n" +
783786
indent + "{\n" +
784-
indent + INDENT + "if (index < 0 || index >= %3$d)\n" +
785-
indent + INDENT + "{\n" +
787+
indent + INDENT + "if (index < 0 || index >= %3$d) {\n" +
786788
indent + INDENT + INDENT + "throw new IndexOutOfRangeException(\"index out of range: index=\" + index);\n" +
787789
indent + INDENT + "}\n\n" +
788790
indent + INDENT + "_buffer.%4$sPut%7$s(_offset + %5$d + (index * %6$d), value);\n" +
789791
indent + "}\n",
790-
propName,
791-
typeName,
792-
fieldLength,
793-
typePrefix,
794-
offset,
795-
typeSize,
796-
byteOrderStr));
792+
propName, typeName, fieldLength, typePrefix, offset, typeSize, byteOrderStr));
797793

798794
if (token.encoding().primitiveType() == PrimitiveType.CHAR)
799795
{
@@ -803,39 +799,43 @@ private CharSequence generateArrayProperty(
803799
indent + "public int Get%1$s(byte[] dst, int dstOffset)\n" +
804800
indent + "{\n" +
805801
indent + INDENT + "const int length = %2$d;\n" +
806-
indent + INDENT + "if (dstOffset < 0 || dstOffset > (dst.Length - length))\n" +
807-
indent + INDENT + "{\n" +
808-
indent + INDENT + INDENT + "throw new IndexOutOfRangeException(" +
809-
"\"dstOffset out of range for copy: offset=\" + dstOffset);\n" +
802+
"%3$s" +
803+
indent + INDENT + "return Get%1$s(new Span<byte>(dst, dstOffset, length));\n" +
804+
indent + "}\n",
805+
propName, fieldLength, generateArrayFieldNotPresentCondition(token.version(), indent), offset));
806+
807+
sb.append(String.format("\n" +
808+
indent + "public int Get%1$s(Span<byte> dst)\n" +
809+
indent + "{\n" +
810+
indent + INDENT + "const int length = %2$d;\n" +
811+
indent + INDENT + "if (dst.Length < length) {\n" +
812+
indent + INDENT + INDENT +
813+
"throw new ArgumentOutOfRangeException($\"dst.Length={dst.Length} is too large.\");\n" +
810814
indent + INDENT + "}\n\n" +
811815
"%3$s" +
812-
indent + INDENT + "_buffer.GetBytes(_offset + %4$d, dst, dstOffset, length);\n" +
816+
indent + INDENT + "_buffer.GetBytes(_offset + %4$d, dst);\n" +
813817
indent + INDENT + "return length;\n" +
814818
indent + "}\n",
815-
propName,
816-
fieldLength,
817-
generateArrayFieldNotPresentCondition(token.version(), indent),
818-
offset));
819+
propName, fieldLength, generateArrayFieldNotPresentCondition(token.version(), indent), offset));
819820

820821
sb.append(String.format("\n" +
821822
indent + "public void Set%1$s(byte[] src, int srcOffset)\n" +
822823
indent + "{\n" +
824+
indent + INDENT + "Set%1$s(new ReadOnlySpan<byte>(src, srcOffset, src.Length - srcOffset));\n" +
825+
indent + "}\n",
826+
propName, fieldLength, offset));
827+
828+
sb.append(String.format("\n" +
829+
indent + "public void Set%1$s(ReadOnlySpan<byte> src)\n" +
830+
indent + "{\n" +
823831
indent + INDENT + "const int length = %2$d;\n" +
824-
indent + INDENT + "if (srcOffset < 0 || srcOffset > src.Length)\n" +
825-
indent + INDENT + "{\n" +
826-
indent + INDENT + INDENT +
827-
"throw new IndexOutOfRangeException(\"srcOffset out of range for copy: offset=\" + srcOffset);\n" +
828-
indent + INDENT + "}\n\n" +
829-
indent + INDENT + "if (src.Length > length)\n" +
830-
indent + INDENT + "{\n" +
832+
indent + INDENT + "if (src.Length > length) {\n" +
831833
indent + INDENT + INDENT +
832834
"throw new ArgumentOutOfRangeException($\"src.Length={src.Length} is too large.\");\n" +
833835
indent + INDENT + "}\n\n" +
834-
indent + INDENT + "_buffer.SetBytes(_offset + %3$d, src, srcOffset, src.Length - srcOffset);\n" +
836+
indent + INDENT + "_buffer.SetBytes(_offset + %3$d, src);\n" +
835837
indent + "}\n",
836-
propName,
837-
fieldLength,
838-
offset));
838+
propName, fieldLength, offset));
839839
}
840840

841841
return sb;

0 commit comments

Comments
 (0)