mã máy x86-64, 44 byte
(Mã máy tương tự cũng hoạt động ở chế độ 32 bit.)
Câu trả lời của @Daniel Schepler là điểm khởi đầu cho điều này, nhưng điều này có ít nhất một ý tưởng thuật toán mới (không chỉ là chơi golf tốt hơn cùng ý tưởng): Mã ASCII cho 'B'
( 1000010
) và 'X'
( 1011000
) đưa ra 16 và 2 sau khi che dấu0b0010010
.
Vì vậy, sau khi loại trừ số thập phân (chữ số hàng đầu khác không) và số bát phân (char sau '0'
nhỏ hơn 'B'
), chúng ta chỉ có thể đặt cơ sở =c & 0b0010010
và nhảy vào vòng lặp chữ số.
Có thể gọi với x86-64 System V dưới dạng unsigned __int128 parse_cxx14_int(int dummy, const char*rsi);
Trích xuất giá trị trả về EDX từ nửa cao của unsigned __int128
kết quả với tmp>>64
.
.globl parse_cxx14_int
## Input: pointer to 0-terminated string in RSI
## output: integer in EDX
## clobbers: RAX, RCX (base), RSI (points to terminator on return)
parse_cxx14_int:
xor %eax,%eax # initialize high bits of digit reader
cdq # also initialize result accumulator edx to 0
lea 10(%rax), %ecx # base 10 default
lodsb # fetch first character
cmp $'0', %al
jne .Lentry2
# leading zero. Legal 2nd characters are b/B (base 2), x/X (base 16)
# Or NUL terminator = 0 in base 10
# or any digit or ' separator (octal). These have ASCII codes below the alphabetic ranges
lodsb
mov $8, %cl # after '0' have either digit, apostrophe, or terminator,
cmp $'B', %al # or 'b'/'B' or 'x'/'X' (set a new base)
jb .Lentry2 # enter the parse loop with base=8 and an already-loaded character
# else hex or binary. The bit patterns for those letters are very convenient
and $0b0010010, %al # b/B -> 2, x/X -> 16
xchg %eax, %ecx
jmp .Lentry
.Lprocessdigit:
sub $'0' & (~32), %al
jb .Lentry # chars below '0' are treated as a separator, including '
cmp $10, %al
jb .Lnum
add $('0'&~32) - 'A' + 10, %al # digit value = c-'A' + 10. we have al = c - '0'&~32.
# c = al + '0'&~32. val = m+'0'&~32 - 'A' + 10
.Lnum:
imul %ecx, %edx
add %eax, %edx # accum = accum * base + newdigit
.Lentry:
lodsb # fetch next character
.Lentry2:
and $~32, %al # uppercase letters (and as side effect,
# digits are translated to N+16)
jnz .Lprocessdigit # space also counts as a terminator
.Lend:
ret
Các khối thay đổi so với phiên bản của Daniel (hầu hết) được thụt lề ít hơn so với hướng dẫn khác. Ngoài ra vòng lặp chính có nhánh có điều kiện ở phía dưới. Điều này hóa ra là một sự thay đổi trung lập vì không con đường nào có thể rơi vào đỉnh của nó, vàdec ecx / loop .Lentry
ý tưởng để vào vòng lặp hóa ra không phải là một chiến thắng sau khi xử lý bát phân khác nhau. Nhưng nó có ít hướng dẫn hơn trong vòng lặp với vòng lặp ở dạng thành ngữ làm {} trong khi cấu trúc, vì vậy tôi đã giữ nó.
Khai thác kiểm tra C ++ của Daniel hoạt động không thay đổi trong chế độ 64 bit với mã này, sử dụng quy ước gọi tương tự như câu trả lời 32 bit của anh ta.
g++ -Og parse-cxx14.cpp parse-cxx14.s &&
./a.out < tests | diff -u -w - tests.good
Tháo gỡ, bao gồm các byte mã máy là câu trả lời thực tế
0000000000000000 <parse_cxx14_int>:
0: 31 c0 xor %eax,%eax
2: 99 cltd
3: 8d 48 0a lea 0xa(%rax),%ecx
6: ac lods %ds:(%rsi),%al
7: 3c 30 cmp $0x30,%al
9: 75 1c jne 27 <parse_cxx14_int+0x27>
b: ac lods %ds:(%rsi),%al
c: b1 08 mov $0x8,%cl
e: 3c 42 cmp $0x42,%al
10: 72 15 jb 27 <parse_cxx14_int+0x27>
12: 24 12 and $0x12,%al
14: 91 xchg %eax,%ecx
15: eb 0f jmp 26 <parse_cxx14_int+0x26>
17: 2c 10 sub $0x10,%al
19: 72 0b jb 26 <parse_cxx14_int+0x26>
1b: 3c 0a cmp $0xa,%al
1d: 72 02 jb 21 <parse_cxx14_int+0x21>
1f: 04 d9 add $0xd9,%al
21: 0f af d1 imul %ecx,%edx
24: 01 c2 add %eax,%edx
26: ac lods %ds:(%rsi),%al
27: 24 df and $0xdf,%al
29: 75 ec jne 17 <parse_cxx14_int+0x17>
2b: c3 retq
Các thay đổi khác từ phiên bản của Daniel bao gồm lưu sub $16, %al
từ bên trong vòng lặp số, bằng cách sử dụng nhiều hơn sub
thay vìtest
là một phần của việc phát hiện dấu phân cách và chữ số so với các ký tự chữ cái.
Không giống như Daniel, mọi nhân vật dưới đây '0'
đều được coi là một dấu tách, không chỉ '\''
. (Ngoại trừ ' '
: and $~32, %al
/ jnz
trong cả hai vòng lặp của chúng tôi coi không gian là dấu kết thúc, có thể thuận tiện cho việc kiểm tra với một số nguyên ở đầu dòng.)
Mỗi hoạt động sửa đổi %al
bên trong vòng lặp đều có một cờ tiêu thụ nhánh được đặt theo kết quả và mỗi nhánh đi (hoặc rơi qua) đến một vị trí khác nhau.