x86-64 machine code, 14 bytes
Callable from C (x86-64 SysV calling convention) with this prototype:
void casexchg(char *rdi, char *rsi); // modify both strings in place
An explicit-length version with length in rcx
is the same size. void casexchg(char *rdi, char *rsi, int dummy, size_t len);
This uses the same bit-exchange algo as the C and Java answers: If both letters are the same case, neither needs to change. If they're opposite case, they both need to change.
Use XOR to diff the case bit of the two strings. mask = (a XOR b) AND 0x20
is 0 for same or 0x20 for differing. a ^= mask; b ^= mask
caseflip both letters iff they were opposite case. (Because the ASCII letter codes for upper and lower differ only in bit 5.)
NASM listing (from nasm -felf64 -l/dev/stdout
). Use cut -b 26- <casexchg.lst >casexchg.lst
to turn this back into something you can assemble.
addr machine
6 code global casexchg
7 bytes casexchg:
8 .loop:
9 00000000 AC lodsb ; al=[rsi] ; rsi++
10 00000001 3207 xor al, [rdi]
11 00000003 2420 and al, 0x20 ; 0 if their cases were the same: no flipping needed
12
13 00000005 3007 xor [rdi], al ; caseflip both iff their cases were opposite
14 00000007 3046FF xor [rsi-1], al
15
16 0000000A AE scasb ; cmp al,[rdi] / inc rdi
17 ; AL=0 or 0x20.
18 ; At the terminating 0 in both strings, AL will be 0 so JNE will fall through.
19 ; 0x20 is ASCII space, which isn't allowed, so AL=0x20 won't cause early exit
20 0000000B 75F3 jne .loop
21 ; loop .loop ; caller passes explict length in RCX
22
23 0000000D C3 ret
size = 0xe bytes = 14
24 0000000E 0E db $ - casexchg_bitdiff
The slow loop
instruction is also 2 bytes, same as a short jcc
. scasb
is still the best way to increment rdi
with a one-byte instruction. I guess we could xor al, [rdi]
/ stosb
. That would be the same size but probably faster for the loop
case (memory src + store is cheaper than memory dst + reload). And would still set ZF appropriately for the implicit-length case!
Try it online! with a _start that calls it on argv[1], argv[2] and uses sys_write on the result
9
Completely unrelated to this answer of yours, but it's easier than creating a chat. ;p Did you notice the Java-10 TIO has a bug when using
– Kevin Cruijssen – 2018-06-04T13:26:58.463array[i++%n]+=...;
?array[t=i++%n]=array[t]+...;
works fine; andarray[i%n]+=...;i++;
works fine as well, but usingi++
or++i
with a modulo and+=
to append to a row in an array doesn't work.. Here a Java 10 TIO as example to see the problem. Is this a bug (or feature :S) in the Java 10 JDK or in the Java 10 TIO compiler?1@KevinCruijssen I see the issue, but it seems weird. I see that the version used on TIO is 10.0.0_46 (of 20-03-2018). The latest version is 10.0.1. We should probably ask TIO to update their version of Java. – Olivier Grégoire – 2018-06-04T13:42:19.780
3
@KevinCruijssen Dennis updated the version to 10.0.1 and the issue is still happening (I don't have Java 10 installed yet so I rely on TIO, just like you). I've asked on Stack Overflow as I just don't know what happens here... It's baffling!
– Olivier Grégoire – 2018-06-04T15:18:26.313I've upvoted and favorited your SO question. It seems
array[something] += a;
is interpret by the compiler correctly asint temp = something; array[temp] = array[temp] + a;
in Java 8, but incorrectly asarray[something] = array[something] + a;
in Java 10 (NOTE: This is just pseudo-code, no idea if the compiler is exactly like this). The test cone by @DidierL. is pretty good and seems to confirm this, though:String[] array = {""}; array[test()] += "a";
withstatic int test() { System.out.println("evaluated"); return 0; }
will print evaluated twice. – Kevin Cruijssen – 2018-06-04T16:32:45.973Ah, I see adding a counter for the iterations will result in 50 for the bugged Java 10 code, but 100 for the Java 8 code. So
i++
(and everything else inside the block-quoted of[...] +=
) is evaluated twice. PS: Sorry to spam this answer of yours. As soon as the "Move to chat" option appears it would be best to do so. ;) – Kevin Cruijssen – 2018-06-04T16:35:52.4605
@KevinCruijssen It's ok, it's not like this answer attracts a lot of upvotes :P Anyways... The thing is that you actually found a bug. Since the spec says it should be acting as you would think it does, keep writing your answer that way, optimized for Java 10 if you require so. That way, you have a valid Java 10 answer, but untestable because of that bug. Just write it and test it in Java 8, then make the proper Java 10 changes like changing
– Olivier Grégoire – 2018-06-04T19:40:54.850String
tovar
.6I think it's really neat that you found a bug in JDK 10. Good job :] – Poke – 2018-06-05T19:42:13.850
@Poke It indeed is. :) And rofl at that 500 upvotes. XD Anyway, if anyone want to use it in their java 10 answers, as provided by the accepted answer on SO, adding the compiler-flag
– Kevin Cruijssen – 2018-06-08T11:54:05.503-XDstringConcat=inline
seems to work. Try it online in Java 10.@KevinCruijssen That post is crazy. It got featured on Hacker News, on Reddit, and the OpenJDK bug was raised from "Major loss of functionality" to "Crash, loss of data, major memory leak". Even my colleagues saw it and asked me if I was the one posting it. I've hit the rep-cap 4 days in a row now, and I think I might hit it again today. Personally, I don't think it's such a big deal given the corner case it is. Only codegolfers could have find it.
– Olivier Grégoire – 2018-06-08T12:07:54.403I think it was mentioned in the SO post but the thing to remember is that JDK 9 and 10 are not LTS versions. If you're using java in a professional environment you're hopefully on JDK 8 waiting for 11 to be released in September. All that aside, though, it's a pretty big bug – Poke – 2018-06-08T15:30:18.450