mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-01-31 20:41:45 +01:00
New narrow() implementation
This commit is contained in:
parent
0f87c4485d
commit
b0f5796c90
@ -15,29 +15,35 @@
|
||||
|
||||
static std::unique_ptr<wchar_t[]> to_wchar(const std::string& source)
|
||||
{
|
||||
const auto buf_size = source.size() + 1; // size + null terminator
|
||||
// String size + null terminator
|
||||
const std::size_t buf_size = source.size() + 1;
|
||||
|
||||
const int size = source.size() < INT_MAX ? static_cast<int>(buf_size) : (fmt::throw_exception("to_wchar(): invalid source length (0x%llx)", source.size()), 0);
|
||||
// Safe size
|
||||
const int size = narrow<int>(buf_size, "to_wchar" HERE);
|
||||
|
||||
std::unique_ptr<wchar_t[]> buffer(new wchar_t[buf_size]); // allocate buffer assuming that length is the max possible size
|
||||
// Buffer for max possible output length
|
||||
std::unique_ptr<wchar_t[]> buffer(new wchar_t[buf_size]);
|
||||
|
||||
verify("to_wchar" HERE), MultiByteToWideChar(CP_UTF8, 0, source.c_str(), size, buffer.get(), size);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
static void to_utf8(std::string& result, const wchar_t* source)
|
||||
static void to_utf8(std::string& out, const wchar_t* source)
|
||||
{
|
||||
const auto length = std::wcslen(source);
|
||||
// String size
|
||||
const std::size_t length = std::wcslen(source);
|
||||
|
||||
const int buf_size = length <= INT_MAX / 3 ? static_cast<int>(length) * 3 + 1 : (fmt::throw_exception("to_utf8(): invalid source length (0x%llx)", length), 0);
|
||||
// Safe buffer size for max possible output length (including null terminator)
|
||||
const int buf_size = narrow<int>(length * 3 + 1, "to_utf8" HERE);
|
||||
|
||||
result.resize(buf_size); // set max possible length for utf-8 + null terminator
|
||||
// Resize buffer
|
||||
out.resize(buf_size - 1);
|
||||
|
||||
const int nwritten = verify(WideCharToMultiByte(CP_UTF8, 0, source, static_cast<int>(length) + 1, &result.front(), buf_size, NULL, NULL), "to_utf8" HERE);
|
||||
const int result = WideCharToMultiByte(CP_UTF8, 0, source, static_cast<int>(length) + 1, &out.front(), buf_size, NULL, NULL);
|
||||
|
||||
// fix the size, remove null terminator
|
||||
result.resize(nwritten - 1);
|
||||
// Fix the size
|
||||
out.resize(verify(result, "to_utf8" HERE) - 1);
|
||||
}
|
||||
|
||||
static time_t to_time(const ULARGE_INTEGER& ft)
|
||||
@ -722,8 +728,7 @@ bool fs::file::open(const std::string& path, bs_t<open_mode> mode)
|
||||
u64 read(void* buffer, u64 count) override
|
||||
{
|
||||
// TODO (call ReadFile multiple times if count is too big)
|
||||
const int size = ::narrow<int>(count, "Too big count" HERE);
|
||||
EXPECTS(size >= 0);
|
||||
const int size = narrow<int>(count, "file::read" HERE);
|
||||
|
||||
DWORD nread;
|
||||
verify("file::read" HERE), ReadFile(m_handle, buffer, size, &nread, NULL);
|
||||
@ -734,8 +739,7 @@ bool fs::file::open(const std::string& path, bs_t<open_mode> mode)
|
||||
u64 write(const void* buffer, u64 count) override
|
||||
{
|
||||
// TODO (call WriteFile multiple times if count is too big)
|
||||
const int size = ::narrow<int>(count, "Too big count" HERE);
|
||||
EXPECTS(size >= 0);
|
||||
const int size = narrow<int>(count, "file::write" HERE);
|
||||
|
||||
DWORD nwritten;
|
||||
verify("file::write" HERE), WriteFile(m_handle, buffer, size, &nwritten, NULL);
|
||||
|
@ -574,19 +574,110 @@ inline std::remove_reference_t<T>&& verify_move(T&& value, const char* cause, F&
|
||||
return std::move(value);
|
||||
}
|
||||
|
||||
// Narrow cast (throws on failure)
|
||||
// narrow() function details
|
||||
template <typename From, typename To = void, typename = void>
|
||||
struct narrow_impl
|
||||
{
|
||||
// Temporarily (diagnostic)
|
||||
static_assert(std::is_void<To>::value, "narrow_impl<> specialization not found");
|
||||
|
||||
// Returns true if value cannot be represented in type To
|
||||
static constexpr bool test(const From& value)
|
||||
{
|
||||
// Unspecialized cases (including cast to void) always considered narrowing
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
// Unsigned to unsigned narrowing
|
||||
template <typename From, typename To>
|
||||
struct narrow_impl<From, To, std::enable_if_t<std::is_unsigned<From>::value && std::is_unsigned<To>::value>>
|
||||
{
|
||||
static constexpr bool test(const From& value)
|
||||
{
|
||||
return sizeof(To) < sizeof(From) && static_cast<To>(value) != value;
|
||||
}
|
||||
};
|
||||
|
||||
// Signed to signed narrowing
|
||||
template <typename From, typename To>
|
||||
struct narrow_impl<From, To, std::enable_if_t<std::is_signed<From>::value && std::is_signed<To>::value>>
|
||||
{
|
||||
static constexpr bool test(const From& value)
|
||||
{
|
||||
return sizeof(To) < sizeof(From) && static_cast<To>(value) != value;
|
||||
}
|
||||
};
|
||||
|
||||
// Unsigned to signed narrowing
|
||||
template <typename From, typename To>
|
||||
struct narrow_impl<From, To, std::enable_if_t<std::is_unsigned<From>::value && std::is_signed<To>::value>>
|
||||
{
|
||||
static constexpr bool test(const From& value)
|
||||
{
|
||||
return sizeof(To) <= sizeof(From) && value > (static_cast<std::make_unsigned_t<To>>(-1) >> 1);
|
||||
}
|
||||
};
|
||||
|
||||
// Signed to unsigned narrowing (I)
|
||||
template <typename From, typename To>
|
||||
struct narrow_impl<From, To, std::enable_if_t<std::is_signed<From>::value && std::is_unsigned<To>::value && sizeof(To) >= sizeof(From)>>
|
||||
{
|
||||
static constexpr bool test(const From& value)
|
||||
{
|
||||
return value < static_cast<From>(0);
|
||||
}
|
||||
};
|
||||
|
||||
// Signed to unsigned narrowing (II)
|
||||
template <typename From, typename To>
|
||||
struct narrow_impl<From, To, std::enable_if_t<std::is_signed<From>::value && std::is_unsigned<To>::value && sizeof(To) < sizeof(From)>>
|
||||
{
|
||||
static constexpr bool test(const From& value)
|
||||
{
|
||||
return static_cast<std::make_unsigned_t<From>>(value) > static_cast<To>(-1);
|
||||
}
|
||||
};
|
||||
|
||||
// Enum to integer (TODO?)
|
||||
template <typename From, typename To>
|
||||
struct narrow_impl<From, To, std::enable_if_t<std::is_enum<From>::value && std::is_integral<To>::value>>
|
||||
: narrow_impl<std::underlying_type_t<From>, To>
|
||||
{
|
||||
};
|
||||
|
||||
// Integer to enum (TODO?)
|
||||
template <typename From, typename To>
|
||||
struct narrow_impl<From, To, std::enable_if_t<std::is_integral<From>::value && std::is_enum<To>::value>>
|
||||
: narrow_impl<From, std::underlying_type_t<To>>
|
||||
{
|
||||
};
|
||||
|
||||
// Enum to enum (TODO?)
|
||||
template <typename From, typename To>
|
||||
struct narrow_impl<From, To, std::enable_if_t<std::is_enum<From>::value && std::is_enum<To>::value>>
|
||||
: narrow_impl<std::underlying_type_t<From>, std::underlying_type_t<To>>
|
||||
{
|
||||
};
|
||||
|
||||
// Simple type enabled (TODO?)
|
||||
template <typename From, typename To>
|
||||
struct narrow_impl<From, To, void_t<typename From::simple_type>>
|
||||
: narrow_impl<simple_t<From>, To>
|
||||
{
|
||||
};
|
||||
|
||||
template <typename To = void, typename From, typename = decltype(static_cast<To>(std::declval<From>()))>
|
||||
inline To narrow(const From& value, const char* msg = nullptr)
|
||||
{
|
||||
// Allow "narrowing to void" and ensure it always fails in this case
|
||||
auto&& result = static_cast<std::conditional_t<std::is_void<To>::value, From, To>>(value);
|
||||
if (std::is_void<To>::value || static_cast<From>(result) != value)
|
||||
// Narrow check
|
||||
if (narrow_impl<From, To>::test(value))
|
||||
{
|
||||
// Pack value as formatting argument
|
||||
fmt::raw_narrow_error(msg, fmt::get_type_info<typename fmt_unveil<From>::type>(), fmt_unveil<From>::get(value));
|
||||
}
|
||||
|
||||
return static_cast<std::conditional_t<std::is_void<To>::value, void, decltype(result)>>(result);
|
||||
return static_cast<To>(value);
|
||||
}
|
||||
|
||||
// Returns u32 size() for container
|
||||
|
Loading…
x
Reference in New Issue
Block a user