EXCEPTION macro removed

fmt::throw_exception<> implemented
::narrow improved
Minor fixes
This commit is contained in:
Nekotekina 2016-08-08 19:01:06 +03:00
parent 46735d6b3d
commit a7e808b35b
198 changed files with 3025 additions and 2956 deletions

View file

@ -951,12 +951,6 @@ public:
return atomic_op(atomic_post_dec<type>{});
}
template<typename T2 = T>
auto test(const T2& rhs) const
{
return load().test(rhs);
}
template<typename T2 = T>
auto test_and_set(const T2& rhs)
{

View file

@ -12,7 +12,7 @@ namespace cfg
{
if (_type != type::node)
{
throw std::logic_error("Invalid root node");
fmt::throw_exception<std::logic_error>("Invalid root node" HERE);
}
}
@ -21,7 +21,7 @@ namespace cfg
{
if (!owner.m_nodes.emplace(name, this).second)
{
throw std::logic_error("Node already exists");
fmt::throw_exception<std::logic_error>("Node already exists: %s" HERE, name);
}
}
@ -32,7 +32,7 @@ namespace cfg
return *static_cast<const node&>(*this).m_nodes.at(name);
}
throw std::logic_error("Invalid node type");
fmt::throw_exception<std::logic_error>("Invalid node type" HERE);
}
entry_base& entry_base::operator[](const char* name) const
@ -42,7 +42,17 @@ namespace cfg
return *static_cast<const node&>(*this).m_nodes.at(name);
}
throw std::logic_error("Invalid node type");
fmt::throw_exception<std::logic_error>("Invalid node type" HERE);
}
bool entry_base::from_string(const std::string&)
{
fmt::throw_exception<std::logic_error>("from_string() purecall" HERE);
}
bool entry_base::from_list(std::vector<std::string>&&)
{
fmt::throw_exception<std::logic_error>("from_list() purecall" HERE);
}
// Emit YAML

View file

@ -69,10 +69,7 @@ namespace cfg
}
// Try to convert from string (optional)
virtual bool from_string(const std::string&)
{
throw std::logic_error("from_string() not specified");
}
virtual bool from_string(const std::string&);
// Get string list (optional)
virtual std::vector<std::string> to_list() const
@ -81,10 +78,7 @@ namespace cfg
}
// Set multiple values. Implementation-specific, optional.
virtual bool from_list(std::vector<std::string>&&)
{
throw std::logic_error("from_list() not specified");
}
virtual bool from_list(std::vector<std::string>&&);
};
// Config tree node which contains another nodes
@ -223,7 +217,7 @@ namespace cfg
}
map_entry(node& owner, const std::string& name, std::size_t def_index, init_type init)
: map_entry(owner, name, def_index < init.size() ? (init.begin() + def_index)->first : throw std::logic_error("Invalid default value index"), init)
: map_entry(owner, name, (init.begin() + (def_index < init.size() ? def_index : 0))->first, init)
{
}
@ -358,7 +352,7 @@ namespace cfg
{
if (value < Min || value > Max)
{
throw fmt::exception("Value out of the valid range: %lld" HERE, s64{ value });
fmt::throw_exception("Value out of the valid range: %lld" HERE, s64{ value });
}
m_value = value;

View file

@ -18,13 +18,13 @@ static std::unique_ptr<wchar_t[]> to_wchar(const std::string& source)
{
const auto buf_size = source.size() + 1; // size + null terminator
const int size = source.size() < INT_MAX ? static_cast<int>(buf_size) : throw fmt::exception("to_wchar(): invalid source length (0x%llx)", source.size());
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);
std::unique_ptr<wchar_t[]> buffer(new wchar_t[buf_size]); // allocate buffer assuming that length is the max possible size
if (!MultiByteToWideChar(CP_UTF8, 0, source.c_str(), size, buffer.get(), size))
{
throw fmt::exception("to_wchar(): MultiByteToWideChar() failed: error %u.", GetLastError());
fmt::throw_exception("to_wchar(): MultiByteToWideChar() failed: error %u.", GetLastError());
}
return buffer;
@ -34,7 +34,7 @@ static void to_utf8(std::string& result, const wchar_t* source)
{
const auto length = std::wcslen(source);
const int buf_size = length <= INT_MAX / 3 ? static_cast<int>(length) * 3 + 1 : throw fmt::exception("to_utf8(): invalid source length (0x%llx)", length);
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);
result.resize(buf_size); // set max possible length for utf-8 + null terminator
@ -44,7 +44,7 @@ static void to_utf8(std::string& result, const wchar_t* source)
}
else
{
throw fmt::exception("to_utf8(): WideCharToMultiByte() failed: error %u.", GetLastError());
fmt::throw_exception("to_utf8(): WideCharToMultiByte() failed: error %u.", GetLastError());
}
}
@ -82,7 +82,7 @@ static fs::error to_error(DWORD e)
case ERROR_NEGATIVE_SEEK: return fs::error::inval;
case ERROR_DIRECTORY: return fs::error::inval;
case ERROR_INVALID_NAME: return fs::error::inval;
default: throw fmt::exception("Unknown Win32 error: %u.", e);
default: fmt::throw_exception("Unknown Win32 error: %u.", e);
}
}
@ -111,7 +111,7 @@ static fs::error to_error(int e)
case ENOENT: return fs::error::noent;
case EEXIST: return fs::error::exist;
case EINVAL: return fs::error::inval;
default: throw fmt::exception("Unknown system error: %d.", e);
default: fmt::throw_exception("Unknown system error: %d.", e);
}
}
@ -465,7 +465,7 @@ bool fs::rename(const std::string& from, const std::string& to)
if (device != get_virtual_device(to))
{
throw fmt::exception("fs::rename() between different devices not implemented.\nFrom: %s\nTo: %s", from, to);
fmt::throw_exception("fs::rename() between different devices not implemented.\nFrom: %s\nTo: %s", from, to);
}
if (device)
@ -498,7 +498,7 @@ bool fs::copy_file(const std::string& from, const std::string& to, bool overwrit
if (device != get_virtual_device(to) || device) // TODO
{
throw fmt::exception("fs::copy_file() for virtual devices not implemented.\nFrom: %s\nTo: %s", from, to);
fmt::throw_exception("fs::copy_file() for virtual devices not implemented.\nFrom: %s\nTo: %s", from, to);
}
#ifdef _WIN32
@ -622,12 +622,12 @@ bool fs::truncate_file(const std::string& path, u64 length)
void fs::file::xnull() const
{
throw std::logic_error("fs::file is null");
fmt::throw_exception<std::logic_error>("fs::file is null");
}
void fs::file::xfail() const
{
throw fmt::exception("Unexpected fs::error %s", g_tls_error);
fmt::throw_exception("Unexpected fs::error %s", g_tls_error);
}
bool fs::file::open(const std::string& path, bs_t<open_mode> mode)
@ -694,7 +694,7 @@ bool fs::file::open(const std::string& path, bs_t<open_mode> mode)
FILE_BASIC_INFO basic_info;
if (!GetFileInformationByHandleEx(m_handle, FileBasicInfo, &basic_info, sizeof(FILE_BASIC_INFO)))
{
throw fmt::exception("Win32 error: %u." HERE, GetLastError());
fmt::throw_exception("Win32 error: %u." HERE, GetLastError());
}
stat_t info;
@ -730,7 +730,7 @@ bool fs::file::open(const std::string& path, bs_t<open_mode> mode)
if (!result || !SetFilePointerEx(m_handle, old, NULL, FILE_BEGIN)) // restore position
{
throw fmt::exception("Win32 error: %u." HERE, GetLastError());
fmt::throw_exception("Win32 error: %u." HERE, GetLastError());
}
return result != FALSE;
@ -745,7 +745,7 @@ bool fs::file::open(const std::string& path, bs_t<open_mode> mode)
DWORD nread;
if (!ReadFile(m_handle, buffer, size, &nread, NULL))
{
throw fmt::exception("Win32 error: %u." HERE, GetLastError());
fmt::throw_exception("Win32 error: %u." HERE, GetLastError());
}
return nread;
@ -760,7 +760,7 @@ bool fs::file::open(const std::string& path, bs_t<open_mode> mode)
DWORD nwritten;
if (!WriteFile(m_handle, buffer, size, &nwritten, NULL))
{
throw fmt::exception("Win32 error: %u." HERE, GetLastError());
fmt::throw_exception("Win32 error: %u." HERE, GetLastError());
}
return nwritten;
@ -775,11 +775,11 @@ bool fs::file::open(const std::string& path, bs_t<open_mode> mode)
whence == seek_set ? FILE_BEGIN :
whence == seek_cur ? FILE_CURRENT :
whence == seek_end ? FILE_END :
throw fmt::exception("Invalid whence (0x%x)" HERE, whence);
(fmt::throw_exception("Invalid whence (0x%x)" HERE, whence), 0);
if (!SetFilePointerEx(m_handle, pos, &pos, mode))
{
throw fmt::exception("Win32 error: %u." HERE, GetLastError());
fmt::throw_exception("Win32 error: %u." HERE, GetLastError());
}
return pos.QuadPart;
@ -790,7 +790,7 @@ bool fs::file::open(const std::string& path, bs_t<open_mode> mode)
LARGE_INTEGER size;
if (!GetFileSizeEx(m_handle, &size))
{
throw fmt::exception("Win32 error: %u." HERE, GetLastError());
fmt::throw_exception("Win32 error: %u." HERE, GetLastError());
}
return size.QuadPart;
@ -838,7 +838,7 @@ bool fs::file::open(const std::string& path, bs_t<open_mode> mode)
struct ::stat file_info;
if (::fstat(m_fd, &file_info) != 0)
{
throw fmt::exception("System error: %d." HERE, errno);
fmt::throw_exception("System error: %d." HERE, errno);
}
stat_t info;
@ -868,7 +868,7 @@ bool fs::file::open(const std::string& path, bs_t<open_mode> mode)
const auto result = ::read(m_fd, buffer, count);
if (result == -1)
{
throw fmt::exception("System error: %d." HERE, errno);
fmt::throw_exception("System error: %d." HERE, errno);
}
return result;
@ -879,7 +879,7 @@ bool fs::file::open(const std::string& path, bs_t<open_mode> mode)
const auto result = ::write(m_fd, buffer, count);
if (result == -1)
{
throw fmt::exception("System error: %d." HERE, errno);
fmt::throw_exception("System error: %d." HERE, errno);
}
return result;
@ -891,12 +891,12 @@ bool fs::file::open(const std::string& path, bs_t<open_mode> mode)
whence == seek_set ? SEEK_SET :
whence == seek_cur ? SEEK_CUR :
whence == seek_end ? SEEK_END :
throw fmt::exception("Invalid whence (0x%x)" HERE, whence);
(fmt::throw_exception("Invalid whence (0x%x)" HERE, whence), 0);
const auto result = ::lseek(m_fd, offset, mode);
if (result == -1)
{
throw fmt::exception("System error: %d." HERE, errno);
fmt::throw_exception("System error: %d." HERE, errno);
}
return result;
@ -907,7 +907,7 @@ bool fs::file::open(const std::string& path, bs_t<open_mode> mode)
struct ::stat file_info;
if (::fstat(m_fd, &file_info) != 0)
{
throw fmt::exception("System error: %d." HERE, errno);
fmt::throw_exception("System error: %d." HERE, errno);
}
return file_info.st_size;
@ -938,26 +938,27 @@ fs::file::file(const void* ptr, std::size_t size)
fs::stat_t stat() override
{
throw std::logic_error("Not supported" HERE);
fmt::throw_exception<std::logic_error>("Not supported" HERE);
}
bool trunc(u64 length) override
{
throw std::logic_error("Not allowed" HERE);
fmt::throw_exception<std::logic_error>("Not allowed" HERE);
}
u64 read(void* buffer, u64 count) override
{
const u64 start = m_pos;
const u64 end = seek(count, fs::seek_cur);
const u64 read_size = end >= start ? end - start : throw std::logic_error("Stream overflow" HERE);
if (end < start) fmt::throw_exception<std::logic_error>("Stream overflow" HERE);
const u64 read_size = end - start;
std::memcpy(buffer, m_ptr + start, read_size);
return read_size;
}
u64 write(const void* buffer, u64 count) override
{
throw std::logic_error("Not allowed" HERE);
fmt::throw_exception<std::logic_error>("Not allowed" HERE);
}
u64 seek(s64 offset, fs::seek_mode whence) override
@ -966,7 +967,7 @@ fs::file::file(const void* ptr, std::size_t size)
whence == fs::seek_set ? m_pos = std::min<u64>(offset, m_size) :
whence == fs::seek_cur ? m_pos = std::min<u64>(offset + m_pos, m_size) :
whence == fs::seek_end ? m_pos = std::min<u64>(offset + m_size, m_size) :
throw fmt::exception("Invalid whence (0x%x)" HERE, whence);
(fmt::throw_exception("Invalid whence (0x%x)" HERE, whence), 0);
}
u64 size() override
@ -980,7 +981,7 @@ fs::file::file(const void* ptr, std::size_t size)
void fs::dir::xnull() const
{
throw std::logic_error("fs::dir is null");
fmt::throw_exception<std::logic_error>("fs::dir is null");
}
bool fs::dir::open(const std::string& path)
@ -1052,7 +1053,7 @@ bool fs::dir::open(const std::string& path)
return false;
}
throw fmt::exception("Win32 error: %u." HERE, GetLastError());
fmt::throw_exception("Win32 error: %u." HERE, GetLastError());
}
add_entry(found);
@ -1104,7 +1105,7 @@ bool fs::dir::open(const std::string& path)
struct ::stat file_info;
if (::fstatat(::dirfd(m_dd), found->d_name, &file_info, 0) != 0)
{
throw fmt::exception("System error: %d." HERE, errno);
fmt::throw_exception("System error: %d." HERE, errno);
}
info.name = found->d_name;

View file

@ -80,7 +80,7 @@ struct MemoryManager final : llvm::RTDyldMemoryManager
[[noreturn]] static void null()
{
throw std::runtime_error("Null function" HERE);
fmt::throw_exception("Null function" HERE);
}
virtual u64 getSymbolAddress(const std::string& name) override
@ -237,7 +237,7 @@ jit_compiler::jit_compiler(std::unique_ptr<llvm::Module>&& _module, std::unorder
if (!m_engine)
{
throw fmt::exception("LLVM: Failed to create ExecutionEngine: %s", result);
fmt::throw_exception("LLVM: Failed to create ExecutionEngine: %s", result);
}
m_engine->setProcessAllSections(true); // ???

View file

@ -112,7 +112,7 @@ logs::file_writer::file_writer(const std::string& name)
{
if (!m_file.open(fs::get_config_dir() + name, fs::rewrite + fs::append))
{
throw fmt::exception("Can't create log file %s (error %s)", name, fs::g_tls_error);
fmt::throw_exception("Can't create log file %s (error %s)", name, fs::g_tls_error);
}
}
catch (...)

View file

@ -71,7 +71,7 @@ namespace logs
{
if (UNLIKELY(sev <= enabled))
{
message{this, sev}.broadcast(fmt, fmt_type_info::get<fmt_unveil_t<Args>...>(), fmt_args_t<Args...>{fmt_unveil<Args>::get(args)...});
message{this, sev}.broadcast(fmt, fmt::get_type_info<fmt_unveil_t<Args>...>(), fmt_args_t<Args...>{fmt_unveil<Args>::get(args)...});
}
}

View file

@ -1,41 +1,6 @@
#pragma once
#include <cstdint>
#include <exception>
template<typename T, typename = std::enable_if_t<std::is_integral<T>::value>>
constexpr T align(const T& value, std::uint64_t align)
{
return static_cast<T>((value + (align - 1)) & ~(align - 1));
}
template<typename To, typename From>
constexpr To narrow_impl(const To& result, const From& value, const char* message)
{
return static_cast<From>(result) != value ? throw std::runtime_error(message) : result;
}
// Narrow cast (similar to gsl::narrow) with fixed message
template<typename To, typename From>
constexpr auto narrow(const From& value, const char* fixed_msg = "::narrow() failed") -> decltype(static_cast<To>(static_cast<From>(std::declval<To>())))
{
return narrow_impl(static_cast<To>(value), value, fixed_msg);
}
// Return 32 bit .size() for container
template<typename CT>
constexpr auto size32(const CT& container, const char* fixed_msg = "::size32() failed") -> decltype(static_cast<std::uint32_t>(container.size()))
{
return narrow<std::uint32_t>(container.size(), fixed_msg);
}
// Return 32 bit size for an array
template<typename T, std::size_t Size>
constexpr std::uint32_t size32(const T(&)[Size])
{
static_assert(Size <= UINT32_MAX, "size32() error: too big");
return static_cast<std::uint32_t>(Size);
}
#include "types.h"
#define CHECK_SIZE(type, size) static_assert(sizeof(type) == size, "Invalid " #type " type size")
#define CHECK_ALIGN(type, align) static_assert(alignof(type) == align, "Invalid " #type " type alignment")
@ -71,12 +36,12 @@ constexpr std::uint32_t size32(const T(&)[Size])
#define HERE "\n(in file " __FILE__ ":" STRINGIZE(__LINE__) ")"
// Ensure that the expression is evaluated to true. Always evaluated and allowed to have side effects (unlike assert() macro).
#define VERIFY(expr) do { if (!(expr)) throw std::runtime_error("Verification failed: " #expr HERE); } while (0)
#define VERIFY(expr) do { if (!(expr)) fmt::raw_error("Verification failed: " #expr HERE); } while (0)
// EXPECTS() and ENSURES() are intended to check function arguments and results.
// Expressions are not guaranteed to evaluate.
#define EXPECTS(expr) do { if (!(expr)) throw std::runtime_error("Precondition failed: " #expr HERE); } while (0)
#define ENSURES(expr) do { if (!(expr)) throw std::runtime_error("Postcondition failed: " #expr HERE); } while (0)
#define EXPECTS(expr) do { if (!(expr)) fmt::raw_error("Precondition failed: " #expr HERE); } while (0)
#define ENSURES(expr) do { if (!(expr)) fmt::raw_error("Postcondition failed: " #expr HERE); } while (0)
#define DECLARE(...) decltype(__VA_ARGS__) __VA_ARGS__

View file

@ -128,6 +128,52 @@ void fmt_class_string<v128>::format(std::string& out, u64 arg)
namespace fmt
{
void raw_error(const char* msg)
{
std::string out;
out += "Error: ";
out += msg;
throw std::runtime_error(out);
}
void raw_narrow_error(const char* msg, const fmt_type_info* sup, u64 arg)
{
std::string out;
out += "Narrow error: (";
sup->fmt_string(out, arg); // Print value
out += ")";
if (msg)
{
out += " ";
out += msg;
}
throw std::range_error(out);
}
// Hidden template
template<typename T>
void raw_throw_exception(const char* fmt, const fmt_type_info* sup, const u64* args)
{
std::string out;
raw_append(out, fmt, sup, args);
throw T{out};
}
// Explicit instantiations (not exhaustive)
template void raw_throw_exception<std::runtime_error>(const char*, const fmt_type_info*, const u64*);
template void raw_throw_exception<std::logic_error>(const char*, const fmt_type_info*, const u64*);
template void raw_throw_exception<std::domain_error>(const char*, const fmt_type_info*, const u64*);
template void raw_throw_exception<std::invalid_argument>(const char*, const fmt_type_info*, const u64*);
template void raw_throw_exception<std::out_of_range>(const char*, const fmt_type_info*, const u64*);
template void raw_throw_exception<std::range_error>(const char*, const fmt_type_info*, const u64*);
template void raw_throw_exception<std::overflow_error>(const char*, const fmt_type_info*, const u64*);
template void raw_throw_exception<std::underflow_error>(const char*, const fmt_type_info*, const u64*);
struct cfmt_src;
}
@ -191,13 +237,6 @@ void fmt::raw_append(std::string& out, const char* fmt, const fmt_type_info* sup
cfmt_append(out, fmt, cfmt_src{sup, args});
}
char* fmt::alloc_format(const char* fmt, const fmt_type_info* sup, const u64* args) noexcept
{
std::string str;
raw_append(str, fmt, sup, args);
return static_cast<char*>(std::memcpy(std::malloc(str.size() + 1), str.data(), str.size() + 1));
}
std::string fmt::replace_first(const std::string& src, const std::string& from, const std::string& to)
{
auto pos = src.find(from);

View file

@ -2,7 +2,6 @@
#include <exception>
#include <string>
#include <memory>
#include "Platform.h"
#include "types.h"
@ -212,18 +211,6 @@ struct fmt_type_info
&fmt_class_string<T>::format,
};
}
template<typename... Args>
static inline const fmt_type_info* get()
{
// Constantly initialized null-terminated list of type-specific information
static constexpr fmt_type_info result[sizeof...(Args) + 1]
{
make<Args>()...
};
return result;
}
};
template<typename Arg>
@ -235,6 +222,18 @@ using fmt_args_t = const u64(&&)[sizeof...(Args) + 1];
namespace fmt
{
template<typename... Args>
const fmt_type_info* get_type_info()
{
// Constantly initialized null-terminated list of type-specific information
static constexpr fmt_type_info result[sizeof...(Args) + 1]
{
fmt_type_info::make<Args>()...
};
return result;
}
// Internal formatting function
void raw_append(std::string& out, const char*, const fmt_type_info*, const u64*) noexcept;
@ -242,7 +241,7 @@ namespace fmt
template<typename... Args>
static SAFE_BUFFERS void append(std::string& out, const char* fmt, const Args&... args)
{
raw_append(out, fmt, fmt_type_info::get<fmt_unveil_t<Args>...>(), fmt_args_t<Args...>{fmt_unveil<Args>::get(args)...});
raw_append(out, fmt, fmt::get_type_info<fmt_unveil_t<Args>...>(), fmt_args_t<Args...>{fmt_unveil<Args>::get(args)...});
}
// Formatting function
@ -254,24 +253,14 @@ namespace fmt
return result;
}
// Internal helper function
char* alloc_format(const char*, const fmt_type_info*, const u64*) noexcept;
// Internal exception message formatting template, must be explicitly specialized or instantiated in cpp to minimize code bloat
template<typename T>
[[noreturn]] void raw_throw_exception(const char*, const fmt_type_info*, const u64*);
// Exception type with formatting constructor
template<typename Base>
class exception_t : public Base
// Throw exception with formatting
template<typename T = std::runtime_error, typename... Args>
[[noreturn]] SAFE_BUFFERS FORCE_INLINE void throw_exception(const char* fmt, const Args&... args)
{
using base = Base;
public:
template<typename... Args>
SAFE_BUFFERS exception_t(const char* fmt, const Args&... args)
: base((fmt = alloc_format(fmt, fmt_type_info::get<fmt_unveil_t<Args>...>(), fmt_args_t<Args...>{fmt_unveil<Args>::get(args)...})))
{
std::free(const_cast<char*>(fmt));
}
};
// Exception type derived from std::runtime_error with formatting constructor
using exception = exception_t<std::runtime_error>;
raw_throw_exception<T>(fmt, fmt::get_type_info<fmt_unveil_t<Args>...>(), fmt_args_t<Args...>{fmt_unveil<Args>::get(args)...});
}
}

