Leashed Fpc (trunk) has these swappers, has anyone mentioned them?
That settles it.
SysUtils.Swap<T> already does the optimal thing: a bitwise swap, which for managed types (strings, dynarrays, interfaces) moves the references with
zero refcount churn - faster than a naive temp-variable swap.
In Unleashed it's already as short as it gets, no
specialize thanks to implicit generics:
uses SysUtils;
Swap<YourType>(a, b);
And it's not just short - it's optimal. Here's
Swap<Integer>(a, b) at
-O3:
movl 32(%rsp), %eax
movl 36(%rsp), %edx
movl %edx, 32(%rsp)
movl %eax, 36(%rsp)
Four moves, fully inlined, no call, no stack temp. You can't beat that - swapping two memory locations is 2 loads + 2 stores, and there's no memory-to-memory
xchg on x86 (
xchg isn't faster than plain moves on modern CPUs anyway).
And here's
Swap<String>(a, b) - the managed case:
movq -8(%rbp), %rax
movq -16(%rbp), %rdx
movq %rdx, -8(%rbp)
movq %rax, -16(%rbp)
Just the two pointers swapped -
no fpc_ansistr_incr_ref /
decr_ref calls, no refcount churn at all. A naive
tmp := a; a := b; b := tmp would emit those refcount calls; the bitwise swap skips them entirely. A compiler intrinsic would emit the exact same four instructions.
So: do we close this, or are there other arguments for a dedicated intrinsic? The only one I can see is dropping the
SysUtils dependency - making swap available in any unit without a
uses clause. That's a convenience argument, not a performance one. If that's worth it to people, say so; otherwise
SysUtils.Swap<T> already covers this and there's nothing to add.