i assume that @xwu probably meant:
Character.init(Unicode.Scalar.init(digit)).hexDigitValue.flatMap(UInt8.init(exactly:))
i plugged this into godbolt (with -O):
func test1(_ digit:UInt8) -> UInt8?
{
Character.init(Unicode.Scalar.init(digit)).hexDigitValue.flatMap(UInt8.init(exactly:))
}
func test2(_ digit:UInt8) -> UInt8?
{
switch digit
{
case 0x30 ... 0x39: return digit - 0x30
case 0x61 ... 0x66: return digit + 10 - 0x61
case 0x41 ... 0x46: return digit + 10 - 0x41
default: return nil
}
}
version 1:
output.test1(Swift.UInt8) -> Swift.UInt8?:
test dil, dil
js .LBB1_6
inc dil
movzx eax, dil
test eax, eax
je .LBB1_3
.LBB1_4:
bsr ecx, eax
xor ecx, 31
jmp .LBB1_5
.LBB1_6:
movzx eax, dil
mov ecx, eax
and ecx, 63
shl ecx, 8
shr eax, 6
add eax, ecx
add eax, 33217
test eax, eax
jne .LBB1_4
.LBB1_3:
mov ecx, 32
.LBB1_5:
push rbp
push r14
push rbx
sub rsp, 16
shr ecx, 3
mov esi, 4
sub rsi, rcx
lea ecx, [8*rsi]
mov rdx, -1
shl rdx, cl
not rdx
mov eax, eax
movabs rcx, 71775015237779199
add rcx, rax
and rcx, rdx
mov qword ptr [rsp], rcx
mov rdi, rsp
call ($sSS18_uncheckedFromUTF8ySSSRys5UInt8VGFZ)@PLT
mov r14, rdx
mov rdi, rax
mov rsi, rdx
call ($sSJ13hexDigitValueSiSgvg)@PLT
mov rbx, rax
mov ebp, edx
mov rdi, r14
call swift_bridgeObjectRelease@PLT
test rbx, rbx
sets cl
or cl, bpl
cmp rbx, 256
setae al
mov edx, 256
cmovb rdx, rbx
or al, cl
and al, 1
movzx esi, al
shl esi, 8
movzx edx, dl
xor eax, eax
test cl, 1
cmove eax, edx
or eax, esi
add rsp, 16
pop rbx
pop r14
pop rbp
ret
version 2:
output.test2(Swift.UInt8) -> Swift.UInt8?:
lea eax, [rdi - 58]
cmp al, -10
jae .LBB2_3
lea eax, [rdi - 103]
cmp al, -6
jae .LBB2_4
lea eax, [rdi - 71]
add dil, -55
xor ecx, ecx
cmp al, -6
setb al
movzx edi, dil
cmovb edi, ecx
jmp .LBB2_6
.LBB2_3:
add dil, -48
jmp .LBB2_5
.LBB2_4:
add dil, -87
.LBB2_5:
xor eax, eax
.LBB2_6:
movzx ecx, al
shl ecx, 8
movzx eax, dil
or eax, ecx
ret
so i think version 2 is a clear winner here, and the “performance issues notwithstanding” are actually quite significant.