View file

@ -27,14 +27,18 @@ namespace gsl
enum class byte : u8;
}
namespace fmt
{
}
// Formatting helper, type-specific preprocessing for improving safety and functionality
template<typename T, typename = void>
struct fmt_unveil;
struct fmt_type_info;
namespace fmt
{
template<typename... Args>
const fmt_type_info* get_type_info();
}
template<typename T, std::size_t Align = alignof(T), std::size_t Size = sizeof(T)>
struct se_storage;
@ -410,6 +414,84 @@ struct ignore
}
};
template<typename T, typename = std::enable_if_t<std::is_integral<T>::value>>
constexpr T align(const T& value, std::uint64_t align)
{
return static_cast<T>((value + (align - 1)) & ~(align - 1));
}
namespace fmt
{
[[noreturn]] void raw_error(const char* msg);
[[noreturn]] void raw_narrow_error(const char* msg, const fmt_type_info* sup, u64 arg);
}
// Narrow cast (throws on failure)
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)
{
// 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);
}
// Returns u32 size() for container
template<typename CT, typename = decltype(static_cast<u32>(std::declval<CT>().size()))>
inline u32 size32(const CT& container, const char* msg = nullptr)
{
return narrow<u32>(container.size(), msg);
}
// Returns u32 size for an array
template<typename T, std::size_t Size>
constexpr u32 size32(const T(&)[Size], const char* msg = nullptr)
{
return static_cast<u32>(Size);
}
template<typename T1, typename = std::enable_if_t<std::is_integral<T1>::value>>
constexpr bool test(const T1& value)
{
return value != 0;
}
template<typename T1, typename T2, typename = std::enable_if_t<std::is_integral<T1>::value && std::is_integral<T2>::value>>
constexpr bool test(const T1& lhs, const T2& rhs)
{
return (lhs & rhs) != 0;
}
template<typename T, typename T2, typename = std::enable_if_t<std::is_integral<T>::value && std::is_integral<T2>::value>>
inline bool test_and_set(T& lhs, const T2& rhs)
{
const bool result = (lhs & rhs) != 0;
lhs |= rhs;
return result;
}
template<typename T, typename T2, typename = std::enable_if_t<std::is_integral<T>::value && std::is_integral<T2>::value>>
inline bool test_and_reset(T& lhs, const T2& rhs)
{
const bool result = (lhs & rhs) != 0;
lhs &= ~rhs;
return result;
}
template<typename T, typename T2, typename = std::enable_if_t<std::is_integral<T>::value && std::is_integral<T2>::value>>
inline bool test_and_complement(T& lhs, const T2& rhs)
{
const bool result = (lhs & rhs) != 0;
lhs ^= rhs;
return result;
}
// Simplified hash algorithm for pointers. May be used in std::unordered_(map|set).
template<typename T, std::size_t Align = alignof(T)>
struct pointer_hash

View file

@ -14,7 +14,7 @@ namespace utils
case version_type::release: return "Release";
}
throw type;
return "Unknown";
}
uint version::to_hex() const