Skip to content

Instantly share code, notes, and snippets.

@olivier-spinelli
Created December 20, 2021 09:18
Show Gist options
  • Save olivier-spinelli/2697fbbe124f377056786e9284882a38 to your computer and use it in GitHub Desktop.
Save olivier-spinelli/2697fbbe124f377056786e9284882a38 to your computer and use it in GitHub Desktop.
using System;
using System.Runtime.CompilerServices;
public ref struct ROSpanMatcher
{
public ReadOnlySpan<char> Head;
public int _le;
public ROSpanMatcher( ReadOnlySpan<char> text )
{
Head = text;
_le = 7;
}
[MethodImpl( MethodImplOptions.AggressiveInlining )]
public int UncheckedForward( int length )
{
// Slice throws ArgumentOutOfRangeException if length is negative.
Head = Head[length..];
return Head.Length;
}
[MethodImpl( MethodImplOptions.AggressiveInlining )]
public int Forward( int length )
{
// Slice throws ArgumentOutOfRangeException if length is negative.
Head = Head.Slice( Math.Min( length, Head.Length ) );
return Head.Length;
}
}
public class C {
public static bool TryMatch( ref ReadOnlySpan<char> h, out char color )
{
color = default;
if( h.Length == 0 ) return false;
switch( h[0] )
{
case 'W': color = 'w'; break;
case 'R': color = 'r'; break;
case 'G': color = 'g'; break;
default: return false;
};
h = h.Slice( 1 );
return true;
}
// 3 more bytes.
public static bool TryMatch( ref ROSpanMatcher h, out char color )
{
color = default;
if( h.Head.Length == 0 ) return false;
switch( h.Head[0] )
{
case 'W': color = 'w'; break;
case 'R': color = 'r'; break;
case 'G': color = 'g'; break;
default: return false;
};
h.Head = h.Head.Slice( 1 );
return true;
}
// Using the range operator costs 9 bytes...
public static bool TryMatchBad( ref ROSpanMatcher h, out char color )
{
color = default;
if( h.Head.Length == 0 ) return false;
switch( h.Head[0] )
{
case 'W': color = 'w'; break;
case 'R': color = 'r'; break;
case 'G': color = 'g'; break;
default: return false;
};
h.Head = h.Head[1..];
return true;
}
}
; Core CLR 6.0.21.52210 on amd64
ROSpanMatcher..ctor(System.ReadOnlySpan`1<Char>)
L0000: push rdi
L0001: push rsi
L0002: push rbx
L0003: mov rbx, rcx
L0006: mov rdi, rbx
L0009: mov rsi, rdx
L000c: call 0x00007ffd108ca640
L0011: movsq [rdi], [rsi]
L0013: mov dword ptr [rbx+0x10], 7
L001a: pop rbx
L001b: pop rsi
L001c: pop rdi
L001d: ret
ROSpanMatcher.UncheckedForward(Int32)
L0000: sub rsp, 0x28
L0004: mov rax, [rcx]
L0007: mov r8d, [rcx+8]
L000b: mov r9d, r8d
L000e: sub r9d, edx
L0011: mov edx, edx
L0013: mov r10d, r9d
L0016: add r10, rdx
L0019: mov r8d, r8d
L001c: cmp r10, r8
L001f: ja short L0034
L0021: lea rax, [rax+rdx*2]
L0025: mov [rcx], rax
L0028: mov [rcx+8], r9d
L002c: mov eax, [rcx+8]
L002f: add rsp, 0x28
L0033: ret
L0034: call 0x00007ffcb0fa5680
L0039: int3
ROSpanMatcher.Forward(Int32)
L0000: sub rsp, 0x28
L0004: mov rax, rcx
L0007: mov eax, [rax+8]
L000a: mov r8d, eax
L000d: cmp edx, r8d
L0010: jg short L002f
L0012: cmp edx, eax
L0014: ja short L0036
L0016: mov r8, [rcx]
L0019: sub eax, edx
L001b: mov edx, edx
L001d: lea rdx, [r8+rdx*2]
L0021: mov [rcx], rdx
L0024: mov [rcx+8], eax
L0027: mov eax, [rcx+8]
L002a: add rsp, 0x28
L002e: ret
L002f: mov edx, r8d
L0032: cmp edx, eax
L0034: jbe short L0016
L0036: call 0x00007ffcb0fa5680
L003b: int3
C..ctor()
L0000: ret
C.TryMatch(System.ReadOnlySpan`1<Char> ByRef, Char ByRef)
L0000: sub rsp, 0x28
L0004: mov word ptr [rdx], 0
L0009: mov eax, [rcx+8]
L000c: test eax, eax
L000e: jne short L0017
L0010: xor eax, eax
L0012: add rsp, 0x28
L0016: ret
L0017: mov rax, [rcx]
L001a: movzx eax, word ptr [rax]
L001d: cmp eax, 0x47
L0020: je short L003a
L0022: cmp eax, 0x52
L0025: je short L0033
L0027: cmp eax, 0x57
L002a: jne short L005f
L002c: mov word ptr [rdx], 0x77
L0031: jmp short L003f
L0033: mov word ptr [rdx], 0x72
L0038: jmp short L003f
L003a: mov word ptr [rdx], 0x67
L003f: mov eax, [rcx+8]
L0042: test eax, eax
L0044: je short L0066
L0046: mov rdx, [rcx]
L0049: dec eax
L004b: add rdx, 2
L004f: mov [rcx], rdx
L0052: mov [rcx+8], eax
L0055: mov eax, 1
L005a: add rsp, 0x28
L005e: ret
L005f: xor eax, eax
L0061: add rsp, 0x28
L0065: ret
L0066: call 0x00007ffcb0fa5680
L006b: int3
C.TryMatch(ROSpanMatcher ByRef, Char ByRef)
L0000: sub rsp, 0x28
L0004: mov word ptr [rdx], 0
L0009: mov eax, [rcx+8]
L000c: test eax, eax
L000e: jne short L0017
L0010: xor eax, eax
L0012: add rsp, 0x28
L0016: ret
L0017: mov rax, [rcx]
L001a: movzx eax, word ptr [rax]
L001d: cmp eax, 0x47
L0020: je short L003a
L0022: cmp eax, 0x52
L0025: je short L0033
L0027: cmp eax, 0x57
L002a: jne short L0062
L002c: mov word ptr [rdx], 0x77
L0031: jmp short L003f
L0033: mov word ptr [rdx], 0x72
L0038: jmp short L003f
L003a: mov word ptr [rdx], 0x67
L003f: mov rax, rcx
L0042: mov eax, [rax+8]
L0045: test eax, eax
L0047: je short L0069
L0049: mov rdx, [rcx]
L004c: dec eax
L004e: add rdx, 2
L0052: mov [rcx], rdx
L0055: mov [rcx+8], eax
L0058: mov eax, 1
L005d: add rsp, 0x28
L0061: ret
L0062: xor eax, eax
L0064: add rsp, 0x28
L0068: ret
L0069: call 0x00007ffcb0fa5680
L006e: int3
C.TryMatchBad(ROSpanMatcher ByRef, Char ByRef)
L0000: sub rsp, 0x28
L0004: mov word ptr [rdx], 0
L0009: mov eax, [rcx+8]
L000c: test eax, eax
L000e: jne short L0017
L0010: xor eax, eax
L0012: add rsp, 0x28
L0016: ret
L0017: mov rax, [rcx]
L001a: movzx eax, word ptr [rax]
L001d: cmp eax, 0x47
L0020: je short L003a
L0022: cmp eax, 0x52
L0025: je short L0033
L0027: cmp eax, 0x57
L002a: jne short L006b
L002c: mov word ptr [rdx], 0x77
L0031: jmp short L003f
L0033: mov word ptr [rdx], 0x72
L0038: jmp short L003f
L003a: mov word ptr [rdx], 0x67
L003f: mov rax, [rcx]
L0042: mov edx, [rcx+8]
L0045: lea r8d, [rdx-1]
L0049: mov r9d, r8d
L004c: inc r9
L004f: mov edx, edx
L0051: cmp r9, rdx
L0054: ja short L0072
L0056: add rax, 2
L005a: mov [rcx], rax
L005d: mov [rcx+8], r8d
L0061: mov eax, 1
L0066: add rsp, 0x28
L006a: ret
L006b: xor eax, eax
L006d: add rsp, 0x28
L0071: ret
L0072: call 0x00007ffcb0fa5680
L0077: int3
{
"version": 1,
"target": "JIT ASM",
"mode": "Release",
"branch": "core-x64"
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment