diff --git a/libc/src/__support/wctype_utils.h b/libc/src/__support/wctype_utils.h index aa137c278323e..2ae5ec93b2a63 100644 --- a/libc/src/__support/wctype_utils.h +++ b/libc/src/__support/wctype_utils.h @@ -17,6 +17,565 @@ namespace LIBC_NAMESPACE_DECL { namespace internal { +// ----------------------------------------------------------------------------- +// ****************** WARNING ****************** +// ****************** DO NOT TRY TO OPTIMIZE THESE FUNCTIONS! ****************** +// ----------------------------------------------------------------------------- +// This switch/case form is easier for the compiler to understand, and is +// optimized into a form that is almost always the same as or better than +// versions written by hand (see https://godbolt.org/z/qvrebqvvr). Also this +// form makes these functions encoding independent. If you want to rewrite these +// functions, make sure you have benchmarks to show your new solution is faster, +// as well as a way to support non-ASCII character encodings. + +// Similarly, do not change these fumarks to show your new solution is faster, +// as well as a way to support non-Anctions to use case ranges. e.g. +// bool iswlower(wint_t ch) { +// switch(ch) { +// case L'a'...L'z': +// return true; +// } +// } +// This assumes the character ranges are contiguous, which they aren't in +// EBCDIC. Technically we could use some smaller ranges, but that's even harder +// to read. + +LIBC_INLINE static constexpr bool iswlower(wint_t wch) { + switch (wch) { + case L'a': + case L'b': + case L'c': + case L'd': + case L'e': + case L'f': + case L'g': + case L'h': + case L'i': + case L'j': + case L'k': + case L'l': + case L'm': + case L'n': + case L'o': + case L'p': + case L'q': + case L'r': + case L's': + case L't': + case L'u': + case L'v': + case L'w': + case L'x': + case L'y': + case L'z': + return true; + default: + return false; + } +} + +LIBC_INLINE static constexpr bool iswupper(wint_t wch) { + switch (wch) { + case L'A': + case L'B': + case L'C': + case L'D': + case L'E': + case L'F': + case L'G': + case L'H': + case L'I': + case L'J': + case L'K': + case L'L': + case L'M': + case L'N': + case L'O': + case L'P': + case L'Q': + case L'R': + case L'S': + case L'T': + case L'U': + case L'V': + case L'W': + case L'X': + case L'Y': + case L'Z': + return true; + default: + return false; + } +} + +LIBC_INLINE static constexpr bool iswdigit(wint_t wch) { + switch (wch) { + case L'0': + case L'1': + case L'2': + case L'3': + case L'4': + case L'5': + case L'6': + case L'7': + case L'8': + case L'9': + return true; + default: + return false; + } +} + +LIBC_INLINE static constexpr wint_t towlower(wint_t wch) { + switch (wch) { + case L'A': + return L'a'; + case L'B': + return L'b'; + case L'C': + return L'c'; + case L'D': + return L'd'; + case L'E': + return L'e'; + case L'F': + return L'f'; + case L'G': + return L'g'; + case L'H': + return L'h'; + case L'I': + return L'i'; + case L'J': + return L'j'; + case L'K': + return L'k'; + case L'L': + return L'l'; + case L'M': + return L'm'; + case L'N': + return L'n'; + case L'O': + return L'o'; + case L'P': + return L'p'; + case L'Q': + return L'q'; + case L'R': + return L'r'; + case L'S': + return L's'; + case L'T': + return L't'; + case L'U': + return L'u'; + case L'V': + return L'v'; + case L'W': + return L'w'; + case L'X': + return L'x'; + case L'Y': + return L'y'; + case L'Z': + return L'z'; + default: + return wch; + } +} + +LIBC_INLINE static constexpr wint_t towupper(wint_t wch) { + switch (wch) { + case L'a': + return L'A'; + case L'b': + return L'B'; + case L'c': + return L'C'; + case L'd': + return L'D'; + case L'e': + return L'E'; + case L'f': + return L'F'; + case L'g': + return L'G'; + case L'h': + return L'H'; + case L'i': + return L'I'; + case L'j': + return L'J'; + case L'k': + return L'K'; + case L'l': + return L'L'; + case L'm': + return L'M'; + case L'n': + return L'N'; + case L'o': + return L'O'; + case L'p': + return L'P'; + case L'q': + return L'Q'; + case L'r': + return L'R'; + case L's': + return L'S'; + case L't': + return L'T'; + case L'u': + return L'U'; + case L'v': + return L'V'; + case L'w': + return L'W'; + case L'x': + return L'X'; + case L'y': + return L'Y'; + case L'z': + return L'Z'; + default: + return wch; + } +} + +LIBC_INLINE static constexpr bool iswalpha(wint_t wch) { + switch (wch) { + case L'a': + case L'b': + case L'c': + case L'd': + case L'e': + case L'f': + case L'g': + case L'h': + case L'i': + case L'j': + case L'k': + case L'l': + case L'm': + case L'n': + case L'o': + case L'p': + case L'q': + case L'r': + case L's': + case L't': + case L'u': + case L'v': + case L'w': + case L'x': + case L'y': + case L'z': + case L'A': + case L'B': + case L'C': + case L'D': + case L'E': + case L'F': + case L'G': + case L'H': + case L'I': + case L'J': + case L'K': + case L'L': + case L'M': + case L'N': + case L'O': + case L'P': + case L'Q': + case L'R': + case L'S': + case L'T': + case L'U': + case L'V': + case L'W': + case L'X': + case L'Y': + case L'Z': + return true; + default: + return false; + } +} + +LIBC_INLINE static constexpr bool iswalnum(wint_t wch) { + switch (wch) { + case L'a': + case L'b': + case L'c': + case L'd': + case L'e': + case L'f': + case L'g': + case L'h': + case L'i': + case L'j': + case L'k': + case L'l': + case L'm': + case L'n': + case L'o': + case L'p': + case L'q': + case L'r': + case L's': + case L't': + case L'u': + case L'v': + case L'w': + case L'x': + case L'y': + case L'z': + case L'A': + case L'B': + case L'C': + case L'D': + case L'E': + case L'F': + case L'G': + case L'H': + case L'I': + case L'J': + case L'K': + case L'L': + case L'M': + case L'N': + case L'O': + case L'P': + case L'Q': + case L'R': + case L'S': + case L'T': + case L'U': + case L'V': + case L'W': + case L'X': + case L'Y': + case L'Z': + case L'0': + case L'1': + case L'2': + case L'3': + case L'4': + case L'5': + case L'6': + case L'7': + case L'8': + case L'9': + return true; + default: + return false; + } +} + +LIBC_INLINE static constexpr int b36_wchar_to_int(wint_t wch) { + switch (wch) { + case L'0': + return 0; + case L'1': + return 1; + case L'2': + return 2; + case L'3': + return 3; + case L'4': + return 4; + case L'5': + return 5; + case L'6': + return 6; + case L'7': + return 7; + case L'8': + return 8; + case L'9': + return 9; + case L'a': + case L'A': + return 10; + case L'b': + case L'B': + return 11; + case L'c': + case L'C': + return 12; + case L'd': + case L'D': + return 13; + case L'e': + case L'E': + return 14; + case L'f': + case L'F': + return 15; + case L'g': + case L'G': + return 16; + case L'h': + case L'H': + return 17; + case L'i': + case L'I': + return 18; + case L'j': + case L'J': + return 19; + case L'k': + case L'K': + return 20; + case L'l': + case L'L': + return 21; + case L'm': + case L'M': + return 22; + case L'n': + case L'N': + return 23; + case L'o': + case L'O': + return 24; + case L'p': + case L'P': + return 25; + case L'q': + case L'Q': + return 26; + case L'r': + case L'R': + return 27; + case L's': + case L'S': + return 28; + case L't': + case L'T': + return 29; + case L'u': + case L'U': + return 30; + case L'v': + case L'V': + return 31; + case L'w': + case L'W': + return 32; + case L'x': + case L'X': + return 33; + case L'y': + case L'Y': + return 34; + case L'z': + case L'Z': + return 35; + default: + return 0; + } +} + +LIBC_INLINE static constexpr wint_t int_to_b36_wchar(int num) { + // Can't actually use LIBC_ASSERT here because it depends on integer_to_string + // which depends on this. + + // LIBC_ASSERT(num < 36); + switch (num) { + case 0: + return L'0'; + case 1: + return L'1'; + case 2: + return L'2'; + case 3: + return L'3'; + case 4: + return L'4'; + case 5: + return L'5'; + case 6: + return L'6'; + case 7: + return L'7'; + case 8: + return L'8'; + case 9: + return L'9'; + case 10: + return L'a'; + case 11: + return L'b'; + case 12: + return L'c'; + case 13: + return L'd'; + case 14: + return L'e'; + case 15: + return L'f'; + case 16: + return L'g'; + case 17: + return L'h'; + case 18: + return L'i'; + case 19: + return L'j'; + case 20: + return L'k'; + case 21: + return L'l'; + case 22: + return L'm'; + case 23: + return L'n'; + case 24: + return L'o'; + case 25: + return L'p'; + case 26: + return L'q'; + case 27: + return L'r'; + case 28: + return L's'; + case 29: + return L't'; + case 30: + return L'u'; + case 31: + return L'v'; + case 32: + return L'w'; + case 33: + return L'x'; + case 34: + return L'y'; + case 35: + return L'z'; + default: + return L'!'; + } +} + +LIBC_INLINE static constexpr bool iswspace(wint_t wch) { + switch (wch) { + case L' ': + case L'\t': + case L'\n': + case L'\v': + case L'\f': + case L'\r': + return true; + default: + return false; + } +} + // ------------------------------------------------------ // Rationale: Since these classification functions are // called in other functions, we will avoid the overhead