152 lines
3.4 KiB
C++
152 lines
3.4 KiB
C++
#pragma once
|
|
|
|
#include "types.hpp"
|
|
#include <cctype>
|
|
#include <limits>
|
|
#include <string_view>
|
|
#include <type_traits>
|
|
|
|
#ifdef _WIN32
|
|
#define WIN32_LEAN_AND_MEAN
|
|
#define NOMINMAX
|
|
#include <Windows.h>
|
|
#endif
|
|
|
|
#include <algorithm>
|
|
#include <locale>
|
|
#include <sstream>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
namespace util {
|
|
#ifdef _WIN32
|
|
inline std::string to_string(std::wstring_view wstr) {
|
|
const auto size = WideCharToMultiByte(CP_UTF8, 0, wstr.data(), wstr.length(),
|
|
nullptr, 0, nullptr, nullptr);
|
|
|
|
std::string str(size, 0);
|
|
|
|
WideCharToMultiByte(CP_UTF8, 0, wstr.data(), wstr.length(), str.data(),
|
|
str.length(), nullptr, nullptr);
|
|
|
|
return str;
|
|
}
|
|
|
|
inline std::wstring to_wstring(std::string_view str) {
|
|
const auto size =
|
|
MultiByteToWideChar(CP_UTF8, 0, str.data(), str.length(), nullptr, 0);
|
|
|
|
std::wstring wstr(size, 0);
|
|
|
|
MultiByteToWideChar(CP_UTF8, 0, str.data(), str.length(), wstr.data(),
|
|
wstr.length());
|
|
|
|
return wstr;
|
|
}
|
|
#endif
|
|
|
|
template <typename A>
|
|
std::basic_string<A> to_lower(std::basic_string_view<A> view) {
|
|
std::basic_string<A> out(view.size(), '\0');
|
|
|
|
std::transform(
|
|
std::begin(view), std::end(view), std::begin(out),
|
|
[](typename std::basic_string<A>::value_type c) {
|
|
return std::use_facet<
|
|
std::ctype<typename std::basic_string<A>::value_type>>(
|
|
std::locale())
|
|
.tolower(c);
|
|
});
|
|
|
|
return out;
|
|
}
|
|
|
|
template <typename CharT>
|
|
constexpr bool string_eq_nocase(std::basic_string_view<CharT> rh,
|
|
std::basic_string_view<CharT> lh) {
|
|
const auto rh_lower = to_lower<CharT>(rh);
|
|
const auto lh_lower = to_lower<CharT>(lh);
|
|
|
|
return rh_lower == lh_lower;
|
|
}
|
|
|
|
template <typename CharT>
|
|
auto split_with(const std::basic_string<CharT> &str, CharT delimiter)
|
|
-> std::vector<std::basic_string<CharT>> {
|
|
std::vector<std::basic_string<CharT>> parts;
|
|
std::basic_string<CharT> part;
|
|
|
|
const auto start = str.find_first_not_of(delimiter);
|
|
const auto end = str.find_last_not_of(delimiter);
|
|
std::basic_istringstream<CharT> stream(
|
|
str.substr(start, end == std::string::npos ? end : end + 1));
|
|
|
|
while (std::getline(stream, part, delimiter))
|
|
parts.push_back(part);
|
|
|
|
return parts;
|
|
}
|
|
|
|
#include <concepts>
|
|
|
|
template <std::integral I>
|
|
inline constexpr auto from_char_radix(const char &c, I radix = 10) -> I {
|
|
I value = 0;
|
|
|
|
if (std::isdigit(c)) {
|
|
value = c - '0';
|
|
} else if (std::isalpha(c)) {
|
|
if (std::isupper(c)) {
|
|
value = c + 10 - 'A';
|
|
} else {
|
|
value = c + 10 - 'a';
|
|
}
|
|
}
|
|
|
|
return value < radix ? value : std::numeric_limits<I>::max();
|
|
}
|
|
|
|
template <std::integral I>
|
|
inline constexpr auto from_string_view_radix(std::string_view view,
|
|
I radix = 10) -> I {
|
|
auto negative = false;
|
|
if (view.starts_with('-')) {
|
|
negative = true;
|
|
view.remove_prefix(1);
|
|
} else if (view.starts_with('+')) {
|
|
negative = false;
|
|
view.remove_prefix(1);
|
|
}
|
|
|
|
I value = 0;
|
|
const auto max = std::numeric_limits<I>::max();
|
|
|
|
for (auto &&c : view) {
|
|
const auto i = from_char_radix<I>(c, radix);
|
|
|
|
if (i >= radix) {
|
|
return max;
|
|
}
|
|
|
|
if (value > max / radix) {
|
|
return max;
|
|
}
|
|
|
|
value *= radix;
|
|
|
|
if (i > max - value) {
|
|
return max;
|
|
}
|
|
|
|
value += i;
|
|
}
|
|
|
|
if (negative && std::is_signed_v<I>) {
|
|
return -value;
|
|
} else {
|
|
return value;
|
|
}
|
|
}
|
|
|
|
} // namespace util
|