blob: 2ae5ec93b2a63e6a0e848023957ba823bab0f316 [file]
//===-- Collection of utils for implementing wide char functions --*-C++-*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_LIBC_SRC___SUPPORT_WCTYPE_UTILS_H
#define LLVM_LIBC_SRC___SUPPORT_WCTYPE_UTILS_H
#include "hdr/types/wint_t.h"
#include "src/__support/CPP/optional.h"
#include "src/__support/macros/attributes.h" // LIBC_INLINE
#include "src/__support/macros/config.h"
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
// of a function call by inlining them.
// ------------------------------------------------------
LIBC_INLINE cpp::optional<int> wctob(wint_t c) {
// This needs to be translated to EOF at the callsite. This is to avoid
// including stdio.h in this file.
// The standard states that wint_t may either be an alias of wchar_t or
// an alias of an integer type, different platforms define this type with
// different signedness. This is equivalent to `(c > 127) || (c < 0)` but also
// works without -Wtype-limits warnings when `wint_t` is unsigned.
if ((c & ~127) != 0)
return cpp::nullopt;
return static_cast<int>(c);
}
LIBC_INLINE cpp::optional<wint_t> btowc(int c) {
if (c > 127 || c < 0)
return cpp::nullopt;
return static_cast<wint_t>(c);
}
} // namespace internal
} // namespace LIBC_NAMESPACE_DECL
#endif // LLVM_LIBC_SRC___SUPPORT_WCTYPE_UTILS_H