Here's even faster (SSE2)
Code: Select all
DeclareModule HexData
Declare.s HexData(*mem, size, lowercase = #False)
EndDeclareModule
Module HexData
DisableDebugger
EnableExplicit
EnableASM
CompilerIf #PB_Compiler_Processor = #PB_Processor_x86
Macro rax : eax : EndMacro
Macro rcx : ecx : EndMacro
Macro rdx : edx : EndMacro
Macro rsp : esp : EndMacro
CompilerEndIf
Macro M_movdqa(r1, r2)
!movdqa r1, r2
EndMacro
Macro M_movdqu(r1, r2)
!movdqu r1, r2
EndMacro
Procedure.s HexData(*mem, size, lowercase = #False)
Protected Dim b.u(size + 30)
; init xmm registers
!mov eax, [p.v_lowercase]
!shl eax, 29
!and eax, 0x20000000
!or eax, 0x0739300f
!movd xmm0, eax
!punpcklbw xmm0, xmm0
!punpcklwd xmm0, xmm0
!pshufd xmm2, xmm0, 00000000b
!pshufd xmm3, xmm0, 01010101b
!pshufd xmm4, xmm0, 10101010b
!pshufd xmm5, xmm0, 11111111b
; load source, destination and size
mov rax, [p.a_b]
mov rcx, [p.v_size]
mov rdx, [p.p_mem]
add rcx, rdx
shr rdx, 4
shl rdx, 4
; backup xmm6 and xmm7
M_movdqu ([rsp - 16], xmm6)
M_movdqu ([rsp - 32], xmm7)
; main loop
!.l_hexdata_loop:
M_movdqa (xmm0, [rdx])
!movdqa xmm1, xmm0
!psrld xmm0, 4
!pand xmm0, xmm2
!pand xmm1, xmm2
!por xmm0, xmm3
!por xmm1, xmm3
!movdqa xmm6, xmm0
!movdqa xmm7, xmm1
!pcmpgtb xmm6, xmm4
!pcmpgtb xmm7, xmm4
!pand xmm6, xmm5
!pand xmm7, xmm5
!paddb xmm0, xmm6
!paddb xmm7, xmm1
!movdqa xmm1, xmm0
!punpcklbw xmm0, xmm7
!punpckhbw xmm1, xmm7
M_movdqu ([rax], xmm0)
M_movdqu ([rax + 16], xmm1)
add rdx, 16
add rax, 32
cmp rdx, rcx
!jb .l_hexdata_loop
; restore xmm6 and xmm7
M_movdqu (xmm6, [rsp - 16])
M_movdqu (xmm7, [rsp - 32])
*mem & 15 : b(*mem + size) = 0
ProcedureReturn PeekS(@b(*mem), -1, #PB_Ascii)
EndProcedure
EndModule
; test module
A.q = $0123456789abcdef
Debug HexData::HexData(@A, 8, #True)
Dim Buffer.b(100)
RandomData(@Buffer(), 100)
Debug HexData::HexData(@Buffer(), 100, #True)
Edit:
Newer versions of PureBasic use unicode internally.
The code above creates the result in ascii and converts it to unicode when returning the result.
While this is very fast on macOS, it seems to be slower on Windows and Linux.
If you are using Windows or Linux, you might want to try the unicode version below and see if it is faster.
Code: Select all
; Unicode only !!!
DeclareModule HexData
Declare.s HexData(*mem, size, lowercase = #False)
EndDeclareModule
Module HexData
DisableDebugger
EnableExplicit
EnableASM
CompilerIf #PB_Compiler_Processor = #PB_Processor_x86
Macro rax : eax : EndMacro
Macro rcx : ecx : EndMacro
Macro rdx : edx : EndMacro
Macro rsp : esp : EndMacro
CompilerEndIf
Macro M_movdqa(r1, r2)
!movdqa r1, r2
EndMacro
Macro M_movdqu(r1, r2)
!movdqu r1, r2
EndMacro
Procedure.s HexData(*mem, size, lowercase = #False)
Protected Dim b.l(size + 30)
; init xmm registers
!mov eax, [p.v_lowercase]
!shl eax, 29
!and eax, 0x20000000
!or eax, 0x0739300f
!movd xmm0, eax
!punpcklbw xmm0, xmm0
!punpcklwd xmm0, xmm0
!pshufd xmm2, xmm0, 00000000b
!pshufd xmm3, xmm0, 01010101b
!pshufd xmm4, xmm0, 10101010b
!pshufd xmm5, xmm0, 11111111b
; load source, destination and size
mov rax, [p.a_b]
mov rcx, [p.v_size]
mov rdx, [p.p_mem]
add rcx, rdx
shr rdx, 4
shl rdx, 4
; backup xmm6 and xmm7
M_movdqu ([rsp - 16], xmm6)
M_movdqu ([rsp - 32], xmm7)
; main loop
!.l_hexdata_loop:
M_movdqa (xmm0, [rdx])
!movdqa xmm1, xmm0
!psrld xmm0, 4
!pand xmm0, xmm2
!pand xmm1, xmm2
!por xmm0, xmm3
!por xmm1, xmm3
!movdqa xmm6, xmm0
!movdqa xmm7, xmm1
!pcmpgtb xmm6, xmm4
!pcmpgtb xmm7, xmm4
!pand xmm6, xmm5
!pand xmm7, xmm5
!paddb xmm0, xmm6
!paddb xmm7, xmm1
!movdqa xmm1, xmm0
!punpcklbw xmm0, xmm7
!punpckhbw xmm1, xmm7
!pxor xmm7, xmm7
!movdqa xmm6, xmm0
!punpcklbw xmm0, xmm7
!punpckhbw xmm6, xmm7
M_movdqu ([rax], xmm0)
M_movdqu ([rax + 16], xmm6)
!movdqa xmm6, xmm1
!punpcklbw xmm1, xmm7
!punpckhbw xmm6, xmm7
M_movdqu ([rax + 32], xmm1)
M_movdqu ([rax + 48], xmm6)
add rdx, 16
add rax, 64
cmp rdx, rcx
!jb .l_hexdata_loop
; restore xmm6 and xmm7
M_movdqu (xmm6, [rsp - 16])
M_movdqu (xmm7, [rsp - 32])
*mem & 15 : b(*mem + size) = 0
ProcedureReturn PeekS(@b(*mem))
EndProcedure
EndModule
; test module
A.q = $0123456789abcdef
Debug HexData::HexData(@A, 8, #True)
Dim Buffer.b(100)
RandomData(@Buffer(), 100)
Debug HexData::HexData(@Buffer(), 100, #True)