├── src
└── SpanDex
│ ├── Properties
│ └── AssemblyInfo.cs
│ ├── SpanDex.csproj
│ ├── SpanDex.xml
│ ├── SpanReader.cs
│ ├── SpanWriter.cs
│ ├── SpanWriting.cs
│ ├── SpanReading.cs
│ └── SpanExtensions.cs
├── .travis.yml
├── example
└── SpanDex.Example
│ ├── SpanDex.Example.csproj
│ └── Program.cs
├── SpanDex.Benchmarking
├── SpanDex.Benchmarking.csproj
└── Program.cs
├── CONTRIBUTING.md
├── tests
└── SpanDex.Tests
│ ├── SpanDex.Tests.csproj
│ ├── SpanReaderTests.cs
│ ├── SpanWriterTests.cs
│ └── SpanExtensionTests.cs
├── LICENSE
├── SpanDex.sln
├── README.md
└── .gitignore
/src/SpanDex/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | [assembly: CLSCompliant(true)]
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: csharp
2 | mono: none
3 | dist: bionic
4 | dotnet: 2.2.105
5 | script:
6 | - dotnet restore
7 | - dotnet build
8 | - dotnet test tests/SpanDex.Tests/SpanDex.Tests.csproj
--------------------------------------------------------------------------------
/example/SpanDex.Example/SpanDex.Example.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | netcoreapp2.1
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/SpanDex.Benchmarking/SpanDex.Benchmarking.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | netcoreapp2.2
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing to SpanDex
2 |
3 | Thanks for thinking about contributing! :+1:
4 |
5 | If you have encountered a bug (or just have a question on how to use the library), feel free to open an issue immediately. If reporting a bug, please include the version of SpanDex you are using, your runtime platform and version, and code to reproduce the problem.
6 |
7 | If you have an idea for code, or would like to contribute some code, open an issue for discussion.. If it works well with the library then create a PR and I'll review it.
8 |
9 | That's it! Thanks for considering contributing! :+1:
--------------------------------------------------------------------------------
/tests/SpanDex.Tests/SpanDex.Tests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp2.2
5 |
6 | false
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/tests/SpanDex.Tests/SpanReaderTests.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.VisualStudio.TestTools.UnitTesting;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Text;
5 |
6 | namespace SpanDex.Tests {
7 | [TestClass]
8 | public class SpanReaderTests {
9 | [TestMethod]
10 | public void ImplicitConstructors_LengthIsCorrect() {
11 | var byteArray = new byte[10];
12 | Span span = new byte[20];
13 | ReadOnlySpan readOnlySpan = new byte[30];
14 |
15 | SpanReader spanReader = byteArray;
16 | Assert.AreEqual(byteArray.Length, spanReader.Length);
17 | spanReader = span;
18 | Assert.AreEqual(span.Length, spanReader.Length);
19 | spanReader = readOnlySpan;
20 | Assert.AreEqual(readOnlySpan.Length, spanReader.Length);
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/SpanDex/SpanDex.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.0
5 | true
6 | 1.0.2
7 | Jono Rogers
8 |
9 | Utilities to read/write primitives from/to spans easily
10 | MIT
11 | span spanreader spanwriter binaryprimitives
12 | https://github.com/jonorogers/SpanDex
13 | https://github.com/jonorogers/SpanDex
14 | 7.3
15 | 1.0.2.0
16 |
17 |
18 |
19 | C:\code\SpanDex\src\SpanDex\SpanDex.xml
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 Jono Rogers
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/tests/SpanDex.Tests/SpanWriterTests.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.VisualStudio.TestTools.UnitTesting;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Text;
5 |
6 | namespace SpanDex.Tests {
7 | [TestClass]
8 | public class SpanWriterTests {
9 | [TestMethod]
10 | public void NullMemory_ThrowsArgumentNullException() {
11 | Assert.ThrowsException(() => {
12 | var spanWriter = new SpanWriter(null);
13 | });
14 | }
15 |
16 | [TestMethod]
17 | public void ImplicitConstructors_LengthIsCorrect() {
18 | var byteArray = new byte[10];
19 | Span span = new byte[20];
20 |
21 | SpanWriter spanWriter = byteArray;
22 | Assert.AreEqual(byteArray.Length, spanWriter.Length);
23 | spanWriter = span;
24 | Assert.AreEqual(span.Length, spanWriter.Length);
25 | }
26 |
27 | [TestMethod]
28 | public void CreateFromSpan_WithCursor_InitializesCorrectly() {
29 | SpanWriter writer = new SpanWriter(new byte[20], 10);
30 | Assert.AreEqual(10, writer.Cursor);
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/SpanDex.Benchmarking/Program.cs:
--------------------------------------------------------------------------------
1 | using BenchmarkDotNet.Attributes;
2 | using BenchmarkDotNet.Running;
3 | using System;
4 | using System.Collections.Generic;
5 |
6 | namespace SpanDex.Benchmarking {
7 | [RankColumn]
8 | [MemoryDiagnoser]
9 | [MarkdownExporterAttribute.Default]
10 | [MarkdownExporterAttribute.GitHub]
11 | public class SpanReaderVsBitConverter {
12 | private byte[] data;
13 |
14 | [Params(1000, 10000)]
15 | public int N;
16 |
17 | [GlobalSetup]
18 | public void Setup() {
19 | data = new byte[N * sizeof(Int16)];
20 | }
21 |
22 | [Benchmark]
23 | public void SpanReader() {
24 | SpanReader reader = data;
25 |
26 | for (int i = 0; i < N; i += 2) {
27 | var v = reader.ReadInt16LittleEndian();
28 | }
29 | }
30 |
31 | [Benchmark]
32 | public void BitConvert() {
33 | for (int i = 0; i < N; i += 2) {
34 | var v = BitConverter.ToInt16(data, i);
35 | }
36 | }
37 |
38 | [Benchmark]
39 | public void Manual() {
40 | for (int i = 0; i < N; i += 2) {
41 | var v = (short)((data[i] << 8) | data[i + 1]);
42 | }
43 | }
44 | }
45 |
46 | public class Program {
47 | public static void Main() {
48 | var summary = BenchmarkRunner.Run();
49 | }
50 | }
51 | }
--------------------------------------------------------------------------------
/example/SpanDex.Example/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using SpanDex.Extensions;
3 |
4 | namespace SpanDex.Example {
5 | internal static class Program {
6 | private static void Main() {
7 | // Create a buffer
8 | var bytes = new byte[] { 0xA0, 0x1A, 0x35, 0x91, 0xE9, 0x51, 0x0C, 0x79, 0x04, 0xD1, 0x57, 0x81, 0x1D, 0x27 };
9 | var span = new ReadOnlySpan(bytes);
10 | // Read from it
11 | int cursor = 0;
12 | ushort one = span.ReadUInt16BigEndian(ref cursor);
13 | uint two = span.ReadUInt32BigEndian(ref cursor);
14 | ulong three = span.ReadUInt64BigEndian(ref cursor);
15 |
16 | Console.WriteLine($"One: {one}");
17 | Console.WriteLine($"Two: {two}");
18 | Console.WriteLine($"Three: {three}");
19 |
20 | const string testString = "this is a test string!";
21 |
22 | var writer = new SpanWriter(36);
23 | writer.WriteInt16BigEndian(-31_971);
24 | writer.WriteInt32BigEndian(-1_598_468_598);
25 | writer.WriteInt64BigEndian(-7_223_372_036_854_775_808);
26 | writer.WriteAsciiString(testString);
27 |
28 | var reader = new SpanReader(writer.Span);
29 | Console.WriteLine(reader.ReadInt16BigEndian());
30 | Console.WriteLine(reader.ReadInt32BigEndian());
31 | Console.WriteLine(reader.ReadInt64BigEndian());
32 | Console.WriteLine(reader.ReadAsciiString(testString.Length));
33 |
34 | Console.ReadKey();
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/SpanDex.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 16
4 | VisualStudioVersion = 16.0.29020.237
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SpanDex", "src\SpanDex\SpanDex.csproj", "{DF644125-142B-4ED6-9F9A-16F1DDE6C983}"
7 | EndProject
8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SpanDex.Example", "example\SpanDex.Example\SpanDex.Example.csproj", "{83A8BDA3-F2AD-4F77-87B9-D6E235952010}"
9 | EndProject
10 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SpanDex.Tests", "tests\SpanDex.Tests\SpanDex.Tests.csproj", "{C5398393-4686-40AD-834D-07AEE06617C0}"
11 | EndProject
12 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SpanDex.Benchmarking", "SpanDex.Benchmarking\SpanDex.Benchmarking.csproj", "{D9900867-305A-496A-B848-FBD4A01850BE}"
13 | EndProject
14 | Global
15 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
16 | Debug|Any CPU = Debug|Any CPU
17 | Release|Any CPU = Release|Any CPU
18 | EndGlobalSection
19 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
20 | {DF644125-142B-4ED6-9F9A-16F1DDE6C983}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
21 | {DF644125-142B-4ED6-9F9A-16F1DDE6C983}.Debug|Any CPU.Build.0 = Debug|Any CPU
22 | {DF644125-142B-4ED6-9F9A-16F1DDE6C983}.Release|Any CPU.ActiveCfg = Release|Any CPU
23 | {DF644125-142B-4ED6-9F9A-16F1DDE6C983}.Release|Any CPU.Build.0 = Release|Any CPU
24 | {83A8BDA3-F2AD-4F77-87B9-D6E235952010}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
25 | {83A8BDA3-F2AD-4F77-87B9-D6E235952010}.Debug|Any CPU.Build.0 = Debug|Any CPU
26 | {83A8BDA3-F2AD-4F77-87B9-D6E235952010}.Release|Any CPU.ActiveCfg = Release|Any CPU
27 | {83A8BDA3-F2AD-4F77-87B9-D6E235952010}.Release|Any CPU.Build.0 = Release|Any CPU
28 | {C5398393-4686-40AD-834D-07AEE06617C0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
29 | {C5398393-4686-40AD-834D-07AEE06617C0}.Debug|Any CPU.Build.0 = Debug|Any CPU
30 | {C5398393-4686-40AD-834D-07AEE06617C0}.Release|Any CPU.ActiveCfg = Release|Any CPU
31 | {C5398393-4686-40AD-834D-07AEE06617C0}.Release|Any CPU.Build.0 = Release|Any CPU
32 | {D9900867-305A-496A-B848-FBD4A01850BE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
33 | {D9900867-305A-496A-B848-FBD4A01850BE}.Debug|Any CPU.Build.0 = Debug|Any CPU
34 | {D9900867-305A-496A-B848-FBD4A01850BE}.Release|Any CPU.ActiveCfg = Release|Any CPU
35 | {D9900867-305A-496A-B848-FBD4A01850BE}.Release|Any CPU.Build.0 = Release|Any CPU
36 | EndGlobalSection
37 | GlobalSection(SolutionProperties) = preSolution
38 | HideSolutionNode = FALSE
39 | EndGlobalSection
40 | GlobalSection(ExtensibilityGlobals) = postSolution
41 | SolutionGuid = {B9224358-D078-45C4-9578-6126A31BCF01}
42 | EndGlobalSection
43 | EndGlobal
44 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # SpanDex
2 |
3 | [](https://travis-ci.org/jonorogers/SpanDex) [](https://www.nuget.org/packages/SpanDex/) [](https://docs.microsoft.com/en-us/dotnet/standard/net-standard)
4 |
5 | Utilities to read/write primitives from/to spans easily. Uses the C# Span struct.
6 |
7 | ## Getting Started
8 |
9 | Install the [Nuget Package](https://www.nuget.org/packages/SpanDex)
10 |
11 | ### Motivation
12 |
13 | Reading/writing spans can be a chore, keeping track of where you're up to reading a span. This lib lets you simplify this:
14 |
15 | ```cs
16 | var one = BinaryPrimitives.ReadUInt16LittleEndian(span.Slice(3, 2));
17 | var two = BinaryPrimitives.ReadUInt32LittleEndian(span.Slice(5, 4));
18 | var three = BinaryPrimitives.ReadUInt16BigEndian(span.Slice(9, 2));
19 | ```
20 |
21 | to this:
22 |
23 | ```cs
24 | int cursor = 0;
25 | var one = span.ReadUInt16LittleEndian(ref cursor);
26 | var two = span.ReadUInt32LittleEndian(ref cursor);
27 | var three = span.ReadUInt16BigEndian(ref cursor);
28 | ```
29 |
30 | or:
31 |
32 | ```cs
33 | var spanReader = new SpanReader(span);
34 | var one = spanReader.ReadUInt16LittleEndian();
35 | var two = spanReader.ReadUInt32LittleEndian();
36 | var three = spanReader.ReadUInt16BigEndian();
37 | ```
38 |
39 | This lib is based around the `System.Buffers.Binary.BinaryPrimitives` class, with some other methods sprinkled in for some spice.
40 |
41 | ### Included types
42 |
43 | - `SpanReader` for reading a span
44 | - `SpanWriter` for creating and writing to a span; initialize with `size` or `Memory`
45 | - A tonne of extension methods, applicable to `Span` and `ReadOnlySpan` - all ripped straight from `System.Buffers.Binary.BinaryPrimitives`, as well as:
46 | - `span.ReadSpan()` - same as slice, but keeps track of where you're up to
47 | - `span.ReadASCIIString()` - does what it says on the packet
48 | - `span.ReadUTF8String()` - I think you get the drift
49 |
50 | ### Benchmark Results
51 |
52 | ``` ini
53 |
54 | BenchmarkDotNet=v0.11.5, OS=Windows 10.0.19041
55 | Intel Core i7-9750H CPU 2.60GHz, 1 CPU, 12 logical and 6 physical cores
56 | .NET Core SDK=5.0.104
57 | [Host] : .NET Core 2.2.8 (CoreCLR 4.6.28207.03, CoreFX 4.6.28208.02), 64bit RyuJIT
58 | DefaultJob : .NET Core 2.2.8 (CoreCLR 4.6.28207.03, CoreFX 4.6.28208.02), 64bit RyuJIT
59 |
60 |
61 | ```
62 | | Method | N | Mean | Error | StdDev | Rank | Gen 0 | Gen 1 | Gen 2 | Allocated |
63 | |----------- |------ |------------:|----------:|----------:|-----:|------:|------:|------:|----------:|
64 | | **SpanReader** | **1000** | **1,201.3 ns** | **22.18 ns** | **20.75 ns** | **3** | **-** | **-** | **-** | **-** |
65 | | BitConvert | 1000 | 947.9 ns | 18.67 ns | 27.37 ns | 2 | - | - | - | - |
66 | | Manual | 1000 | 553.7 ns | 10.96 ns | 10.77 ns | 1 | - | - | - | - |
67 | | **SpanReader** | **10000** | **13,152.5 ns** | **262.35 ns** | **376.25 ns** | **6** | **-** | **-** | **-** | **-** |
68 | | BitConvert | 10000 | 9,786.4 ns | 168.66 ns | 187.47 ns | 5 | - | - | - | - |
69 | | Manual | 10000 | 5,379.4 ns | 107.46 ns | 182.47 ns | 4 | - | - | - | - |
70 |
71 |
--------------------------------------------------------------------------------
/src/SpanDex/SpanDex.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | SpanDex
5 |
6 |
7 |
8 |
9 | Provides an easy way to read from a Span
10 |
11 |
12 |
13 |
14 | Initializes a SpanReader using the given memory
15 |
16 | The memory to use
17 | Optional initial cursor position (defaults to 0)
18 |
19 |
20 |
21 | The current cursor position
22 |
23 |
24 |
25 |
26 | The space remaining in the memory
27 |
28 |
29 |
30 |
31 | The length of the memory
32 |
33 |
34 |
35 |
36 | Manually advances the cursor by the given length
37 |
38 | The amount (in bytes) to move the cursor
39 |
40 |
41 |
42 | Provides an easy way to write to a Span
43 |
44 |
45 |
46 |
47 | The underlying span
48 |
49 |
50 |
51 |
52 | Initializes a new SpanWriter with the provided size in bytes.
53 |
54 | The size (in bytes) of the underlying memory
55 |
56 |
57 |
58 | Initializes a new SpanWriter using an existing Span of memory
59 |
60 | The memory to use
61 | Optional initial cursor position to use (defaults to 0)
62 |
63 |
64 |
65 | The current cursor position
66 |
67 |
68 |
69 |
70 | The space remaining in the memory
71 |
72 |
73 |
74 |
75 | The length of the memory
76 |
77 |
78 |
79 |
80 | Returns a byte[] of the memory
81 |
82 |
83 |
84 |
85 | Returns a read only span of the memory
86 |
87 |
88 |
89 |
90 | Manually advances the cursor by the given length
91 |
92 | The amount (in bytes) to move the cursor
93 |
94 |
95 |
96 |
--------------------------------------------------------------------------------
/src/SpanDex/SpanReader.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using SpanDex.Extensions;
3 |
4 | namespace SpanDex {
5 | ///
6 | /// Provides an easy way to read from a Span
7 | ///
8 | public ref struct SpanReader {
9 | private readonly ReadOnlySpan span;
10 | private int cursor;
11 |
12 | ///
13 | /// Initializes a SpanReader using the given memory
14 | ///
15 | /// The memory to use
16 | /// Optional initial cursor position (defaults to 0)
17 | public SpanReader(ReadOnlySpan span, int cursor = 0) {
18 | this.span = span;
19 | this.cursor = cursor;
20 | }
21 |
22 | public static implicit operator SpanReader(byte[] array) => new SpanReader(array);
23 | public static implicit operator SpanReader(Span span) => new SpanReader(span);
24 | public static implicit operator SpanReader(ReadOnlySpan span) => new SpanReader(span);
25 | public static implicit operator SpanReader(ArraySegment segment) => new SpanReader(segment);
26 |
27 | ///
28 | /// The current cursor position
29 | ///
30 | public int Cursor => cursor;
31 |
32 | ///
33 | /// The space remaining in the memory
34 | ///
35 | public int Remaining => span.Length - cursor;
36 |
37 | ///
38 | /// The length of the memory
39 | ///
40 | public int Length => span.Length;
41 |
42 | ///
43 | /// Manually advances the cursor by the given length
44 | ///
45 | /// The amount (in bytes) to move the cursor
46 | public void Advance(int length) {
47 | if (length <= 0)
48 | throw new ArgumentException("Length must be a non-negative integer");
49 |
50 | cursor = checked(cursor + length);
51 | }
52 |
53 | public short ReadInt16BigEndian() => span.ReadInt16BigEndian(ref cursor);
54 |
55 | public short ReadInt16LittleEndian() => span.ReadInt16LittleEndian(ref cursor);
56 |
57 | public int ReadInt32BigEndian() => span.ReadInt32BigEndian(ref cursor);
58 |
59 | public int ReadInt32LittleEndian() => span.ReadInt32LittleEndian(ref cursor);
60 |
61 | public long ReadInt64BigEndian() => span.ReadInt64BigEndian(ref cursor);
62 |
63 | public long ReadInt64LittleEndian() => span.ReadInt64LittleEndian(ref cursor);
64 |
65 | [CLSCompliant(false)]
66 | public ushort ReadUInt16BigEndian() => span.ReadUInt16BigEndian(ref cursor);
67 |
68 | [CLSCompliant(false)]
69 | public ushort ReadUInt16LittleEndian() => span.ReadUInt16LittleEndian(ref cursor);
70 |
71 | [CLSCompliant(false)]
72 | public uint ReadUInt32BigEndian() => span.ReadUInt32BigEndian(ref cursor);
73 |
74 | [CLSCompliant(false)]
75 | public uint ReadUInt32LittleEndian() => span.ReadUInt32LittleEndian(ref cursor);
76 |
77 | [CLSCompliant(false)]
78 | public ulong ReadUInt64BigEndian() => span.ReadUInt64BigEndian(ref cursor);
79 |
80 | [CLSCompliant(false)]
81 | public ulong ReadUInt64LittleEndian() => span.ReadUInt64LittleEndian(ref cursor);
82 |
83 | public ReadOnlySpan ReadSpan(int size) => span.ReadSpan(size, ref cursor);
84 |
85 | public string ReadAsciiString(int size) => span.ReadAsciiString(size, ref cursor);
86 |
87 | public string ReadUtf8string(int size) => span.ReadUtf8String(size, ref cursor);
88 |
89 | public byte ReadByte() => span.ReadByte(ref cursor);
90 |
91 | public bool TryReadInt16BigEndian(out short value) => span.TryReadInt16BigEndian(out value, ref cursor);
92 |
93 | public bool TryReadInt16LittleEndian(out short value) => span.TryReadInt16LittleEndian(out value, ref cursor);
94 |
95 | public bool TryReadInt32BigEndian(out int value) => span.TryReadInt32BigEndian(out value, ref cursor);
96 |
97 | public bool TryReadInt32LittleEndian(out int value) => span.TryReadInt32LittleEndian(out value, ref cursor);
98 |
99 | public bool TryReadInt64BigEndian(out long value) => span.TryReadInt64BigEndian(out value, ref cursor);
100 |
101 | public bool TryReadInt64LittleEndian(out long value) => span.TryReadInt64LittleEndian(out value, ref cursor);
102 |
103 | [CLSCompliant(false)]
104 | public bool TryReadUInt16BigEndian(out ushort value) => span.TryReadUInt16BigEndian(out value, ref cursor);
105 |
106 | [CLSCompliant(false)]
107 | public bool TryReadUInt16LittleEndian(out ushort value) => span.TryReadUInt16LittleEndian(out value, ref cursor);
108 |
109 | [CLSCompliant(false)]
110 | public bool TryReadUInt32BigEndian(out uint value) => span.TryReadUInt32BigEndian(out value, ref cursor);
111 |
112 | [CLSCompliant(false)]
113 | public bool TryReadUInt32LittleEndian(out uint value) => span.TryReadUInt32LittleEndian(out value, ref cursor);
114 |
115 | [CLSCompliant(false)]
116 | public bool TryReadUInt64BigEndian(out ulong value) => span.TryReadUInt64BigEndian(out value, ref cursor);
117 |
118 | [CLSCompliant(false)]
119 | public bool TryReadUInt64LittleEndian(out ulong value) => span.TryReadUInt64LittleEndian(out value, ref cursor);
120 |
121 | public bool TryReadSpan(out ReadOnlySpan value, int size) => span.TryReadSpan(out value, size, ref cursor);
122 |
123 | public bool TryReadAsciiString(out string value, int size) => span.TryReadAsciiString(out value, size, ref cursor);
124 |
125 | public bool TryReadUtf8string(out string value, int size) => span.TryReadUtf8String(out value, size, ref cursor);
126 |
127 | public bool TryReadByte(out byte value) => span.TryReadByte(out value, ref cursor);
128 | }
129 | }
130 |
--------------------------------------------------------------------------------
/src/SpanDex/SpanWriter.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using SpanDex.Extensions;
3 |
4 | namespace SpanDex {
5 | ///
6 | /// Provides an easy way to write to a Span
7 | ///
8 | public ref struct SpanWriter {
9 | ///
10 | /// The underlying span
11 | ///
12 | public readonly Span Span;
13 | private int cursor;
14 |
15 | ///
16 | /// Initializes a new SpanWriter with the provided size in bytes.
17 | ///
18 | /// The size (in bytes) of the underlying memory
19 | public SpanWriter(int size) {
20 | if (size <= 0)
21 | throw new ArgumentException("Size must be a non-negative integer");
22 |
23 | this.Span = new byte[size];
24 | this.cursor = 0;
25 | }
26 |
27 | ///
28 | /// Initializes a new SpanWriter using an existing Span of memory
29 | ///
30 | /// The memory to use
31 | /// Optional initial cursor position to use (defaults to 0)
32 | public SpanWriter(Span span, int cursor = 0) {
33 | if (span.Length == 0)
34 | throw new ArgumentNullException(nameof(span));
35 |
36 | this.Span = span;
37 | this.cursor = cursor;
38 | }
39 |
40 | public static implicit operator SpanWriter(byte[] array) => new SpanWriter(array);
41 | public static implicit operator SpanWriter(Span span) => new SpanWriter(span);
42 | public static implicit operator SpanWriter(ArraySegment segment) => new SpanWriter(segment);
43 |
44 | ///
45 | /// The current cursor position
46 | ///
47 | public int Cursor => cursor;
48 |
49 | ///
50 | /// The space remaining in the memory
51 | ///
52 | public int Remaining => Span.Length - cursor;
53 |
54 | ///
55 | /// The length of the memory
56 | ///
57 | public int Length => Span.Length;
58 |
59 | ///
60 | /// Returns a byte[] of the memory
61 | ///
62 | public byte[] ToArray() => Span.ToArray();
63 |
64 | ///
65 | /// Returns a read only span of the memory
66 | ///
67 | public ReadOnlySpan ToReadOnlySpan() => new ReadOnlySpan(ToArray());
68 |
69 | ///
70 | /// Manually advances the cursor by the given length
71 | ///
72 | /// The amount (in bytes) to move the cursor
73 | public void Advance(int length) {
74 | if (length <= 0)
75 | throw new ArgumentException("Length must be a non-negative integer");
76 |
77 | cursor = checked(cursor + length);
78 | }
79 |
80 | public bool TryWriteInt16BigEndian(short value) => Span.TryWriteInt16BigEndian(value, ref cursor);
81 |
82 | public bool TryWriteInt16LittleEndian(short value) => Span.TryWriteInt16LittleEndian(value, ref cursor);
83 |
84 | public bool TryWriteInt32BigEndian(int value) => Span.TryWriteInt32BigEndian(value, ref cursor);
85 |
86 | public bool TryWriteInt32LittleEndian(int value) => Span.TryWriteInt32LittleEndian(value, ref cursor);
87 |
88 | public bool TryWriteInt64BigEndian(long value) => Span.TryWriteInt64BigEndian(value, ref cursor);
89 |
90 | public bool TryWriteInt64LittleEndian(long value) => Span.TryWriteInt64LittleEndian(value, ref cursor);
91 |
92 | [CLSCompliant(false)]
93 | public bool TryWriteUInt16BigEndian(ushort value) => Span.TryWriteUInt16BigEndian(value, ref cursor);
94 |
95 | [CLSCompliant(false)]
96 | public bool TryWriteUInt16LittleEndian(ushort value) => Span.TryWriteUInt16LittleEndian(value, ref cursor);
97 |
98 | [CLSCompliant(false)]
99 | public bool TryWriteUInt32BigEndian(uint value) => Span.TryWriteUInt32BigEndian(value, ref cursor);
100 |
101 | [CLSCompliant(false)]
102 | public bool TryWriteUInt32LittleEndian(uint value) => Span.TryWriteUInt32LittleEndian(value, ref cursor);
103 |
104 | [CLSCompliant(false)]
105 | public bool TryWriteUInt64BigEndian(ulong value) => Span.TryWriteUInt64BigEndian(value, ref cursor);
106 |
107 | [CLSCompliant(false)]
108 | public bool TryWriteUInt64LittleEndian(ulong value) => Span.TryWriteUInt64LittleEndian(value, ref cursor);
109 |
110 | public bool TryWriteSpan(ReadOnlySpan value) => Span.TryWriteSpan(value, ref cursor);
111 |
112 | public bool TryWriteAsciiString(string value) => Span.TryWriteAsciiString(value, ref cursor);
113 |
114 | public bool TryWriteUtf8String(string value) => Span.TryWriteUtf8String(value, ref cursor);
115 |
116 | public bool TryWriteByte(byte value) => Span.TryWriteByte(value, ref cursor);
117 |
118 | public void WriteInt16BigEndian(short value) => Span.WriteInt16BigEndian(value, ref cursor);
119 |
120 | public void WriteInt16LittleEndian(short value) => Span.WriteInt16LittleEndian(value, ref cursor);
121 |
122 | public void WriteInt32BigEndian(int value) => Span.WriteInt32BigEndian(value, ref cursor);
123 |
124 | public void WriteInt32LittleEndian(int value) => Span.WriteInt32LittleEndian(value, ref cursor);
125 |
126 | public void WriteInt64BigEndian(long value) => Span.WriteInt64BigEndian(value, ref cursor);
127 |
128 | public void WriteInt64LittleEndian(long value) => Span.WriteInt64LittleEndian(value, ref cursor);
129 |
130 | [CLSCompliant(false)]
131 | public void WriteUInt16BigEndian(ushort value) => Span.WriteUInt16BigEndian(value, ref cursor);
132 |
133 | [CLSCompliant(false)]
134 | public void WriteUInt16LittleEndian(ushort value) => Span.WriteUInt16LittleEndian(value, ref cursor);
135 |
136 | [CLSCompliant(false)]
137 | public void WriteUInt32BigEndian(uint value) => Span.WriteUInt32BigEndian(value, ref cursor);
138 |
139 | [CLSCompliant(false)]
140 | public void WriteUInt32LittleEndian(uint value) => Span.WriteUInt32LittleEndian(value, ref cursor);
141 |
142 | [CLSCompliant(false)]
143 | public void WriteUInt64BigEndian(ulong value) => Span.WriteUInt64BigEndian(value, ref cursor);
144 |
145 | [CLSCompliant(false)]
146 | public void WriteUInt64LittleEndian(ulong value) => Span.WriteUInt64LittleEndian(value, ref cursor);
147 |
148 | public void WriteSpan(ReadOnlySpan value) => Span.WriteSpan(value, ref cursor);
149 |
150 | public void WriteAsciiString(string value) => Span.WriteAsciiString(value, ref cursor);
151 |
152 | public void WriteUtf8String(string value) => Span.WriteUtf8String(value, ref cursor);
153 |
154 | public void WriteByte(byte value) => Span.WriteByte(value, ref cursor);
155 | }
156 | }
157 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 | ##
4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
5 |
6 | # User-specific files
7 | *.suo
8 | *.user
9 | *.userosscache
10 | *.sln.docstates
11 |
12 | # User-specific files (MonoDevelop/Xamarin Studio)
13 | *.userprefs
14 |
15 | # Build results
16 | [Dd]ebug/
17 | [Dd]ebugPublic/
18 | [Rr]elease/
19 | [Rr]eleases/
20 | x64/
21 | x86/
22 | bld/
23 | [Bb]in/
24 | [Oo]bj/
25 | [Ll]og/
26 |
27 | # Visual Studio 2015/2017 cache/options directory
28 | .vs/
29 | # Uncomment if you have tasks that create the project's static files in wwwroot
30 | #wwwroot/
31 |
32 | # Visual Studio 2017 auto generated files
33 | Generated\ Files/
34 |
35 | # MSTest test Results
36 | [Tt]est[Rr]esult*/
37 | [Bb]uild[Ll]og.*
38 |
39 | # NUNIT
40 | *.VisualState.xml
41 | TestResult.xml
42 |
43 | # Build Results of an ATL Project
44 | [Dd]ebugPS/
45 | [Rr]eleasePS/
46 | dlldata.c
47 |
48 | # Benchmark Results
49 | BenchmarkDotNet.Artifacts/
50 |
51 | # .NET Core
52 | project.lock.json
53 | project.fragment.lock.json
54 | artifacts/
55 | **/Properties/launchSettings.json
56 |
57 | # StyleCop
58 | StyleCopReport.xml
59 |
60 | # Files built by Visual Studio
61 | *_i.c
62 | *_p.c
63 | *_i.h
64 | *.ilk
65 | *.meta
66 | *.obj
67 | *.iobj
68 | *.pch
69 | *.pdb
70 | *.ipdb
71 | *.pgc
72 | *.pgd
73 | *.rsp
74 | *.sbr
75 | *.tlb
76 | *.tli
77 | *.tlh
78 | *.tmp
79 | *.tmp_proj
80 | *.log
81 | *.vspscc
82 | *.vssscc
83 | .builds
84 | *.pidb
85 | *.svclog
86 | *.scc
87 |
88 | # Chutzpah Test files
89 | _Chutzpah*
90 |
91 | # Visual C++ cache files
92 | ipch/
93 | *.aps
94 | *.ncb
95 | *.opendb
96 | *.opensdf
97 | *.sdf
98 | *.cachefile
99 | *.VC.db
100 | *.VC.VC.opendb
101 |
102 | # Visual Studio profiler
103 | *.psess
104 | *.vsp
105 | *.vspx
106 | *.sap
107 |
108 | # Visual Studio Trace Files
109 | *.e2e
110 |
111 | # TFS 2012 Local Workspace
112 | $tf/
113 |
114 | # Guidance Automation Toolkit
115 | *.gpState
116 |
117 | # ReSharper is a .NET coding add-in
118 | _ReSharper*/
119 | *.[Rr]e[Ss]harper
120 | *.DotSettings.user
121 |
122 | # JustCode is a .NET coding add-in
123 | .JustCode
124 |
125 | # TeamCity is a build add-in
126 | _TeamCity*
127 |
128 | # DotCover is a Code Coverage Tool
129 | *.dotCover
130 |
131 | # AxoCover is a Code Coverage Tool
132 | .axoCover/*
133 | !.axoCover/settings.json
134 |
135 | # Visual Studio code coverage results
136 | *.coverage
137 | *.coveragexml
138 |
139 | # NCrunch
140 | _NCrunch_*
141 | .*crunch*.local.xml
142 | nCrunchTemp_*
143 |
144 | # MightyMoose
145 | *.mm.*
146 | AutoTest.Net/
147 |
148 | # Web workbench (sass)
149 | .sass-cache/
150 |
151 | # Installshield output folder
152 | [Ee]xpress/
153 |
154 | # DocProject is a documentation generator add-in
155 | DocProject/buildhelp/
156 | DocProject/Help/*.HxT
157 | DocProject/Help/*.HxC
158 | DocProject/Help/*.hhc
159 | DocProject/Help/*.hhk
160 | DocProject/Help/*.hhp
161 | DocProject/Help/Html2
162 | DocProject/Help/html
163 |
164 | # Click-Once directory
165 | publish/
166 |
167 | # Publish Web Output
168 | *.[Pp]ublish.xml
169 | *.azurePubxml
170 | # Note: Comment the next line if you want to checkin your web deploy settings,
171 | # but database connection strings (with potential passwords) will be unencrypted
172 | *.pubxml
173 | *.publishproj
174 |
175 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
176 | # checkin your Azure Web App publish settings, but sensitive information contained
177 | # in these scripts will be unencrypted
178 | PublishScripts/
179 |
180 | # NuGet Packages
181 | *.nupkg
182 | # The packages folder can be ignored because of Package Restore
183 | **/[Pp]ackages/*
184 | # except build/, which is used as an MSBuild target.
185 | !**/[Pp]ackages/build/
186 | # Uncomment if necessary however generally it will be regenerated when needed
187 | #!**/[Pp]ackages/repositories.config
188 | # NuGet v3's project.json files produces more ignorable files
189 | *.nuget.props
190 | *.nuget.targets
191 |
192 | # Microsoft Azure Build Output
193 | csx/
194 | *.build.csdef
195 |
196 | # Microsoft Azure Emulator
197 | ecf/
198 | rcf/
199 |
200 | # Windows Store app package directories and files
201 | AppPackages/
202 | BundleArtifacts/
203 | Package.StoreAssociation.xml
204 | _pkginfo.txt
205 | *.appx
206 |
207 | # Visual Studio cache files
208 | # files ending in .cache can be ignored
209 | *.[Cc]ache
210 | # but keep track of directories ending in .cache
211 | !*.[Cc]ache/
212 |
213 | # Others
214 | ClientBin/
215 | ~$*
216 | *~
217 | *.dbmdl
218 | *.dbproj.schemaview
219 | *.jfm
220 | *.pfx
221 | *.publishsettings
222 | orleans.codegen.cs
223 |
224 | # Including strong name files can present a security risk
225 | # (https://github.com/github/gitignore/pull/2483#issue-259490424)
226 | #*.snk
227 |
228 | # Since there are multiple workflows, uncomment next line to ignore bower_components
229 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
230 | #bower_components/
231 |
232 | # RIA/Silverlight projects
233 | Generated_Code/
234 |
235 | # Backup & report files from converting an old project file
236 | # to a newer Visual Studio version. Backup files are not needed,
237 | # because we have git ;-)
238 | _UpgradeReport_Files/
239 | Backup*/
240 | UpgradeLog*.XML
241 | UpgradeLog*.htm
242 | ServiceFabricBackup/
243 | *.rptproj.bak
244 |
245 | # SQL Server files
246 | *.mdf
247 | *.ldf
248 | *.ndf
249 |
250 | # Business Intelligence projects
251 | *.rdl.data
252 | *.bim.layout
253 | *.bim_*.settings
254 | *.rptproj.rsuser
255 |
256 | # Microsoft Fakes
257 | FakesAssemblies/
258 |
259 | # GhostDoc plugin setting file
260 | *.GhostDoc.xml
261 |
262 | # Node.js Tools for Visual Studio
263 | .ntvs_analysis.dat
264 | node_modules/
265 |
266 | # Visual Studio 6 build log
267 | *.plg
268 |
269 | # Visual Studio 6 workspace options file
270 | *.opt
271 |
272 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
273 | *.vbw
274 |
275 | # Visual Studio LightSwitch build output
276 | **/*.HTMLClient/GeneratedArtifacts
277 | **/*.DesktopClient/GeneratedArtifacts
278 | **/*.DesktopClient/ModelManifest.xml
279 | **/*.Server/GeneratedArtifacts
280 | **/*.Server/ModelManifest.xml
281 | _Pvt_Extensions
282 |
283 | # Paket dependency manager
284 | .paket/paket.exe
285 | paket-files/
286 |
287 | # FAKE - F# Make
288 | .fake/
289 |
290 | # JetBrains Rider
291 | .idea/
292 | *.sln.iml
293 |
294 | # CodeRush
295 | .cr/
296 |
297 | # Python Tools for Visual Studio (PTVS)
298 | __pycache__/
299 | *.pyc
300 |
301 | # Cake - Uncomment if you are using it
302 | # tools/**
303 | # !tools/packages.config
304 |
305 | # Tabs Studio
306 | *.tss
307 |
308 | # Telerik's JustMock configuration file
309 | *.jmconfig
310 |
311 | # BizTalk build output
312 | *.btp.cs
313 | *.btm.cs
314 | *.odx.cs
315 | *.xsd.cs
316 |
317 | # OpenCover UI analysis results
318 | OpenCover/
319 |
320 | # Azure Stream Analytics local run output
321 | ASALocalRun/
322 |
323 | # MSBuild Binary and Structured Log
324 | *.binlog
325 |
326 | # NVidia Nsight GPU debugger configuration file
327 | *.nvuser
328 |
329 | # MFractors (Xamarin productivity tool) working folder
330 | .mfractor/
331 |
--------------------------------------------------------------------------------
/src/SpanDex/SpanWriting.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Buffers.Binary;
3 | using System.Text;
4 |
5 | namespace SpanDex {
6 | internal static class SpanWriting {
7 | internal static bool TryWriteInt16BigEndian(Span destination, short value, ref int cursor) {
8 | if (!ValidateTryWrite(destination, cursor, 2))
9 | return false;
10 |
11 | return TryAdvance(BinaryPrimitives.TryWriteInt16BigEndian(destination.Slice(cursor, 2), value), ref cursor, 2);
12 | }
13 |
14 | internal static bool TryWriteInt16LittleEndian(Span destination, short value, ref int cursor) {
15 | if (!ValidateTryWrite(destination, cursor, 2))
16 | return false;
17 |
18 | return TryAdvance(BinaryPrimitives.TryWriteInt16LittleEndian(destination.Slice(cursor, 2), value), ref cursor, 2);
19 | }
20 |
21 | internal static bool TryWriteInt32BigEndian(Span destination, int value, ref int cursor) {
22 | if (!ValidateTryWrite(destination, cursor, 4))
23 | return false;
24 |
25 | return TryAdvance(BinaryPrimitives.TryWriteInt32BigEndian(destination.Slice(cursor, 4), value), ref cursor, 4);
26 | }
27 |
28 | internal static bool TryWriteInt32LittleEndian(Span destination, int value, ref int cursor) {
29 | if (!ValidateTryWrite(destination, cursor, 4))
30 | return false;
31 |
32 | return TryAdvance(BinaryPrimitives.TryWriteInt32LittleEndian(destination.Slice(cursor, 4), value), ref cursor, 4);
33 | }
34 |
35 | internal static bool TryWriteInt64BigEndian(Span destination, long value, ref int cursor) {
36 | if (!ValidateTryWrite(destination, cursor, 8))
37 | return false;
38 |
39 | return TryAdvance(BinaryPrimitives.TryWriteInt64BigEndian(destination.Slice(cursor, 8), value), ref cursor, 8);
40 | }
41 |
42 | internal static bool TryWriteInt64LittleEndian(Span destination, long value, ref int cursor) {
43 | if (!ValidateTryWrite(destination, cursor, 8))
44 | return false;
45 |
46 | return TryAdvance(BinaryPrimitives.TryWriteInt64LittleEndian(destination.Slice(cursor, 8), value), ref cursor, 8);
47 | }
48 |
49 | internal static bool TryWriteUInt16BigEndian(Span destination, ushort value, ref int cursor) {
50 | if (!ValidateTryWrite(destination, cursor, 2))
51 | return false;
52 |
53 | return TryAdvance(BinaryPrimitives.TryWriteUInt16BigEndian(destination.Slice(cursor, 2), value), ref cursor, 2);
54 | }
55 |
56 | internal static bool TryWriteUInt16LittleEndian(Span destination, ushort value, ref int cursor) {
57 | if (!ValidateTryWrite(destination, cursor, 2))
58 | return false;
59 |
60 | return TryAdvance(BinaryPrimitives.TryWriteUInt16LittleEndian(destination.Slice(cursor, 2), value), ref cursor, 2);
61 | }
62 |
63 | internal static bool TryWriteUInt32BigEndian(Span destination, uint value, ref int cursor) {
64 | if (!ValidateTryWrite(destination, cursor, 4))
65 | return false;
66 |
67 | return TryAdvance(BinaryPrimitives.TryWriteUInt32BigEndian(destination.Slice(cursor, 4), value), ref cursor, 4);
68 | }
69 |
70 | internal static bool TryWriteUInt32LittleEndian(Span destination, uint value, ref int cursor) {
71 | if (!ValidateTryWrite(destination, cursor, 4))
72 | return false;
73 |
74 | return TryAdvance(BinaryPrimitives.TryWriteUInt32LittleEndian(destination.Slice(cursor, 4), value), ref cursor, 4);
75 | }
76 |
77 | internal static bool TryWriteUInt64BigEndian(Span destination, ulong value, ref int cursor) {
78 | if (!ValidateTryWrite(destination, cursor, 8))
79 | return false;
80 |
81 | return TryAdvance(BinaryPrimitives.TryWriteUInt64BigEndian(destination.Slice(cursor, 8), value), ref cursor, 8);
82 | }
83 |
84 | internal static bool TryWriteUInt64LittleEndian(Span destination, ulong value, ref int cursor) {
85 | if (!ValidateTryWrite(destination, cursor, 8))
86 | return false;
87 |
88 | return TryAdvance(BinaryPrimitives.TryWriteUInt64LittleEndian(destination.Slice(cursor, 8), value), ref cursor, 8);
89 | }
90 |
91 | internal static bool TryWriteSpan(Span destination, ReadOnlySpan value, ref int cursor) {
92 | ValidateCursor(cursor);
93 | if (value == default)
94 | throw new ArgumentNullException(nameof(value));
95 |
96 | if (destination.HasSpace(cursor + value.Length)) {
97 | WriteSpan(destination, value, ref cursor);
98 | return true;
99 | }
100 | return false;
101 | }
102 |
103 | internal static bool TryWriteAsciiString(Span destination, string value, ref int cursor) {
104 | ValidateCursor(cursor);
105 | if (value == null)
106 | throw new ArgumentNullException(nameof(value));
107 |
108 | return TryWriteSpan(destination, Encoding.ASCII.GetBytes(value), ref cursor);
109 | }
110 |
111 | internal static bool TryWriteUtf8String(Span destination, string value, ref int cursor) {
112 | ValidateCursor(cursor);
113 | if (value == null)
114 | throw new ArgumentNullException(nameof(value));
115 |
116 | return TryWriteSpan(destination, Encoding.UTF8.GetBytes(value), ref cursor);
117 | }
118 |
119 | internal static bool TryWriteByte(Span destination, byte value, ref int cursor) {
120 | if(destination.HasSpace(cursor + 1)) {
121 | WriteByte(destination, value, ref cursor);
122 | return true;
123 | }
124 | return false;
125 | }
126 |
127 | internal static void WriteInt16BigEndian(Span destination, short value, ref int cursor) {
128 | ValidateCursor(cursor);
129 | BinaryPrimitives.WriteInt16BigEndian(destination.SliceAndAdvance(ref cursor, 2), value);
130 | }
131 |
132 | internal static void WriteInt16LittleEndian(Span destination, short value, ref int cursor) {
133 | ValidateCursor(cursor);
134 | BinaryPrimitives.WriteInt16LittleEndian(destination.SliceAndAdvance(ref cursor, 2), value);
135 | }
136 |
137 | internal static void WriteInt32BigEndian(Span destination, int value, ref int cursor) {
138 | ValidateCursor(cursor);
139 | BinaryPrimitives.WriteInt32BigEndian(destination.SliceAndAdvance(ref cursor, 4), value);
140 | }
141 |
142 | internal static void WriteInt32LittleEndian(Span destination, int value, ref int cursor) {
143 | ValidateCursor(cursor);
144 | BinaryPrimitives.WriteInt32LittleEndian(destination.SliceAndAdvance(ref cursor, 4), value);
145 | }
146 |
147 | internal static void WriteInt64BigEndian(Span destination, long value, ref int cursor) {
148 | ValidateCursor(cursor);
149 | BinaryPrimitives.WriteInt64BigEndian(destination.SliceAndAdvance(ref cursor, 8), value);
150 | }
151 |
152 | internal static void WriteInt64LittleEndian(Span destination, long value, ref int cursor) {
153 | ValidateCursor(cursor);
154 | BinaryPrimitives.WriteInt64LittleEndian(destination.SliceAndAdvance(ref cursor, 8), value);
155 | }
156 |
157 | internal static void WriteUInt16BigEndian(Span destination, ushort value, ref int cursor) {
158 | ValidateCursor(cursor);
159 | BinaryPrimitives.WriteUInt16BigEndian(destination.SliceAndAdvance(ref cursor, 2), value);
160 | }
161 |
162 | internal static void WriteUInt16LittleEndian(Span destination, ushort value, ref int cursor) {
163 | ValidateCursor(cursor);
164 | BinaryPrimitives.WriteUInt16LittleEndian(destination.SliceAndAdvance(ref cursor, 2), value);
165 | }
166 |
167 | internal static void WriteUInt32BigEndian(Span destination, uint value, ref int cursor) {
168 | ValidateCursor(cursor);
169 | BinaryPrimitives.WriteUInt32BigEndian(destination.SliceAndAdvance(ref cursor, 4), value);
170 | }
171 |
172 | internal static void WriteUInt32LittleEndian(Span destination, uint value, ref int cursor) {
173 | ValidateCursor(cursor);
174 | BinaryPrimitives.WriteUInt32LittleEndian(destination.SliceAndAdvance(ref cursor, 4), value);
175 | }
176 |
177 | internal static void WriteUInt64BigEndian(Span destination, ulong value, ref int cursor) {
178 | ValidateCursor(cursor);
179 | BinaryPrimitives.WriteUInt64BigEndian(destination.SliceAndAdvance(ref cursor, 8), value);
180 | }
181 |
182 | internal static void WriteUInt64LittleEndian(Span destination, ulong value, ref int cursor) {
183 | ValidateCursor(cursor);
184 | BinaryPrimitives.WriteUInt64LittleEndian(destination.SliceAndAdvance(ref cursor, 8), value);
185 | }
186 |
187 | internal static void WriteSpan(Span destination, ReadOnlySpan value, ref int cursor) {
188 | ValidateCursor(cursor);
189 | if (value == default)
190 | throw new ArgumentNullException(nameof(value));
191 |
192 | value.CopyTo(destination.Slice(cursor, value.Length));
193 | IncrementCursor(ref cursor, value.Length);
194 | }
195 |
196 | internal static void WriteAsciiString(Span destination, string value, ref int cursor) {
197 | ValidateCursor(cursor);
198 | if (value == null)
199 | throw new ArgumentNullException(nameof(value));
200 |
201 | WriteSpan(destination, Encoding.ASCII.GetBytes(value), ref cursor);
202 | }
203 |
204 | internal static void WriteUtf8String(Span destination, string value, ref int cursor) {
205 | ValidateCursor(cursor);
206 | if (value == null)
207 | throw new ArgumentNullException(nameof(value));
208 |
209 | WriteSpan(destination, Encoding.UTF8.GetBytes(value), ref cursor);
210 | }
211 |
212 | internal static void WriteByte(Span destination, byte value, ref int cursor) {
213 | ValidateCursor(cursor);
214 | destination[cursor] = value;
215 | IncrementCursor(ref cursor, 1);
216 | }
217 |
218 | private static bool ValidateTryWrite(Span source, int cursor, int size) {
219 | ValidateCursor(cursor);
220 | return HasSpace(source, cursor + size);
221 | }
222 |
223 | private static Span SliceAndAdvance(this Span source, ref int cursor, int size) {
224 | Span slice = source.Slice(cursor, size);
225 | IncrementCursor(ref cursor, size);
226 | return slice;
227 | }
228 |
229 | private static bool TryAdvance(bool succeeded, ref int cursor, int size) {
230 | if (succeeded)
231 | IncrementCursor(ref cursor, size);
232 | return succeeded;
233 | }
234 |
235 | private static void IncrementCursor(ref int cursor, int size) => cursor = checked(cursor + size);
236 |
237 | private static bool HasSpace(this Span source, int space) => source.Length >= space;
238 |
239 | private static void ValidateCursor(int cursor) {
240 | if (cursor < 0)
241 | throw new ArgumentException("Cursor cannot be less than 0");
242 | }
243 | }
244 | }
245 |
--------------------------------------------------------------------------------
/src/SpanDex/SpanReading.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Buffers.Binary;
3 | using System.Diagnostics.Contracts;
4 | using System.Text;
5 |
6 | namespace SpanDex {
7 | internal static class SpanReading {
8 | internal static short ReadInt16BigEndian(ReadOnlySpan source, ref int cursor) {
9 | ValidateCursor(cursor);
10 | return BinaryPrimitives.ReadInt16BigEndian(source.SliceAndAdvance(ref cursor, 2));
11 | }
12 |
13 | internal static short ReadInt16LittleEndian(ReadOnlySpan source, ref int cursor) {
14 | ValidateCursor(cursor);
15 | return BinaryPrimitives.ReadInt16LittleEndian(source.SliceAndAdvance(ref cursor, 2));
16 | }
17 |
18 | internal static int ReadInt32BigEndian(ReadOnlySpan source, ref int cursor) {
19 | ValidateCursor(cursor);
20 | return BinaryPrimitives.ReadInt32BigEndian(source.SliceAndAdvance(ref cursor, 4));
21 | }
22 |
23 | internal static int ReadInt32LittleEndian(ReadOnlySpan source, ref int cursor) {
24 | ValidateCursor(cursor);
25 | return BinaryPrimitives.ReadInt32LittleEndian(source.SliceAndAdvance(ref cursor, 4));
26 | }
27 |
28 | internal static long ReadInt64BigEndian(ReadOnlySpan source, ref int cursor) {
29 | ValidateCursor(cursor);
30 | return BinaryPrimitives.ReadInt64BigEndian(source.SliceAndAdvance(ref cursor, 8));
31 | }
32 |
33 | internal static long ReadInt64LittleEndian(ReadOnlySpan source, ref int cursor) {
34 | ValidateCursor(cursor);
35 | return BinaryPrimitives.ReadInt64LittleEndian(source.SliceAndAdvance(ref cursor, 8));
36 | }
37 |
38 | internal static ushort ReadUInt16BigEndian(ReadOnlySpan source, ref int cursor) {
39 | ValidateCursor(cursor);
40 | return BinaryPrimitives.ReadUInt16BigEndian(source.SliceAndAdvance(ref cursor, 2));
41 | }
42 |
43 | internal static ushort ReadUInt16LittleEndian(ReadOnlySpan source, ref int cursor) {
44 | ValidateCursor(cursor);
45 | return BinaryPrimitives.ReadUInt16LittleEndian(source.SliceAndAdvance(ref cursor, 2));
46 | }
47 |
48 | internal static uint ReadUInt32BigEndian(ReadOnlySpan source, ref int cursor) {
49 | ValidateCursor(cursor);
50 | return BinaryPrimitives.ReadUInt32BigEndian(source.SliceAndAdvance(ref cursor, 4));
51 | }
52 |
53 | internal static uint ReadUInt32LittleEndian(ReadOnlySpan source, ref int cursor) {
54 | ValidateCursor(cursor);
55 | return BinaryPrimitives.ReadUInt32LittleEndian(source.SliceAndAdvance(ref cursor, 4));
56 | }
57 |
58 | internal static ulong ReadUInt64BigEndian(ReadOnlySpan source, ref int cursor) {
59 | ValidateCursor(cursor);
60 | return BinaryPrimitives.ReadUInt64BigEndian(source.SliceAndAdvance(ref cursor, 8));
61 | }
62 |
63 | internal static ulong ReadUInt64LittleEndian(ReadOnlySpan source, ref int cursor) {
64 | ValidateCursor(cursor);
65 | return BinaryPrimitives.ReadUInt64LittleEndian(source.SliceAndAdvance(ref cursor, 8));
66 | }
67 |
68 | internal static ReadOnlySpan ReadSpan(ReadOnlySpan source, int size, ref int cursor) {
69 | ValidateCursor(cursor);
70 | return source.SliceAndAdvance(ref cursor, size);
71 | }
72 |
73 | internal static string ReadAsciiString(ReadOnlySpan source, int size, ref int cursor) {
74 | ValidateCursor(cursor);
75 | var slice = ReadSpan(source, size, ref cursor);
76 | return Encoding.ASCII.GetString(slice.ToArray());
77 | }
78 |
79 | internal static string ReadUtf8String(ReadOnlySpan source, int size, ref int cursor) {
80 | ValidateCursor(cursor);
81 | var slice = ReadSpan(source, size, ref cursor);
82 | return Encoding.UTF8.GetString(slice.ToArray());
83 | }
84 |
85 | internal static byte ReadByte(ReadOnlySpan source, ref int cursor) {
86 | ValidateCursor(cursor);
87 | var bite = source[cursor];
88 | IncrementCursor(ref cursor, 1);
89 | return bite;
90 | }
91 |
92 | internal static bool TryReadInt16BigEndian(ReadOnlySpan source, out short value, ref int cursor) {
93 | if (!ValidateTryRead(source, out value, cursor, 2))
94 | return false;
95 |
96 | return TryAdvance(BinaryPrimitives.TryReadInt16BigEndian(source.Slice(cursor, 2), out value), ref cursor, 2);
97 | }
98 |
99 | internal static bool TryReadInt16LittleEndian(ReadOnlySpan source, out short value, ref int cursor) {
100 | if (!ValidateTryRead(source, out value, cursor, 2))
101 | return false;
102 |
103 | return TryAdvance(BinaryPrimitives.TryReadInt16LittleEndian(source.Slice(cursor, 2), out value), ref cursor, 2);
104 | }
105 |
106 | internal static bool TryReadInt32BigEndian(ReadOnlySpan source, out int value, ref int cursor) {
107 | if (!ValidateTryRead(source, out value, cursor, 4))
108 | return false;
109 |
110 | return TryAdvance(BinaryPrimitives.TryReadInt32BigEndian(source.Slice(cursor, 4), out value), ref cursor, 4);
111 | }
112 |
113 | internal static bool TryReadInt32LittleEndian(ReadOnlySpan source, out int value, ref int cursor) {
114 | if (!ValidateTryRead(source, out value, cursor, 4))
115 | return false;
116 |
117 | return TryAdvance(BinaryPrimitives.TryReadInt32LittleEndian(source.Slice(cursor, 4), out value), ref cursor, 4);
118 | }
119 |
120 | internal static bool TryReadInt64BigEndian(ReadOnlySpan source, out long value, ref int cursor) {
121 | if (!ValidateTryRead(source, out value, cursor, 8))
122 | return false;
123 |
124 | return TryAdvance(BinaryPrimitives.TryReadInt64BigEndian(source.Slice(cursor, 8), out value), ref cursor, 8);
125 | }
126 |
127 | internal static bool TryReadInt64LittleEndian(ReadOnlySpan source, out long value, ref int cursor) {
128 | if (!ValidateTryRead(source, out value, cursor, 8))
129 | return false;
130 |
131 | return TryAdvance(BinaryPrimitives.TryReadInt64LittleEndian(source.Slice(cursor, 8), out value), ref cursor, 8);
132 | }
133 |
134 | internal static bool TryReadUInt16BigEndian(ReadOnlySpan source, out ushort value, ref int cursor) {
135 | if (!ValidateTryRead(source, out value, cursor, 2))
136 | return false;
137 |
138 | return TryAdvance(BinaryPrimitives.TryReadUInt16BigEndian(source.Slice(cursor, 2), out value), ref cursor, 2);
139 | }
140 |
141 | internal static bool TryReadUInt16LittleEndian(ReadOnlySpan source, out ushort value, ref int cursor) {
142 | if (!ValidateTryRead(source, out value, cursor, 2))
143 | return false;
144 |
145 | return TryAdvance(BinaryPrimitives.TryReadUInt16LittleEndian(source.Slice(cursor, 2), out value), ref cursor, 2);
146 | }
147 |
148 | internal static bool TryReadUInt32BigEndian(ReadOnlySpan source, out uint value, ref int cursor) {
149 | if (!ValidateTryRead(source, out value, cursor, 4))
150 | return false;
151 |
152 | return TryAdvance(BinaryPrimitives.TryReadUInt32BigEndian(source.Slice(cursor, 4), out value), ref cursor, 4);
153 | }
154 |
155 | internal static bool TryReadUInt32LittleEndian(ReadOnlySpan source, out uint value, ref int cursor) {
156 | if (!ValidateTryRead(source, out value, cursor, 4))
157 | return false;
158 |
159 | return TryAdvance(BinaryPrimitives.TryReadUInt32LittleEndian(source.Slice(cursor, 4), out value), ref cursor, 4);
160 | }
161 |
162 | internal static bool TryReadUInt64BigEndian(ReadOnlySpan source, out ulong value, ref int cursor) {
163 | if (!ValidateTryRead(source, out value, cursor, 8))
164 | return false;
165 |
166 | return TryAdvance(BinaryPrimitives.TryReadUInt64BigEndian(source.Slice(cursor, 8), out value), ref cursor, 8);
167 | }
168 |
169 | internal static bool TryReadUInt64LittleEndian(ReadOnlySpan source, out ulong value, ref int cursor) {
170 | if (!ValidateTryRead(source, out value, cursor, 8))
171 | return false;
172 |
173 | return TryAdvance(BinaryPrimitives.TryReadUInt64LittleEndian(source.Slice(cursor, 8), out value), ref cursor, 8);
174 | }
175 |
176 | internal static bool TryReadSpan(ReadOnlySpan source, out ReadOnlySpan value, int size, ref int cursor) {
177 | ValidateCursor(cursor);
178 | value = default;
179 | if (source.HasSpace(cursor + size)) {
180 | value = ReadSpan(source, size, ref cursor);
181 | return true;
182 | }
183 | return false;
184 | }
185 |
186 | internal static bool TryReadAsciiString(ReadOnlySpan source, out string value, int size, ref int cursor) {
187 | ValidateCursor(cursor);
188 | value = default;
189 | if (source.HasSpace(cursor + size)) {
190 | value = ReadAsciiString(source, size, ref cursor);
191 | return true;
192 | }
193 | return false;
194 | }
195 |
196 | internal static bool TryReadUtf8String(ReadOnlySpan source, out string value, int size, ref int cursor) {
197 | ValidateCursor(cursor);
198 | value = default;
199 | if (source.HasSpace(cursor + size)) {
200 | value = ReadUtf8String(source, size, ref cursor);
201 | return true;
202 | }
203 | return false;
204 | }
205 |
206 | internal static bool TryReadByte(ReadOnlySpan source, out byte value, ref int cursor) {
207 | ValidateCursor(cursor);
208 |
209 | value = default;
210 | if (source.HasSpace(cursor + 1)) {
211 | value = ReadByte(source, ref cursor);
212 | return true;
213 | }
214 | return false;
215 | }
216 |
217 | private static bool ValidateTryRead(ReadOnlySpan source, out T value, int cursor, int size) {
218 | ValidateCursor(cursor);
219 |
220 | value = default;
221 | return HasSpace(source, cursor + size);
222 | }
223 |
224 | private static ReadOnlySpan SliceAndAdvance(this ReadOnlySpan source, ref int cursor, int size) {
225 | if (size <= 0)
226 | throw new ArgumentException("Size must be a positive integer");
227 |
228 | ReadOnlySpan slice = source.Slice(cursor, size);
229 | IncrementCursor(ref cursor, size);
230 | return slice;
231 | }
232 |
233 | private static bool TryAdvance(bool succeeded, ref int cursor, int size) {
234 | if (succeeded)
235 | IncrementCursor(ref cursor, size);
236 | return succeeded;
237 | }
238 |
239 | private static void IncrementCursor(ref int cursor, int size) => cursor = checked(cursor + size);
240 |
241 | private static bool HasSpace(this ReadOnlySpan source, int space) => source.Length >= space;
242 |
243 | private static void ValidateCursor(int cursor) {
244 | if (cursor < 0)
245 | throw new ArgumentException("Cursor cannot be less than 0");
246 | }
247 | }
248 | }
249 |
--------------------------------------------------------------------------------
/src/SpanDex/SpanExtensions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace SpanDex.Extensions {
4 | public static class SpanExtensions {
5 | public static short ReadInt16BigEndian(this ReadOnlySpan source, ref int cursor) => SpanReading.ReadInt16BigEndian(source, ref cursor);
6 | public static short ReadInt16LittleEndian(this ReadOnlySpan source, ref int cursor) => SpanReading.ReadInt16LittleEndian(source, ref cursor);
7 | public static int ReadInt32BigEndian(this ReadOnlySpan source, ref int cursor) => SpanReading.ReadInt32BigEndian(source, ref cursor);
8 | public static int ReadInt32LittleEndian(this ReadOnlySpan source, ref int cursor) => SpanReading.ReadInt32LittleEndian(source, ref cursor);
9 | public static long ReadInt64BigEndian(this ReadOnlySpan source, ref int cursor) => SpanReading.ReadInt64BigEndian(source, ref cursor);
10 | public static long ReadInt64LittleEndian(this ReadOnlySpan source, ref int cursor) => SpanReading.ReadInt64LittleEndian(source, ref cursor);
11 |
12 | [CLSCompliant(false)]
13 | public static ushort ReadUInt16BigEndian(this ReadOnlySpan source, ref int cursor) => SpanReading.ReadUInt16BigEndian(source, ref cursor);
14 |
15 | [CLSCompliant(false)]
16 | public static ushort ReadUInt16LittleEndian(this ReadOnlySpan source, ref int cursor) => SpanReading.ReadUInt16LittleEndian(source, ref cursor);
17 |
18 | [CLSCompliant(false)]
19 | public static uint ReadUInt32BigEndian(this ReadOnlySpan source, ref int cursor) => SpanReading.ReadUInt32BigEndian(source, ref cursor);
20 |
21 | [CLSCompliant(false)]
22 | public static uint ReadUInt32LittleEndian(this ReadOnlySpan source, ref int cursor) => SpanReading.ReadUInt32LittleEndian(source, ref cursor);
23 |
24 | [CLSCompliant(false)]
25 | public static ulong ReadUInt64BigEndian(this ReadOnlySpan source, ref int cursor) => SpanReading.ReadUInt64BigEndian(source, ref cursor);
26 |
27 | [CLSCompliant(false)]
28 | public static ulong ReadUInt64LittleEndian(this ReadOnlySpan source, ref int cursor) => SpanReading.ReadUInt64LittleEndian(source, ref cursor);
29 |
30 | public static ReadOnlySpan ReadSpan(this ReadOnlySpan source, int size, ref int cursor) => SpanReading.ReadSpan(source, size, ref cursor);
31 | public static string ReadAsciiString(this ReadOnlySpan source, int size, ref int cursor) => SpanReading.ReadAsciiString(source, size, ref cursor);
32 | public static string ReadUtf8String(this ReadOnlySpan source, int size, ref int cursor) => SpanReading.ReadUtf8String(source, size, ref cursor);
33 | public static byte ReadByte(this ReadOnlySpan source, ref int cursor) => SpanReading.ReadByte(source, ref cursor);
34 | public static bool TryReadInt16BigEndian(this ReadOnlySpan source, out short value, ref int cursor) => SpanReading.TryReadInt16BigEndian(source, out value, ref cursor);
35 | public static bool TryReadInt16LittleEndian(this ReadOnlySpan source, out short value, ref int cursor) => SpanReading.TryReadInt16LittleEndian(source, out value, ref cursor);
36 | public static bool TryReadInt32BigEndian(this ReadOnlySpan source, out int value, ref int cursor) => SpanReading.TryReadInt32BigEndian(source, out value, ref cursor);
37 | public static bool TryReadInt32LittleEndian(this ReadOnlySpan source, out int value, ref int cursor) => SpanReading.TryReadInt32LittleEndian(source, out value, ref cursor);
38 | public static bool TryReadInt64BigEndian(this ReadOnlySpan source, out long value, ref int cursor) => SpanReading.TryReadInt64BigEndian(source, out value, ref cursor);
39 | public static bool TryReadInt64LittleEndian(this ReadOnlySpan source, out long value, ref int cursor) => SpanReading.TryReadInt64LittleEndian(source, out value, ref cursor);
40 |
41 | [CLSCompliant(false)]
42 | public static bool TryReadUInt16BigEndian(this ReadOnlySpan source, out ushort value, ref int cursor) => SpanReading.TryReadUInt16BigEndian(source, out value, ref cursor);
43 |
44 | [CLSCompliant(false)]
45 | public static bool TryReadUInt16LittleEndian(this ReadOnlySpan source, out ushort value, ref int cursor) => SpanReading.TryReadUInt16LittleEndian(source, out value, ref cursor);
46 |
47 | [CLSCompliant(false)]
48 | public static bool TryReadUInt32BigEndian(this ReadOnlySpan source, out uint value, ref int cursor) => SpanReading.TryReadUInt32BigEndian(source, out value, ref cursor);
49 |
50 | [CLSCompliant(false)]
51 | public static bool TryReadUInt32LittleEndian(this ReadOnlySpan source, out uint value, ref int cursor) => SpanReading.TryReadUInt32LittleEndian(source, out value, ref cursor);
52 |
53 | [CLSCompliant(false)]
54 | public static bool TryReadUInt64BigEndian(this ReadOnlySpan source, out ulong value, ref int cursor) => SpanReading.TryReadUInt64BigEndian(source, out value, ref cursor);
55 |
56 | [CLSCompliant(false)]
57 | public static bool TryReadUInt64LittleEndian(this ReadOnlySpan source, out ulong value, ref int cursor) => SpanReading.TryReadUInt64LittleEndian(source, out value, ref cursor);
58 |
59 | public static bool TryReadSpan(this ReadOnlySpan source, out ReadOnlySpan value, int size, ref int cursor) => SpanReading.TryReadSpan(source, out value, size, ref cursor);
60 | public static bool TryReadAsciiString(this ReadOnlySpan source, out string value, int size, ref int cursor) => SpanReading.TryReadAsciiString(source, out value, size, ref cursor);
61 | public static bool TryReadUtf8String(this ReadOnlySpan source, out string value, int size, ref int cursor) => SpanReading.TryReadUtf8String(source, out value, size, ref cursor);
62 | public static bool TryReadByte(this ReadOnlySpan source, out byte value, ref int cursor) => SpanReading.TryReadByte(source, out value, ref cursor);
63 | public static short ReadInt16BigEndian(this Span source, ref int cursor) => SpanReading.ReadInt16BigEndian(source, ref cursor);
64 | public static short ReadInt16LittleEndian(this Span source, ref int cursor) => SpanReading.ReadInt16LittleEndian(source, ref cursor);
65 | public static int ReadInt32BigEndian(this Span source, ref int cursor) => SpanReading.ReadInt32BigEndian(source, ref cursor);
66 | public static int ReadInt32LittleEndian(this Span source, ref int cursor) => SpanReading.ReadInt32LittleEndian(source, ref cursor);
67 | public static long ReadInt64BigEndian(this Span source, ref int cursor) => SpanReading.ReadInt64BigEndian(source, ref cursor);
68 | public static long ReadInt64LittleEndian(this Span source, ref int cursor) => SpanReading.ReadInt64LittleEndian(source, ref cursor);
69 |
70 | [CLSCompliant(false)]
71 | public static ushort ReadUInt16BigEndian(this Span source, ref int cursor) => SpanReading.ReadUInt16BigEndian(source, ref cursor);
72 |
73 | [CLSCompliant(false)]
74 | public static ushort ReadUInt16LittleEndian(this Span source, ref int cursor) => SpanReading.ReadUInt16LittleEndian(source, ref cursor);
75 |
76 | [CLSCompliant(false)]
77 | public static uint ReadUInt32BigEndian(this Span source, ref int cursor) => SpanReading.ReadUInt32BigEndian(source, ref cursor);
78 |
79 | [CLSCompliant(false)]
80 | public static uint ReadUInt32LittleEndian(this Span source, ref int cursor) => SpanReading.ReadUInt32LittleEndian(source, ref cursor);
81 |
82 | [CLSCompliant(false)]
83 | public static ulong ReadUInt64BigEndian(this Span source, ref int cursor) => SpanReading.ReadUInt64BigEndian(source, ref cursor);
84 |
85 | [CLSCompliant(false)]
86 | public static ulong ReadUInt64LittleEndian(this Span source, ref int cursor) => SpanReading.ReadUInt64LittleEndian(source, ref cursor);
87 |
88 | public static ReadOnlySpan ReadSpan(this Span source, int size, ref int cursor) => SpanReading.ReadSpan(source, size, ref cursor);
89 | public static string ReadAsciiString(this Span source, int size, ref int cursor) => SpanReading.ReadAsciiString(source, size, ref cursor);
90 | public static string ReadUtf8String(this Span source, int size, ref int cursor) => SpanReading.ReadUtf8String(source, size, ref cursor);
91 | public static byte ReadByte(this Span source, ref int cursor) => SpanReading.ReadByte(source, ref cursor);
92 | public static bool TryReadInt16BigEndian(this Span source, out short value, ref int cursor) => SpanReading.TryReadInt16BigEndian(source, out value, ref cursor);
93 | public static bool TryReadInt16LittleEndian(this Span source, out short value, ref int cursor) => SpanReading.TryReadInt16LittleEndian(source, out value, ref cursor);
94 | public static bool TryReadInt32BigEndian(this Span source, out int value, ref int cursor) => SpanReading.TryReadInt32BigEndian(source, out value, ref cursor);
95 | public static bool TryReadInt32LittleEndian(this Span source, out int value, ref int cursor) => SpanReading.TryReadInt32LittleEndian(source, out value, ref cursor);
96 | public static bool TryReadInt64BigEndian(this Span source, out long value, ref int cursor) => SpanReading.TryReadInt64BigEndian(source, out value, ref cursor);
97 | public static bool TryReadInt64LittleEndian(this Span source, out long value, ref int cursor) => SpanReading.TryReadInt64LittleEndian(source, out value, ref cursor);
98 |
99 | [CLSCompliant(false)]
100 | public static bool TryReadUInt16BigEndian(this Span source, out ushort value, ref int cursor) => SpanReading.TryReadUInt16BigEndian(source, out value, ref cursor);
101 |
102 | [CLSCompliant(false)]
103 | public static bool TryReadUInt16LittleEndian(this Span source, out ushort value, ref int cursor) => SpanReading.TryReadUInt16LittleEndian(source, out value, ref cursor);
104 |
105 | [CLSCompliant(false)]
106 | public static bool TryReadUInt32BigEndian(this Span source, out uint value, ref int cursor) => SpanReading.TryReadUInt32BigEndian(source, out value, ref cursor);
107 |
108 | [CLSCompliant(false)]
109 | public static bool TryReadUInt32LittleEndian(this Span source, out uint value, ref int cursor) => SpanReading.TryReadUInt32LittleEndian(source, out value, ref cursor);
110 |
111 | [CLSCompliant(false)]
112 | public static bool TryReadUInt64BigEndian(this Span source, out ulong value, ref int cursor) => SpanReading.TryReadUInt64BigEndian(source, out value, ref cursor);
113 |
114 | [CLSCompliant(false)]
115 | public static bool TryReadUInt64LittleEndian(this Span source, out ulong value, ref int cursor) => SpanReading.TryReadUInt64LittleEndian(source, out value, ref cursor);
116 |
117 | public static bool TryReadSpan(this Span source, out ReadOnlySpan value, int size, ref int cursor) => SpanReading.TryReadSpan(source, out value, size, ref cursor);
118 | public static bool TryReadAsciiString(this Span source, out string value, int size, ref int cursor) => SpanReading.TryReadAsciiString(source, out value, size, ref cursor);
119 | public static bool TryReadUtf8String(this Span source, out string value, int size, ref int cursor) => SpanReading.TryReadUtf8String(source, out value, size, ref cursor);
120 | public static bool TryReadByte(this Span source, out byte value, ref int cursor) => SpanReading.TryReadByte(source, out value, ref cursor);
121 |
122 | public static bool TryWriteInt16BigEndian(this Span destination, short value, ref int cursor) => SpanWriting.TryWriteInt16BigEndian(destination, value, ref cursor);
123 | public static bool TryWriteInt16LittleEndian(this Span destination, short value, ref int cursor) => SpanWriting.TryWriteInt16LittleEndian(destination, value, ref cursor);
124 | public static bool TryWriteInt32BigEndian(this Span destination, int value, ref int cursor) => SpanWriting.TryWriteInt32BigEndian(destination, value, ref cursor);
125 | public static bool TryWriteInt32LittleEndian(this Span destination, int value, ref int cursor) => SpanWriting.TryWriteInt32LittleEndian(destination, value, ref cursor);
126 | public static bool TryWriteInt64BigEndian(this Span destination, long value, ref int cursor) => SpanWriting.TryWriteInt64BigEndian(destination, value, ref cursor);
127 | public static bool TryWriteInt64LittleEndian(this Span destination, long value, ref int cursor) => SpanWriting.TryWriteInt64LittleEndian(destination, value, ref cursor);
128 |
129 | [CLSCompliant(false)]
130 | public static bool TryWriteUInt16BigEndian(this Span destination, ushort value, ref int cursor) => SpanWriting.TryWriteUInt16BigEndian(destination, value, ref cursor);
131 |
132 | [CLSCompliant(false)]
133 | public static bool TryWriteUInt16LittleEndian(this Span destination, ushort value, ref int cursor) => SpanWriting.TryWriteUInt16LittleEndian(destination, value, ref cursor);
134 |
135 | [CLSCompliant(false)]
136 | public static bool TryWriteUInt32BigEndian(this Span destination, uint value, ref int cursor) => SpanWriting.TryWriteUInt32BigEndian(destination, value, ref cursor);
137 |
138 | [CLSCompliant(false)]
139 | public static bool TryWriteUInt32LittleEndian(this Span destination, uint value, ref int cursor) => SpanWriting.TryWriteUInt32LittleEndian(destination, value, ref cursor);
140 |
141 | [CLSCompliant(false)]
142 | public static bool TryWriteUInt64BigEndian(this Span destination, ulong value, ref int cursor) => SpanWriting.TryWriteUInt64BigEndian(destination, value, ref cursor);
143 |
144 | [CLSCompliant(false)]
145 | public static bool TryWriteUInt64LittleEndian(this Span destination, ulong value, ref int cursor) => SpanWriting.TryWriteUInt64LittleEndian(destination, value, ref cursor);
146 |
147 | public static bool TryWriteSpan(this Span destination, ReadOnlySpan value, ref int cursor) => SpanWriting.TryWriteSpan(destination, value, ref cursor);
148 | public static bool TryWriteAsciiString(this Span destination, string value, ref int cursor) => SpanWriting.TryWriteAsciiString(destination, value, ref cursor);
149 | public static bool TryWriteUtf8String(this Span destination, string value, ref int cursor) => SpanWriting.TryWriteUtf8String(destination, value, ref cursor);
150 | public static bool TryWriteByte(this Span destination, byte value, ref int cursor) => SpanWriting.TryWriteByte(destination, value, ref cursor);
151 | public static void WriteInt16BigEndian(this Span destination, short value, ref int cursor) => SpanWriting.WriteInt16BigEndian(destination, value, ref cursor);
152 | public static void WriteInt16LittleEndian(this Span destination, short value, ref int cursor) => SpanWriting.WriteInt16LittleEndian(destination, value, ref cursor);
153 | public static void WriteInt32BigEndian(this Span destination, int value, ref int cursor) => SpanWriting.WriteInt32BigEndian(destination, value, ref cursor);
154 | public static void WriteInt32LittleEndian(this Span destination, int value, ref int cursor) => SpanWriting.WriteInt32LittleEndian(destination, value, ref cursor);
155 | public static void WriteInt64BigEndian(this Span destination, long value, ref int cursor) => SpanWriting.WriteInt64BigEndian(destination, value, ref cursor);
156 | public static void WriteInt64LittleEndian(this Span destination, long value, ref int cursor) => SpanWriting.WriteInt64LittleEndian(destination, value, ref cursor);
157 |
158 | [CLSCompliant(false)]
159 | public static void WriteUInt16BigEndian(this Span destination, ushort value, ref int cursor) => SpanWriting.WriteUInt16BigEndian(destination, value, ref cursor);
160 |
161 | [CLSCompliant(false)]
162 | public static void WriteUInt16LittleEndian(this Span destination, ushort value, ref int cursor) => SpanWriting.WriteUInt16LittleEndian(destination, value, ref cursor);
163 |
164 | [CLSCompliant(false)]
165 | public static void WriteUInt32BigEndian(this Span destination, uint value, ref int cursor) => SpanWriting.WriteUInt32BigEndian(destination, value, ref cursor);
166 |
167 | [CLSCompliant(false)]
168 | public static void WriteUInt32LittleEndian(this Span destination, uint value, ref int cursor) => SpanWriting.WriteUInt32LittleEndian(destination, value, ref cursor);
169 |
170 | [CLSCompliant(false)]
171 | public static void WriteUInt64BigEndian(this Span destination, ulong value, ref int cursor) => SpanWriting.WriteUInt64BigEndian(destination, value, ref cursor);
172 |
173 | [CLSCompliant(false)]
174 | public static void WriteUInt64LittleEndian(this Span destination, ulong value, ref int cursor) => SpanWriting.WriteUInt64LittleEndian(destination, value, ref cursor);
175 |
176 | public static void WriteSpan(this Span destination, ReadOnlySpan value, ref int cursor) => SpanWriting.WriteSpan(destination, value, ref cursor);
177 | public static void WriteAsciiString(this Span destination, string value, ref int cursor) => SpanWriting.WriteAsciiString(destination, value, ref cursor);
178 | public static void WriteUtf8String(this Span destination, string value, ref int cursor) => SpanWriting.WriteUtf8String(destination, value, ref cursor);
179 | public static void WriteByte(this Span destination, byte value, ref int cursor) => SpanWriting.WriteByte(destination, value, ref cursor);
180 | }
181 | }
182 |
--------------------------------------------------------------------------------
/tests/SpanDex.Tests/SpanExtensionTests.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.VisualStudio.TestTools.UnitTesting;
2 | using System;
3 | using SpanDex.Extensions;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Buffers.Binary;
7 |
8 | namespace SpanDex.Tests {
9 | internal enum Endianness {
10 | Little,
11 | Big
12 | }
13 |
14 | [TestClass]
15 | public class SpanExtensionTests {
16 | private int cursor = 0;
17 |
18 | [TestMethod]
19 | public void Read_NegativeSize_ThrowsArgumentException() {
20 | Assert.ThrowsException(() => {
21 | ReadOnlySpan span = new byte[1];
22 | span.ReadSpan(-1, ref cursor);
23 | });
24 | }
25 |
26 | [TestMethod]
27 | public void ReadInt16BigEndian_ReadsCorrectly() {
28 | var span = GetSpan((short)-31_971, Endianness.Big);
29 | var value = span.ReadInt16BigEndian(ref cursor);
30 | Assert.AreEqual(-31_971, value);
31 | }
32 |
33 | [TestMethod]
34 | public void ReadInt16LittleEndian_ReadsCorrectly() {
35 | var span = GetSpan(-31_971, Endianness.Little);
36 | var value = span.ReadInt16LittleEndian(ref cursor);
37 | Assert.AreEqual(-31_971, value);
38 | }
39 |
40 | [TestMethod]
41 | public void ReadInt32BigEndian_ReadsCorrectly() {
42 | var span = GetSpan(-1_598_468_598, Endianness.Big);
43 | var value = span.ReadInt32BigEndian(ref cursor);
44 | Assert.AreEqual(-1_598_468_598, value);
45 | }
46 |
47 | [TestMethod]
48 | public void ReadInt32LittleEndian_ReadsCorrectly() {
49 | var span = GetSpan(-1_598_468_598, Endianness.Little);
50 | var value = span.ReadInt32LittleEndian(ref cursor);
51 | Assert.AreEqual(-1_598_468_598, value);
52 | }
53 |
54 | [TestMethod]
55 | public void ReadInt64BigEndian_ReadsCorrectly() {
56 | var span = GetSpan(-7_223_372_036_854_775_808, Endianness.Big);
57 | var value = span.ReadInt64BigEndian(ref cursor);
58 | Assert.AreEqual(-7_223_372_036_854_775_808, value);
59 | }
60 |
61 | [TestMethod]
62 | public void ReadInt64LittleEndian_ReadsCorrectly() {
63 | var span = GetSpan(-7_223_372_036_854_775_808, Endianness.Little);
64 | var value = span.ReadInt64LittleEndian(ref cursor);
65 | Assert.AreEqual(-7_223_372_036_854_775_808, value);
66 | }
67 |
68 | [TestMethod]
69 | public void ReadUInt16BigEndian_ReadsCorrectly() {
70 | var span = GetSpan((ushort)26_598, Endianness.Big);
71 | var value = span.ReadUInt16BigEndian(ref cursor);
72 | Assert.AreEqual(26_598, value);
73 | }
74 |
75 | [TestMethod]
76 | public void ReadUInt16LittleEndian_ReadsCorrectly() {
77 | var span = GetSpan(26_598, Endianness.Little);
78 | var value = span.ReadUInt16LittleEndian(ref cursor);
79 | Assert.AreEqual(26_598, value);
80 | }
81 |
82 | [TestMethod]
83 | public void ReadUInt32BigEndian_ReadsCorrectly() {
84 | var span = GetSpan(4_293_568_955, Endianness.Big);
85 | var value = span.ReadUInt32BigEndian(ref cursor);
86 | Assert.AreEqual(4_293_568_955, value);
87 | }
88 |
89 | [TestMethod]
90 | public void ReadUInt32LittleEndian_ReadsCorrectly() {
91 | var span = GetSpan(4_293_568_955, Endianness.Little);
92 | var value = span.ReadUInt32LittleEndian(ref cursor);
93 | Assert.AreEqual(4_293_568_955, value);
94 | }
95 |
96 | [TestMethod]
97 | public void ReadUInt64BigEndian_ReadsCorrectly() {
98 | var span = GetSpan(18_378_564_784_564_235_456, Endianness.Big);
99 | var value = span.ReadUInt64BigEndian(ref cursor);
100 | Assert.AreEqual(18_378_564_784_564_235_456, value);
101 | }
102 |
103 | [TestMethod]
104 | public void ReadUInt64LittleEndian_ReadsCorrectly() {
105 | var span = GetSpan(18_378_564_784_564_235_456, Endianness.Little);
106 | var value = span.ReadUInt64LittleEndian(ref cursor);
107 | Assert.AreEqual(18_378_564_784_564_235_456, value);
108 | }
109 |
110 | [TestMethod]
111 | public void ReadSpan_ReadsCorrectly() {
112 | ReadOnlySpan span = new byte[10];
113 | var value = span.ReadSpan(10, ref cursor);
114 |
115 | Assert.AreEqual(span.Length, cursor);
116 | CollectionAssert.AreEqual(span.ToArray(), value.ToArray());
117 | }
118 |
119 | [TestMethod]
120 | public void ReadAsciiString_ReadsCorrectly() {
121 | const string testString = "A little more than one hundred days into the fortieth year of her confinement, Dajeil Gelian was visited in her lonely tower overlooking the sea by an avatar of the great ship that was her home.";
122 | var bytes = Encoding.ASCII.GetBytes(testString);
123 | ReadOnlySpan span = bytes;
124 | var value = span.ReadAsciiString(testString.Length, ref cursor);
125 |
126 | Assert.AreEqual(testString, value);
127 | Assert.AreEqual(testString.Length, cursor);
128 | }
129 |
130 | [TestMethod]
131 | public void ReadUtf8String_ReadsCorrectly() {
132 | const string testString = "A little more than one hundred days into the fortieth year of her confinement, Dajeil Gelian was visited in her lonely tower overlooking the sea by an avatar of the great ship that was her home.";
133 | var bytes = Encoding.UTF8.GetBytes(testString);
134 | ReadOnlySpan span = bytes;
135 | var value = span.ReadUtf8String(testString.Length, ref cursor);
136 |
137 | Assert.AreEqual(testString, value);
138 | Assert.AreEqual(testString.Length, cursor);
139 | }
140 |
141 | [TestMethod]
142 | public void ReadByte_ReadsCorrectly() {
143 | ReadOnlySpan span = new byte[1] { 253 };
144 | var value = span.ReadByte(ref cursor);
145 |
146 | Assert.AreEqual(253, value);
147 | }
148 |
149 | [TestMethod]
150 |
151 | public void TryReadInt16BigEndian_ReadsCorrectly() {
152 | var span = GetSpan((short)-31_971, Endianness.Big);
153 | if (span.TryReadInt16BigEndian(out short value, ref cursor)) {
154 | Assert.AreEqual(-31_971, value);
155 | } else {
156 | Assert.Fail();
157 | }
158 | }
159 |
160 | [TestMethod]
161 | public void TryReadInt16LittleEndian_ReadsCorrectly() {
162 | var span = GetSpan((short)-31_971, Endianness.Little);
163 | if (span.TryReadInt16LittleEndian(out short value, ref cursor)) {
164 | Assert.AreEqual(-31_971, value);
165 | } else {
166 | Assert.Fail();
167 | }
168 | }
169 |
170 | [TestMethod]
171 | public void TryReadInt32BigEndian_ReadsCorrectly() {
172 | var span = GetSpan(-1_598_468_598, Endianness.Big);
173 | if (span.TryReadInt32BigEndian(out int value, ref cursor)) {
174 | Assert.AreEqual(-1_598_468_598, value);
175 | } else {
176 | Assert.Fail();
177 | }
178 | }
179 |
180 | [TestMethod]
181 | public void TryReadInt32LittleEndian_ReadsCorrectly() {
182 | var span = GetSpan(-1_598_468_598, Endianness.Little);
183 | if (span.TryReadInt32LittleEndian(out int value, ref cursor)) {
184 | Assert.AreEqual(-1_598_468_598, value);
185 | } else {
186 | Assert.Fail();
187 | }
188 | }
189 |
190 | [TestMethod]
191 | public void TryReadInt64BigEndian_ReadsCorrectly() {
192 | var span = GetSpan(-7_223_372_036_854_775_808, Endianness.Big);
193 | if (span.TryReadInt64BigEndian(out long value, ref cursor)) {
194 | Assert.AreEqual(-7_223_372_036_854_775_808, value);
195 | } else {
196 | Assert.Fail();
197 | }
198 | }
199 |
200 | [TestMethod]
201 | public void TryReadInt64LittleEndian_ReadsCorrectly() {
202 | var span = GetSpan(-7_223_372_036_854_775_808, Endianness.Little);
203 | if (span.TryReadInt64LittleEndian(out long value, ref cursor)) {
204 | Assert.AreEqual(-7_223_372_036_854_775_808, value);
205 | } else {
206 | Assert.Fail();
207 | }
208 | }
209 |
210 | [TestMethod]
211 | public void TryReadUInt16BigEndian_ReadsCorrectly() {
212 | var span = GetSpan((ushort)26_598, Endianness.Big);
213 | if (span.TryReadUInt16BigEndian(out ushort value, ref cursor)) {
214 | Assert.AreEqual(26_598, value);
215 | } else {
216 | Assert.Fail();
217 | }
218 | }
219 |
220 | [TestMethod]
221 | public void TryReadUInt16LittleEndian_ReadsCorrectly() {
222 | var span = GetSpan((ushort)26_598, Endianness.Little);
223 | if (span.TryReadUInt16LittleEndian(out ushort value, ref cursor)) {
224 | Assert.AreEqual(26_598, value);
225 | } else {
226 | Assert.Fail();
227 | }
228 | }
229 |
230 | [TestMethod]
231 | public void TryReadUInt32BigEndian_ReadsCorrectly() {
232 | var span = GetSpan(4_293_568_955, Endianness.Big);
233 | if (span.TryReadUInt32BigEndian(out uint value, ref cursor)) {
234 | Assert.AreEqual(4_293_568_955, value);
235 | } else {
236 | Assert.Fail();
237 | }
238 | }
239 |
240 | [TestMethod]
241 | public void TryReadUInt32LittleEndian_ReadsCorrectly() {
242 | var span = GetSpan(4_293_568_955, Endianness.Little);
243 | if (span.TryReadUInt32LittleEndian(out uint value, ref cursor)) {
244 | Assert.AreEqual(4_293_568_955, value);
245 | } else {
246 | Assert.Fail();
247 | }
248 | }
249 |
250 | [TestMethod]
251 | public void TryReadUInt64BigEndian_ReadsCorrectly() {
252 | var span = GetSpan(18_378_564_784_564_235_456, Endianness.Big);
253 | if (span.TryReadUInt64BigEndian(out ulong value, ref cursor)) {
254 | Assert.AreEqual(18_378_564_784_564_235_456, value);
255 | } else {
256 | Assert.Fail();
257 | }
258 | }
259 |
260 | [TestMethod]
261 | public void TryReadUInt64LittleEndian_ReadsCorrectly() {
262 | var span = GetSpan(18_378_564_784_564_235_456, Endianness.Little);
263 | if (span.TryReadUInt64LittleEndian(out ulong value, ref cursor)) {
264 | Assert.AreEqual(18_378_564_784_564_235_456, value);
265 | } else {
266 | Assert.Fail();
267 | }
268 | }
269 |
270 | [TestMethod]
271 | public void TryReadUInt64LittleEndian_NegativeCursor_ThrowsArgumentException() {
272 | Assert.ThrowsException(() => {
273 | var span = GetSpan(18_378_564_784_564_235_456, Endianness.Little);
274 | cursor = -1;
275 | span.TryReadUInt64LittleEndian(out ulong value, ref cursor);
276 | });
277 | }
278 |
279 | [TestMethod]
280 | public void TryReadSpan_ReadsCorrectly() {
281 | ReadOnlySpan span = new byte[10];
282 | if(span.TryReadSpan(out var value, 10, ref cursor)) {
283 | Assert.AreEqual(span.Length, cursor);
284 | CollectionAssert.AreEqual(span.ToArray(), value.ToArray());
285 | } else {
286 | Assert.Fail();
287 | }
288 | }
289 |
290 | [TestMethod]
291 | public void TryReadSpan_IncorrectLength_Fails() {
292 | ReadOnlySpan span = new byte[10];
293 | if (span.TryReadSpan(out var _, 20, ref cursor)) {
294 | Assert.Fail();
295 | } else {
296 | Assert.AreEqual(0, cursor);
297 | }
298 | }
299 |
300 | [TestMethod]
301 | public void TryReadAsciiString_ReadsCorrectly() {
302 | const string testString = "A little more than one hundred days into the fortieth year of her confinement, Dajeil Gelian was visited in her lonely tower overlooking the sea by an avatar of the great ship that was her home.";
303 | var bytes = Encoding.ASCII.GetBytes(testString);
304 | ReadOnlySpan span = bytes;
305 |
306 | if(span.TryReadAsciiString(out var value, testString.Length, ref cursor)) {
307 | Assert.AreEqual(testString, value);
308 | Assert.AreEqual(testString.Length, cursor);
309 | } else {
310 | Assert.Fail();
311 | }
312 | }
313 |
314 | [TestMethod]
315 | public void TryReadUtf8String_ReadsCorrectly() {
316 | const string testString = "A little more than one hundred days into the fortieth year of her confinement, Dajeil Gelian was visited in her lonely tower overlooking the sea by an avatar of the great ship that was her home.";
317 | var bytes = Encoding.UTF8.GetBytes(testString);
318 | ReadOnlySpan span = bytes;
319 | if(span.TryReadUtf8String(out var value, testString.Length, ref cursor)) {
320 | Assert.AreEqual(testString, value);
321 | Assert.AreEqual(testString.Length, cursor);
322 | } else {
323 | Assert.Fail();
324 | }
325 | }
326 |
327 | [TestMethod]
328 | public void TryReadByte_ReadsCorrectly() {
329 | ReadOnlySpan span = new byte[1] { 253 };
330 | if(span.TryReadByte(out var value, ref cursor)) {
331 | Assert.AreEqual(253, value);
332 | Assert.AreEqual(1, cursor);
333 | } else {
334 | Assert.Fail();
335 | }
336 | }
337 |
338 | [TestMethod]
339 | public void TryWriteInt16BigEndian_WritesCorrectly() {
340 | var bitConverterSpan = GetSpan((short)-31_971, Endianness.Big);
341 | Span span = new byte[sizeof(short)];
342 | var succeeded = span.TryWriteInt16BigEndian(-31_971, ref cursor);
343 |
344 | Assert.IsTrue(succeeded);
345 | Assert.AreEqual(sizeof(short), cursor);
346 | CollectionAssert.AreEqual(bitConverterSpan.ToArray(), span.ToArray());
347 | }
348 |
349 | [TestMethod]
350 | public void TryWriteInt16LittleEndian_WritesCorrectly() {
351 | var bitConverterSpan = GetSpan((short)-31_971, Endianness.Little);
352 | Span span = new byte[sizeof(short)];
353 | var succeeded = span.TryWriteInt16LittleEndian(-31_971, ref cursor);
354 |
355 | Assert.IsTrue(succeeded);
356 | Assert.AreEqual(sizeof(short), cursor);
357 | CollectionAssert.AreEqual(bitConverterSpan.ToArray(), span.ToArray());
358 | }
359 |
360 | [TestMethod]
361 | public void TryWriteInt32BigEndian_WritesCorrectly() {
362 | var bitConverterSpan = GetSpan(-1_598_468_598, Endianness.Big);
363 | Span span = new byte[sizeof(int)];
364 | var succeeded = span.TryWriteInt32BigEndian(-1_598_468_598, ref cursor);
365 |
366 | Assert.IsTrue(succeeded);
367 | Assert.AreEqual(sizeof(int), cursor);
368 | CollectionAssert.AreEqual(bitConverterSpan.ToArray(), span.ToArray());
369 | }
370 |
371 | [TestMethod]
372 | public void TryWriteInt32LittleEndian_WritesCorrectly() {
373 | var bitConverterSpan = GetSpan(-1_598_468_598, Endianness.Little);
374 | Span span = new byte[sizeof(int)];
375 | var succeeded = span.TryWriteInt32LittleEndian(-1_598_468_598, ref cursor);
376 |
377 | Assert.IsTrue(succeeded);
378 | Assert.AreEqual(sizeof(int), cursor);
379 | CollectionAssert.AreEqual(bitConverterSpan.ToArray(), span.ToArray());
380 | }
381 |
382 | [TestMethod]
383 | public void TryWriteInt64BigEndian_WritesCorrectly() {
384 | var bitConverterSpan = GetSpan(-7_223_372_036_854_775_808, Endianness.Big);
385 | Span span = new byte[sizeof(long)];
386 | var succeeded = span.TryWriteInt64BigEndian(-7_223_372_036_854_775_808, ref cursor);
387 |
388 | Assert.IsTrue(succeeded);
389 | Assert.AreEqual(sizeof(long), cursor);
390 | CollectionAssert.AreEqual(bitConverterSpan.ToArray(), span.ToArray());
391 | }
392 |
393 | [TestMethod]
394 | public void TryWriteInt64LittleEndian_WritesCorrectly() {
395 | var bitConverterSpan = GetSpan(-7_223_372_036_854_775_808, Endianness.Little);
396 | Span span = new byte[sizeof(long)];
397 | var succeeded = span.TryWriteInt64LittleEndian(-7_223_372_036_854_775_808, ref cursor);
398 |
399 | Assert.IsTrue(succeeded);
400 | Assert.AreEqual(sizeof(long), cursor);
401 | CollectionAssert.AreEqual(bitConverterSpan.ToArray(), span.ToArray());
402 | }
403 |
404 | [TestMethod]
405 | public void TryWriteUInt16BigEndian_WritesCorrectly() {
406 | var bitConverterSpan = GetSpan((ushort)26_598, Endianness.Big);
407 | Span span = new byte[sizeof(ushort)];
408 | var succeeded = span.TryWriteUInt16BigEndian(26_598, ref cursor);
409 |
410 | Assert.IsTrue(succeeded);
411 | Assert.AreEqual(sizeof(ushort), cursor);
412 | CollectionAssert.AreEqual(bitConverterSpan.ToArray(), span.ToArray());
413 | }
414 |
415 | [TestMethod]
416 | public void TryWriteUInt16LittleEndian_WritesCorrectly() {
417 | var bitConverterSpan = GetSpan((ushort)26_598, Endianness.Little);
418 | Span span = new byte[sizeof(ushort)];
419 | var succeeded = span.TryWriteUInt16LittleEndian(26_598, ref cursor);
420 |
421 | Assert.IsTrue(succeeded);
422 | Assert.AreEqual(sizeof(ushort), cursor);
423 | CollectionAssert.AreEqual(bitConverterSpan.ToArray(), span.ToArray());
424 | }
425 |
426 | [TestMethod]
427 | public void TryWriteUInt32BigEndian_WritesCorrectly() {
428 | var bitConverterSpan = GetSpan(4_293_568_955, Endianness.Big);
429 | Span span = new byte[sizeof(uint)];
430 | var succeeded = span.TryWriteUInt32BigEndian(4_293_568_955, ref cursor);
431 |
432 | Assert.IsTrue(succeeded);
433 | Assert.AreEqual(sizeof(uint), cursor);
434 | CollectionAssert.AreEqual(bitConverterSpan.ToArray(), span.ToArray());
435 | }
436 |
437 | [TestMethod]
438 | public void TryWriteUInt32LittleEndian_WritesCorrectly() {
439 | var bitConverterSpan = GetSpan(4_293_568_955, Endianness.Little);
440 | Span span = new byte[sizeof(uint)];
441 | var succeeded = span.TryWriteUInt32LittleEndian(4_293_568_955, ref cursor);
442 |
443 | Assert.IsTrue(succeeded);
444 | Assert.AreEqual(sizeof(uint), cursor);
445 | CollectionAssert.AreEqual(bitConverterSpan.ToArray(), span.ToArray());
446 | }
447 |
448 | [TestMethod]
449 | public void TryWriteUInt64BigEndian_WritesCorrectly() {
450 | var bitConverterSpan = GetSpan(18_378_564_784_564_235_456, Endianness.Big);
451 | Span span = new byte[sizeof(ulong)];
452 | var succeeded = span.TryWriteUInt64BigEndian(18_378_564_784_564_235_456, ref cursor);
453 |
454 | Assert.IsTrue(succeeded);
455 | Assert.AreEqual(sizeof(ulong), cursor);
456 | CollectionAssert.AreEqual(bitConverterSpan.ToArray(), span.ToArray());
457 | }
458 |
459 | [TestMethod]
460 | public void TryWriteUInt64LittleEndian_WritesCorrectly() {
461 | var bitConverterSpan = GetSpan(18_378_564_784_564_235_456, Endianness.Little);
462 | Span span = new byte[sizeof(ulong)];
463 | var succeeded = span.TryWriteUInt64LittleEndian(18_378_564_784_564_235_456, ref cursor);
464 |
465 | Assert.IsTrue(succeeded);
466 | Assert.AreEqual(sizeof(ulong), cursor);
467 | CollectionAssert.AreEqual(bitConverterSpan.ToArray(), span.ToArray());
468 | }
469 |
470 | [TestMethod]
471 | public void TryWriteSpan_WritesCorrectly() {
472 | Span span = new byte[10];
473 | var toWrite = new byte[10] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
474 | var succeeded = span.TryWriteSpan(toWrite, ref cursor);
475 |
476 | Assert.IsTrue(succeeded);
477 | Assert.AreEqual(toWrite.Length, cursor);
478 | CollectionAssert.AreEqual(toWrite.ToArray(), span.ToArray());
479 | }
480 |
481 | [TestMethod]
482 | public void TryWriteSpan_IncorrectSize_Fails() {
483 | Span span = new byte[1];
484 | var toWrite = new byte[10] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
485 | var succeeded = span.TryWriteSpan(toWrite, ref cursor);
486 |
487 | Assert.IsFalse(succeeded);
488 | }
489 |
490 | [TestMethod]
491 | public void TryWriteAsciiString_WritesCorrectly() {
492 | Span span = new byte[11];
493 | const string toWrite = "test string";
494 | var succeeded = span.TryWriteAsciiString(toWrite, ref cursor);
495 |
496 | var encodingArray = Encoding.ASCII.GetBytes(toWrite);
497 |
498 | Assert.IsTrue(succeeded);
499 | Assert.AreEqual(toWrite.Length, cursor);
500 | CollectionAssert.AreEqual(encodingArray, span.ToArray());
501 | }
502 |
503 | [TestMethod]
504 | public void TryWriteUtf8String_WritesCorrectly() {
505 | Span span = new byte[11];
506 | const string toWrite = "test string";
507 | var succeeded = span.TryWriteUtf8String(toWrite, ref cursor);
508 | var encodingArray = Encoding.UTF8.GetBytes(toWrite);
509 |
510 | Assert.IsTrue(succeeded);
511 | Assert.AreEqual(toWrite.Length, cursor);
512 | CollectionAssert.AreEqual(encodingArray, span.ToArray());
513 | }
514 |
515 | [TestMethod]
516 | public void TryWriteByte_WritesCorrectly() {
517 | Span span = new byte[1];
518 | const byte toWrite = 234;
519 | var succeeded = span.TryWriteByte(toWrite, ref cursor);
520 |
521 | Assert.IsTrue(succeeded);
522 | Assert.AreEqual(1, cursor);
523 | Assert.AreEqual(toWrite, span[0]);
524 | }
525 |
526 | [TestMethod]
527 | public void WriteInt16BigEndian_WritesCorrectly() {
528 | var bitConverterSpan = GetSpan((short)-31_971, Endianness.Big);
529 | Span span = new byte[sizeof(short)];
530 | span.WriteInt16BigEndian(-31_971, ref cursor);
531 |
532 | Assert.AreEqual(sizeof(short), cursor);
533 | CollectionAssert.AreEqual(bitConverterSpan.ToArray(), span.ToArray());
534 | }
535 |
536 | [TestMethod]
537 | public void WriteInt16LittleEndian_WritesCorrectly() {
538 | var bitConverterSpan = GetSpan((short)-31_971, Endianness.Little);
539 | Span span = new byte[sizeof(short)];
540 | span.WriteInt16LittleEndian(-31_971, ref cursor);
541 |
542 | Assert.AreEqual(sizeof(short), cursor);
543 | CollectionAssert.AreEqual(bitConverterSpan.ToArray(), span.ToArray());
544 | }
545 |
546 | [TestMethod]
547 | public void WriteInt32BigEndian_WritesCorrectly() {
548 | var bitConverterSpan = GetSpan(-1_598_468_598, Endianness.Big);
549 | Span span = new byte[sizeof(int)];
550 | span.WriteInt32BigEndian(-1_598_468_598, ref cursor);
551 |
552 | Assert.AreEqual(sizeof(int), cursor);
553 | CollectionAssert.AreEqual(bitConverterSpan.ToArray(), span.ToArray());
554 | }
555 |
556 | [TestMethod]
557 | public void WriteInt32LittleEndian_WritesCorrectly() {
558 | var bitConverterSpan = GetSpan(-1_598_468_598, Endianness.Little);
559 | Span span = new byte[sizeof(int)];
560 | span.WriteInt32LittleEndian(-1_598_468_598, ref cursor);
561 |
562 | Assert.AreEqual(sizeof(int), cursor);
563 | CollectionAssert.AreEqual(bitConverterSpan.ToArray(), span.ToArray());
564 | }
565 |
566 | [TestMethod]
567 | public void WriteInt64BigEndian_WritesCorrectly() {
568 | var bitConverterSpan = GetSpan(-7_223_372_036_854_775_808, Endianness.Big);
569 | Span span = new byte[sizeof(long)];
570 | span.WriteInt64BigEndian(-7_223_372_036_854_775_808, ref cursor);
571 |
572 | Assert.AreEqual(sizeof(long), cursor);
573 | CollectionAssert.AreEqual(bitConverterSpan.ToArray(), span.ToArray());
574 | }
575 |
576 | [TestMethod]
577 | public void WriteInt64LittleEndian_WritesCorrectly() {
578 | var bitConverterSpan = GetSpan(-7_223_372_036_854_775_808, Endianness.Little);
579 | Span span = new byte[sizeof(long)];
580 | span.WriteInt64LittleEndian(-7_223_372_036_854_775_808, ref cursor);
581 |
582 | Assert.AreEqual(sizeof(long), cursor);
583 | CollectionAssert.AreEqual(bitConverterSpan.ToArray(), span.ToArray());
584 | }
585 |
586 | [TestMethod]
587 | public void WriteUInt16BigEndian_WritesCorrectly() {
588 | var bitConverterSpan = GetSpan((ushort)26_598, Endianness.Big);
589 | Span span = new byte[sizeof(ushort)];
590 | span.WriteUInt16BigEndian(26_598, ref cursor);
591 |
592 | Assert.AreEqual(sizeof(ushort), cursor);
593 | CollectionAssert.AreEqual(bitConverterSpan.ToArray(), span.ToArray());
594 | }
595 |
596 | [TestMethod]
597 | public void WriteUInt16LittleEndian_WritesCorrectly() {
598 | var bitConverterSpan = GetSpan((ushort)26_598, Endianness.Little);
599 | Span span = new byte[sizeof(ushort)];
600 | span.WriteUInt16LittleEndian(26_598, ref cursor);
601 |
602 | Assert.AreEqual(sizeof(ushort), cursor);
603 | CollectionAssert.AreEqual(bitConverterSpan.ToArray(), span.ToArray());
604 | }
605 |
606 | [TestMethod]
607 | public void WriteUInt32BigEndian_WritesCorrectly() {
608 | var bitConverterSpan = GetSpan(4_293_568_955, Endianness.Big);
609 | Span span = new byte[sizeof(uint)];
610 | span.WriteUInt32BigEndian(4_293_568_955, ref cursor);
611 |
612 | Assert.AreEqual(sizeof(uint), cursor);
613 | CollectionAssert.AreEqual(bitConverterSpan.ToArray(), span.ToArray());
614 | }
615 |
616 | [TestMethod]
617 | public void WriteUInt32LittleEndian_WritesCorrectly() {
618 | var bitConverterSpan = GetSpan(4_293_568_955, Endianness.Little);
619 | Span span = new byte[sizeof(uint)];
620 | span.WriteUInt32LittleEndian(4_293_568_955, ref cursor);
621 |
622 | Assert.AreEqual(sizeof(uint), cursor);
623 | CollectionAssert.AreEqual(bitConverterSpan.ToArray(), span.ToArray());
624 | }
625 |
626 | [TestMethod]
627 | public void WriteUInt64BigEndian_WritesCorrectly() {
628 | var bitConverterSpan = GetSpan(18_378_564_784_564_235_456, Endianness.Big);
629 | Span span = new byte[sizeof(ulong)];
630 | span.WriteUInt64BigEndian(18_378_564_784_564_235_456, ref cursor);
631 |
632 | Assert.AreEqual(sizeof(ulong), cursor);
633 | CollectionAssert.AreEqual(bitConverterSpan.ToArray(), span.ToArray());
634 | }
635 |
636 | [TestMethod]
637 | public void WriteUInt64LittleEndian_WritesCorrectly() {
638 | var bitConverterSpan = GetSpan(18_378_564_784_564_235_456, Endianness.Little);
639 | Span span = new byte[sizeof(ulong)];
640 | span.WriteUInt64LittleEndian(18_378_564_784_564_235_456, ref cursor);
641 |
642 | Assert.AreEqual(sizeof(ulong), cursor);
643 | CollectionAssert.AreEqual(bitConverterSpan.ToArray(), span.ToArray());
644 | }
645 |
646 | [TestMethod]
647 | public void WriteSpan_WritesCorrectly() {
648 | Span span = new byte[10];
649 | var toWrite = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
650 |
651 | span.WriteSpan(toWrite, ref cursor);
652 |
653 | Assert.AreEqual(toWrite.Length, cursor);
654 | CollectionAssert.AreEqual(toWrite, span.ToArray());
655 | }
656 |
657 | [TestMethod]
658 | public void WriteSpan_Null_ThrowsArgumentNullException() {
659 | Assert.ThrowsException(() => {
660 | Span span = new byte[10];
661 | byte[] toWrite = null;
662 |
663 | span.WriteSpan(toWrite, ref cursor);
664 | });
665 | }
666 |
667 | [TestMethod]
668 | public void WriteAsciiString_WritesCorrectly() {
669 | Span span = new byte[11];
670 | const string toWrite = "test string";
671 | var encodingArray = Encoding.ASCII.GetBytes(toWrite);
672 |
673 | span.WriteAsciiString(toWrite, ref cursor);
674 |
675 | Assert.AreEqual(toWrite.Length, cursor);
676 | CollectionAssert.AreEqual(encodingArray, span.ToArray());
677 | }
678 |
679 | [TestMethod]
680 | public void WriteAsciiString_Null_ThrowsArgumentNullException() {
681 | Assert.ThrowsException(() => {
682 | Span span = new byte[11];
683 | const string toWrite = null;
684 |
685 | span.WriteAsciiString(toWrite, ref cursor);
686 | });
687 | }
688 |
689 | [TestMethod]
690 | public void WriteAsciiString_Empty_DoesntThrow() {
691 | Span span = new byte[11];
692 | var toWrite = string.Empty;
693 |
694 | span.WriteAsciiString(toWrite, ref cursor);
695 |
696 | Assert.AreEqual(toWrite.Length, cursor);
697 | }
698 |
699 | [TestMethod]
700 | public void WriteUT8String_WritesCorrectly() {
701 | Span span = new byte[11];
702 | const string toWrite = "test string";
703 | var encodingArray = Encoding.UTF8.GetBytes(toWrite);
704 |
705 | span.WriteUtf8String(toWrite, ref cursor);
706 |
707 | Assert.AreEqual(toWrite.Length, cursor);
708 | CollectionAssert.AreEqual(encodingArray, span.ToArray());
709 | }
710 |
711 | [TestMethod]
712 | public void WriteByte_WritesCorrectly() {
713 | Span