Gli intervalli alfabetici minuscoli e maiuscoli non attraversano un %32
limite di "allineamento" nel sistema di codifica ASCII.
Questo è il motivo per cui bit 0x20
è l'unica differenza tra le versioni maiuscole / minuscole della stessa lettera.
Se così non fosse, avresti bisogno di aggiungere o sottrarre 0x20
, non solo attivare e disattivare, e per alcune lettere verrebbe eseguito per capovolgere altri bit più alti. (E non ci sarebbe una singola operazione che potrebbe alternare, e in primo luogo verificare la presenza di caratteri alfabetici sarebbe più difficile perché non potresti | = 0x20 per forzare lcase.)
Trucchi solo ASCII correlati: è possibile verificare la presenza di un carattere ASCII alfabetico forzando le lettere minuscole con c |= 0x20
e quindi se (non firmato) c - 'a' <= ('z'-'a')
. Quindi solo 3 operazioni: OR + SUB + CMP contro un costante 25. Naturalmente, i compilatori sanno come ottimizzare (c>='a' && c<='z')
in asm come questo per te , quindi al massimo dovresti fare la c|=0x20
parte da solo. È piuttosto scomodo fare tutto il cast necessario, in particolare per aggirare le promozioni di numeri interi predefiniti da firmare int
.
unsigned char lcase = y|0x20;
if (lcase - 'a' <= (unsigned)('z'-'a')) { // lcase-'a' will wrap for characters below 'a'
// c is alphabetic ASCII
}
// else it's not
Vedi anche Converti una stringa in C ++ in maiuscolo (stringa SIMD toupper
solo per ASCII, mascherando l'operando per XOR usando quel controllo).
E anche Come accedere a un array di caratteri e cambiare le lettere minuscole in lettere maiuscole e viceversa
(C con intrinseche SIMD e scalare x86 asm maiuscole / minuscole per caratteri ASCII alfabetici, lasciando gli altri non modificati).
Questi trucchi sono per lo più utili solo se si ottimizza a mano alcune elaborazioni di testo con SIMD (es. SSE2 o NEON), dopo aver verificato che nessuna delle char
s in un vettore abbia il bit alto impostato. (E quindi nessuno dei byte fa parte di una codifica UTF-8 multi-byte per un singolo carattere, che potrebbe avere diverse maiuscole / minuscole). Se ne trovi, puoi tornare allo scalare per questo blocco di 16 byte o per il resto della stringa.
Ci sono anche alcuni locali in cui toupper()
o tolower()
su alcuni caratteri nell'intervallo ASCII producono caratteri al di fuori di tale intervallo, in particolare il turco dove I ↔ ı e İ ↔ i. In quei locali, avresti bisogno di un controllo più sofisticato, o probabilmente non tenterai affatto di utilizzare questa ottimizzazione.
Ma in alcuni casi, ti è consentito assumere ASCII invece di UTF-8, ad esempio utilità Unix con LANG=C
(la locale POSIX), non en_CA.UTF-8
o altro.
Ma se riesci a verificare che è sicuro, puoi toupper
stringhe di media lunghezza molto più velocemente rispetto a chiamare toupper()
in un ciclo (come 5x), e alla fine ho provato con Boost 1.58 , molto più veloce di quello boost::to_upper_copy<char*, std::string>()
che fa uno stupido dynamic_cast
per ogni personaggio.
@
in `usando^ 32
.