x86 / x86-64 machine code, 22 bytes
Takes pointer (RSI), length (RCX) in registers, modifies the string in-place. Callable from C with the x86-64 SysV calling convention as
void vowel_alt_caseflip(int dummy, char *RSI, int dummy, size_t RCX). Same machine code works in 32-bit mode, although none of the standard 32-bit C calling conventions match.
NASM listing, with address, machine-code bytes, and source the machine-code answer was generated from.
1 ;;; char *str /* RSI */, size_t len /* RCX */
3 00000000 BF22822000 mov edi, 0x0208222 ; ASCII vowel bitmap, 1-indexed like ASCII codes are with 'a' = 0x61 not 0x60
4 00000005 31D2 xor edx, edx ; first vowel is not flipped
6 00000007 AC lodsb ; al = *str++
7 00000008 0FA3C7 bt edi, eax ; if (bitmap & (1<<(al&31)))
8 0000000B 7306 jnc .non_vowel
9 0000000D 3056FF xor [rsi-1], dl ; caseflip or not the current character
10 00000010 80F220 xor dl, 0x20 ; toggle state for the next
12 00000013 E2F2 loop .loop
13 00000015 C3 ret
; next address is 0x16, size is 0x16 = 22 bytes
Since the input string is guaranteed to be all lowercase alphabetic, I just used XOR instead of AND with
~0x20 to flip instead of clear the ASCII lower-case bit. It would work out to the same size with
mov dl, 0xFF /
and [rsi-1], dl.
Try it online! with a Linux
_start caller that passes it the alphabet twice and makes write system calls before/after, so we can see that it correctly treats
u as a vowel.
For more about the immediate bitmap strategy, and variations like using it branchlessly, see SO and two of my previous x86 answers:
Alternate version, same size
I had hoped to be able to use
xor al, 0x20 to save a byte vs. DL, but we need AL for efficient string-reading via
lodsb. (We need a char from the string in a register to use as a source for
bt.) We could start with
mov there and use
stosb to store, but that would have to be separate from a reg-reg XOR or AND, and still doesn't free up AL.
We could use
scasb as a 1-byte
inc rdi. Using
mov dl, [rdi] to start, and saving the
-1 in the memory-dest addressing mode, and another byte from
xor al, 0x20 short-form, that's break-even for size and worse for efficiency (useless
scasb reload). Or similar efficiency in 32-bit mode since we could use
inc edi there.
;;; char *str /* RDI */, size_t len /* RCX */
mov esi, 0x0208222 ; ASCII vowel bitmap, 1-indexed like ASCII codes are with 'a' = 0x61 not 0x60
xor eax, eax ; first vowel is not flipped
mov dl, [rdi]
bt esi, edx ; if (bitmap & (1<<(c&31)))
xor [rdi], al ; caseflip or not the current character
xor al, 0x20 ; toggle state for the next
scasb ; inc rdi in one byte even on x86-64