/*
* Copyright (c) 2024 The RefValue Project
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
module;
#include
#ifdef __UCLIBC__
#include
#elif __has_include( )
#include
#else
#include
#endif
module essence.basic;
import std;
import :encoding;
import :char_and_byte;
import :abi.string;
import :abi.vector;
namespace essence {
namespace {
#ifdef __UCLIBC__
constexpr auto c16rtomb_impl = [](char* s, char16_t c16, std::mbstate_t* ps) -> std::size_t { return -1; };
constexpr auto mbrtoc16_impl = [](char16_t* pc16, const char* s, std::size_t n,
std::mbstate_t* ps) -> std::size_t { return -1; };
#elif __has_include( )
constexpr auto&& c16rtomb_impl = c16rtomb;
constexpr auto&& mbrtoc16_impl = mbrtoc16;
#else
constexpr auto&& c16rtomb_impl = ::c16rtomb;
constexpr auto&& mbrtoc16_impl = ::mbrtoc16;
#endif
} // namespace
} // namespace essence
namespace essence {
namespace {
template
concept mutable_container = requires(T obj, std::size_t size) {
typename T::value_type;
obj.shrink_to_fit();
obj.reserve(size);
obj.push_back(typename T::value_type{});
};
template
concept utf16_value = std::same_as || std::same_as
|| (sizeof(wchar_t) == sizeof(char16_t) && std::same_as);
template
requires byte_like
Container u16_to_native_bytes(std::span str) {
Container result;
if (str.empty()) {
return result;
}
mbstate_t state{};
std::array buffer{};
result.reserve(str.size() * 2);
for (auto&& item : str) {
if (auto rc =
c16rtomb_impl(reinterpret_cast(buffer.data()), static_cast(item), &state);
rc != static_cast<:size_t>(-1)) {
result.append(buffer.data(), rc);
}
}
result.shrink_to_fit();
return result;
}
template
requires utf16_value
Container native_bytes_to_u16(std::span str) {
Container result;
if (str.empty()) {
return result;
}
auto ptr = str.data();
auto ptr_end = str.data() + str.size();
char16_t c16{};
mbstate_t state{};
result.reserve(str.size());
while (auto rc = mbrtoc16_impl(&c16, ptr, ptr_end - ptr + 1, &state)) {
if (rc == static_cast<:size_t>(-3)) {
continue;
}
if (rc == static_cast<:size_t>(-2)) {
break;
}
if (rc == static_cast<:size_t>(-1)) {
break;
}
ptr += rc;
result.push_back(static_cast(c16));
}
result.shrink_to_fit();
return result;
}
} // namespace
#ifdef _WIN32
namespace internal {
std::string to_utf8_string(nstring_view str) {
return u16_to_native_bytes<:string>(std::span{str});
}
nstring to_native_string(std::string_view utf8_str) {
return native_bytes_to_u16(std::span{utf8_str});
}
} // namespace internal
abi::string to_utf8_string(nstring_view str) {
return u16_to_native_bytes<:string>(std::span{str});
}
abi::nstring to_native_string(std::string_view utf8_str) {
return native_bytes_to_u16<:nstring>(std::span{utf8_str});
}
#else
namespace internal {
std::string to_utf8_string(nstring_view str) {
return std::string{str};
}
nstring to_native_string(std::string_view utf8_str) {
return nstring{utf8_str};
}
} // namespace internal
abi::string to_utf8_string(nstring_view str) {
return abi::string{str};
}
abi::nstring to_native_string(std::string_view utf8_str) {
return abi::nstring{utf8_str};
}
#endif
namespace internal {
std::string to_utf8_string(std::u16string_view str) {
return u16_to_native_bytes<:string>(std::span{str.begin(), str.end()});
}
std::string to_utf8_string(std::span literal) {
return u16_to_native_bytes<:string>(literal);
}
std::u16string to_utf16_string(std::string_view utf8_str) {
return native_bytes_to_u16<:u16string>(std::span{utf8_str.begin(), utf8_str.end()});
}
std::vector<:uint16_t> to_uint16_t_literal(std::string_view utf8_str) {
return native_bytes_to_u16<:vector>>(std::span{utf8_str.begin(), utf8_str.end()});
}
} // namespace internal
abi::string to_utf8_string(std::u16string_view str) {
return u16_to_native_bytes<:string>(std::span{str.begin(), str.end()});
}
abi::string to_utf8_string(std::span literal) {
return u16_to_native_bytes<:string>(literal);
}
abi::u16string to_utf16_string(std::string_view utf8_str) {
return native_bytes_to_u16<:u16string>(std::span{utf8_str.begin(), utf8_str.end()});
}
abi::vector<:uint16_t> to_uint16_t_literal(std::string_view utf8_str) {
return native_bytes_to_u16<:vector>>(std::span{utf8_str.begin(), utf8_str.end()});
}
} // namespace essence