Passing (negative) char is technically undefined behavior.
}
if (util::starts_with(arg, "-x")) {
- if (arg.length() >= 3 && !islower(arg[2])) {
+ if (arg.length() >= 3 && !util::is_lower(arg[2])) {
// -xCODE (where CODE can be e.g. Host or CORE-AVX2, always starting with
// an uppercase letter) is an ordinary Intel compiler option, not a
// language specification. (GCC's "-x" language argument is always
do {
line.remove_suffix(1);
} while (!line.empty() && line.back() != '('
- && (std::isdigit(line.back()) || line.back() == ','));
+ && (util::is_digit(line.back()) || line.back() == ','));
if (!line.empty() && line.back() == '(') {
path_end = line.size() - 1;
-// Copyright (C) 2022-2024 Joel Rosdahl and other contributors
+// Copyright (C) 2022-2025 Joel Rosdahl and other contributors
//
// See doc/authors.adoc for a complete list of contributors.
//
for (std::string_view line : util::split_into_views(file_content, "\r\n")) {
if (util::starts_with(line, prefix)) {
size_t pos = prefix.size();
- while (pos < line.size() && isspace(line[pos])) {
+ while (pos < line.size() && util::is_space(line[pos])) {
++pos;
}
std::string_view include = line.substr(pos);
while (true) {
// Find start of next token.
- while (i < length && text[i] != '\n' && isspace(text[i])) {
+ while (i < length && text[i] != '\n' && util::is_space(text[i])) {
++i;
}
// Parse token.
std::string token;
while (i < length) {
- if (text[i] == ':' && token.length() == 1 && !isspace(token[0])
+ if (text[i] == ':' && token.length() == 1 && !util::is_space(token[0])
&& i + 1 < length && (text[i + 1] == '/' || text[i + 1] == '\\')) {
// It's a Windows path, so the colon is not a separator and instead
// added to the token.
continue;
}
- if (text[i] == ':' || isspace(text[i])
+ if (text[i] == ':' || util::is_space(text[i])
|| (text[i] == '\\' && i + 1 < length && text[i + 1] == '\n')) {
// End of token.
break;
// Check char before and after macro to verify that the found macro isn't part
// of another identifier.
- if ((pos == 1 || (str[pos - 2] != '_' && !isalnum(str[pos - 2])))
+ if ((pos == 1 || (str[pos - 2] != '_' && !util::is_alnum(str[pos - 2])))
&& (pos + macro_len == str.length()
- || (str[pos + macro_len] != '_' && !isalnum(str[pos + macro_len])))) {
+ || (str[pos + macro_len] != '_'
+ && !util::is_alnum(str[pos + macro_len])))) {
return found;
}
-// Copyright (C) 2023-2024 Joel Rosdahl and other contributors
+// Copyright (C) 2023-2025 Joel Rosdahl and other contributors
//
// See doc/authors.adoc for a complete list of contributors.
//
++left;
}
right = left;
- while (isalnum(*right) || *right == '_') {
+ while (util::is_alnum(*right) || *right == '_') {
++right;
}
if (curly && *right != '}') {
return tl::unexpected(FMT("invalid size: \"{}\"", value));
}
- while (isspace(*p)) {
+ while (util::is_space(*p)) {
++p;
}
{
const auto from_hex = [](const char digit) {
return static_cast<uint8_t>(
- std::isdigit(digit) ? digit - '0' : std::tolower(digit) - 'a' + 10);
+ util::is_digit(digit) ? digit - '0' : util::to_lower(digit) - 'a' + 10);
};
std::string result;
while (i < string.size()) {
if (string[i] != '%') {
result += string[i];
- } else if (i + 2 >= string.size() || !std::isxdigit(string[i + 1])
- || !std::isxdigit(string[i + 2])) {
+ } else if (i + 2 >= string.size() || !util::is_xdigit(string[i + 1])
+ || !util::is_xdigit(string[i + 2])) {
return tl::unexpected(
FMT("invalid percent-encoded string at position {}: {}", i, string));
} else {
std::string
strip_whitespace(const std::string_view string)
{
- const auto is_space = [](const int ch) { return std::isspace(ch); };
- const auto start = std::find_if_not(string.begin(), string.end(), is_space);
+ const auto start =
+ std::find_if_not(string.begin(), string.end(), util::is_space);
const auto end =
- std::find_if_not(string.rbegin(), string.rend(), is_space).base();
+ std::find_if_not(string.rbegin(), string.rend(), util::is_space).base();
return start < end ? std::string(start, end) : std::string();
}
{
std::string result;
result.resize(string.length());
- std::transform(string.begin(), string.end(), result.begin(), tolower);
+ std::transform(string.begin(), string.end(), result.begin(), util::to_lower);
return result;
}
std::string format_iso8601_timestamp(const TimePoint& time,
TimeZone time_zone = TimeZone::local);
+// Check if `ch` is alphanumeric.
+bool is_alnum(char ch);
+
+// Check if `ch` is a digit.
+bool is_digit(char ch);
+
+// Check if `ch` is a lowercase.
+bool is_lower(char ch);
+
+// Check if `ch` is a whitespace character.
+bool is_space(char ch);
+
+// Check if `ch` is a hexadecimal digit.
+bool is_xdigit(char ch);
+
// Join stringified elements of `container` delimited by `delimiter` into a
// string. There must exist an `std::string to_string(T::value_type)` function.
template<typename T>
// Strip whitespace from left and right side of a string.
[[nodiscard]] std::string strip_whitespace(std::string_view string);
+// Return lowercase `ch`.
+char to_lower(char ch);
+
// Convert a string to lowercase.
[[nodiscard]] std::string to_lowercase(std::string_view string);
&& string.substr(string.length() - suffix.length()) == suffix;
}
+inline bool
+is_alnum(char ch)
+{
+ return std::isalnum(static_cast<unsigned char>(ch));
+}
+
+inline bool
+is_digit(char ch)
+{
+ return std::isdigit(static_cast<unsigned char>(ch));
+}
+
+inline bool
+is_lower(char ch)
+{
+ return std::islower(static_cast<unsigned char>(ch));
+}
+
+inline bool
+is_space(char ch)
+{
+ return std::isspace(static_cast<unsigned char>(ch));
+}
+
+inline bool
+is_xdigit(char ch)
+{
+ return std::isxdigit(static_cast<unsigned char>(ch));
+}
+
template<typename T>
inline std::string
join(const T& container, const std::string_view delimiter)
return string.substr(0, prefix.size()) == prefix;
}
+inline char
+to_lower(char ch)
+{
+ return std::tolower(static_cast<unsigned char>(ch));
+}
+
} // namespace util