cpp-utils/include/string.hpp
2022-06-23 17:26:19 +01:00

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