Created
March 16, 2021 08:15
-
-
Save xoofx/4bda0160ff8adc20b3096cbd8270e727 to your computer and use it in GitHub Desktop.
Unpack variable 1-4 int
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// From Twitter discussion: https://twitter.com/firstdrafthell/status/1371704847783895042 | |
// | |
// | Method | Mean | Error | StdDev | | |
// |----------------------------- |----------:|----------:|----------:| | |
// | TestUnpack | 25.454 ns | 0.1450 ns | 0.1356 ns | | |
// | TestUnpack2 | 25.033 ns | 0.0853 ns | 0.0798 ns | | |
// | TestUnpackWithSpan | 6.936 ns | 0.0535 ns | 0.0500 ns | | |
// | TestUnpackWithSpanStackAlloc | 8.733 ns | 0.1149 ns | 0.1075 ns | | |
using System; | |
using System.Buffers.Binary; | |
using System.IO; | |
using System.Runtime.CompilerServices; | |
using BenchmarkDotNet.Attributes; | |
using BenchmarkDotNet.Running; | |
public class Program | |
{ | |
private static readonly BinaryReader Reader = new BinaryReader(new InfiniteStream()); | |
private static int _length; | |
private static int NextLength() => (_length++ & 3) + 1; | |
[Benchmark] | |
public void TestUnpack() | |
{ | |
Unpack(Reader, NextLength()); | |
} | |
[Benchmark] | |
public void TestUnpack2() | |
{ | |
Unpack2(Reader, NextLength()); | |
} | |
[Benchmark] | |
public void TestUnpackWithSpan() | |
{ | |
UnpackWithSpan(Reader, NextLength()); | |
} | |
[Benchmark] | |
public void TestUnpackWithSpanStackAlloc() | |
{ | |
UnpackWithSpanStackAlloc(Reader, NextLength()); | |
} | |
public int Unpack2(BinaryReader reader, int length) | |
{ | |
var result = 0; | |
for (var offset = 8 * (length - 1); offset >= 0; offset -= 8) | |
result += reader.ReadByte() << offset; | |
return result; | |
} | |
public static int Unpack(BinaryReader reader, int length) | |
{ | |
var result = 0; | |
for (var index = 0; index < length; index++) | |
{ | |
var offset = 8 * (length - index - 1); | |
var value = reader.ReadByte(); | |
result |= offset == 0 ? value : value << offset; | |
} | |
return result; | |
} | |
[SkipLocalsInit] | |
public static unsafe int UnpackWithSpan(BinaryReader reader, int length) | |
{ | |
uint data = 0; | |
reader.Read(new Span<byte>(&data, length)); | |
return (int)((BitConverter.IsLittleEndian ? BinaryPrimitives.ReverseEndianness(data) : data) >> ((4 - length) << 3)); | |
} | |
public static int UnpackWithSpanStackAlloc(BinaryReader reader, int length) | |
{ | |
Span<byte> buffer = stackalloc byte[4]; | |
reader.Read(buffer); | |
var data = BitConverter.ToUInt32(buffer); | |
return (int)((BitConverter.IsLittleEndian ? BinaryPrimitives.ReverseEndianness(data) : data) >> ((4 - length) << 3)); | |
} | |
private static void Main(string[] args) | |
{ | |
BenchmarkRunner.Run<Program>(); | |
} | |
private class InfiniteStream : Stream | |
{ | |
public override void Flush() | |
{ | |
} | |
public override int Read(byte[] buffer, int offset, int count) | |
{ | |
Position += count; | |
return count; | |
} | |
public override int Read(Span<byte> buffer) | |
{ | |
Position += buffer.Length; | |
return buffer.Length; | |
} | |
public override long Seek(long offset, SeekOrigin origin) | |
{ | |
return offset; | |
} | |
public override void SetLength(long value) | |
{ | |
} | |
public override void Write(byte[] buffer, int offset, int count) | |
{ | |
} | |
public override bool CanRead => true; | |
public override bool CanSeek => true; | |
public override bool CanWrite => true; | |
public override long Length => long.MaxValue; | |
public override long Position { get; set; } | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment