diff --git a/Utilities/BitSet.h b/Utilities/BitSet.h new file mode 100644 index 0000000000..77d8f7c4de --- /dev/null +++ b/Utilities/BitSet.h @@ -0,0 +1,253 @@ +#pragma once + +#include "types.h" + +// Small bitset for enum class types with available values [0, BitSize). +// T must be either enum type or convertible to (registered with via simple_t). +// Internal representation is single value of type T. +template +struct bitset_t +{ + using type = simple_t; + using under = std::underlying_type_t; + + static constexpr auto bitsize = BitSize; + + bitset_t() = default; + + constexpr bitset_t(type _enum_const) + : m_value(static_cast(shift(_enum_const))) + { + } + + constexpr bitset_t(under raw_value, const std::nothrow_t&) + : m_value(static_cast(raw_value)) + { + } + + // Get underlying value + constexpr under _value() const + { + return static_cast(m_value); + } + + explicit constexpr operator bool() const + { + return _value() ? true : false; + } + + bitset_t& operator +=(bitset_t rhs) + { + return *this = { _value() | rhs._value(), std::nothrow }; + } + + bitset_t& operator -=(bitset_t rhs) + { + return *this = { _value() & ~rhs._value(), std::nothrow }; + } + + bitset_t& operator &=(bitset_t rhs) + { + return *this = { _value() & rhs._value(), std::nothrow }; + } + + bitset_t& operator ^=(bitset_t rhs) + { + return *this = { _value() ^ rhs._value(), std::nothrow }; + } + + friend constexpr bitset_t operator +(bitset_t lhs, bitset_t rhs) + { + return{ lhs._value() | rhs._value(), std::nothrow }; + } + + friend constexpr bitset_t operator -(bitset_t lhs, bitset_t rhs) + { + return{ lhs._value() & ~rhs._value(), std::nothrow }; + } + + friend constexpr bitset_t operator &(bitset_t lhs, bitset_t rhs) + { + return{ lhs._value() & rhs._value(), std::nothrow }; + } + + friend constexpr bitset_t operator ^(bitset_t lhs, bitset_t rhs) + { + return{ lhs._value() ^ rhs._value(), std::nothrow }; + } + + bool test(bitset_t rhs) const + { + const under v = _value(); + const under s = rhs._value(); + return (v & s) != 0; + } + + bool test_and_set(bitset_t rhs) + { + const under v = _value(); + const under s = rhs._value(); + *this = { v | s, std::nothrow }; + return (v & s) != 0; + } + + bool test_and_reset(bitset_t rhs) + { + const under v = _value(); + const under s = rhs._value(); + *this = { v & ~s, std::nothrow }; + return (v & s) != 0; + } + + bool test_and_complement(bitset_t rhs) + { + const under v = _value(); + const under s = rhs._value(); + *this = { v ^ s, std::nothrow }; + return (v & s) != 0; + } + +private: + static constexpr under shift(const T& value) + { + return static_cast(value) < BitSize ? static_cast(1) << static_cast(value) : throw value; + } + + T m_value; +}; + +template +constexpr RT make_bitset() +{ + return RT{}; +} + +// Fold enum constants into bitset_t<> (must be implemented with constexpr initializer_list constructor instead) +template::value, bitset_t, T>> +constexpr RT make_bitset(Arg&& _enum_const, Args&&... args) +{ + return RT{ std::forward(_enum_const) } + make_bitset(std::forward(args)...); +} + +template +struct atomic_add, CT, std::enable_if_t::value>> +{ + using under = typename bitset_t::under; + + static inline bitset_t op1(bitset_t& left, bitset_t right) + { + return{ atomic_storage::fetch_or(reinterpret_cast(left), right._value()), std::nothrow }; + } + + static constexpr auto fetch_op = &op1; + + static inline bitset_t op2(bitset_t& left, bitset_t right) + { + return{ atomic_storage::or_fetch(reinterpret_cast(left), right._value()), std::nothrow }; + } + + static constexpr auto op_fetch = &op2; + static constexpr auto atomic_op = &op2; +}; + +template +struct atomic_sub, CT, std::enable_if_t::value>> +{ + using under = typename bitset_t::under; + + static inline bitset_t op1(bitset_t& left, bitset_t right) + { + return{ atomic_storage::fetch_and(reinterpret_cast(left), ~right._value()), std::nothrow }; + } + + static constexpr auto fetch_op = &op1; + + static inline bitset_t op2(bitset_t& left, bitset_t right) + { + return{ atomic_storage::and_fetch(reinterpret_cast(left), ~right._value()), std::nothrow }; + } + + static constexpr auto op_fetch = &op2; + static constexpr auto atomic_op = &op2; +}; + +template +struct atomic_and, CT, std::enable_if_t::value>> +{ + using under = typename bitset_t::under; + + static inline bitset_t op1(bitset_t& left, bitset_t right) + { + return{ atomic_storage::fetch_and(reinterpret_cast(left), right._value()), std::nothrow }; + } + + static constexpr auto fetch_op = &op1; + + static inline bitset_t op2(bitset_t& left, bitset_t right) + { + return{ atomic_storage::and_fetch(reinterpret_cast(left), right._value()), std::nothrow }; + } + + static constexpr auto op_fetch = &op2; + static constexpr auto atomic_op = &op2; +}; + +template +struct atomic_xor, CT, std::enable_if_t::value>> +{ + using under = typename bitset_t::under; + + static inline bitset_t op1(bitset_t& left, bitset_t right) + { + return{ atomic_storage::fetch_xor(reinterpret_cast(left), right._value()), std::nothrow }; + } + + static constexpr auto fetch_op = &op1; + + static inline bitset_t op2(bitset_t& left, bitset_t right) + { + return{ atomic_storage::xor_fetch(reinterpret_cast(left), right._value()), std::nothrow }; + } + + static constexpr auto op_fetch = &op2; + static constexpr auto atomic_op = &op2; +}; + +template +struct atomic_test_and_set, T, std::enable_if_t::value>> +{ + using under = typename bitset_t::under; + + static inline bool _op(bitset_t& left, const T& value) + { + return atomic_storage::bts(reinterpret_cast(left), static_cast(value)); + } + + static constexpr auto atomic_op = &_op; +}; + +template +struct atomic_test_and_reset, T, std::enable_if_t::value>> +{ + using under = typename bitset_t::under; + + static inline bool _op(bitset_t& left, const T& value) + { + return atomic_storage::btr(reinterpret_cast(left), static_cast(value)); + } + + static constexpr auto atomic_op = &_op; +}; + +template +struct atomic_test_and_complement, T, std::enable_if_t::value>> +{ + using under = typename bitset_t::under; + + static inline bool _op(bitset_t& left, const T& value) + { + return atomic_storage::btc(reinterpret_cast(left), static_cast(value)); + } + + static constexpr auto atomic_op = &_op; +}; diff --git a/Utilities/Config.h b/Utilities/Config.h index 6d81580d60..d9b0d76938 100644 --- a/Utilities/Config.h +++ b/Utilities/Config.h @@ -296,11 +296,11 @@ namespace cfg std::string to_string() const override { - for (const auto& pair : bijective::map) + for (std::size_t i = 0; i < sizeof(bijective::map) / sizeof(bijective_pair); i++) { - if (pair.first == m_value) + if (bijective::map[i].v1 == m_value) { - return pair.second; + return bijective::map[i].v2; } } @@ -309,11 +309,11 @@ namespace cfg bool from_string(const std::string& value) override { - for (const auto& pair : bijective::map) + for (std::size_t i = 0; i < sizeof(bijective::map) / sizeof(bijective_pair); i++) { - if (pair.second == value) + if (bijective::map[i].v2 == value) { - m_value = pair.first; + m_value = bijective::map[i].v1; return true; } } @@ -325,9 +325,9 @@ namespace cfg { std::vector result; - for (const auto& pair : bijective::map) + for (std::size_t i = 0; i < sizeof(bijective::map) / sizeof(bijective_pair); i++) { - result.emplace_back(pair.second); + result.emplace_back(bijective::map[i].v2); } return result; diff --git a/Utilities/File.cpp b/Utilities/File.cpp index 246735f950..ea24c4d26f 100644 --- a/Utilities/File.cpp +++ b/Utilities/File.cpp @@ -5,6 +5,7 @@ #include #include +#include #ifdef _WIN32 @@ -90,6 +91,8 @@ static time_t to_time(const FILETIME& ft) namespace fs { + thread_local uint error = 0; + class device_manager final { mutable shared_mutex m_mutex; @@ -213,8 +216,8 @@ bool fs::stat(const std::string& path, stat_t& info) // TODO: convert Win32 error code to errno switch (DWORD error = GetLastError()) { - case ERROR_FILE_NOT_FOUND: errno = ENOENT; break; - case ERROR_PATH_NOT_FOUND: errno = ENOENT; break; + case ERROR_FILE_NOT_FOUND: fs::error = ENOENT; break; + case ERROR_PATH_NOT_FOUND: fs::error = ENOENT; break; default: throw fmt::exception("Unknown Win32 error: %u (%s)." HERE, error, path); } @@ -231,6 +234,7 @@ bool fs::stat(const std::string& path, stat_t& info) struct ::stat file_info; if (::stat(path.c_str(), &file_info) != 0) { + fs::error = errno; return false; } @@ -259,8 +263,8 @@ bool fs::exists(const std::string& path) // TODO: convert Win32 error code to errno switch (DWORD error = GetLastError()) { - case ERROR_FILE_NOT_FOUND: errno = ENOENT; break; - case ERROR_PATH_NOT_FOUND: errno = ENOENT; break; + case ERROR_FILE_NOT_FOUND: fs::error = ENOENT; break; + case ERROR_PATH_NOT_FOUND: fs::error = ENOENT; break; default: throw fmt::exception("Unknown Win32 error: %u (%s)." HERE, error, path); } @@ -270,7 +274,13 @@ bool fs::exists(const std::string& path) return true; #else struct ::stat file_info; - return !::stat(path.c_str(), &file_info); + if (::stat(path.c_str(), &file_info) != 0) + { + fs::error = errno; + return false; + } + + return true; #endif } @@ -286,7 +296,7 @@ bool fs::is_file(const std::string& path) if (info.is_directory) { - errno = EEXIST; + fs::error = EEXIST; return false; } @@ -300,8 +310,8 @@ bool fs::is_file(const std::string& path) // TODO: convert Win32 error code to errno switch (DWORD error = GetLastError()) { - case ERROR_FILE_NOT_FOUND: errno = ENOENT; break; - case ERROR_PATH_NOT_FOUND: errno = ENOENT; break; + case ERROR_FILE_NOT_FOUND: fs::error = ENOENT; break; + case ERROR_PATH_NOT_FOUND: fs::error = ENOENT; break; default: throw fmt::exception("Unknown Win32 error: %u (%s)." HERE, error, path); } @@ -311,6 +321,7 @@ bool fs::is_file(const std::string& path) struct ::stat file_info; if (::stat(path.c_str(), &file_info) != 0) { + fs::error = errno; return false; } #endif @@ -322,7 +333,7 @@ bool fs::is_file(const std::string& path) if (S_ISDIR(file_info.st_mode)) #endif { - errno = EEXIST; + fs::error = EEXIST; return false; } @@ -341,7 +352,7 @@ bool fs::is_dir(const std::string& path) if (info.is_directory == false) { - errno = EEXIST; + fs::error = EEXIST; return false; } @@ -355,8 +366,8 @@ bool fs::is_dir(const std::string& path) // TODO: convert Win32 error code to errno switch (DWORD error = GetLastError()) { - case ERROR_FILE_NOT_FOUND: errno = ENOENT; break; - case ERROR_PATH_NOT_FOUND: errno = ENOENT; break; + case ERROR_FILE_NOT_FOUND: fs::error = ENOENT; break; + case ERROR_PATH_NOT_FOUND: fs::error = ENOENT; break; default: throw fmt::exception("Unknown Win32 error: %u (%s)." HERE, error, path); } @@ -366,6 +377,7 @@ bool fs::is_dir(const std::string& path) struct ::stat file_info; if (::stat(path.c_str(), &file_info) != 0) { + fs::error = errno; return false; } #endif @@ -376,7 +388,7 @@ bool fs::is_dir(const std::string& path) if (!S_ISDIR(file_info.st_mode)) #endif { - errno = EEXIST; + fs::error = EEXIST; return false; } @@ -396,8 +408,8 @@ bool fs::create_dir(const std::string& path) // TODO: convert Win32 error code to errno switch (DWORD error = GetLastError()) { - case ERROR_ALREADY_EXISTS: errno = EEXIST; break; - case ERROR_PATH_NOT_FOUND: errno = ENOENT; break; + case ERROR_ALREADY_EXISTS: fs::error = EEXIST; break; + case ERROR_PATH_NOT_FOUND: fs::error = ENOENT; break; default: throw fmt::exception("Unknown Win32 error: %u (%s)." HERE, error, path); } @@ -406,7 +418,13 @@ bool fs::create_dir(const std::string& path) return true; #else - return !::mkdir(path.c_str(), S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH); + if (::mkdir(path.c_str(), S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) != 0) + { + fs::error = errno; + return false; + } + + return true; #endif } @@ -435,7 +453,7 @@ bool fs::remove_dir(const std::string& path) // TODO: convert Win32 error code to errno switch (DWORD error = GetLastError()) { - case ERROR_PATH_NOT_FOUND: errno = ENOENT; break; + case ERROR_PATH_NOT_FOUND: fs::error = ENOENT; break; default: throw fmt::exception("Unknown Win32 error: %u (%s)." HERE, error, path); } @@ -444,7 +462,13 @@ bool fs::remove_dir(const std::string& path) return true; #else - return !::rmdir(path.c_str()); + if (::rmdir(path.c_str()) != 0) + { + fs::error = errno; + return false; + } + + return true; #endif } @@ -468,7 +492,7 @@ bool fs::rename(const std::string& from, const std::string& to) // TODO: convert Win32 error code to errno switch (DWORD error = GetLastError()) { - case ERROR_PATH_NOT_FOUND: errno = ENOENT; break; + case ERROR_PATH_NOT_FOUND: fs::error = ENOENT; break; default: throw fmt::exception("Unknown Win32 error: %u.\nFrom: %s\nTo: %s" HERE, error, from, to); } @@ -477,7 +501,13 @@ bool fs::rename(const std::string& from, const std::string& to) return true; #else - return !::rename(from.c_str(), to.c_str()); + if (::rename(from.c_str(), to.c_str()) != 0) + { + fs::error = errno; + return false; + } + + return true; #endif } @@ -496,7 +526,7 @@ bool fs::copy_file(const std::string& from, const std::string& to, bool overwrit // TODO: convert Win32 error code to errno switch (DWORD error = GetLastError()) { - case ERROR_PATH_NOT_FOUND: errno = ENOENT; break; + case ERROR_PATH_NOT_FOUND: fs::error = ENOENT; break; default: throw fmt::exception("Unknown Win32 error: %u.\nFrom: %s\nTo: %s" HERE, error, from, to); } @@ -510,6 +540,7 @@ bool fs::copy_file(const std::string& from, const std::string& to, bool overwrit const int input = ::open(from.c_str(), O_RDONLY); if (input == -1) { + fs::error = errno; return false; } @@ -519,7 +550,7 @@ bool fs::copy_file(const std::string& from, const std::string& to, bool overwrit const int err = errno; ::close(input); - errno = err; + fs::error = err; return false; } @@ -538,7 +569,7 @@ bool fs::copy_file(const std::string& from, const std::string& to, bool overwrit ::close(input); ::close(output); - errno = err; + fs::error = err; return false; } @@ -561,8 +592,8 @@ bool fs::remove_file(const std::string& path) // TODO: convert Win32 error code to errno switch (DWORD error = GetLastError()) { - case ERROR_FILE_NOT_FOUND: errno = ENOENT; break; - case ERROR_PATH_NOT_FOUND: errno = ENOENT; break; + case ERROR_FILE_NOT_FOUND: fs::error = ENOENT; break; + case ERROR_PATH_NOT_FOUND: fs::error = ENOENT; break; default: throw fmt::exception("Unknown Win32 error: %u (%s)." HERE, error, path); } @@ -571,7 +602,13 @@ bool fs::remove_file(const std::string& path) return true; #else - return !::unlink(path.c_str()); + if (::unlink(path.c_str()) != 0) + { + fs::error = errno; + return false; + } + + return true; #endif } @@ -590,8 +627,8 @@ bool fs::truncate_file(const std::string& path, u64 length) // TODO: convert Win32 error code to errno switch (DWORD error = GetLastError()) { - case ERROR_FILE_NOT_FOUND: errno = ENOENT; break; - case ERROR_PATH_NOT_FOUND: errno = ENOENT; break; + case ERROR_FILE_NOT_FOUND: fs::error = ENOENT; break; + case ERROR_PATH_NOT_FOUND: fs::error = ENOENT; break; default: throw fmt::exception("Unknown Win32 error: %u (%s)." HERE, error, path); } @@ -607,7 +644,7 @@ bool fs::truncate_file(const std::string& path, u64 length) // TODO: convert Win32 error code to errno switch (DWORD error = GetLastError()) { - case ERROR_NEGATIVE_SEEK: errno = EINVAL; break; + case ERROR_NEGATIVE_SEEK: fs::error = EINVAL; break; default: throw fmt::exception("Unknown Win32 error: %u (length=0x%llx)." HERE, error, length); } @@ -618,7 +655,13 @@ bool fs::truncate_file(const std::string& path, u64 length) CloseHandle(handle); return true; #else - return !::truncate(path.c_str(), length); + if (::truncate(path.c_str(), length) != 0) + { + fs::error = errno; + return false; + } + + return true; #endif } @@ -629,10 +672,10 @@ void fs::file::xnull() const void fs::file::xfail() const { - throw fmt::exception("Unexpected fs::file error %d", errno); + throw fmt::exception("Unexpected fs::file error %u", fs::error); } -bool fs::file::open(const std::string& path, mset mode) +bool fs::file::open(const std::string& path, bitset_t mode) { if (auto device = get_virtual_device(path)) { @@ -661,7 +704,7 @@ bool fs::file::open(const std::string& path, mset mode) { if (mode & fs::excl) { - errno = EINVAL; + fs::error = EINVAL; return false; } @@ -675,9 +718,9 @@ bool fs::file::open(const std::string& path, mset mode) // TODO: convert Win32 error code to errno switch (DWORD error = GetLastError()) { - case ERROR_FILE_NOT_FOUND: errno = ENOENT; break; - case ERROR_PATH_NOT_FOUND: errno = ENOENT; break; - case ERROR_FILE_EXISTS: errno = EEXIST; break; + case ERROR_FILE_NOT_FOUND: fs::error = ENOENT; break; + case ERROR_PATH_NOT_FOUND: fs::error = ENOENT; break; + case ERROR_FILE_EXISTS: fs::error = EEXIST; break; default: throw fmt::exception("Unknown Win32 error: %u (%s)." HERE, error, path); } @@ -746,7 +789,7 @@ bool fs::file::open(const std::string& path, mset mode) // TODO: convert Win32 error code to errno switch (DWORD error = GetLastError()) { - case ERROR_NEGATIVE_SEEK: errno = EINVAL; break; + case ERROR_NEGATIVE_SEEK: fs::error = EINVAL; break; default: throw fmt::exception("Unknown Win32 error: %u." HERE, error); } @@ -871,6 +914,7 @@ bool fs::file::open(const std::string& path, mset mode) if (fd == -1) { // TODO: errno + fs::error = errno; return false; } @@ -1086,8 +1130,8 @@ bool fs::dir::open(const std::string& path) // TODO: convert Win32 error code to errno switch (DWORD error = GetLastError()) { - case ERROR_FILE_NOT_FOUND: errno = ENOENT; break; - case ERROR_PATH_NOT_FOUND: errno = ENOENT; break; + case ERROR_FILE_NOT_FOUND: fs::error = ENOENT; break; + case ERROR_PATH_NOT_FOUND: fs::error = ENOENT; break; default: throw fmt::exception("Unknown Win32 error: %u." HERE, error); } @@ -1162,6 +1206,7 @@ bool fs::dir::open(const std::string& path) if (!ptr) { // TODO: errno + fs::error = errno; return false; } diff --git a/Utilities/File.h b/Utilities/File.h index 52d82f800a..0c6e0284ee 100644 --- a/Utilities/File.h +++ b/Utilities/File.h @@ -6,9 +6,13 @@ #include #include "types.h" +#include "BitSet.h" namespace fs { + // Error code returned + extern thread_local uint error; + // File open mode flags enum struct open_mode : u32 { @@ -20,14 +24,14 @@ namespace fs excl, }; - constexpr mset read = open_mode::read; // Enable reading - constexpr mset write = open_mode::write; // Enable writing - constexpr mset append = open_mode::append; // Always append to the end of the file - constexpr mset create = open_mode::create; // Create file if it doesn't exist - constexpr mset trunc = open_mode::trunc; // Clear opened file if it's not empty - constexpr mset excl = open_mode::excl; // Failure if the file already exists (used with `create`) + constexpr bitset_t read = open_mode::read; // Enable reading + constexpr bitset_t write = open_mode::write; // Enable writing + constexpr bitset_t append = open_mode::append; // Always append to the end of the file + constexpr bitset_t create = open_mode::create; // Create file if it doesn't exist + constexpr bitset_t trunc = open_mode::trunc; // Clear opened file if it's not empty + constexpr bitset_t excl = open_mode::excl; // Failure if the file already exists (used with `create`) - constexpr mset rewrite = write + create + trunc; + constexpr bitset_t rewrite = write + create + trunc; // File seek mode enum class seek_mode : u32 @@ -92,7 +96,7 @@ namespace fs virtual bool remove(const std::string& path) = 0; virtual bool trunc(const std::string& path, u64 length) = 0; - virtual std::unique_ptr open(const std::string& path, mset mode) = 0; + virtual std::unique_ptr open(const std::string& path, bitset_t mode) = 0; virtual std::unique_ptr open_dir(const std::string& path) = 0; }; @@ -150,13 +154,13 @@ namespace fs file() = default; // Open file with specified mode - explicit file(const std::string& path, mset mode = ::fs::read) + explicit file(const std::string& path, bitset_t mode = ::fs::read) { open(path, mode); } // Open file with specified mode - bool open(const std::string& path, mset mode = ::fs::read); + bool open(const std::string& path, bitset_t mode = ::fs::read); // Open memory for read explicit file(const void* ptr, std::size_t size); diff --git a/Utilities/Log.cpp b/Utilities/Log.cpp index 66600ac33c..3a48116d9f 100644 --- a/Utilities/Log.cpp +++ b/Utilities/Log.cpp @@ -1,8 +1,53 @@ #include "Log.h" +#include "File.h" +#include "StrFmt.h" + #include +#include + +// Thread-specific log prefix provider +thread_local std::string(*g_tls_log_prefix)() = nullptr; namespace _log { + struct listener + { + listener() = default; + + virtual ~listener() = default; + + virtual void log(const channel& ch, level sev, const std::string& text) = 0; + }; + + class file_writer + { + // Could be memory-mapped file + fs::file m_file; + + public: + file_writer(const std::string& name); + + virtual ~file_writer() = default; + + // Append raw data + void log(const std::string& text); + + // Get current file size (may be used by secondary readers) + std::size_t size() const; + }; + + struct file_listener : public file_writer, public listener + { + file_listener(const std::string& name) + : file_writer(name) + , listener() + { + } + + // Encode level, current thread name, channel name and write log message + virtual void log(const channel& ch, level sev, const std::string& text) override; + }; + static file_listener& get_logger() { // Use magic static @@ -10,8 +55,6 @@ namespace _log return logger; } - file_writer g_tty_file("TTY.log"); - channel GENERAL(nullptr, level::notice); channel LOADER("LDR", level::notice); channel MEMORY("MEM", level::notice); @@ -20,15 +63,13 @@ namespace _log channel PPU("PPU", level::notice); channel SPU("SPU", level::notice); channel ARMv7("ARMv7"); - - thread_local std::string(*g_tls_make_prefix)(const channel&, level, const std::string&) = nullptr; } void _log::channel::broadcast(const _log::channel& ch, _log::level sev, const char* fmt...) { va_list args; va_start(args, fmt); - get_logger().log(ch, sev, fmt::_vformat(fmt, args)); + get_logger().log(ch, sev, fmt::unsafe_vformat(fmt, args)); va_end(args); } @@ -40,7 +81,7 @@ _log::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 %d)", name, errno); + throw fmt::exception("Can't create log file %s (error %d)", name, fs::error); } } catch (...) @@ -78,10 +119,10 @@ void _log::file_listener::log(const _log::channel& ch, _log::level sev, const st // TODO: print time? - if (auto func = g_tls_make_prefix) + if (auto prefix = g_tls_log_prefix) { msg += '{'; - msg += func(ch, sev, text); + msg += prefix(); msg += "} "; } diff --git a/Utilities/Log.h b/Utilities/Log.h index 8e662cb42e..4a6d72e35b 100644 --- a/Utilities/Log.h +++ b/Utilities/Log.h @@ -2,8 +2,6 @@ #include "types.h" #include "Atomic.h" -#include "File.h" -#include "StrFmt.h" namespace _log { @@ -19,10 +17,6 @@ namespace _log trace, // lowest level (usually disabled) }; - struct channel; - struct listener; - - // Log channel struct channel { // Channel prefix (added to every log message) @@ -33,23 +27,20 @@ namespace _log // Constant initialization: name and initial log level constexpr channel(const char* name, level enabled = level::trace) - : name{ name } - , enabled{ enabled } + : name(name) + , enabled(enabled) { } - // Log without formatting - void log(level sev, const std::string& text) const - { - if (sev <= enabled) - broadcast(*this, sev, "%s", text.c_str()); - } - - // Log with formatting + // Formatting function template void format(level sev, const char* fmt, const Args&... args) const { +#ifdef _MSC_VER if (sev <= enabled) +#else + if (__builtin_expect(sev <= enabled, 0)) +#endif broadcast(*this, sev, fmt, ::unveil::get(args)...); } @@ -75,49 +66,7 @@ namespace _log static void broadcast(const channel& ch, level sev, const char* fmt...); }; - // Log listener (destination) - struct listener - { - listener() = default; - - virtual ~listener() = default; - - virtual void log(const channel& ch, level sev, const std::string& text) = 0; - }; - - class file_writer - { - // Could be memory-mapped file - fs::file m_file; - - public: - file_writer(const std::string& name); - - virtual ~file_writer() = default; - - // Append raw data - void log(const std::string& text); - - // Get current file size (may be used by secondary readers) - std::size_t size() const; - }; - - struct file_listener : public file_writer, public listener - { - file_listener(const std::string& name) - : file_writer(name) - , listener() - { - } - - // Encode level, current thread name, channel name and write log message - virtual void log(const channel& ch, level sev, const std::string& text) override; - }; - - // Global variable for TTY.log - extern file_writer g_tty_file; - - // Small set of predefined channels: + /* Small set of predefined channels */ extern channel GENERAL; extern channel LOADER; @@ -127,14 +76,12 @@ namespace _log extern channel PPU; extern channel SPU; extern channel ARMv7; - - extern thread_local std::string(*g_tls_make_prefix)(const channel&, level, const std::string&); } template<> struct bijective<_log::level, const char*> { - static constexpr std::pair<_log::level, const char*> map[] + static constexpr bijective_pair<_log::level, const char*> map[] { { _log::level::always, "Nothing" }, { _log::level::fatal, "Fatal" }, diff --git a/Utilities/Macro.h b/Utilities/Macro.h index d8fdc67f92..7e08fa83de 100644 --- a/Utilities/Macro.h +++ b/Utilities/Macro.h @@ -75,5 +75,6 @@ constexpr std::uint32_t size32(const T(&)[Size]) #define Expects ASSERT #define Ensures ASSERT -#define DECLARE(static_member) decltype(static_member) static_member +#define DECLARE(...) decltype(__VA_ARGS__) __VA_ARGS__ + #define STR_CASE(value) case value: return #value diff --git a/Utilities/Platform.h b/Utilities/Platform.h index 557b2eb0c7..c554c07dea 100644 --- a/Utilities/Platform.h +++ b/Utilities/Platform.h @@ -88,114 +88,6 @@ inline std::uint64_t cntlz64(std::uint64_t arg) #endif } -template -struct add_flags_result_t -{ - T result; - bool carry; - //bool overflow; - bool zero; - bool sign; - - add_flags_result_t() = default; - - // Straighforward ADD with flags - add_flags_result_t(T a, T b) - : result(a + b) - , carry(result < a) - //, overflow((result ^ ~(a ^ b)) >> (sizeof(T) * 8 - 1) != 0) - , zero(result == 0) - , sign(result >> (sizeof(T) * 8 - 1) != 0) - { - } - - // Straighforward ADC with flags - add_flags_result_t(T a, T b, bool c) - : add_flags_result_t(a, b) - { - add_flags_result_t r(result, c); - result = r.result; - carry |= r.carry; - //overflow |= r.overflow; - zero = r.zero; - sign = r.sign; - } -}; - -inline add_flags_result_t add32_flags(std::uint32_t a, std::uint32_t b) -{ - //add_flags_result_t r; - //r.carry = _addcarry_u32(0, a, b, &r.result) != 0; - //r.zero = r.result == 0; - //r.sign = r.result >> 31; - //return r; - - return{ a, b }; -} - -inline add_flags_result_t add32_flags(std::uint32_t a, std::uint32_t b, bool c) -{ - return{ a, b, c }; -} - -inline add_flags_result_t add64_flags(std::uint64_t a, std::uint64_t b) -{ - return{ a, b }; -} - -inline add_flags_result_t add64_flags(std::uint64_t a, std::uint64_t b, bool c) -{ - return{ a, b, c }; -} - -// Compare 16 packed unsigned bytes (greater than) -inline __m128i sse_cmpgt_epu8(__m128i A, __m128i B) -{ - // (A xor 0x80) > (B xor 0x80) - const auto sign = _mm_set1_epi32(0x80808080); - return _mm_cmpgt_epi8(_mm_xor_si128(A, sign), _mm_xor_si128(B, sign)); -} - -inline __m128i sse_cmpgt_epu16(__m128i A, __m128i B) -{ - const auto sign = _mm_set1_epi32(0x80008000); - return _mm_cmpgt_epi16(_mm_xor_si128(A, sign), _mm_xor_si128(B, sign)); -} - -inline __m128i sse_cmpgt_epu32(__m128i A, __m128i B) -{ - const auto sign = _mm_set1_epi32(0x80000000); - return _mm_cmpgt_epi32(_mm_xor_si128(A, sign), _mm_xor_si128(B, sign)); -} - -inline __m128 sse_exp2_ps(__m128 A) -{ - const auto x0 = _mm_max_ps(_mm_min_ps(A, _mm_set1_ps(127.4999961f)), _mm_set1_ps(-127.4999961f)); - const auto x1 = _mm_add_ps(x0, _mm_set1_ps(0.5f)); - const auto x2 = _mm_sub_epi32(_mm_cvtps_epi32(x1), _mm_and_si128(_mm_castps_si128(_mm_cmpnlt_ps(_mm_setzero_ps(), x1)), _mm_set1_epi32(1))); - const auto x3 = _mm_sub_ps(x0, _mm_cvtepi32_ps(x2)); - const auto x4 = _mm_mul_ps(x3, x3); - const auto x5 = _mm_mul_ps(x3, _mm_add_ps(_mm_mul_ps(_mm_add_ps(_mm_mul_ps(x4, _mm_set1_ps(0.023093347705f)), _mm_set1_ps(20.20206567f)), x4), _mm_set1_ps(1513.906801f))); - const auto x6 = _mm_mul_ps(x5, _mm_rcp_ps(_mm_sub_ps(_mm_add_ps(_mm_mul_ps(_mm_set1_ps(233.1842117f), x4), _mm_set1_ps(4368.211667f)), x5))); - return _mm_mul_ps(_mm_add_ps(_mm_add_ps(x6, x6), _mm_set1_ps(1.0f)), _mm_castsi128_ps(_mm_slli_epi32(_mm_add_epi32(x2, _mm_set1_epi32(127)), 23))); -} - -inline __m128 sse_log2_ps(__m128 A) -{ - const auto _1 = _mm_set1_ps(1.0f); - const auto _c = _mm_set1_ps(1.442695040f); - const auto x0 = _mm_max_ps(A, _mm_castsi128_ps(_mm_set1_epi32(0x00800000))); - const auto x1 = _mm_or_ps(_mm_and_ps(x0, _mm_castsi128_ps(_mm_set1_epi32(0x807fffff))), _1); - const auto x2 = _mm_rcp_ps(_mm_add_ps(x1, _1)); - const auto x3 = _mm_mul_ps(_mm_sub_ps(x1, _1), x2); - const auto x4 = _mm_add_ps(x3, x3); - const auto x5 = _mm_mul_ps(x4, x4); - const auto x6 = _mm_add_ps(_mm_mul_ps(_mm_add_ps(_mm_mul_ps(_mm_set1_ps(-0.7895802789f), x5), _mm_set1_ps(16.38666457f)), x5), _mm_set1_ps(-64.1409953f)); - const auto x7 = _mm_rcp_ps(_mm_add_ps(_mm_mul_ps(_mm_add_ps(_mm_mul_ps(_mm_set1_ps(-35.67227983f), x5), _mm_set1_ps(312.0937664f)), x5), _mm_set1_ps(-769.6919436f))); - const auto x8 = _mm_cvtepi32_ps(_mm_sub_epi32(_mm_srli_epi32(_mm_castps_si128(x0), 23), _mm_set1_epi32(127))); - return _mm_add_ps(_mm_mul_ps(_mm_mul_ps(_mm_mul_ps(_mm_mul_ps(x5, x6), x7), x4), _c), _mm_add_ps(_mm_mul_ps(x4, _c), x8)); -} - // Helper function, used by ""_u16, ""_u32, ""_u64 constexpr std::uint8_t to_u8(char c) { diff --git a/Utilities/Semaphore.cpp b/Utilities/Semaphore.cpp index e6ea21b123..76fab20e08 100644 --- a/Utilities/Semaphore.cpp +++ b/Utilities/Semaphore.cpp @@ -1,120 +1,90 @@ -#include "stdafx.h" #include "Utilities/Semaphore.h" -bool semaphore_t::try_wait() +#include +#include + +struct benaphore::internal { - // check m_value without interlocked op - if (m_var.load().value == 0) - { - return false; - } + std::mutex mutex; - // try to decrement m_value atomically - const auto old = m_var.fetch_op([](sync_var_t& var) - { - if (var.value) - { - var.value--; - } - }); + std::size_t acq_order{}; + std::size_t rel_order{}; - // recheck atomic result - if (old.value == 0) - { - return false; - } + std::condition_variable cond; +}; - return true; -} - -bool semaphore_t::try_post() +void benaphore::wait_hard() { - // check m_value without interlocked op - if (m_var.load().value >= max_value) - { - return false; - } - - // try to increment m_value atomically - const auto old = m_var.fetch_op([&](sync_var_t& var) - { - if (var.value < max_value) - { - var.value++; - } - }); - - // recheck atomic result - if (old.value >= max_value) - { - return false; - } - - if (old.waiters) - { - // notify waiting thread - std::lock_guard lock(m_mutex); - - m_cv.notify_one(); - } - - return true; -} - -void semaphore_t::wait() -{ - if (m_var.atomic_op([](sync_var_t& var) -> bool - { - if (var.value) - { - var.value--; - - return true; - } - else - { - //var.waiters++; - - return false; - } - })) + initialize_once(); + + std::unique_lock lock(m_data->mutex); + + // Notify non-zero waiter queue size + if (m_value.exchange(-1) == 1) { + // Return immediately (acquired) + m_value = 0; return; } - std::unique_lock lock(m_mutex); + // Remember the order + const std::size_t order = ++m_data->acq_order; - m_var.atomic_op([](sync_var_t& var) + // Wait for the appropriate rel_order (TODO) + while (m_data->rel_order < order) { - var.waiters++; - }); + m_data->cond.wait(lock); + } - while (!m_var.atomic_op([](sync_var_t& var) -> bool + if (order == m_data->acq_order && m_data->acq_order == m_data->rel_order) { - if (var.value) - { - var.value--; - var.waiters--; - - return true; - } - else - { - return false; - } - })) - { - m_cv.wait(lock); + // Cleaup + m_data->acq_order = 0; + m_data->rel_order = 0; + m_value.compare_and_swap(-1, 0); } } -bool semaphore_t::post_and_wait() +void benaphore::post_hard() { - // TODO: merge these functions? Probably has a race condition. - if (try_wait()) return false; + initialize_once(); - try_post(); - wait(); + std::unique_lock lock(m_data->mutex); - return true; + if (m_value.compare_and_swap(0, 1) != -1) + { + // Do nothing (released) + return; + } + + if (m_data->acq_order == m_data->rel_order) + { + m_value = 1; + return; + } + + // Awake one thread + m_data->rel_order += 1; + + // Unlock and notify + lock.unlock(); + m_data->cond.notify_one(); +} + +void benaphore::initialize_once() +{ + if (UNLIKELY(!m_data)) + { + auto ptr = new benaphore::internal; + + if (!m_data.compare_and_swap_test(nullptr, ptr)) + { + delete ptr; + } + } +} + +benaphore::~benaphore() +{ + delete m_data; } diff --git a/Utilities/Semaphore.h b/Utilities/Semaphore.h index c5d3550dd7..4042cbbcbc 100644 --- a/Utilities/Semaphore.h +++ b/Utilities/Semaphore.h @@ -2,39 +2,47 @@ #include "types.h" #include "Atomic.h" +#include "Platform.h" -class semaphore_t +// Binary semaphore +class benaphore { - // semaphore mutex - std::mutex m_mutex; + struct internal; - // semaphore condition variable - std::condition_variable m_cv; + // Reserved value (-1) enforces *_hard() calls + atomic_t m_value{}; - struct alignas(8) sync_var_t - { - u32 value; // current semaphore value - u32 waiters; // current amount of waiters - }; + atomic_t m_data{}; - // current semaphore value - atomic_t m_var; + void wait_hard(); + void post_hard(); public: - // max semaphore value - const u32 max_value; + constexpr benaphore() = default; - semaphore_t(u32 max_value = 1, u32 value = 0) - : m_var(sync_var_t{ value, 0 }) - , max_value(max_value) + ~benaphore(); + + // Initialize internal data + void initialize_once(); + + void wait() { + if (UNLIKELY(!m_value.compare_and_swap_test(1, 0))) + { + wait_hard(); + } } - bool try_wait(); + bool try_wait() + { + return LIKELY(m_value.compare_and_swap_test(1, 0)); + } - bool try_post(); - - void wait(); - - bool post_and_wait(); + void post() + { + if (UNLIKELY(!m_value.compare_and_swap_test(0, 1))) + { + post_hard(); + } + } }; diff --git a/Utilities/SharedMutex.cpp b/Utilities/SharedMutex.cpp index 7b0e20bcd6..b6b30c3b6f 100644 --- a/Utilities/SharedMutex.cpp +++ b/Utilities/SharedMutex.cpp @@ -15,24 +15,6 @@ struct shared_mutex::internal std::condition_variable ocv; // For current exclusive owner }; -shared_mutex::~shared_mutex() -{ - delete m_data; -} - -void shared_mutex::initialize_once() -{ - if (!m_data) - { - auto ptr = new shared_mutex::internal; - - if (!m_data.compare_and_swap_test(nullptr, ptr)) - { - delete ptr; - } - } -} - void shared_mutex::lock_shared_hard() { initialize_once(); @@ -81,17 +63,18 @@ void shared_mutex::unlock_shared_notify() { initialize_once(); - // Mutex is locked for reliable notification because m_ctrl has been changed outside - std::lock_guard lock(m_data->mutex); + std::unique_lock lock(m_data->mutex); if ((m_ctrl & SM_READER_MASK) == 0 && m_data->wq_size) { // Notify exclusive owner + lock.unlock(); m_data->ocv.notify_one(); } else if (m_data->rq_size) { // Notify other readers + lock.unlock(); m_data->rcv.notify_one(); } } @@ -141,17 +124,36 @@ void shared_mutex::unlock_notify() { initialize_once(); - // Mutex is locked for reliable notification because m_ctrl has been changed outside - std::lock_guard lock(m_data->mutex); + std::unique_lock lock(m_data->mutex); if (m_data->wq_size) { // Notify next exclusive owner + lock.unlock(); m_data->wcv.notify_one(); } else if (m_data->rq_size) { // Notify all readers + lock.unlock(); m_data->rcv.notify_all(); } } + +void shared_mutex::initialize_once() +{ + if (UNLIKELY(!m_data)) + { + auto ptr = new shared_mutex::internal; + + if (!m_data.compare_and_swap_test(nullptr, ptr)) + { + delete ptr; + } + } +} + +shared_mutex::~shared_mutex() +{ + delete m_data; +} diff --git a/Utilities/SharedMutex.h b/Utilities/SharedMutex.h index be66f75a94..b1200cffad 100644 --- a/Utilities/SharedMutex.h +++ b/Utilities/SharedMutex.h @@ -35,11 +35,11 @@ class shared_mutex final public: constexpr shared_mutex() = default; - ~shared_mutex(); - // Initialize internal data void initialize_once(); + ~shared_mutex(); + bool try_lock_shared() { auto ctrl = m_ctrl.load(); diff --git a/Utilities/StrFmt.cpp b/Utilities/StrFmt.cpp index 3e9b8c1719..8d61b09b25 100644 --- a/Utilities/StrFmt.cpp +++ b/Utilities/StrFmt.cpp @@ -1,5 +1,6 @@ #include "StrFmt.h" #include "BEType.h" +#include "StrUtil.h" #include #include @@ -15,70 +16,7 @@ std::string v128::to_xyzw() const return fmt::format("x: %g y: %g z: %g w: %g", _f[3], _f[2], _f[1], _f[0]); } -std::string fmt::to_hex(u64 value, u64 count) -{ - if (count - 1 >= 16) - { - throw exception("fmt::to_hex(): invalid count: 0x%llx", count); - } - - count = std::max(count, 16 - cntlz64(value) / 4); - - char res[16] = {}; - - for (size_t i = count - 1; ~i; i--, value /= 16) - { - res[i] = "0123456789abcdef"[value % 16]; - } - - return std::string(res, count); -} - -std::string fmt::to_udec(u64 value) -{ - char res[20] = {}; - size_t first = sizeof(res); - - if (!value) - { - res[--first] = '0'; - } - - for (; value; value /= 10) - { - res[--first] = '0' + (value % 10); - } - - return std::string(&res[first], sizeof(res) - first); -} - -std::string fmt::to_sdec(s64 svalue) -{ - const bool sign = svalue < 0; - u64 value = sign ? -svalue : svalue; - - char res[20] = {}; - size_t first = sizeof(res); - - if (!value) - { - res[--first] = '0'; - } - - for (; value; value /= 10) - { - res[--first] = '0' + (value % 10); - } - - if (sign) - { - res[--first] = '-'; - } - - return std::string(&res[first], sizeof(res) - first); -} - -std::string fmt::_vformat(const char* fmt, va_list _args) noexcept +std::string fmt::unsafe_vformat(const char* fmt, va_list _args) noexcept { // Fixed stack buffer for the first attempt std::array fixed_buf; @@ -115,18 +53,18 @@ std::string fmt::_vformat(const char* fmt, va_list _args) noexcept } } -std::string fmt::_format(const char* fmt...) noexcept +std::string fmt::unsafe_format(const char* fmt...) noexcept { va_list args; va_start(args, fmt); - auto result = fmt::_vformat(fmt, args); + auto result = unsafe_vformat(fmt, args); va_end(args); return result; } fmt::exception_base::exception_base(const char* fmt...) - : std::runtime_error((va_start(m_args, fmt), _vformat(fmt, m_args))) + : std::runtime_error((va_start(m_args, fmt), unsafe_vformat(fmt, m_args))) { va_end(m_args); } @@ -196,73 +134,11 @@ std::string fmt::trim(const std::string& source, const std::string& values) return source.substr(begin, source.find_last_not_of(values) + 1); } -std::string fmt::escape(const std::string& source, std::initializer_list more) -{ - const std::pair escape_list[] = - { - { "\\", "\\\\" }, - { "\a", "\\a" }, - { "\b", "\\b" }, - { "\f", "\\f" }, - { "\n", "\\n" }, - { "\r", "\\r" }, - { "\t", "\\t" }, - { "\v", "\\v" }, - }; - - std::string result = fmt::replace_all(source, escape_list); - - for (char c = 0; c < 32; c++) - { - result = fmt::replace_all(result, std::string(1, c), fmt::format("\\x%02X", c)); - } - - for (char c : more) - { - result = fmt::replace_all(result, std::string(1, c), fmt::format("\\x%02X", c)); - } - - return result; -} - -std::string fmt::unescape(const std::string& source) +std::string fmt::to_upper(const std::string& string) { std::string result; - - for (auto it = source.begin(); it != source.end();) - { - const char bs = *it++; - - if (bs == '\\' && it != source.end()) - { - switch (const char code = *it++) - { - case 'a': result += '\a'; break; - case 'b': result += '\b'; break; - case 'f': result += '\f'; break; - case 'n': result += '\n'; break; - case 'r': result += '\r'; break; - case 't': result += '\t'; break; - case 'v': result += '\v'; break; - case 'x': - { - // Detect hexadecimal character code (TODO) - if (source.end() - it >= 2) - { - result += std::stoi(std::string{ *it++, *it++ }, 0, 16); - } - - } - // Octal/unicode not supported - default: result += code; - } - } - else - { - result += bs; - } - } - + result.resize(string.size()); + std::transform(string.begin(), string.end(), result.begin(), ::toupper); return result; } diff --git a/Utilities/StrFmt.h b/Utilities/StrFmt.h index a44c73b300..b2dbe5551a 100644 --- a/Utilities/StrFmt.h +++ b/Utilities/StrFmt.h @@ -2,114 +2,21 @@ #include #include -#include -#include +#include #include "Platform.h" #include "types.h" -// Copy null-terminated string from std::string to char array with truncation -template -force_inline void strcpy_trunc(char(&dst)[N], const std::string& src) -{ - const std::size_t count = src.size() >= N ? N - 1 : src.size(); - std::memcpy(dst, src.c_str(), count); - dst[count] = '\0'; -} - -// Copy null-terminated string from char array to another char array with truncation -template -force_inline void strcpy_trunc(char(&dst)[N], const char(&src)[N2]) -{ - const std::size_t count = N2 >= N ? N - 1 : N2; - std::memcpy(dst, src, count); - dst[count] = '\0'; -} - -// Formatting helper, type-specific preprocessing for improving safety and functionality -template -struct unveil -{ - // TODO - static inline const T& get(const T& arg) - { - return arg; - } -}; - -template<> -struct unveil -{ - static inline const char* get(const std::string& arg) - { - return arg.c_str(); - } -}; - namespace fmt { - std::string replace_first(const std::string& src, const std::string& from, const std::string& to); - std::string replace_all(const std::string &src, const std::string& from, const std::string& to); + std::string unsafe_format(const char* fmt...) noexcept; + std::string unsafe_vformat(const char*, va_list) noexcept; - template - std::string replace_all(std::string src, const std::pair(&list)[list_size]) - { - for (size_t pos = 0; pos < src.length(); ++pos) - { - for (size_t i = 0; i < list_size; ++i) - { - const size_t comp_length = list[i].first.length(); - - if (src.length() - pos < comp_length) - continue; - - if (src.substr(pos, comp_length) == list[i].first) - { - src = (pos ? src.substr(0, pos) + list[i].second : list[i].second) + src.substr(pos + comp_length); - pos += list[i].second.length() - 1; - break; - } - } - } - - return src; - } - - template - std::string replace_all(std::string src, const std::pair>(&list)[list_size]) - { - for (size_t pos = 0; pos < src.length(); ++pos) - { - for (size_t i = 0; i < list_size; ++i) - { - const size_t comp_length = list[i].first.length(); - - if (src.length() - pos < comp_length) - continue; - - if (src.substr(pos, comp_length) == list[i].first) - { - src = (pos ? src.substr(0, pos) + list[i].second() : list[i].second()) + src.substr(pos + comp_length); - pos += list[i].second().length() - 1; - break; - } - } - } - - return src; - } - - std::string to_hex(u64 value, u64 count = 1); - std::string to_udec(u64 value); - std::string to_sdec(s64 value); - std::string _format(const char* fmt...) noexcept; - std::string _vformat(const char*, va_list) noexcept; - - // Formatting function with special functionality (fmt::unveil) + // Formatting function template - force_inline std::string format(const char* fmt, const Args&... args) noexcept + inline std::string format(const char* fmt, const Args&... args) noexcept { - return _format(fmt, ::unveil::get(args)...); + return unsafe_format(fmt, ::unveil::get(args)...); } // Helper class @@ -143,86 +50,4 @@ namespace fmt if (static_cast(result) != value) throw fmt::exception(format_str, value, args...); return result; } - - std::vector split(const std::string& source, std::initializer_list separators, bool is_skip_empty = true); - std::string trim(const std::string& source, const std::string& values = " \t"); - - template - std::string merge(const T& source, const std::string& separator) - { - if (!source.size()) - { - return{}; - } - - std::string result; - - auto it = source.begin(); - auto end = source.end(); - for (--end; it != end; ++it) - { - result += *it + separator; - } - - return result + source.back(); - } - - template - std::string merge(std::initializer_list sources, const std::string& separator) - { - if (!sources.size()) - { - return{}; - } - - std::string result; - bool first = true; - - for (auto &v : sources) - { - if (first) - { - result = fmt::merge(v, separator); - first = false; - } - else - { - result += separator + fmt::merge(v, separator); - } - } - - return result; - } - - template - std::string to_lower(IT _begin, IT _end) - { - std::string result; result.resize(_end - _begin); - std::transform(_begin, _end, result.begin(), ::tolower); - return result; - } - - template - std::string to_lower(const T& string) - { - return to_lower(std::begin(string), std::end(string)); - } - - template - std::string to_upper(IT _begin, IT _end) - { - std::string result; result.resize(_end - _begin); - std::transform(_begin, _end, result.begin(), ::toupper); - return result; - } - - template - std::string to_upper(const T& string) - { - return to_upper(std::begin(string), std::end(string)); - } - - std::string escape(const std::string& source, std::initializer_list more = {}); - std::string unescape(const std::string& source); - bool match(const std::string &source, const std::string &mask); } diff --git a/Utilities/StrUtil.h b/Utilities/StrUtil.h new file mode 100644 index 0000000000..7a38bd2891 --- /dev/null +++ b/Utilities/StrUtil.h @@ -0,0 +1,133 @@ +#pragma once + +#include +#include +#include +#include +#include + +// Copy null-terminated string from std::string to char array with truncation +template +inline void strcpy_trunc(char(&dst)[N], const std::string& src) +{ + const std::size_t count = src.size() >= N ? N - 1 : src.size(); + std::memcpy(dst, src.c_str(), count); + dst[count] = '\0'; +} + +// Copy null-terminated string from char array to another char array with truncation +template +inline void strcpy_trunc(char(&dst)[N], const char(&src)[N2]) +{ + const std::size_t count = N2 >= N ? N - 1 : N2; + std::memcpy(dst, src, count); + dst[count] = '\0'; +} + +namespace fmt +{ + std::string replace_first(const std::string& src, const std::string& from, const std::string& to); + std::string replace_all(const std::string &src, const std::string& from, const std::string& to); + + template + std::string replace_all(std::string src, const std::pair(&list)[list_size]) + { + for (size_t pos = 0; pos < src.length(); ++pos) + { + for (size_t i = 0; i < list_size; ++i) + { + const size_t comp_length = list[i].first.length(); + + if (src.length() - pos < comp_length) + continue; + + if (src.substr(pos, comp_length) == list[i].first) + { + src = (pos ? src.substr(0, pos) + list[i].second : list[i].second) + src.substr(pos + comp_length); + pos += list[i].second.length() - 1; + break; + } + } + } + + return src; + } + + template + std::string replace_all(std::string src, const std::pair>(&list)[list_size]) + { + for (size_t pos = 0; pos < src.length(); ++pos) + { + for (size_t i = 0; i < list_size; ++i) + { + const size_t comp_length = list[i].first.length(); + + if (src.length() - pos < comp_length) + continue; + + if (src.substr(pos, comp_length) == list[i].first) + { + src = (pos ? src.substr(0, pos) + list[i].second() : list[i].second()) + src.substr(pos + comp_length); + pos += list[i].second().length() - 1; + break; + } + } + } + + return src; + } + + std::vector split(const std::string& source, std::initializer_list separators, bool is_skip_empty = true); + std::string trim(const std::string& source, const std::string& values = " \t"); + + template + std::string merge(const T& source, const std::string& separator) + { + if (!source.size()) + { + return{}; + } + + std::string result; + + auto it = source.begin(); + auto end = source.end(); + for (--end; it != end; ++it) + { + result += *it + separator; + } + + return result + source.back(); + } + + template + std::string merge(std::initializer_list sources, const std::string& separator) + { + if (!sources.size()) + { + return{}; + } + + std::string result; + bool first = true; + + for (auto &v : sources) + { + if (first) + { + result = fmt::merge(v, separator); + first = false; + } + else + { + result += separator + fmt::merge(v, separator); + } + } + + return result; + } + + std::string to_upper(const std::string& string); + + bool match(const std::string &source, const std::string &mask); +} diff --git a/Utilities/Thread.cpp b/Utilities/Thread.cpp index ac9cf21b48..4ab6439fac 100644 --- a/Utilities/Thread.cpp +++ b/Utilities/Thread.cpp @@ -1294,11 +1294,20 @@ extern std::mutex& get_current_thread_mutex() // TODO extern atomic_t g_thread_count(0); +extern thread_local std::string(*g_tls_log_prefix)(); + void thread_ctrl::initialize() { // Initialize TLS variable g_tls_this_thread = this; + g_tls_log_prefix = [] + { + return g_tls_this_thread->m_name; + }; + + ++g_thread_count; + #if defined(_MSC_VER) struct THREADNAME_INFO @@ -1328,13 +1337,6 @@ void thread_ctrl::initialize() } #endif - - _log::g_tls_make_prefix = [](const auto&, auto, const auto&) - { - return g_tls_this_thread->m_name; - }; - - ++g_thread_count; } void thread_ctrl::set_exception() noexcept @@ -1378,7 +1380,7 @@ thread_ctrl::~thread_ctrl() void thread_ctrl::initialize_once() const { - if (!m_data) + if (UNLIKELY(!m_data)) { auto ptr = new thread_ctrl::internal; @@ -1391,10 +1393,10 @@ void thread_ctrl::initialize_once() const void thread_ctrl::join() { - if (m_thread.joinable()) + if (LIKELY(m_thread.joinable())) { // Increase contention counter - if (m_joining++) + if (UNLIKELY(m_joining++)) { // Hard way initialize_once(); @@ -1408,7 +1410,7 @@ void thread_ctrl::join() m_thread.join(); // Notify others if necessary - if (m_joining > 1) + if (UNLIKELY(m_joining > 1)) { initialize_once(); @@ -1420,7 +1422,7 @@ void thread_ctrl::join() } } - if (m_data && m_data->exception) + if (UNLIKELY(m_data && m_data->exception)) { std::rethrow_exception(m_data->exception); } diff --git a/Utilities/geometry.h b/Utilities/geometry.h new file mode 100644 index 0000000000..f488f4ead0 --- /dev/null +++ b/Utilities/geometry.h @@ -0,0 +1,1037 @@ +#pragma once + +#include + +template +struct size2_base +{ + T width, height; + + constexpr size2_base() : width{}, height{} + { + } + + constexpr size2_base(T width, T height) : width{ width }, height{ height } + { + } + + constexpr size2_base(const size2_base& rhs) : width{ rhs.width }, height{ rhs.height } + { + } + + constexpr size2_base operator -(const size2_base& rhs) const + { + return{ width - rhs.width, height - rhs.height }; + } + constexpr size2_base operator -(T rhs) const + { + return{ width - rhs, height - rhs }; + } + constexpr size2_base operator +(const size2_base& rhs) const + { + return{ width + rhs.width, height + rhs.height }; + } + constexpr size2_base operator +(T rhs) const + { + return{ width + rhs, height + rhs }; + } + constexpr size2_base operator /(const size2_base& rhs) const + { + return{ width / rhs.width, height / rhs.height }; + } + constexpr size2_base operator /(T rhs) const + { + return{ width / rhs, height / rhs }; + } + constexpr size2_base operator *(const size2_base& rhs) const + { + return{ width * rhs.width, height * rhs.height }; + } + constexpr size2_base operator *(T rhs) const + { + return{ width * rhs, height * rhs }; + } + + size2_base& operator -=(const size2_base& rhs) + { + width -= rhs.width; + height -= rhs.height; + return *this; + } + size2_base& operator -=(T rhs) + { + width -= rhs; + height -= rhs; + return *this; + } + size2_base& operator +=(const size2_base& rhs) + { + width += rhs.width; + height += rhs.height; + return *this; + } + size2_base& operator +=(T rhs) + { + width += rhs; + height += rhs; + return *this; + } + size2_base& operator /=(const size2_base& rhs) + { + width /= rhs.width; + height /= rhs.height; + return *this; + } + size2_base& operator /=(T rhs) + { + width /= rhs; + height /= rhs; + return *this; + } + size2_base& operator *=(const size2_base& rhs) + { + width *= rhs.width; + height *= rhs.height; + return *this; + } + size2_base& operator *=(T rhs) + { + width *= rhs; + height *= rhs; + return *this; + } + + constexpr bool operator == (const size2_base& rhs) const + { + return width == rhs.width && height == rhs.height; + } + + constexpr bool operator != (const size2_base& rhs) const + { + return width != rhs.width || height != rhs.height; + } + + template + constexpr operator size2_base() const + { + return{ (NT)width, (NT)height }; + } +}; + +template +struct position1_base +{ + T x; + + position1_base operator -(const position1_base& rhs) const + { + return{ x - rhs.x }; + } + position1_base operator -(T rhs) const + { + return{ x - rhs }; + } + position1_base operator +(const position1_base& rhs) const + { + return{ x + rhs.x }; + } + position1_base operator +(T rhs) const + { + return{ x + rhs }; + } + template + position1_base operator *(RhsT rhs) const + { + return{ T(x * rhs) }; + } + position1_base operator *(const position1_base& rhs) const + { + return{ T(x * rhs.x) }; + } + template + position1_base operator /(RhsT rhs) const + { + return{ x / rhs }; + } + position1_base operator /(const position1_base& rhs) const + { + return{ x / rhs.x }; + } + + position1_base& operator -=(const position1_base& rhs) + { + x -= rhs.x; + return *this; + } + position1_base& operator -=(T rhs) + { + x -= rhs; + return *this; + } + position1_base& operator +=(const position1_base& rhs) + { + x += rhs.x; + return *this; + } + position1_base& operator +=(T rhs) + { + x += rhs; + return *this; + } + + template + position1_base& operator *=(RhsT rhs) const + { + x *= rhs; + return *this; + } + position1_base& operator *=(const position1_base& rhs) const + { + x *= rhs.x; + return *this; + } + template + position1_base& operator /=(RhsT rhs) const + { + x /= rhs; + return *this; + } + position1_base& operator /=(const position1_base& rhs) const + { + x /= rhs.x; + return *this; + } + + bool operator ==(const position1_base& rhs) const + { + return x == rhs.x; + } + + bool operator ==(T rhs) const + { + return x == rhs; + } + + bool operator !=(const position1_base& rhs) const + { + return !(*this == rhs); + } + + bool operator !=(T rhs) const + { + return !(*this == rhs); + } + + template + operator position1_base() const + { + return{ (NT)x }; + } + + double distance(const position1_base& to) + { + return abs(x - to.x); + } +}; + +template +struct position2_base +{ + T x, y; + + constexpr position2_base() : x{}, y{} + { + } + + constexpr position2_base(T x, T y) : x{ x }, y{ y } + { + } + + constexpr position2_base(const position2_base& rhs) : x{ rhs.x }, y{ rhs.y } + { + } + + constexpr bool operator >(const position2_base& rhs) const + { + return x > rhs.x && y > rhs.y; + } + constexpr bool operator >(T rhs) const + { + return x > rhs && y > rhs; + } + constexpr bool operator <(const position2_base& rhs) const + { + return x < rhs.x && y < rhs.y; + } + constexpr bool operator <(T rhs) const + { + return x < rhs && y < rhs; + } + constexpr bool operator >=(const position2_base& rhs) const + { + return x >= rhs.x && y >= rhs.y; + } + constexpr bool operator >=(T rhs) const + { + return x >= rhs && y >= rhs; + } + constexpr bool operator <=(const position2_base& rhs) const + { + return x <= rhs.x && y <= rhs.y; + } + constexpr bool operator <=(T rhs) const + { + return x <= rhs && y <= rhs; + } + + constexpr position2_base operator -(const position2_base& rhs) const + { + return{ x - rhs.x, y - rhs.y }; + } + constexpr position2_base operator -(T rhs) const + { + return{ x - rhs, y - rhs }; + } + constexpr position2_base operator +(const position2_base& rhs) const + { + return{ x + rhs.x, y + rhs.y }; + } + constexpr position2_base operator +(T rhs) const + { + return{ x + rhs, y + rhs }; + } + template + constexpr position2_base operator *(RhsT rhs) const + { + return{ T(x * rhs), T(y * rhs) }; + } + constexpr position2_base operator *(const position2_base& rhs) const + { + return{ T(x * rhs.x), T(y * rhs.y) }; + } + template + constexpr position2_base operator /(RhsT rhs) const + { + return{ x / rhs, y / rhs }; + } + constexpr position2_base operator /(const position2_base& rhs) const + { + return{ x / rhs.x, y / rhs.y }; + } + constexpr position2_base operator /(const size2_base& rhs) const + { + return{ x / rhs.width, y / rhs.height }; + } + + position2_base& operator -=(const position2_base& rhs) + { + x -= rhs.x; + y -= rhs.y; + return *this; + } + position2_base& operator -=(T rhs) + { + x -= rhs; + y -= rhs; + return *this; + } + position2_base& operator +=(const position2_base& rhs) + { + x += rhs.x; + y += rhs.y; + return *this; + } + position2_base& operator +=(T rhs) + { + x += rhs; + y += rhs; + return *this; + } + + template + position2_base& operator *=(RhsT rhs) + { + x *= rhs; + y *= rhs; + return *this; + } + position2_base& operator *=(const position2_base& rhs) + { + x *= rhs.x; + y *= rhs.y; + return *this; + } + template + position2_base& operator /=(RhsT rhs) + { + x /= rhs; + y /= rhs; + return *this; + } + position2_base& operator /=(const position2_base& rhs) + { + x /= rhs.x; + y /= rhs.y; + return *this; + } + + constexpr bool operator ==(const position2_base& rhs) const + { + return x == rhs.x && y == rhs.y; + } + + constexpr bool operator ==(T rhs) const + { + return x == rhs && y == rhs; + } + + constexpr bool operator !=(const position2_base& rhs) const + { + return !(*this == rhs); + } + + constexpr bool operator !=(T rhs) const + { + return !(*this == rhs); + } + + template + constexpr operator position2_base() const + { + return{ (NT)x, (NT)y }; + } + + double distance(const position2_base& to) const + { + return std::sqrt(double((x - to.x) * (x - to.x) + (y - to.y) * (y - to.y))); + } +}; + +template +struct position3_base +{ + T x, y, z; + /* + position3_base() : x{}, y{}, z{} + { + } + + position3_base(T x, T y, T z) : x{ x }, y{ y }, z{ z } + { + } + */ + + position3_base operator -(const position3_base& rhs) const + { + return{ x - rhs.x, y - rhs.y, z - rhs.z }; + } + position3_base operator -(T rhs) const + { + return{ x - rhs, y - rhs, z - rhs }; + } + position3_base operator +(const position3_base& rhs) const + { + return{ x + rhs.x, y + rhs.y, z + rhs.z }; + } + position3_base operator +(T rhs) const + { + return{ x + rhs, y + rhs, z + rhs }; + } + + position3_base& operator -=(const position3_base& rhs) + { + x -= rhs.x; + y -= rhs.y; + z -= rhs.z; + return *this; + } + position3_base& operator -=(T rhs) + { + x -= rhs; + y -= rhs; + z -= rhs; + return *this; + } + position3_base& operator +=(const position3_base& rhs) + { + x += rhs.x; + y += rhs.y; + z += rhs.z; + return *this; + } + position3_base& operator +=(T rhs) + { + x += rhs; + y += rhs; + z += rhs; + return *this; + } + + bool operator ==(const position3_base& rhs) const + { + return x == rhs.x && y == rhs.y && z == rhs.z; + } + + bool operator ==(T rhs) const + { + return x == rhs && y == rhs && z == rhs; + } + + bool operator !=(const position3_base& rhs) const + { + return !(*this == rhs); + } + + bool operator !=(T rhs) const + { + return !(*this == rhs); + } + + template + operator position3_base() const + { + return{ (NT)x, (NT)y, (NT)z }; + } +}; + +template +struct position4_base +{ + T x, y, z, w; + + constexpr position4_base() : x{}, y{}, z{}, w{} + { + } + + constexpr position4_base(T x, T y = {}, T z = {}, T w = { T(1) }) : x{ x }, y{ y }, z{ z }, w{ w } + { + } + + constexpr position4_base operator -(const position4_base& rhs) const + { + return{ x - rhs.x, y - rhs.y, z - rhs.z, w - rhs.w }; + } + constexpr position4_base operator -(T rhs) const + { + return{ x - rhs, y - rhs, z - rhs, w - rhs }; + } + constexpr position4_base operator +(const position4_base& rhs) const + { + return{ x + rhs.x, y + rhs.y, z + rhs.z, w + rhs.w }; + } + constexpr position4_base operator +(T rhs) const + { + return{ x + rhs, y + rhs, z + rhs, w + rhs }; + } + + position4_base& operator -=(const position4_base& rhs) + { + x -= rhs.x; + y -= rhs.y; + z -= rhs.z; + w -= rhs.w; + return *this; + } + position4_base& operator -=(T rhs) + { + x -= rhs; + y -= rhs; + z -= rhs; + w -= rhs; + return *this; + } + position4_base& operator +=(const position4_base& rhs) + { + x += rhs.x; + y += rhs.y; + z += rhs.z; + w += rhs.w; + return *this; + } + position4_base& operator +=(T rhs) + { + x += rhs; + y += rhs; + z += rhs; + w += rhs; + return *this; + } + + constexpr bool operator ==(const position4_base& rhs) const + { + return x == rhs.x && y == rhs.y && z == rhs.z && w == rhs.w; + } + + constexpr bool operator ==(T rhs) const + { + return x == rhs && y == rhs && z == rhs && w == rhs; + } + + constexpr bool operator !=(const position4_base& rhs) const + { + return !(*this == rhs); + } + + constexpr bool operator !=(T rhs) const + { + return !(*this == rhs); + } + + template + constexpr operator position4_base() const + { + return{ (NT)x, (NT)y, (NT)z, (NT)w }; + } +}; + +template +using position_base = position2_base; + +template +struct coord_base +{ + union + { + position_base position; + struct { T x, y; }; + }; + + union + { + size2_base size; + struct { T width, height; }; + }; + + constexpr coord_base() : position{}, size{} +#ifdef _MSC_VER + //compiler error + , x{}, y{}, width{}, height{} +#endif + { + } + + constexpr coord_base(const position_base& position, const size2_base& size) + : position{ position }, size{ size } +#ifdef _MSC_VER + , x{ position.x }, y{ position.y }, width{ size.width }, height{ size.height } +#endif + { + } + + constexpr coord_base(T x, T y, T width, T height) : x{ x }, y{ y }, width{ width }, height{ height } + { + } + + constexpr bool test(const position_base& position) const + { + if (position.x < x || position.x >= x + width) + return false; + + if (position.y < y || position.y >= y + height) + return false; + + return true; + } + + constexpr bool operator == (const coord_base& rhs) const + { + return position == rhs.position && size == rhs.size; + } + + constexpr bool operator != (const coord_base& rhs) const + { + return position != rhs.position || size != rhs.size; + } + + template + constexpr operator coord_base() const + { + return{ (NT)x, (NT)y, (NT)width, (NT)height }; + } +}; + +template +struct area_base +{ + T x1, x2; + T y1, y2; + + constexpr area_base() : x1{}, x2{}, y1{}, y2{} + { + } + + constexpr area_base(T x1, T y1, T x2, T y2) : x1{ x1 }, x2{ x2 }, y1{ y1 }, y2{ y2 } + { + } + + constexpr area_base(const coord_base& coord) : x1{ coord.x }, x2{ coord.x + coord.width }, y1{ coord.y }, y2{ coord.y + coord.height } + { + } + + constexpr operator coord_base() const + { + return{ x1, y1, x2 - x1, y2 - y1 }; + } + + void flip_vertical() + { + T _y = y1; y1 = y2; y2 = _y; + } + + void flip_horizontal() + { + T _x = x1; x1 = x2; x2 = _x; + } + + constexpr area_base flipped_vertical() const + { + return{ x1, y2, x2, y1 }; + } + + constexpr area_base flipped_horizontal() const + { + return{ x2, y1, x1, y2 }; + } + + constexpr bool operator == (const area_base& rhs) const + { + return x1 == rhs.x1 && x2 == rhs.x2 && y1 == rhs.y1 && y2 == rhs.y2; + } + + constexpr bool operator != (const area_base& rhs) const + { + return !(*this == rhs); + } + + constexpr area_base operator - (const size2_base& size) const + { + return{ x1 - size.width, y1 - size.height, x2 - size.width, y2 - size.height }; + } + constexpr area_base operator - (const T& value) const + { + return{ x1 - value, y1 - value, x2 - value, y2 - value }; + } + constexpr area_base operator + (const size2_base& size) const + { + return{ x1 + size.width, y1 + size.height, x2 + size.width, y2 + size.height }; + } + constexpr area_base operator + (const T& value) const + { + return{ x1 + value, y1 + value, x2 + value, y2 + value }; + } + constexpr area_base operator / (const size2_base& size) const + { + return{ x1 / size.width, y1 / size.height, x2 / size.width, y2 / size.height }; + } + constexpr area_base operator / (const T& value) const + { + return{ x1 / value, y1 / value, x2 / value, y2 / value }; + } + constexpr area_base operator * (const size2_base& size) const + { + return{ x1 * size.width, y1 * size.height, x2 * size.width, y2 * size.height }; + } + constexpr area_base operator * (const T& value) const + { + return{ x1 * value, y1 * value, x2 * value, y2 * value }; + } + + template + constexpr operator area_base() const + { + return{ (NT)x1, (NT)y1, (NT)x2, (NT)y2 }; + } +}; + +template +struct size3_base +{ + T width, height, depth; + /* + size3_base() : width{}, height{}, depth{} + { + } + + size3_base(T width, T height, T depth) : width{ width }, height{ height }, depth{ depth } + { + } + */ +}; + +template +struct coord3_base +{ + union + { + position3_base position; + struct { T x, y, z; }; + }; + + union + { + size3_base size; + struct { T width, height, depth; }; + }; + + constexpr coord3_base() : position{}, size{} + { + } + + constexpr coord3_base(const position3_base& position, const size3_base& size) : position{ position }, size{ size } + { + } + + constexpr coord3_base(T x, T y, T z, T width, T height, T depth) : x{ x }, y{ y }, z{ z }, width{ width }, height{ height }, depth{ depth } + { + } + + constexpr bool test(const position3_base& position) const + { + if (position.x < x || position.x >= x + width) + return false; + + if (position.y < y || position.y >= y + height) + return false; + + if (position.z < z || position.z >= z + depth) + return false; + + return true; + } + + template + constexpr operator coord3_base() const + { + return{ (NT)x, (NT)y, (NT)z, (NT)width, (NT)height, (NT)depth }; + } +}; + + +template +struct color4_base +{ + union + { + struct + { + T r, g, b, a; + }; + + struct + { + T x, y, z, w; + }; + + T rgba[4]; + T xyzw[4]; + }; + + color4_base() + : x{} + , y{} + , z{} + , w{ T(1) } + { + } + + color4_base(T x, T y = {}, T z = {}, T w = {}) + : x(x) + , y(y) + , z(z) + , w(w) + { + } + + bool operator == (const color4_base& rhs) const + { + return r == rhs.r && g == rhs.g && b == rhs.b && a == rhs.a; + } + + bool operator != (const color4_base& rhs) const + { + return !(*this == rhs); + } + + template + operator color4_base() const + { + return{ (NT)x, (NT)y, (NT)z, (NT)w }; + } +}; + +template +struct color3_base +{ + union + { + struct + { + T r, g, b; + }; + + struct + { + T x, y, z; + }; + + T rgb[3]; + T xyz[3]; + }; + + constexpr color3_base(T x = {}, T y = {}, T z = {}) + : x(x) + , y(y) + , z(z) + { + } + + constexpr bool operator == (const color3_base& rhs) const + { + return r == rhs.r && g == rhs.g && b == rhs.b; + } + + constexpr bool operator != (const color3_base& rhs) const + { + return !(*this == rhs); + } + + template + constexpr operator color3_base() const + { + return{ (NT)x, (NT)y, (NT)z }; + } +}; + +template +struct color2_base +{ + union + { + struct + { + T r, g; + }; + + struct + { + T x, y; + }; + + T rg[2]; + T xy[2]; + }; + + constexpr color2_base(T x = {}, T y = {}) + : x(x) + , y(y) + { + } + + constexpr bool operator == (const color2_base& rhs) const + { + return r == rhs.r && g == rhs.g; + } + + constexpr bool operator != (const color2_base& rhs) const + { + return !(*this == rhs); + } + + template + constexpr operator color2_base() const + { + return{ (NT)x, (NT)y }; + } +}; + +template +struct color1_base +{ + union + { + T r; + T x; + }; + + constexpr color1_base(T x = {}) + : x(x) + { + } + + constexpr bool operator == (const color1_base& rhs) const + { + return r == rhs.r; + } + + constexpr bool operator != (const color1_base& rhs) const + { + return !(*this == rhs); + } + + template + constexpr operator color1_base() const + { + return{ (NT)x }; + } +}; + +//specializations +using positioni = position_base; +using positionf = position_base; +using positiond = position_base; + +using coordi = coord_base; +using coordf = coord_base; +using coordd = coord_base; + +using areai = area_base; +using areaf = area_base; +using aread = area_base; + +using position1i = position1_base; +using position1f = position1_base; +using position1d = position1_base; + +using position2i = position2_base; +using position2f = position2_base; +using position2d = position2_base; + +using position3i = position3_base; +using position3f = position3_base; +using position3d = position3_base; + +using position4i = position4_base; +using position4f = position4_base; +using position4d = position4_base; + +using size2i = size2_base; +using size2f = size2_base; +using size2d = size2_base; + +using sizei = size2i; +using sizef = size2f; +using sized = size2d; + +using size3i = size3_base; +using size3f = size3_base; +using size3d = size3_base; + +using coord3i = coord3_base; +using coord3f = coord3_base; +using coord3d = coord3_base; + +using color4i = color4_base; +using color4f = color4_base; +using color4d = color4_base; + +using color3i = color3_base; +using color3f = color3_base; +using color3d = color3_base; + +using color2i = color2_base; +using color2f = color2_base; +using color2d = color2_base; + +using color1i = color1_base; +using color1f = color1_base; +using color1d = color1_base; diff --git a/Utilities/types.h b/Utilities/types.h index d8d32f1778..cff51f5c04 100644 --- a/Utilities/types.h +++ b/Utilities/types.h @@ -1,14 +1,8 @@ #pragma once -#include -#include -#include -#include -#include #include -#include - -#include "Platform.h" +#include +#include using schar = signed char; using uchar = unsigned char; @@ -30,10 +24,17 @@ using s64 = std::int64_t; namespace gsl { - enum class byte : std::uint8_t; + enum class byte : u8; } -// Specialization with static constexpr pair map[] member expected +template +struct bijective_pair +{ + T1 v1; + T2 v2; +}; + +// Specialization with static constexpr bijective_pair map[] member expected template struct bijective; @@ -79,10 +80,9 @@ struct atomic_test_and_complement; template class atomic_t; -template -struct unveil; - -// TODO: replace with std::void_t when available +#ifdef _MSC_VER +using std::void_t; +#else namespace void_details { template @@ -93,6 +93,7 @@ namespace void_details } template using void_t = typename void_details::make_void::type; +#endif // Extract T::simple_type if available, remove cv qualifiers template @@ -112,7 +113,7 @@ template using simple_t = typename simple_type_helper::type; // Bool type equivalent class b8 { - std::uint8_t m_value; + u8 m_value; public: b8() = default; @@ -154,11 +155,11 @@ using s128 = __int128_t; // Unsigned 128-bit integer implementation (TODO) struct alignas(16) u128 { - std::uint64_t lo, hi; + u64 lo, hi; u128() = default; - constexpr u128(std::uint64_t l) + constexpr u128(u64 l) : lo(l) , hi(0) { @@ -171,14 +172,14 @@ struct alignas(16) u128 return value; } - friend u128 operator +(const u128& l, std::uint64_t r) + friend u128 operator +(const u128& l, u64 r) { u128 value; _addcarry_u64(_addcarry_u64(0, r, l.lo, &value.lo), l.hi, 0, &value.hi); return value; } - friend u128 operator +(std::uint64_t l, const u128& r) + friend u128 operator +(u64 l, const u128& r) { u128 value; _addcarry_u64(_addcarry_u64(0, r.lo, l, &value.lo), 0, r.hi, &value.hi); @@ -192,14 +193,14 @@ struct alignas(16) u128 return value; } - friend u128 operator -(const u128& l, std::uint64_t r) + friend u128 operator -(const u128& l, u64 r) { u128 value; _subborrow_u64(_subborrow_u64(0, r, l.lo, &value.lo), 0, l.hi, &value.hi); return value; } - friend u128 operator -(std::uint64_t l, const u128& r) + friend u128 operator -(u64 l, const u128& r) { u128 value; _subborrow_u64(_subborrow_u64(0, r.lo, l, &value.lo), r.hi, 0, &value.hi); @@ -313,18 +314,18 @@ struct alignas(16) u128 // Signed 128-bit integer implementation (TODO) struct alignas(16) s128 { - std::uint64_t lo; - std::int64_t hi; + u64 lo; + s64 hi; s128() = default; - constexpr s128(std::int64_t l) + constexpr s128(s64 l) : hi(l >> 63) , lo(l) { } - constexpr s128(std::uint64_t l) + constexpr s128(u64 l) : hi(0) , lo(l) { @@ -475,1306 +476,62 @@ struct multicast } }; -// Small bitset for enum class types with available values [0, bitsize). -// T must be either enum type or convertible to (registered with via simple_t). -// Internal representation is single value of type T. -template -struct mset -{ - using type = simple_t; - using under = std::underlying_type_t; - - static constexpr auto bitsize = sizeof(type) * CHAR_BIT; - - mset() = default; - - constexpr mset(type _enum_const) - : m_value(static_cast(shift(_enum_const))) - { - } - - constexpr mset(under raw_value, const std::nothrow_t&) - : m_value(static_cast(raw_value)) - { - } - - // Get underlying value - constexpr under _value() const - { - return static_cast(m_value); - } - - explicit constexpr operator bool() const - { - return _value() ? true : false; - } - - mset& operator +=(mset rhs) - { - return *this = { _value() | rhs._value(), std::nothrow }; - } - - mset& operator -=(mset rhs) - { - return *this = { _value() & ~rhs._value(), std::nothrow }; - } - - mset& operator &=(mset rhs) - { - return *this = { _value() & rhs._value(), std::nothrow }; - } - - mset& operator ^=(mset rhs) - { - return *this = { _value() ^ rhs._value(), std::nothrow }; - } - - friend constexpr mset operator +(mset lhs, mset rhs) - { - return{ lhs._value() | rhs._value(), std::nothrow }; - } - - friend constexpr mset operator -(mset lhs, mset rhs) - { - return{ lhs._value() & ~rhs._value(), std::nothrow }; - } - - friend constexpr mset operator &(mset lhs, mset rhs) - { - return{ lhs._value() & rhs._value(), std::nothrow }; - } - - friend constexpr mset operator ^(mset lhs, mset rhs) - { - return{ lhs._value() ^ rhs._value(), std::nothrow }; - } - - bool test(mset rhs) const - { - const under v = _value(); - const under s = rhs._value(); - return (v & s) != 0; - } - - bool test_and_set(mset rhs) - { - const under v = _value(); - const under s = rhs._value(); - *this = { v | s, std::nothrow }; - return (v & s) != 0; - } - - bool test_and_reset(mset rhs) - { - const under v = _value(); - const under s = rhs._value(); - *this = { v & ~s, std::nothrow }; - return (v & s) != 0; - } - - bool test_and_complement(mset rhs) - { - const under v = _value(); - const under s = rhs._value(); - *this = { v ^ s, std::nothrow }; - return (v & s) != 0; - } - -private: - [[noreturn]] static under xrange() - { - throw std::out_of_range("mset<>: bit out of range"); - } - - static constexpr under shift(const T& value) - { - return static_cast(value) < bitsize ? static_cast(1) << static_cast(value) : xrange(); - } - - T m_value; -}; - -template -constexpr RT to_mset() -{ - return RT{}; -} - -// Fold enum constants into mset<> -template::value, mset, T>> -constexpr RT to_mset(Arg&& _enum_const, Args&&... args) -{ - return RT{ std::forward(_enum_const) } + to_mset(std::forward(args)...); -} - -template -struct atomic_add, CT, std::enable_if_t::value>> -{ - using under = typename mset::under; - - static force_inline mset op1(mset& left, mset right) - { - return{ atomic_storage::fetch_or(reinterpret_cast(left), right._value()), std::nothrow }; - } - - static constexpr auto fetch_op = &op1; - - static force_inline mset op2(mset& left, mset right) - { - return{ atomic_storage::or_fetch(reinterpret_cast(left), right._value()), std::nothrow }; - } - - static constexpr auto op_fetch = &op2; - static constexpr auto atomic_op = &op2; -}; - -template -struct atomic_sub, CT, std::enable_if_t::value>> -{ - using under = typename mset::under; - - static force_inline mset op1(mset& left, mset right) - { - return{ atomic_storage::fetch_and(reinterpret_cast(left), ~right._value()), std::nothrow }; - } - - static constexpr auto fetch_op = &op1; - - static force_inline mset op2(mset& left, mset right) - { - return{ atomic_storage::and_fetch(reinterpret_cast(left), ~right._value()), std::nothrow }; - } - - static constexpr auto op_fetch = &op2; - static constexpr auto atomic_op = &op2; -}; - -template -struct atomic_and, CT, std::enable_if_t::value>> -{ - using under = typename mset::under; - - static force_inline mset op1(mset& left, mset right) - { - return{ atomic_storage::fetch_and(reinterpret_cast(left), right._value()), std::nothrow }; - } - - static constexpr auto fetch_op = &op1; - - static force_inline mset op2(mset& left, mset right) - { - return{ atomic_storage::and_fetch(reinterpret_cast(left), right._value()), std::nothrow }; - } - - static constexpr auto op_fetch = &op2; - static constexpr auto atomic_op = &op2; -}; - -template -struct atomic_xor, CT, std::enable_if_t::value>> -{ - using under = typename mset::under; - - static force_inline mset op1(mset& left, mset right) - { - return{ atomic_storage::fetch_xor(reinterpret_cast(left), right._value()), std::nothrow }; - } - - static constexpr auto fetch_op = &op1; - - static force_inline mset op2(mset& left, mset right) - { - return{ atomic_storage::xor_fetch(reinterpret_cast(left), right._value()), std::nothrow }; - } - - static constexpr auto op_fetch = &op2; - static constexpr auto atomic_op = &op2; -}; - -template -struct atomic_test_and_set, T, std::enable_if_t::value>> -{ - using under = typename mset::under; - - static force_inline bool _op(mset& left, const T& value) - { - return atomic_storage::bts(reinterpret_cast(left), static_cast(value)); - } - - static constexpr auto atomic_op = &_op; -}; - -template -struct atomic_test_and_reset, T, std::enable_if_t::value>> -{ - using under = typename mset::under; - - static force_inline bool _op(mset& left, const T& value) - { - return atomic_storage::btr(reinterpret_cast(left), static_cast(value)); - } - - static constexpr auto atomic_op = &_op; -}; - -template -struct atomic_test_and_complement, T, std::enable_if_t::value>> -{ - using under = typename mset::under; - - static force_inline bool _op(mset& left, const T& value) - { - return atomic_storage::btc(reinterpret_cast(left), static_cast(value)); - } - - static constexpr auto atomic_op = &_op; -}; - template T2 bijective_find(const T& left, const DT& def = {}) { - for (const auto& pair : bijective::map) + for (std::size_t i = 0; i < sizeof(bijective::map) / sizeof(bijective_pair); i++) { - if (pair.first == left) + if (bijective::map[i].v1 == left) { - return pair.second; + return bijective::map[i].v2; } } return def; } - -template -struct size2_base +// Formatting helper, type-specific preprocessing for improving safety and functionality +template +struct unveil { - T width, height; - - constexpr size2_base() : width{}, height{} + // TODO + static inline const T& get(const T& arg) { - } - - constexpr size2_base(T width, T height) : width{ width }, height{ height } - { - } - - constexpr size2_base(const size2_base& rhs) : width{ rhs.width }, height{ rhs.height } - { - } - - constexpr size2_base operator -(const size2_base& rhs) const - { - return{ width - rhs.width, height - rhs.height }; - } - constexpr size2_base operator -(T rhs) const - { - return{ width - rhs, height - rhs }; - } - constexpr size2_base operator +(const size2_base& rhs) const - { - return{ width + rhs.width, height + rhs.height }; - } - constexpr size2_base operator +(T rhs) const - { - return{ width + rhs, height + rhs }; - } - constexpr size2_base operator /(const size2_base& rhs) const - { - return{ width / rhs.width, height / rhs.height }; - } - constexpr size2_base operator /(T rhs) const - { - return{ width / rhs, height / rhs }; - } - constexpr size2_base operator *(const size2_base& rhs) const - { - return{ width * rhs.width, height * rhs.height }; - } - constexpr size2_base operator *(T rhs) const - { - return{ width * rhs, height * rhs }; - } - - size2_base& operator -=(const size2_base& rhs) - { - width -= rhs.width; - height -= rhs.height; - return *this; - } - size2_base& operator -=(T rhs) - { - width -= rhs; - height -= rhs; - return *this; - } - size2_base& operator +=(const size2_base& rhs) - { - width += rhs.width; - height += rhs.height; - return *this; - } - size2_base& operator +=(T rhs) - { - width += rhs; - height += rhs; - return *this; - } - size2_base& operator /=(const size2_base& rhs) - { - width /= rhs.width; - height /= rhs.height; - return *this; - } - size2_base& operator /=(T rhs) - { - width /= rhs; - height /= rhs; - return *this; - } - size2_base& operator *=(const size2_base& rhs) - { - width *= rhs.width; - height *= rhs.height; - return *this; - } - size2_base& operator *=(T rhs) - { - width *= rhs; - height *= rhs; - return *this; - } - - constexpr bool operator == (const size2_base& rhs) const - { - return width == rhs.width && height == rhs.height; - } - - constexpr bool operator != (const size2_base& rhs) const - { - return width != rhs.width || height != rhs.height; - } - - template - constexpr operator size2_base() const - { - return{ (NT)width, (NT)height }; + return arg; } }; template -struct position1_base +struct unveil().c_str())>> { - T x; - - position1_base operator -(const position1_base& rhs) const + static inline const char* get(const T& arg) { - return{ x - rhs.x }; - } - position1_base operator -(T rhs) const - { - return{ x - rhs }; - } - position1_base operator +(const position1_base& rhs) const - { - return{ x + rhs.x }; - } - position1_base operator +(T rhs) const - { - return{ x + rhs }; - } - template - position1_base operator *(RhsT rhs) const - { - return{ T(x * rhs) }; - } - position1_base operator *(const position1_base& rhs) const - { - return{ T(x * rhs.x) }; - } - template - position1_base operator /(RhsT rhs) const - { - return{ x / rhs }; - } - position1_base operator /(const position1_base& rhs) const - { - return{ x / rhs.x }; - } - - position1_base& operator -=(const position1_base& rhs) - { - x -= rhs.x; - return *this; - } - position1_base& operator -=(T rhs) - { - x -= rhs; - return *this; - } - position1_base& operator +=(const position1_base& rhs) - { - x += rhs.x; - return *this; - } - position1_base& operator +=(T rhs) - { - x += rhs; - return *this; - } - - template - position1_base& operator *=(RhsT rhs) const - { - x *= rhs; - return *this; - } - position1_base& operator *=(const position1_base& rhs) const - { - x *= rhs.x; - return *this; - } - template - position1_base& operator /=(RhsT rhs) const - { - x /= rhs; - return *this; - } - position1_base& operator /=(const position1_base& rhs) const - { - x /= rhs.x; - return *this; - } - - bool operator ==(const position1_base& rhs) const - { - return x == rhs.x; - } - - bool operator ==(T rhs) const - { - return x == rhs; - } - - bool operator !=(const position1_base& rhs) const - { - return !(*this == rhs); - } - - bool operator !=(T rhs) const - { - return !(*this == rhs); - } - - template - operator position1_base() const - { - return{ (NT)x }; - } - - double distance(const position1_base& to) - { - return abs(x - to.x); + return arg.c_str(); } }; -template -struct position2_base +// Tagged ID type +template +class id_value { - T x, y; + // Initial value + mutable ID m_value{ static_cast(-1) }; - constexpr position2_base() : x{}, y{} + // Allow access for ID manager + friend class idm; + + // Update ID + void operator =(const ID& value) const { + m_value = value; } - constexpr position2_base(T x, T y) : x{ x }, y{ y } - { - } +public: + constexpr id_value() {} - constexpr position2_base(const position2_base& rhs) : x{ rhs.x }, y{ rhs.y } + // Get the value + operator ID() const { - } - - constexpr bool operator >(const position2_base& rhs) const - { - return x > rhs.x && y > rhs.y; - } - constexpr bool operator >(T rhs) const - { - return x > rhs && y > rhs; - } - constexpr bool operator <(const position2_base& rhs) const - { - return x < rhs.x && y < rhs.y; - } - constexpr bool operator <(T rhs) const - { - return x < rhs && y < rhs; - } - constexpr bool operator >=(const position2_base& rhs) const - { - return x >= rhs.x && y >= rhs.y; - } - constexpr bool operator >=(T rhs) const - { - return x >= rhs && y >= rhs; - } - constexpr bool operator <=(const position2_base& rhs) const - { - return x <= rhs.x && y <= rhs.y; - } - constexpr bool operator <=(T rhs) const - { - return x <= rhs && y <= rhs; - } - - constexpr position2_base operator -(const position2_base& rhs) const - { - return{ x - rhs.x, y - rhs.y }; - } - constexpr position2_base operator -(T rhs) const - { - return{ x - rhs, y - rhs }; - } - constexpr position2_base operator +(const position2_base& rhs) const - { - return{ x + rhs.x, y + rhs.y }; - } - constexpr position2_base operator +(T rhs) const - { - return{ x + rhs, y + rhs }; - } - template - constexpr position2_base operator *(RhsT rhs) const - { - return{ T(x * rhs), T(y * rhs) }; - } - constexpr position2_base operator *(const position2_base& rhs) const - { - return{ T(x * rhs.x), T(y * rhs.y) }; - } - template - constexpr position2_base operator /(RhsT rhs) const - { - return{ x / rhs, y / rhs }; - } - constexpr position2_base operator /(const position2_base& rhs) const - { - return{ x / rhs.x, y / rhs.y }; - } - constexpr position2_base operator /(const size2_base& rhs) const - { - return{ x / rhs.width, y / rhs.height }; - } - - position2_base& operator -=(const position2_base& rhs) - { - x -= rhs.x; - y -= rhs.y; - return *this; - } - position2_base& operator -=(T rhs) - { - x -= rhs; - y -= rhs; - return *this; - } - position2_base& operator +=(const position2_base& rhs) - { - x += rhs.x; - y += rhs.y; - return *this; - } - position2_base& operator +=(T rhs) - { - x += rhs; - y += rhs; - return *this; - } - - template - position2_base& operator *=(RhsT rhs) - { - x *= rhs; - y *= rhs; - return *this; - } - position2_base& operator *=(const position2_base& rhs) - { - x *= rhs.x; - y *= rhs.y; - return *this; - } - template - position2_base& operator /=(RhsT rhs) - { - x /= rhs; - y /= rhs; - return *this; - } - position2_base& operator /=(const position2_base& rhs) - { - x /= rhs.x; - y /= rhs.y; - return *this; - } - - constexpr bool operator ==(const position2_base& rhs) const - { - return x == rhs.x && y == rhs.y; - } - - constexpr bool operator ==(T rhs) const - { - return x == rhs && y == rhs; - } - - constexpr bool operator !=(const position2_base& rhs) const - { - return !(*this == rhs); - } - - constexpr bool operator !=(T rhs) const - { - return !(*this == rhs); - } - - template - constexpr operator position2_base() const - { - return{ (NT)x, (NT)y }; - } - - double distance(const position2_base& to) const - { - return std::sqrt(double((x - to.x) * (x - to.x) + (y - to.y) * (y - to.y))); + return m_value; } }; - -template -struct position3_base -{ - T x, y, z; - /* - position3_base() : x{}, y{}, z{} - { - } - - position3_base(T x, T y, T z) : x{ x }, y{ y }, z{ z } - { - } - */ - - position3_base operator -(const position3_base& rhs) const - { - return{ x - rhs.x, y - rhs.y, z - rhs.z }; - } - position3_base operator -(T rhs) const - { - return{ x - rhs, y - rhs, z - rhs }; - } - position3_base operator +(const position3_base& rhs) const - { - return{ x + rhs.x, y + rhs.y, z + rhs.z }; - } - position3_base operator +(T rhs) const - { - return{ x + rhs, y + rhs, z + rhs }; - } - - position3_base& operator -=(const position3_base& rhs) - { - x -= rhs.x; - y -= rhs.y; - z -= rhs.z; - return *this; - } - position3_base& operator -=(T rhs) - { - x -= rhs; - y -= rhs; - z -= rhs; - return *this; - } - position3_base& operator +=(const position3_base& rhs) - { - x += rhs.x; - y += rhs.y; - z += rhs.z; - return *this; - } - position3_base& operator +=(T rhs) - { - x += rhs; - y += rhs; - z += rhs; - return *this; - } - - bool operator ==(const position3_base& rhs) const - { - return x == rhs.x && y == rhs.y && z == rhs.z; - } - - bool operator ==(T rhs) const - { - return x == rhs && y == rhs && z == rhs; - } - - bool operator !=(const position3_base& rhs) const - { - return !(*this == rhs); - } - - bool operator !=(T rhs) const - { - return !(*this == rhs); - } - - template - operator position3_base() const - { - return{ (NT)x, (NT)y, (NT)z }; - } -}; - -template -struct position4_base -{ - T x, y, z, w; - - constexpr position4_base() : x{}, y{}, z{}, w{} - { - } - - constexpr position4_base(T x, T y = {}, T z = {}, T w = {T(1)}) : x{ x }, y{ y }, z{ z }, w{ w } - { - } - - constexpr position4_base operator -(const position4_base& rhs) const - { - return{ x - rhs.x, y - rhs.y, z - rhs.z, w - rhs.w }; - } - constexpr position4_base operator -(T rhs) const - { - return{ x - rhs, y - rhs, z - rhs, w - rhs }; - } - constexpr position4_base operator +(const position4_base& rhs) const - { - return{ x + rhs.x, y + rhs.y, z + rhs.z, w + rhs.w }; - } - constexpr position4_base operator +(T rhs) const - { - return{ x + rhs, y + rhs, z + rhs, w + rhs }; - } - - position4_base& operator -=(const position4_base& rhs) - { - x -= rhs.x; - y -= rhs.y; - z -= rhs.z; - w -= rhs.w; - return *this; - } - position4_base& operator -=(T rhs) - { - x -= rhs; - y -= rhs; - z -= rhs; - w -= rhs; - return *this; - } - position4_base& operator +=(const position4_base& rhs) - { - x += rhs.x; - y += rhs.y; - z += rhs.z; - w += rhs.w; - return *this; - } - position4_base& operator +=(T rhs) - { - x += rhs; - y += rhs; - z += rhs; - w += rhs; - return *this; - } - - constexpr bool operator ==(const position4_base& rhs) const - { - return x == rhs.x && y == rhs.y && z == rhs.z && w == rhs.w; - } - - constexpr bool operator ==(T rhs) const - { - return x == rhs && y == rhs && z == rhs && w == rhs; - } - - constexpr bool operator !=(const position4_base& rhs) const - { - return !(*this == rhs); - } - - constexpr bool operator !=(T rhs) const - { - return !(*this == rhs); - } - - template - constexpr operator position4_base() const - { - return{ (NT)x, (NT)y, (NT)z, (NT)w }; - } -}; - -template -using position_base = position2_base; - -template -struct coord_base -{ - union - { - position_base position; - struct { T x, y; }; - }; - - union - { - size2_base size; - struct { T width, height; }; - }; - - constexpr coord_base() : position{}, size{} -#ifdef _MSC_VER - //compiler error - , x{}, y{}, width{}, height{} -#endif - { - } - - constexpr coord_base(const position_base& position, const size2_base& size) - : position{ position }, size{ size } -#ifdef _MSC_VER - , x{ position.x }, y{ position.y }, width{ size.width }, height{ size.height } -#endif - { - } - - constexpr coord_base(T x, T y, T width, T height) : x{ x }, y{ y }, width{ width }, height{ height } - { - } - - constexpr bool test(const position_base& position) const - { - if (position.x < x || position.x >= x + width) - return false; - - if (position.y < y || position.y >= y + height) - return false; - - return true; - } - - constexpr bool operator == (const coord_base& rhs) const - { - return position == rhs.position && size == rhs.size; - } - - constexpr bool operator != (const coord_base& rhs) const - { - return position != rhs.position || size != rhs.size; - } - - template - constexpr operator coord_base() const - { - return{ (NT)x, (NT)y, (NT)width, (NT)height }; - } -}; - -template -struct area_base -{ - T x1, x2; - T y1, y2; - - constexpr area_base() : x1{}, x2{}, y1{}, y2{} - { - } - - constexpr area_base(T x1, T y1, T x2, T y2) : x1{ x1 }, x2{ x2 }, y1{ y1 }, y2{ y2 } - { - } - - constexpr area_base(const coord_base& coord) : x1{ coord.x }, x2{ coord.x + coord.width }, y1{ coord.y }, y2{ coord.y + coord.height } - { - } - - constexpr operator coord_base() const - { - return{ x1, y1, x2 - x1, y2 - y1 }; - } - - void flip_vertical() - { - std::swap(y1, y2); - } - - void flip_horizontal() - { - std::swap(x1, x2); - } - - constexpr area_base flipped_vertical() const - { - return{ x1, y2, x2, y1 }; - } - - constexpr area_base flipped_horizontal() const - { - return{ x2, y1, x1, y2 }; - } - - constexpr bool operator == (const area_base& rhs) const - { - return x1 == rhs.x1 && x2 == rhs.x2 && y1 == rhs.y1 && y2 == rhs.y2; - } - - constexpr bool operator != (const area_base& rhs) const - { - return !(*this == rhs); - } - - constexpr area_base operator - (const size2_base& size) const - { - return{ x1 - size.width, y1 - size.height, x2 - size.width, y2 - size.height }; - } - constexpr area_base operator - (const T& value) const - { - return{ x1 - value, y1 - value, x2 - value, y2 - value }; - } - constexpr area_base operator + (const size2_base& size) const - { - return{ x1 + size.width, y1 + size.height, x2 + size.width, y2 + size.height }; - } - constexpr area_base operator + (const T& value) const - { - return{ x1 + value, y1 + value, x2 + value, y2 + value }; - } - constexpr area_base operator / (const size2_base& size) const - { - return{ x1 / size.width, y1 / size.height, x2 / size.width, y2 / size.height }; - } - constexpr area_base operator / (const T& value) const - { - return{ x1 / value, y1 / value, x2 / value, y2 / value }; - } - constexpr area_base operator * (const size2_base& size) const - { - return{ x1 * size.width, y1 * size.height, x2 * size.width, y2 * size.height }; - } - constexpr area_base operator * (const T& value) const - { - return{ x1 * value, y1 * value, x2 * value, y2 * value }; - } - - template - constexpr operator area_base() const - { - return{(NT)x1, (NT)y1, (NT)x2, (NT)y2}; - } -}; - -template -struct size3_base -{ - T width, height, depth; - /* - size3_base() : width{}, height{}, depth{} - { - } - - size3_base(T width, T height, T depth) : width{ width }, height{ height }, depth{ depth } - { - } - */ -}; - -template -struct coord3_base -{ - union - { - position3_base position; - struct { T x, y, z; }; - }; - - union - { - size3_base size; - struct { T width, height, depth; }; - }; - - constexpr coord3_base() : position{}, size{} - { - } - - constexpr coord3_base(const position3_base& position, const size3_base& size) : position{ position }, size{ size } - { - } - - constexpr coord3_base(T x, T y, T z, T width, T height, T depth) : x{ x }, y{ y }, z{ z }, width{ width }, height{ height }, depth{ depth } - { - } - - constexpr bool test(const position3_base& position) const - { - if (position.x < x || position.x >= x + width) - return false; - - if (position.y < y || position.y >= y + height) - return false; - - if (position.z < z || position.z >= z + depth) - return false; - - return true; - } - - template - constexpr operator coord3_base() const - { - return{ (NT)x, (NT)y, (NT)z, (NT)width, (NT)height, (NT)depth }; - } -}; - - -template -struct color4_base -{ - union - { - struct - { - T r, g, b, a; - }; - - struct - { - T x, y, z, w; - }; - - T rgba[4]; - T xyzw[4]; - }; - - color4_base() - : x{} - , y{} - , z{} - , w{ T(1) } - { - } - - color4_base(T x, T y = {}, T z = {}, T w = {}) - : x(x) - , y(y) - , z(z) - , w(w) - { - } - - bool operator == (const color4_base& rhs) const - { - return r == rhs.r && g == rhs.g && b == rhs.b && a == rhs.a; - } - - bool operator != (const color4_base& rhs) const - { - return !(*this == rhs); - } - - template - operator color4_base() const - { - return{ (NT)x, (NT)y, (NT)z, (NT)w }; - } -}; - -template -struct color3_base -{ - union - { - struct - { - T r, g, b; - }; - - struct - { - T x, y, z; - }; - - T rgb[3]; - T xyz[3]; - }; - - constexpr color3_base(T x = {}, T y = {}, T z = {}) - : x(x) - , y(y) - , z(z) - { - } - - constexpr bool operator == (const color3_base& rhs) const - { - return r == rhs.r && g == rhs.g && b == rhs.b; - } - - constexpr bool operator != (const color3_base& rhs) const - { - return !(*this == rhs); - } - - template - constexpr operator color3_base() const - { - return{ (NT)x, (NT)y, (NT)z }; - } -}; - -template -struct color2_base -{ - union - { - struct - { - T r, g; - }; - - struct - { - T x, y; - }; - - T rg[2]; - T xy[2]; - }; - - constexpr color2_base(T x = {}, T y = {}) - : x(x) - , y(y) - { - } - - constexpr bool operator == (const color2_base& rhs) const - { - return r == rhs.r && g == rhs.g; - } - - constexpr bool operator != (const color2_base& rhs) const - { - return !(*this == rhs); - } - - template - constexpr operator color2_base() const - { - return{ (NT)x, (NT)y }; - } -}; - -template -struct color1_base -{ - union - { - T r; - T x; - }; - - constexpr color1_base(T x = {}) - : x(x) - { - } - - constexpr bool operator == (const color1_base& rhs) const - { - return r == rhs.r; - } - - constexpr bool operator != (const color1_base& rhs) const - { - return !(*this == rhs); - } - - template - constexpr operator color1_base() const - { - return{ (NT)x }; - } -}; - -//specializations -using positioni = position_base; -using positionf = position_base; -using positiond = position_base; - -using coordi = coord_base; -using coordf = coord_base; -using coordd = coord_base; - -using areai = area_base; -using areaf = area_base; -using aread = area_base; - -using position1i = position1_base; -using position1f = position1_base; -using position1d = position1_base; - -using position2i = position2_base; -using position2f = position2_base; -using position2d = position2_base; - -using position3i = position3_base; -using position3f = position3_base; -using position3d = position3_base; - -using position4i = position4_base; -using position4f = position4_base; -using position4d = position4_base; - -using size2i = size2_base; -using size2f = size2_base; -using size2d = size2_base; - -using sizei = size2i; -using sizef = size2f; -using sized = size2d; - -using size3i = size3_base; -using size3f = size3_base; -using size3d = size3_base; - -using coord3i = coord3_base; -using coord3f = coord3_base; -using coord3d = coord3_base; - -using color4i = color4_base; -using color4f = color4_base; -using color4d = color4_base; - -using color3i = color3_base; -using color3f = color3_base; -using color3d = color3_base; - -using color2i = color2_base; -using color2f = color2_base; -using color2d = color2_base; - -using color1i = color1_base; -using color1f = color1_base; -using color1d = color1_base; diff --git a/rpcs3/Emu/ARMv7/ARMv7DisAsm.cpp b/rpcs3/Emu/ARMv7/ARMv7DisAsm.cpp index f7cd9178cd..5334757d1c 100644 --- a/rpcs3/Emu/ARMv7/ARMv7DisAsm.cpp +++ b/rpcs3/Emu/ARMv7/ARMv7DisAsm.cpp @@ -106,10 +106,10 @@ static std::string fmt_shift(u32 type, u32 amount) { switch (type) { - case arm_code::SRType_LSL: return ",lsl #" + fmt::to_udec(amount); - case arm_code::SRType_LSR: return ",lsr #" + fmt::to_udec(amount); - case arm_code::SRType_ASR: return ",asr #" + fmt::to_udec(amount); - case arm_code::SRType_ROR: return ",ror #" + fmt::to_udec(amount); + case arm_code::SRType_LSL: return fmt::format(",lsl #%u", amount); + case arm_code::SRType_LSR: return fmt::format(",lsr #%u", amount); + case arm_code::SRType_ASR: return fmt::format(",asr #%u", amount); + case arm_code::SRType_ROR: return fmt::format(",ror #%u", amount); case arm_code::SRType_RRX: return ",rrx"; default: return ",?????"; } diff --git a/rpcs3/Emu/ARMv7/ARMv7Function.cpp b/rpcs3/Emu/ARMv7/ARMv7Function.cpp index f61bc3486f..7d9154e60e 100644 --- a/rpcs3/Emu/ARMv7/ARMv7Function.cpp +++ b/rpcs3/Emu/ARMv7/ARMv7Function.cpp @@ -57,3 +57,23 @@ s32 arm_error_code::report(s32 error, const char* text) LOG_ERROR(ARMv7, "Illegal call to ppu_report_error(0x%x, '%s')!"); return error; } + +std::vector& arm_function_manager::access() +{ + static std::vector list + { + nullptr, + [](ARMv7Thread& cpu) { cpu.state += cpu_state::ret; }, + }; + + return list; +} + +u32 arm_function_manager::add_function(arm_function_t function) +{ + auto& list = access(); + + list.push_back(function); + + return ::size32(list) - 1; +} diff --git a/rpcs3/Emu/ARMv7/ARMv7Function.h b/rpcs3/Emu/ARMv7/ARMv7Function.h index ebbf02a119..5d2f5d0e64 100644 --- a/rpcs3/Emu/ARMv7/ARMv7Function.h +++ b/rpcs3/Emu/ARMv7/ARMv7Function.h @@ -439,25 +439,9 @@ class arm_function_manager }; // Access global function list - static never_inline auto& access() - { - static std::vector list - { - nullptr, - [](ARMv7Thread& cpu) { cpu.state += cpu_state::ret; }, - }; + static std::vector& access(); - return list; - } - - static never_inline u32 add_function(arm_function_t function) - { - auto& list = access(); - - list.push_back(function); - - return ::size32(list) - 1; - } + static u32 add_function(arm_function_t function); public: // Register function (shall only be called during global initialization) diff --git a/rpcs3/Emu/ARMv7/ARMv7Module.cpp b/rpcs3/Emu/ARMv7/ARMv7Module.cpp index 8f0f2785a6..c4a104ce0d 100644 --- a/rpcs3/Emu/ARMv7/ARMv7Module.cpp +++ b/rpcs3/Emu/ARMv7/ARMv7Module.cpp @@ -57,6 +57,35 @@ arm_static_module::arm_static_module(const char* name) arm_module_manager::register_module(this); } +std::unordered_map& arm_module_manager::access() +{ + static std::unordered_map map; + + return map; +} + +void arm_module_manager::register_module(arm_static_module* module) +{ + access().emplace(module->name, module); +} + +arm_static_function& arm_module_manager::access_static_function(const char* module, u32 fnid) +{ + return access().at(module)->functions[fnid]; +} + +arm_static_variable& arm_module_manager::access_static_variable(const char* module, u32 vnid) +{ + return access().at(module)->variables[vnid]; +} + +const arm_static_module* arm_module_manager::get_module(const std::string& name) +{ + const auto& map = access(); + const auto found = map.find(name); + return found != map.end() ? found->second : nullptr; +} + static void arm_initialize_modules() { const std::initializer_list registered diff --git a/rpcs3/Emu/ARMv7/ARMv7Module.h b/rpcs3/Emu/ARMv7/ARMv7Module.h index 95261f5b80..8083f9b581 100644 --- a/rpcs3/Emu/ARMv7/ARMv7Module.h +++ b/rpcs3/Emu/ARMv7/ARMv7Module.h @@ -57,35 +57,16 @@ class arm_module_manager final { friend class arm_static_module; - static never_inline auto& access() - { - static std::unordered_map map; + static std::unordered_map& access(); - return map; - } + static void register_module(arm_static_module* module); - static never_inline void register_module(arm_static_module* module) - { - access().emplace(module->name, module); - } + static arm_static_function& access_static_function(const char* module, u32 fnid); - static never_inline auto& access_static_function(const char* module, u32 fnid) - { - return access().at(module)->functions[fnid]; - } - - static never_inline auto& access_static_variable(const char* module, u32 vnid) - { - return access().at(module)->variables[vnid]; - } + static arm_static_variable& access_static_variable(const char* module, u32 vnid); public: - static never_inline const arm_static_module* get_module(const std::string& name) - { - const auto& map = access(); - const auto found = map.find(name); - return found != map.end() ? found->second : nullptr; - } + static const arm_static_module* get_module(const std::string& name); template static void register_static_function(const char* module, const char* name, arm_function_t func, u32 fnid, u32 flags) diff --git a/rpcs3/Emu/ARMv7/ARMv7Thread.cpp b/rpcs3/Emu/ARMv7/ARMv7Thread.cpp index 98828c1c81..f491dff093 100644 --- a/rpcs3/Emu/ARMv7/ARMv7Thread.cpp +++ b/rpcs3/Emu/ARMv7/ARMv7Thread.cpp @@ -122,6 +122,8 @@ void ARMv7Thread::cpu_init() TLS = armv7_get_tls(id); } +extern thread_local std::string(*g_tls_log_prefix)(); + void ARMv7Thread::cpu_task() { if (custom_task) @@ -131,7 +133,7 @@ void ARMv7Thread::cpu_task() return custom_task(*this); } - _log::g_tls_make_prefix = [](const auto&, auto, const auto&) + g_tls_log_prefix = [] { const auto cpu = static_cast(get_current_cpu_thread()); diff --git a/rpcs3/Emu/ARMv7/Modules/sceLibKernel.cpp b/rpcs3/Emu/ARMv7/Modules/sceLibKernel.cpp index 57066f455c..f2ce259f97 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceLibKernel.cpp +++ b/rpcs3/Emu/ARMv7/Modules/sceLibKernel.cpp @@ -5,6 +5,8 @@ #include "sceLibKernel.h" +#include "Utilities/StrUtil.h" + LOG_CHANNEL(sceLibKernel); extern u64 get_system_time(); diff --git a/rpcs3/Emu/ARMv7/Modules/sceLibc.cpp b/rpcs3/Emu/ARMv7/Modules/sceLibc.cpp index 0e23fc0e3e..4532f085c7 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceLibc.cpp +++ b/rpcs3/Emu/ARMv7/Modules/sceLibc.cpp @@ -8,6 +8,8 @@ LOG_CHANNEL(sceLibc); +extern fs::file g_tty; + // TODO vm::ptr g_dso; @@ -95,7 +97,7 @@ std::string arm_fmt(ARMv7Thread& cpu, vm::cptr fmt, u32 g_count) if (plus_sign || minus_sign || space_sign || number_sign || zero_padding || width || prec) break; - result += fmt::to_sdec(value); + result += fmt::format("%lld", value); continue; } case 'x': @@ -111,7 +113,7 @@ std::string arm_fmt(ARMv7Thread& cpu, vm::cptr fmt, u32 g_count) result += cf == 'x' ? "0x" : "0X"; } - const std::string& hex = cf == 'x' ? fmt::to_hex(value) : fmt::to_upper(fmt::to_hex(value)); + const std::string& hex = fmt::format(cf == 'x' ? "%llx" : "%llX", value); if (hex.length() >= width) { @@ -211,7 +213,10 @@ namespace sce_libc_func const std::string& result = arm_fmt(cpu, fmt, va_args.count); sceLibc.trace("*** -> '%s'", result); - _log::g_tty_file.log(result); + if (g_tty) + { + g_tty.write(result); + } } void sprintf(ARMv7Thread& cpu, vm::ptr str, vm::cptr fmt, arm_va_args_t va_args) diff --git a/rpcs3/Emu/Audio/XAudio2/XAudio2Thread.cpp b/rpcs3/Emu/Audio/XAudio2/XAudio2Thread.cpp index 65cb3130ad..4a879667e0 100644 --- a/rpcs3/Emu/Audio/XAudio2/XAudio2Thread.cpp +++ b/rpcs3/Emu/Audio/XAudio2/XAudio2Thread.cpp @@ -1,5 +1,6 @@ #ifdef _WIN32 #include "Utilities/Log.h" +#include "Utilities/StrFmt.h" #include "Utilities/Config.h" #include "Emu/System.h" diff --git a/rpcs3/Emu/CPU/CPUThread.cpp b/rpcs3/Emu/CPU/CPUThread.cpp index 9cab30f773..27e970e81a 100644 --- a/rpcs3/Emu/CPU/CPUThread.cpp +++ b/rpcs3/Emu/CPU/CPUThread.cpp @@ -108,7 +108,7 @@ bool cpu_thread::check_status() const auto state_ = state.load(); - if (state_ & to_mset(cpu_state::ret, cpu_state::stop)) + if (state_ & make_bitset(cpu_state::ret, cpu_state::stop)) { return true; } diff --git a/rpcs3/Emu/CPU/CPUThread.h b/rpcs3/Emu/CPU/CPUThread.h index 42623087e2..eae4cacb02 100644 --- a/rpcs3/Emu/CPU/CPUThread.h +++ b/rpcs3/Emu/CPU/CPUThread.h @@ -1,6 +1,7 @@ #pragma once #include "Utilities/Thread.h" +#include "Utilities/BitSet.h" // CPU Thread Type enum class cpu_type : u32 @@ -27,7 +28,7 @@ enum struct cpu_state : u32 }; // CPU Thread State flags: pause state union -constexpr mset cpu_state_pause = to_mset(cpu_state::suspend, cpu_state::dbg_global_pause, cpu_state::dbg_pause); +constexpr bitset_t cpu_state_pause = make_bitset(cpu_state::suspend, cpu_state::dbg_global_pause, cpu_state::dbg_pause); class cpu_thread : public named_thread { @@ -38,13 +39,14 @@ public: virtual ~cpu_thread() override; const std::string name; - const u32 id = -1; const cpu_type type; + const id_value<> id{}; + cpu_thread(cpu_type type, const std::string& name); // Public thread state - atomic_t> state{ cpu_state::stop }; + atomic_t> state{ cpu_state::stop }; // Recursively enter sleep state void sleep() diff --git a/rpcs3/Emu/Cell/Modules/cellDmux.h b/rpcs3/Emu/Cell/Modules/cellDmux.h index 3341718e61..dd93bad2dd 100644 --- a/rpcs3/Emu/Cell/Modules/cellDmux.h +++ b/rpcs3/Emu/Cell/Modules/cellDmux.h @@ -440,7 +440,7 @@ public: ElementaryStream(Demuxer* dmux, u32 addr, u32 size, u32 fidMajor, u32 fidMinor, u32 sup1, u32 sup2, vm::ptr cbFunc, u32 cbArg, u32 spec); Demuxer* dmux; - const u32 id{}; + const id_value<> id{}; const u32 memAddr; const u32 memSize; const u32 fidMajor; diff --git a/rpcs3/Emu/Cell/Modules/cellFs.cpp b/rpcs3/Emu/Cell/Modules/cellFs.cpp index 2374bdd421..220df6262a 100644 --- a/rpcs3/Emu/Cell/Modules/cellFs.cpp +++ b/rpcs3/Emu/Cell/Modules/cellFs.cpp @@ -6,6 +6,8 @@ #include "Emu/Cell/lv2/sys_fs.h" #include "cellFs.h" +#include "Utilities/StrUtil.h" + LOG_CHANNEL(cellFs); s32 cellFsOpen(vm::cptr path, s32 flags, vm::ptr fd, vm::cptr arg, u64 size) diff --git a/rpcs3/Emu/Cell/Modules/cellGame.cpp b/rpcs3/Emu/Cell/Modules/cellGame.cpp index 3d45e3d13f..632d72000b 100644 --- a/rpcs3/Emu/Cell/Modules/cellGame.cpp +++ b/rpcs3/Emu/Cell/Modules/cellGame.cpp @@ -8,6 +8,7 @@ #include "cellGame.h" #include "Loader/PSF.h" +#include "Utilities/StrUtil.h" LOG_CHANNEL(cellGame); diff --git a/rpcs3/Emu/Cell/Modules/cellMsgDialog.h b/rpcs3/Emu/Cell/Modules/cellMsgDialog.h index 37b71020bf..3ddfc52e0a 100644 --- a/rpcs3/Emu/Cell/Modules/cellMsgDialog.h +++ b/rpcs3/Emu/Cell/Modules/cellMsgDialog.h @@ -1,5 +1,7 @@ #pragma once +#include "Utilities/BitField.h" + namespace vm { using namespace ps3; } enum diff --git a/rpcs3/Emu/Cell/Modules/cellNetCtl.cpp b/rpcs3/Emu/Cell/Modules/cellNetCtl.cpp index 361daa9849..65ceda8e18 100644 --- a/rpcs3/Emu/Cell/Modules/cellNetCtl.cpp +++ b/rpcs3/Emu/Cell/Modules/cellNetCtl.cpp @@ -5,6 +5,8 @@ #include "cellSysutil.h" #include "cellNetCtl.h" +#include "Utilities/StrUtil.h" + LOG_CHANNEL(cellNetCtl); cfg::map_entry g_cfg_net_status(cfg::root.net, "Connection status", diff --git a/rpcs3/Emu/Cell/Modules/cellSaveData.cpp b/rpcs3/Emu/Cell/Modules/cellSaveData.cpp index c4a5d45132..97389a9a41 100644 --- a/rpcs3/Emu/Cell/Modules/cellSaveData.cpp +++ b/rpcs3/Emu/Cell/Modules/cellSaveData.cpp @@ -5,6 +5,7 @@ #include "cellSaveData.h" #include "Loader/PSF.h" +#include "Utilities/StrUtil.h" LOG_CHANNEL(cellSaveData); diff --git a/rpcs3/Emu/Cell/Modules/cellSync.h b/rpcs3/Emu/Cell/Modules/cellSync.h index 831ce776d1..bae86aecc4 100644 --- a/rpcs3/Emu/Cell/Modules/cellSync.h +++ b/rpcs3/Emu/Cell/Modules/cellSync.h @@ -1,5 +1,7 @@ #pragma once +#include "Utilities/BitField.h" + namespace vm { using namespace ps3; } // Return Codes @@ -374,23 +376,6 @@ struct alignas(128) CellSyncLFQueue vm::bptr m_eaSignal; // 0x70 be_t m_v2; // 0x78 be_t m_eq_id; // 0x7C - - std::string dump() - { - std::string res = "CellSyncLFQueue dump:"; - - auto data = (be_t*)this; - - for (u32 i = 0; i < sizeof(CellSyncLFQueue) / sizeof(u64); i += 2) - { - res += "\n*** 0x"; - res += fmt::to_hex(data[i + 0], 16); - res += " 0x"; - res += fmt::to_hex(data[i + 1], 16); - } - - return res; - } }; CHECK_SIZE_ALIGN(CellSyncLFQueue, 128, 128); diff --git a/rpcs3/Emu/Cell/Modules/cellSync2.cpp b/rpcs3/Emu/Cell/Modules/cellSync2.cpp index 145d51ba98..21673c5012 100644 --- a/rpcs3/Emu/Cell/Modules/cellSync2.cpp +++ b/rpcs3/Emu/Cell/Modules/cellSync2.cpp @@ -4,6 +4,8 @@ #include "cellSync2.h" +#include "Utilities/StrUtil.h" + LOG_CHANNEL(cellSync2); vm::gvar gCellSync2CallerThreadTypePpuThread; diff --git a/rpcs3/Emu/Cell/Modules/cellSysutil.cpp b/rpcs3/Emu/Cell/Modules/cellSysutil.cpp index 0653f9fa8d..1e92f757ae 100644 --- a/rpcs3/Emu/Cell/Modules/cellSysutil.cpp +++ b/rpcs3/Emu/Cell/Modules/cellSysutil.cpp @@ -5,6 +5,8 @@ #include "cellSysutil.h" +#include "Utilities/StrUtil.h" + LOG_CHANNEL(cellSysutil); // Temporarily diff --git a/rpcs3/Emu/Cell/Modules/cellUserInfo.cpp b/rpcs3/Emu/Cell/Modules/cellUserInfo.cpp index facf4365aa..790d6b9eab 100644 --- a/rpcs3/Emu/Cell/Modules/cellUserInfo.cpp +++ b/rpcs3/Emu/Cell/Modules/cellUserInfo.cpp @@ -4,6 +4,8 @@ #include "cellUserInfo.h" +#include "Utilities/StrUtil.h" + LOG_CHANNEL(cellUserInfo); s32 cellUserInfoGetStat(u32 id, vm::ptr stat) diff --git a/rpcs3/Emu/Cell/Modules/cellVideoOut.cpp b/rpcs3/Emu/Cell/Modules/cellVideoOut.cpp index c3fd404652..a3a2ba826c 100644 --- a/rpcs3/Emu/Cell/Modules/cellVideoOut.cpp +++ b/rpcs3/Emu/Cell/Modules/cellVideoOut.cpp @@ -24,7 +24,7 @@ cfg::map_entry g_cfg_video_out_aspect_ratio(cfg::root.video, "Aspect ratio", { "16x9", CELL_VIDEO_OUT_ASPECT_16_9 }, }); -const extern std::unordered_map g_video_out_resolution_map +const extern std::unordered_map> g_video_out_resolution_map { { CELL_VIDEO_OUT_RESOLUTION_1080, { 1920, 1080 } }, { CELL_VIDEO_OUT_RESOLUTION_720, { 1280, 720 } }, @@ -133,7 +133,7 @@ ppu_error_code cellVideoOutGetConfiguration(u32 videoOut, vm::ptrresolutionId = g_cfg_video_out_resolution.get(); config->format = CELL_VIDEO_OUT_BUFFER_COLOR_FORMAT_X8R8G8B8; config->aspect = g_cfg_video_out_aspect_ratio.get(); - config->pitch = 4 * g_video_out_resolution_map.at(g_cfg_video_out_resolution.get()).width; + config->pitch = 4 * g_video_out_resolution_map.at(g_cfg_video_out_resolution.get()).first; return CELL_OK; diff --git a/rpcs3/Emu/Cell/Modules/sceNpTrophy.cpp b/rpcs3/Emu/Cell/Modules/sceNpTrophy.cpp index a0848e2621..f81d2b535d 100644 --- a/rpcs3/Emu/Cell/Modules/sceNpTrophy.cpp +++ b/rpcs3/Emu/Cell/Modules/sceNpTrophy.cpp @@ -10,11 +10,13 @@ #include "sceNp.h" #include "sceNpTrophy.h" +#include "Utilities/StrUtil.h" + LOG_CHANNEL(sceNpTrophy); struct trophy_context_t { - const u32 id{}; + const id_value<> id{}; std::string trp_name; fs::file trp_stream; @@ -23,7 +25,7 @@ struct trophy_context_t struct trophy_handle_t { - const u32 id{}; + const id_value<> id{}; }; // Functions diff --git a/rpcs3/Emu/Cell/Modules/sysPrxForUser.cpp b/rpcs3/Emu/Cell/Modules/sysPrxForUser.cpp index 7140e8b37e..b531810687 100644 --- a/rpcs3/Emu/Cell/Modules/sysPrxForUser.cpp +++ b/rpcs3/Emu/Cell/Modules/sysPrxForUser.cpp @@ -10,6 +10,8 @@ LOG_CHANNEL(sysPrxForUser); extern u64 get_system_time(); +extern fs::file g_tty; + vm::gvar sys_prx_version; // ??? #define TLS_SYS 0x30 @@ -163,7 +165,10 @@ s32 console_write(vm::ptr data, u32 len) { sysPrxForUser.warning("console_write(data=*0x%x, len=%d)", data, len); - _log::g_tty_file.log({ data.get_ptr(), len }); + if (g_tty) + { + g_tty.write(data.get_ptr(), len); + } return CELL_OK; } diff --git a/rpcs3/Emu/Cell/Modules/sys_libc_.cpp b/rpcs3/Emu/Cell/Modules/sys_libc_.cpp index 61f91faee2..15be5a9f46 100644 --- a/rpcs3/Emu/Cell/Modules/sys_libc_.cpp +++ b/rpcs3/Emu/Cell/Modules/sys_libc_.cpp @@ -3,6 +3,8 @@ extern _log::channel sysPrxForUser; +extern fs::file g_tty; + // TODO static std::string ps3_fmt(PPUThread& context, vm::cptr fmt, u32 g_count) { @@ -83,7 +85,7 @@ static std::string ps3_fmt(PPUThread& context, vm::cptr fmt, u32 g_count) if (plus_sign || minus_sign || space_sign || number_sign || zero_padding || width || prec) break; - result += fmt::to_sdec(value); + result += fmt::format("%lld", value); continue; } case 'x': @@ -99,7 +101,7 @@ static std::string ps3_fmt(PPUThread& context, vm::cptr fmt, u32 g_count) result += cf == 'x' ? "0x" : "0X"; } - const std::string& hex = cf == 'x' ? fmt::to_hex(value) : fmt::to_upper(fmt::to_hex(value)); + const std::string& hex = fmt::format(cf == 'x' ? "%llx" : "%llX", value); if (hex.length() >= width) { @@ -132,7 +134,7 @@ static std::string ps3_fmt(PPUThread& context, vm::cptr fmt, u32 g_count) if (plus_sign || minus_sign || space_sign || number_sign || zero_padding || width || prec) break; - result += fmt::to_udec(value); + result += fmt::format("%llu", value); continue; } } @@ -336,7 +338,10 @@ s32 _sys_printf(PPUThread& ppu, vm::cptr fmt, ppu_va_args_t va_args) { sysPrxForUser.warning("_sys_printf(fmt=*0x%x, ...)", fmt); - _log::g_tty_file.log(ps3_fmt(ppu, fmt, va_args.count)); + if (g_tty) + { + g_tty.write(ps3_fmt(ppu, fmt, va_args.count)); + } return CELL_OK; } diff --git a/rpcs3/Emu/Cell/Modules/sys_lwcond_.cpp b/rpcs3/Emu/Cell/Modules/sys_lwcond_.cpp index d3bf78062c..7b4b019a8d 100644 --- a/rpcs3/Emu/Cell/Modules/sys_lwcond_.cpp +++ b/rpcs3/Emu/Cell/Modules/sys_lwcond_.cpp @@ -210,7 +210,7 @@ s32 sys_lwcond_wait(PPUThread& ppu, vm::ptr lwcond, u64 timeout) { sysPrxForUser.trace("sys_lwcond_wait(lwcond=*0x%x, timeout=0x%llx)", lwcond, timeout); - const be_t tid = ppu.id; + const be_t tid(ppu.id); const vm::ptr lwmutex = lwcond->lwmutex; diff --git a/rpcs3/Emu/Cell/Modules/sys_lwmutex_.cpp b/rpcs3/Emu/Cell/Modules/sys_lwmutex_.cpp index 7e2e9fad4c..7cbaab6dba 100644 --- a/rpcs3/Emu/Cell/Modules/sys_lwmutex_.cpp +++ b/rpcs3/Emu/Cell/Modules/sys_lwmutex_.cpp @@ -74,7 +74,7 @@ s32 sys_lwmutex_lock(PPUThread& ppu, vm::ptr lwmutex, u64 timeout { sysPrxForUser.trace("sys_lwmutex_lock(lwmutex=*0x%x, timeout=0x%llx)", lwmutex, timeout); - const be_t tid = ppu.id; + const be_t tid(ppu.id); // try to lock lightweight mutex const be_t old_owner = lwmutex->vars.owner.compare_and_swap(lwmutex_free, tid); @@ -168,7 +168,7 @@ s32 sys_lwmutex_trylock(PPUThread& ppu, vm::ptr lwmutex) { sysPrxForUser.trace("sys_lwmutex_trylock(lwmutex=*0x%x)", lwmutex); - const be_t tid = ppu.id; + const be_t tid(ppu.id); // try to lock lightweight mutex const be_t old_owner = lwmutex->vars.owner.compare_and_swap(lwmutex_free, tid); @@ -235,7 +235,7 @@ s32 sys_lwmutex_unlock(PPUThread& ppu, vm::ptr lwmutex) { sysPrxForUser.trace("sys_lwmutex_unlock(lwmutex=*0x%x)", lwmutex); - const be_t tid = ppu.id; + const be_t tid(ppu.id); // check owner if (lwmutex->vars.owner.load() != tid) diff --git a/rpcs3/Emu/Cell/PPUFunction.cpp b/rpcs3/Emu/Cell/PPUFunction.cpp index dfeaf54b00..dc1612bb68 100644 --- a/rpcs3/Emu/Cell/PPUFunction.cpp +++ b/rpcs3/Emu/Cell/PPUFunction.cpp @@ -2377,3 +2377,23 @@ s32 ppu_error_code::report(s32 error, const char* text) LOG_ERROR(PPU, "Illegal call to ppu_error_code::report(0x%x, '%s')!"); return error; } + +std::vector& ppu_function_manager::access() +{ + static std::vector list + { + nullptr, + [](PPUThread& ppu) { ppu.state += cpu_state::ret; }, + }; + + return list; +} + +u32 ppu_function_manager::add_function(ppu_function_t function) +{ + auto& list = access(); + + list.push_back(function); + + return ::size32(list) - 1; +} diff --git a/rpcs3/Emu/Cell/PPUFunction.h b/rpcs3/Emu/Cell/PPUFunction.h index 184e8bba7b..a6f066a40c 100644 --- a/rpcs3/Emu/Cell/PPUFunction.h +++ b/rpcs3/Emu/Cell/PPUFunction.h @@ -243,25 +243,9 @@ class ppu_function_manager }; // Access global function list - static never_inline auto& access() - { - static std::vector list - { - nullptr, - [](PPUThread& ppu) { ppu.state += cpu_state::ret; }, - }; + static std::vector& access(); - return list; - } - - static never_inline u32 add_function(ppu_function_t function) - { - auto& list = access(); - - list.push_back(function); - - return ::size32(list) - 1; - } + static u32 add_function(ppu_function_t function); public: // Register function (shall only be called during global initialization) diff --git a/rpcs3/Emu/Cell/PPUInterpreter.cpp b/rpcs3/Emu/Cell/PPUInterpreter.cpp index 29aa118d61..b08b558d1b 100644 --- a/rpcs3/Emu/Cell/PPUInterpreter.cpp +++ b/rpcs3/Emu/Cell/PPUInterpreter.cpp @@ -3,6 +3,7 @@ #include "PPUThread.h" #include "PPUInterpreter.h" +// TODO: fix rol8 and rol16 for __GNUG__ (probably with __asm__) inline u8 rol8(const u8 x, const u8 n) { return x << n | x >> (8 - n); } inline u16 rol16(const u16 x, const u16 n) { return x << n | x >> (16 - n); } inline u32 rol32(const u32 x, const u32 n) { return x << n | x >> (32 - n); } @@ -10,16 +11,16 @@ inline u64 rol64(const u64 x, const u64 n) { return x << n | x >> (64 - n); } inline u64 dup32(const u32 x) { return x | static_cast(x) << 32; } #if defined(__GNUG__) -inline std::uint64_t UMULH64(std::uint64_t a, std::uint64_t b) +inline u64 UMULH64(u64 a, u64 b) { - std::uint64_t result; + u64 result; __asm__("mulq %[b]" : "=d" (result) : [a] "a" (a), [b] "rm" (b)); return result; } -inline std::int64_t MULH64(std::int64_t a, std::int64_t b) +inline s64 MULH64(s64 a, s64 b) { - std::int64_t result; + s64 result; __asm__("imulq %[b]" : "=d" (result) : [a] "a" (a), [b] "rm" (b)); return result; } @@ -30,6 +31,95 @@ inline std::int64_t MULH64(std::int64_t a, std::int64_t b) #define MULH64 __mulh #endif +// Compare 16 packed unsigned bytes (greater than) +inline __m128i sse_cmpgt_epu8(__m128i A, __m128i B) +{ + // (A xor 0x80) > (B xor 0x80) + const auto sign = _mm_set1_epi32(0x80808080); + return _mm_cmpgt_epi8(_mm_xor_si128(A, sign), _mm_xor_si128(B, sign)); +} + +inline __m128i sse_cmpgt_epu16(__m128i A, __m128i B) +{ + const auto sign = _mm_set1_epi32(0x80008000); + return _mm_cmpgt_epi16(_mm_xor_si128(A, sign), _mm_xor_si128(B, sign)); +} + +inline __m128i sse_cmpgt_epu32(__m128i A, __m128i B) +{ + const auto sign = _mm_set1_epi32(0x80000000); + return _mm_cmpgt_epi32(_mm_xor_si128(A, sign), _mm_xor_si128(B, sign)); +} + +inline __m128 sse_exp2_ps(__m128 A) +{ + const auto x0 = _mm_max_ps(_mm_min_ps(A, _mm_set1_ps(127.4999961f)), _mm_set1_ps(-127.4999961f)); + const auto x1 = _mm_add_ps(x0, _mm_set1_ps(0.5f)); + const auto x2 = _mm_sub_epi32(_mm_cvtps_epi32(x1), _mm_and_si128(_mm_castps_si128(_mm_cmpnlt_ps(_mm_setzero_ps(), x1)), _mm_set1_epi32(1))); + const auto x3 = _mm_sub_ps(x0, _mm_cvtepi32_ps(x2)); + const auto x4 = _mm_mul_ps(x3, x3); + const auto x5 = _mm_mul_ps(x3, _mm_add_ps(_mm_mul_ps(_mm_add_ps(_mm_mul_ps(x4, _mm_set1_ps(0.023093347705f)), _mm_set1_ps(20.20206567f)), x4), _mm_set1_ps(1513.906801f))); + const auto x6 = _mm_mul_ps(x5, _mm_rcp_ps(_mm_sub_ps(_mm_add_ps(_mm_mul_ps(_mm_set1_ps(233.1842117f), x4), _mm_set1_ps(4368.211667f)), x5))); + return _mm_mul_ps(_mm_add_ps(_mm_add_ps(x6, x6), _mm_set1_ps(1.0f)), _mm_castsi128_ps(_mm_slli_epi32(_mm_add_epi32(x2, _mm_set1_epi32(127)), 23))); +} + +inline __m128 sse_log2_ps(__m128 A) +{ + const auto _1 = _mm_set1_ps(1.0f); + const auto _c = _mm_set1_ps(1.442695040f); + const auto x0 = _mm_max_ps(A, _mm_castsi128_ps(_mm_set1_epi32(0x00800000))); + const auto x1 = _mm_or_ps(_mm_and_ps(x0, _mm_castsi128_ps(_mm_set1_epi32(0x807fffff))), _1); + const auto x2 = _mm_rcp_ps(_mm_add_ps(x1, _1)); + const auto x3 = _mm_mul_ps(_mm_sub_ps(x1, _1), x2); + const auto x4 = _mm_add_ps(x3, x3); + const auto x5 = _mm_mul_ps(x4, x4); + const auto x6 = _mm_add_ps(_mm_mul_ps(_mm_add_ps(_mm_mul_ps(_mm_set1_ps(-0.7895802789f), x5), _mm_set1_ps(16.38666457f)), x5), _mm_set1_ps(-64.1409953f)); + const auto x7 = _mm_rcp_ps(_mm_add_ps(_mm_mul_ps(_mm_add_ps(_mm_mul_ps(_mm_set1_ps(-35.67227983f), x5), _mm_set1_ps(312.0937664f)), x5), _mm_set1_ps(-769.6919436f))); + const auto x8 = _mm_cvtepi32_ps(_mm_sub_epi32(_mm_srli_epi32(_mm_castps_si128(x0), 23), _mm_set1_epi32(127))); + return _mm_add_ps(_mm_mul_ps(_mm_mul_ps(_mm_mul_ps(_mm_mul_ps(x5, x6), x7), x4), _c), _mm_add_ps(_mm_mul_ps(x4, _c), x8)); +} + +template +struct add_flags_result_t +{ + T result; + bool carry; + bool zero; + bool sign; + + add_flags_result_t() = default; + + // Straighforward ADD with flags + add_flags_result_t(T a, T b) + : result(a + b) + , carry(result < a) + , zero(result == 0) + , sign(result >> (sizeof(T) * 8 - 1) != 0) + { + } + + // Straighforward ADC with flags + add_flags_result_t(T a, T b, bool c) + : add_flags_result_t(a, b) + { + add_flags_result_t r(result, c); + result = r.result; + carry |= r.carry; + zero = r.zero; + sign = r.sign; + } +}; + +static add_flags_result_t add64_flags(u64 a, u64 b) +{ + return{ a, b }; +} + +static add_flags_result_t add64_flags(u64 a, u64 b, bool c) +{ + return{ a, b, c }; +} + extern u64 get_timebased_time(); extern void ppu_execute_syscall(PPUThread& ppu, u64 code); extern void ppu_execute_function(PPUThread& ppu, u32 index); diff --git a/rpcs3/Emu/Cell/PPUModule.cpp b/rpcs3/Emu/Cell/PPUModule.cpp index faec008071..56de5d7234 100644 --- a/rpcs3/Emu/Cell/PPUModule.cpp +++ b/rpcs3/Emu/Cell/PPUModule.cpp @@ -80,6 +80,35 @@ ppu_static_module::ppu_static_module(const char* name) ppu_module_manager::register_module(this); } +std::unordered_map& ppu_module_manager::access() +{ + static std::unordered_map map; + + return map; +} + +void ppu_module_manager::register_module(ppu_static_module* module) +{ + access().emplace(module->name, module); +} + +ppu_static_function& ppu_module_manager::access_static_function(const char* module, u32 fnid) +{ + return access().at(module)->functions[fnid]; +} + +ppu_static_variable& ppu_module_manager::access_static_variable(const char* module, u32 vnid) +{ + return access().at(module)->variables[vnid]; +} + +const ppu_static_module* ppu_module_manager::get_module(const std::string& name) +{ + const auto& map = access(); + const auto found = map.find(name); + return found != map.end() ? found->second : nullptr; +} + // Initialize static modules. static void ppu_initialize_modules() { diff --git a/rpcs3/Emu/Cell/PPUModule.h b/rpcs3/Emu/Cell/PPUModule.h index 81d4dadfcf..5b1438968f 100644 --- a/rpcs3/Emu/Cell/PPUModule.h +++ b/rpcs3/Emu/Cell/PPUModule.h @@ -68,35 +68,16 @@ class ppu_module_manager final { friend class ppu_static_module; - static never_inline auto& access() - { - static std::unordered_map map; + static std::unordered_map& access(); - return map; - } + static void register_module(ppu_static_module* module); - static never_inline void register_module(ppu_static_module* module) - { - access().emplace(module->name, module); - } + static ppu_static_function& access_static_function(const char* module, u32 fnid); - static never_inline auto& access_static_function(const char* module, u32 fnid) - { - return access().at(module)->functions[fnid]; - } - - static never_inline auto& access_static_variable(const char* module, u32 vnid) - { - return access().at(module)->variables[vnid]; - } + static ppu_static_variable& access_static_variable(const char* module, u32 vnid); public: - static never_inline const ppu_static_module* get_module(const std::string& name) - { - const auto& map = access(); - const auto found = map.find(name); - return found != map.end() ? found->second : nullptr; - } + static const ppu_static_module* get_module(const std::string& name); template static void register_static_function(const char* module, const char* name, ppu_function_t func, u32 fnid, u32 flags) diff --git a/rpcs3/Emu/Cell/PPUThread.cpp b/rpcs3/Emu/Cell/PPUThread.cpp index 2e287190aa..c3ddecefce 100644 --- a/rpcs3/Emu/Cell/PPUThread.cpp +++ b/rpcs3/Emu/Cell/PPUThread.cpp @@ -76,6 +76,8 @@ void PPUThread::cpu_init() GPR[1] = align(stack_addr + stack_size, 0x200) - 0x200; } +extern thread_local std::string(*g_tls_log_prefix)(); + void PPUThread::cpu_task() { //SetHostRoundingMode(FPSCR_RN_NEAR); @@ -87,7 +89,7 @@ void PPUThread::cpu_task() return custom_task(*this); } - _log::g_tls_make_prefix = [](const auto&, auto, const auto&) + g_tls_log_prefix = [] { const auto cpu = static_cast(get_current_cpu_thread()); diff --git a/rpcs3/Emu/Cell/SPUASMJITRecompiler.cpp b/rpcs3/Emu/Cell/SPUASMJITRecompiler.cpp index a20f92c4b0..8ac7256513 100644 --- a/rpcs3/Emu/Cell/SPUASMJITRecompiler.cpp +++ b/rpcs3/Emu/Cell/SPUASMJITRecompiler.cpp @@ -2184,7 +2184,7 @@ void spu_recompiler::BR(spu_opcode_t op) c->mov(*addr, target | 0x2000000); //c->cmp(asmjit::host::dword_ptr(*ls, m_pos), 0x32); // compare instruction opcode with BR-to-self //c->je(labels[target / 4]); - c->lock().or_(SPU_OFF_32(state), (to_mset(cpu_state::stop) + cpu_state::ret)._value()); + c->lock().or_(SPU_OFF_32(state), make_bitset(cpu_state::stop, cpu_state::ret)._value()); c->jmp(*end); c->unuse(*addr); return; diff --git a/rpcs3/Emu/Cell/SPUInterpreter.cpp b/rpcs3/Emu/Cell/SPUInterpreter.cpp index 22d1b13eb2..217f35728c 100644 --- a/rpcs3/Emu/Cell/SPUInterpreter.cpp +++ b/rpcs3/Emu/Cell/SPUInterpreter.cpp @@ -7,6 +7,26 @@ #include +// Compare 16 packed unsigned bytes (greater than) +inline __m128i sse_cmpgt_epu8(__m128i A, __m128i B) +{ + // (A xor 0x80) > (B xor 0x80) + const auto sign = _mm_set1_epi32(0x80808080); + return _mm_cmpgt_epi8(_mm_xor_si128(A, sign), _mm_xor_si128(B, sign)); +} + +inline __m128i sse_cmpgt_epu16(__m128i A, __m128i B) +{ + const auto sign = _mm_set1_epi32(0x80008000); + return _mm_cmpgt_epi16(_mm_xor_si128(A, sign), _mm_xor_si128(B, sign)); +} + +inline __m128i sse_cmpgt_epu32(__m128i A, __m128i B) +{ + const auto sign = _mm_set1_epi32(0x80000000); + return _mm_cmpgt_epi32(_mm_xor_si128(A, sign), _mm_xor_si128(B, sign)); +} + void spu_interpreter::UNK(SPUThread& spu, spu_opcode_t op) { throw EXCEPTION("Unknown/Illegal instruction (0x%08x)", op.opcode); diff --git a/rpcs3/Emu/Cell/SPUThread.cpp b/rpcs3/Emu/Cell/SPUThread.cpp index 2325e22dfd..9ec1cd4643 100644 --- a/rpcs3/Emu/Cell/SPUThread.cpp +++ b/rpcs3/Emu/Cell/SPUThread.cpp @@ -116,6 +116,8 @@ void SPUThread::cpu_init() gpr[1]._u32[3] = 0x3FFF0; // initial stack frame pointer } +extern thread_local std::string(*g_tls_log_prefix)(); + void SPUThread::cpu_task() { std::fesetround(FE_TOWARDZERO); @@ -127,7 +129,7 @@ void SPUThread::cpu_task() return custom_task(*this); } - _log::g_tls_make_prefix = [](const auto&, auto, const auto&) + g_tls_log_prefix = [] { const auto cpu = static_cast(get_current_cpu_thread()); diff --git a/rpcs3/Emu/Cell/lv2/sys_event.h b/rpcs3/Emu/Cell/lv2/sys_event.h index e1c088870c..ba9d22b038 100644 --- a/rpcs3/Emu/Cell/lv2/sys_event.h +++ b/rpcs3/Emu/Cell/lv2/sys_event.h @@ -84,7 +84,8 @@ public: const u64 name; const u64 ipc_key; const s32 size; - const u32 id{}; + + const id_value<> id{}; lv2_event_queue_t(u32 protocol, s32 type, u64 name, u64 ipc_key, s32 size) : protocol(protocol) diff --git a/rpcs3/Emu/Cell/lv2/sys_fs.cpp b/rpcs3/Emu/Cell/lv2/sys_fs.cpp index f9dc481f4b..a2e2899cb6 100644 --- a/rpcs3/Emu/Cell/lv2/sys_fs.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_fs.cpp @@ -7,6 +7,9 @@ #include "Emu/Cell/ErrorCodes.h" #include "sys_fs.h" +#include "Utilities/StrUtil.h" +#include + LOG_CHANNEL(sys_fs); s32 sys_fs_test(u32 arg1, u32 arg2, vm::ptr arg3, u32 arg4, vm::ptr arg5, u32 arg6) @@ -42,7 +45,7 @@ s32 sys_fs_open(vm::cptr path, s32 flags, vm::ptr fd, s32 mode, vm::c return CELL_FS_EISDIR; } - mset open_mode{}; + bitset_t open_mode{}; switch (flags & CELL_FS_O_ACCMODE) { @@ -349,7 +352,7 @@ s32 sys_fs_rmdir(vm::cptr path) if (!fs::remove_dir(vfs::get(path.get_ptr()))) { - switch (auto error = errno) + switch (auto error = fs::error) { case ENOENT: return CELL_FS_ENOENT; default: sys_fs.error("sys_fs_rmdir(): unknown error %d", error); @@ -369,7 +372,7 @@ s32 sys_fs_unlink(vm::cptr path) if (!fs::remove_file(vfs::get(path.get_ptr()))) { - switch (auto error = errno) + switch (auto error = fs::error) { case ENOENT: return CELL_FS_ENOENT; default: sys_fs.error("sys_fs_unlink(): unknown error %d", error); @@ -448,7 +451,7 @@ s32 sys_fs_truncate(vm::cptr path, u64 size) if (!fs::truncate_file(vfs::get(path.get_ptr()), size)) { - switch (auto error = errno) + switch (auto error = fs::error) { case ENOENT: return CELL_FS_ENOENT; default: sys_fs.error("sys_fs_truncate(): unknown error %d", error); @@ -475,7 +478,7 @@ s32 sys_fs_ftruncate(u32 fd, u64 size) if (!file->file.trunc(size)) { - switch (auto error = errno) + switch (auto error = fs::error) { case 0: default: sys_fs.error("sys_fs_ftruncate(): unknown error %d", error); diff --git a/rpcs3/Emu/Cell/lv2/sys_fs.h b/rpcs3/Emu/Cell/lv2/sys_fs.h index e943697325..fd63e6df52 100644 --- a/rpcs3/Emu/Cell/lv2/sys_fs.h +++ b/rpcs3/Emu/Cell/lv2/sys_fs.h @@ -173,7 +173,7 @@ struct lv2_fs_object_t static constexpr u32 id_min = 3; static constexpr u32 id_max = 255; - const u32 id{}; + const id_value<> id{}; }; struct lv2_file_t : lv2_fs_object_t diff --git a/rpcs3/Emu/Cell/lv2/sys_interrupt.h b/rpcs3/Emu/Cell/lv2/sys_interrupt.h index 558aede372..b440852af0 100644 --- a/rpcs3/Emu/Cell/lv2/sys_interrupt.h +++ b/rpcs3/Emu/Cell/lv2/sys_interrupt.h @@ -6,7 +6,7 @@ class PPUThread; struct lv2_int_tag_t { - const u32 id{}; + const id_value<> id{}; std::shared_ptr handler; }; @@ -14,7 +14,8 @@ struct lv2_int_tag_t struct lv2_int_serv_t { const std::shared_ptr thread; - const u32 id{}; + + const id_value<> id{}; atomic_t signal{ 0 }; // signal count diff --git a/rpcs3/Emu/Cell/lv2/sys_memory.h b/rpcs3/Emu/Cell/lv2/sys_memory.h index e99580083d..bf9e425430 100644 --- a/rpcs3/Emu/Cell/lv2/sys_memory.h +++ b/rpcs3/Emu/Cell/lv2/sys_memory.h @@ -46,13 +46,15 @@ struct sys_page_attr_t struct lv2_memory_container_t { - const u32 size; // amount of "physical" memory in this container - const u32 id{}; + // Amount of "physical" memory in this container + const u32 size; - // amount of memory allocated + const id_value<> id{}; + + // Amount of memory allocated atomic_t used{ 0 }; - // allocations (addr -> size) + // Allocations (addr -> size) std::map allocs; lv2_memory_container_t(u32 size) diff --git a/rpcs3/Emu/Cell/lv2/sys_mmapper.h b/rpcs3/Emu/Cell/lv2/sys_mmapper.h index e8d9d9a265..0ecaf08d47 100644 --- a/rpcs3/Emu/Cell/lv2/sys_mmapper.h +++ b/rpcs3/Emu/Cell/lv2/sys_mmapper.h @@ -8,7 +8,8 @@ struct lv2_memory_t const u32 align; // required alignment const u64 flags; const std::shared_ptr ct; // memory container the physical memory is taken from - const u32 id{}; + + const id_value<> id{}; atomic_t addr{ 0 }; // actual mapping address diff --git a/rpcs3/Emu/Cell/lv2/sys_prx.h b/rpcs3/Emu/Cell/lv2/sys_prx.h index 4d513b03b3..7893e7918a 100644 --- a/rpcs3/Emu/Cell/lv2/sys_prx.h +++ b/rpcs3/Emu/Cell/lv2/sys_prx.h @@ -74,7 +74,7 @@ struct sys_prx_get_module_list_t struct lv2_prx_t { - const u32 id{}; + const id_value<> id{}; bool is_started = false; diff --git a/rpcs3/Emu/Cell/lv2/sys_timer.h b/rpcs3/Emu/Cell/lv2/sys_timer.h index 185d5f56fe..a156423630 100644 --- a/rpcs3/Emu/Cell/lv2/sys_timer.h +++ b/rpcs3/Emu/Cell/lv2/sys_timer.h @@ -28,7 +28,7 @@ public: void on_stop() override; - const u32 id{}; // Timer id + const id_value<> id{}; atomic_t state{ SYS_TIMER_STATE_RUN }; // Timer state diff --git a/rpcs3/Emu/Cell/lv2/sys_tty.cpp b/rpcs3/Emu/Cell/lv2/sys_tty.cpp index bdbe5fa49f..c91ded14f4 100644 --- a/rpcs3/Emu/Cell/lv2/sys_tty.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_tty.cpp @@ -8,6 +8,8 @@ LOG_CHANNEL(sys_tty); +extern fs::file g_tty; + s32 sys_tty_read(s32 ch, vm::ptr buf, u32 len, vm::ptr preadlen) { sys_tty.todo("sys_tty_read(ch=%d, buf=*0x%x, len=%d, preadlen=*0x%x)", ch, buf, len, preadlen); @@ -34,7 +36,10 @@ s32 sys_tty_write(s32 ch, vm::cptr buf, u32 len, vm::ptr pwritelen) return CELL_OK; } - _log::g_tty_file.log({ buf.get_ptr(), len }); + if (g_tty) + { + g_tty.write(buf.get_ptr(), len); + } *pwritelen = len; diff --git a/rpcs3/Emu/IdManager.cpp b/rpcs3/Emu/IdManager.cpp new file mode 100644 index 0000000000..32ab768c16 --- /dev/null +++ b/rpcs3/Emu/IdManager.cpp @@ -0,0 +1,119 @@ +#include "stdafx.h" +#include "IdManager.h" + +std::vector& id_manager::typeinfo::access() +{ + static std::vector list; + + return list; +} + +u32 id_manager::typeinfo::add_type(typeinfo info) +{ + auto& list = access(); + + list.emplace_back(info); + + return ::size32(list) - 1; +} + +idm::map_type::pointer idm::allocate_id(u32 tag, u32 min, u32 max) +{ + // Check all IDs starting from "next id" + for (u32 i = 0; i <= max - min; i++) + { + // Fix current ID (wrap around) + if (g_id[tag] < min || g_id[tag] > max) g_id[tag] = min; + + // Get ID + const auto r = g_map[tag].emplace(g_id[tag]++, nullptr); + + if (r.second) + { + return &*r.first; + } + } + + // Nothing found + return nullptr; +} + +std::shared_ptr idm::deallocate_id(u32 tag, u32 id) +{ + const auto found = g_map[tag].find(id); + + if (found == g_map[tag].end()) return nullptr; + + auto ptr = std::move(found->second); + + g_map[tag].erase(found); + + return ptr; +} + +idm::map_type::pointer idm::find_id(u32 type, u32 id) +{ + const auto found = g_map[type].find(id); + + if (found == g_map[type].end()) return nullptr; + + return &*found; +} + +std::shared_ptr idm::delete_id(u32 type, u32 tag, u32 id) +{ + writer_lock lock(g_mutex); + + auto&& ptr = deallocate_id(tag, id); + + g_map[type].erase(id); + + return ptr; +} + +void idm::init() +{ + g_map.resize(id_manager::typeinfo::get().size(), {}); + g_id.resize(id_manager::typeinfo::get().size(), 0); +} + +void idm::clear() +{ + // Call recorded finalization functions for all IDs + for (std::size_t i = 0; i < g_map.size(); i++) + { + for (auto& id : g_map[i]) + { + id_manager::typeinfo::get()[i].on_stop(id.second.get()); + } + + g_map[i].clear(); + g_id[i] = 0; + } +} + +std::shared_ptr fxm::remove(u32 type) +{ + writer_lock lock(g_mutex); + + return std::move(g_map[type]); +} + +void fxm::init() +{ + g_map.resize(id_manager::typeinfo::get().size(), {}); +} + +void fxm::clear() +{ + // Call recorded finalization functions for all IDs + for (std::size_t i = 0; i < g_map.size(); i++) + { + if (g_map[i]) + { + id_manager::typeinfo::get()[i].on_stop(g_map[i].get()); + } + + g_map[i].reset(); + } +} diff --git a/rpcs3/Emu/IdManager.h b/rpcs3/Emu/IdManager.h index 01b8843bac..84d4f8bccf 100644 --- a/rpcs3/Emu/IdManager.h +++ b/rpcs3/Emu/IdManager.h @@ -1,7 +1,13 @@ #pragma once +#include "Utilities/types.h" +#include "Utilities/Macro.h" +#include "Utilities/Platform.h" #include "Utilities/SharedMutex.h" +#include +#include +#include #include #include @@ -27,25 +33,6 @@ namespace id_manager static constexpr u32 max = T::id_max; }; - // Optional ID storage - template - struct id_storage - { - static const u32* get(T*) - { - return nullptr; - } - }; - - template - struct id_storage> - { - static const u32* get(T* ptr) - { - return &ptr->id; - } - }; - // Optional object initialization function (called after ID registration) template struct on_init @@ -82,7 +69,6 @@ namespace id_manager } }; - template class typeinfo { // Global variable for each registered type @@ -93,24 +79,12 @@ namespace id_manager }; // Access global type list - static never_inline auto& access() - { - static std::vector list; + static std::vector& access(); - return list; - } - - static never_inline u32 add_type(typeinfo info) - { - auto& list = access(); - - list.emplace_back(info); - - return ::size32(list) - 1; - } + // Add to the global list + static u32 add_type(typeinfo info); public: - const std::type_info* info; void(*on_init)(void*); void(*on_stop)(void*); @@ -131,10 +105,9 @@ namespace id_manager } }; - template template - const u32 typeinfo::registered::index = typeinfo::add_type( + template + const u32 typeinfo::registered::index = typeinfo::add_type( { - &typeid(T), PURE_EXPR(id_manager::on_init::func(static_cast(ptr)), void* ptr), PURE_EXPR(id_manager::on_stop::func(static_cast(ptr)), void* ptr), }); @@ -160,23 +133,18 @@ class idm using map_type = std::unordered_map, id_hash_t>; + static shared_mutex g_mutex; + // Type Index -> ID -> Object. Use global since only one process is supported atm. static std::vector g_map; // Next ID for each category static std::vector g_id; - static shared_mutex g_mutex; - - static const auto& get_types() - { - return id_manager::typeinfo::get(); - } - template static inline u32 get_type() { - return id_manager::typeinfo::get_index(); + return id_manager::typeinfo::get_index(); } template @@ -185,44 +153,25 @@ class idm return get_type::tag>(); } - // Prepares new ID, returns nullptr if out of resources - static map_type::pointer allocate_id(u32 tag, u32 min, u32 max) + // Update optional ID storage + template + static auto set_id_value(T* ptr, u32 id) -> decltype(static_cast(std::declval().id)) { - // Check all IDs starting from "next id" - for (u32 i = 0; i <= max - min; i++) - { - // Fix current ID (wrap around) - if (g_id[tag] < min || g_id[tag] > max) g_id[tag] = min; - - // Get ID - const auto r = g_map[tag].emplace(g_id[tag]++, nullptr); - - if (r.second) - { - return &*r.first; - } - } - - // Nothing found - return nullptr; + ptr->id = id; } + static void set_id_value(...) + { + } + + // Prepares new ID, returns nullptr if out of resources + static map_type::pointer allocate_id(u32 tag, u32 min, u32 max); + // Deallocate ID, returns object - static std::shared_ptr deallocate_id(u32 tag, u32 id) - { - const auto found = g_map[tag].find(id); - - if (found == g_map[tag].end()) return nullptr; - - auto ptr = std::move(found->second); - - g_map[tag].erase(found); - - return ptr; - } + static std::shared_ptr deallocate_id(u32 tag, u32 id); // Allocate new ID and construct it from the provider() - template> + template static map_type::pointer create_id(F&& provider) { writer_lock lock(g_mutex); @@ -231,14 +180,11 @@ class idm { try { - // Get object, write it + // Get object, store it place->second = provider(); - // Update ID storage if available - if (const u32* id = id_manager::id_storage::get(static_cast(place->second.get()))) - { - *const_cast(id) = place->first; - } + // Update ID value if required + set_id_value(static_cast(place->second.get()), place->first); return &*g_map[get_type()].emplace(*place).first; } @@ -252,41 +198,18 @@ class idm return nullptr; } + // Get ID (internal) + static map_type::pointer find_id(u32 type, u32 id); + // Remove ID and return object - static std::shared_ptr delete_id(u32 type, u32 tag, u32 id) - { - writer_lock lock(g_mutex); - - auto&& ptr = deallocate_id(tag, id); - - g_map[type].erase(id); - - return ptr; - } + static std::shared_ptr delete_id(u32 type, u32 tag, u32 id); public: // Initialize object manager - static void init() - { - g_map.resize(get_types().size(), {}); - g_id.resize(get_types().size(), 0); - } + static void init(); // Remove all objects - static void clear() - { - // Call recorded finalization functions for all IDs - for (std::size_t i = 0; i < g_map.size(); i++) - { - for (auto& id : g_map[i]) - { - get_types()[i].on_stop(id.second.get()); - } - - g_map[i].clear(); - g_id[i] = 0; - } - } + static void clear(); // Add a new ID of specified type with specified constructor arguments (returns object or nullptr) template @@ -346,7 +269,7 @@ public: { reader_lock lock(g_mutex); - return g_map[get_type()].count(id) != 0; + return find_id(get_type(), id) != nullptr; } // Get ID @@ -355,9 +278,9 @@ public: { reader_lock lock(g_mutex); - const auto found = g_map[get_type()].find(id); + const auto found = find_id(get_type(), id); - if (found == g_map[get_type()].end()) + if (UNLIKELY(found == nullptr)) { return nullptr; } @@ -387,7 +310,7 @@ public: { auto&& ptr = delete_id(get_type(), get_tag(), id); - if (ptr) + if (LIKELY(ptr)) { id_manager::on_stop::func(static_cast(ptr.get())); } @@ -401,7 +324,7 @@ public: { auto&& ptr = delete_id(get_type(), get_tag(), id); - if (ptr) + if (LIKELY(ptr)) { id_manager::on_stop::func(static_cast(ptr.get())); } @@ -458,45 +381,20 @@ class fxm static shared_mutex g_mutex; - static inline const auto& get_types() - { - return id_manager::typeinfo::get(); - } - template static inline u32 get_type() { - return id_manager::typeinfo::get_index(); + return id_manager::typeinfo::get_index(); } - static std::shared_ptr remove(u32 type) - { - writer_lock lock(g_mutex); - - return std::move(g_map[type]); - } + static std::shared_ptr remove(u32 type); public: // Initialize object manager - static void init() - { - g_map.resize(get_types().size(), {}); - } + static void init(); // Remove all objects - static void clear() - { - // Call recorded finalization functions for all IDs - for (std::size_t i = 0; i < g_map.size(); i++) - { - if (g_map[i]) - { - get_types()[i].on_stop(g_map[i].get()); - } - - g_map[i].reset(); - } - } + static void clear(); // Create the object (returns nullptr if it already exists) template diff --git a/rpcs3/Emu/RSX/Common/ShaderParam.h b/rpcs3/Emu/RSX/Common/ShaderParam.h index c542ac8141..747f45bdcf 100644 --- a/rpcs3/Emu/RSX/Common/ShaderParam.h +++ b/rpcs3/Emu/RSX/Common/ShaderParam.h @@ -1,7 +1,10 @@ #pragma once + #include #include +#include "Utilities/StrUtil.h" + enum class FUNCTION { FUNCTION_DP2, FUNCTION_DP2A, @@ -220,4 +223,4 @@ public: return name + "." + fmt::merge({ swizzles }, "."); } -}; \ No newline at end of file +}; diff --git a/rpcs3/Emu/RSX/GL/GLGSRender.cpp b/rpcs3/Emu/RSX/GL/GLGSRender.cpp index e712e1447c..eea02008a4 100644 --- a/rpcs3/Emu/RSX/GL/GLGSRender.cpp +++ b/rpcs3/Emu/RSX/GL/GLGSRender.cpp @@ -680,7 +680,7 @@ void GLGSRender::flip(int buffer) coordi aspect_ratio; if (1) //enable aspect ratio { - sizei csize = m_frame->client_size(); + sizei csize(m_frame->client_width(), m_frame->client_height()); sizei new_size = csize; const double aq = (double)buffer_width / buffer_height; @@ -702,7 +702,7 @@ void GLGSRender::flip(int buffer) } else { - aspect_ratio.size = m_frame->client_size(); + aspect_ratio.size = { m_frame->client_width(), m_frame->client_height() }; } gl::screen.clear(gl::buffers::color_depth_stencil); diff --git a/rpcs3/Emu/RSX/GL/gl_helpers.h b/rpcs3/Emu/RSX/GL/gl_helpers.h index 7ec6d54f49..18e337b352 100644 --- a/rpcs3/Emu/RSX/GL/gl_helpers.h +++ b/rpcs3/Emu/RSX/GL/gl_helpers.h @@ -10,6 +10,8 @@ #include "OpenGL.h" #include "../GCM.h" +#include "Utilities/geometry.h" + namespace gl { #ifdef _DEBUG diff --git a/rpcs3/Emu/RSX/GSRender.cpp b/rpcs3/Emu/RSX/GSRender.cpp index f02f51d680..1b4a6a97f8 100644 --- a/rpcs3/Emu/RSX/GSRender.cpp +++ b/rpcs3/Emu/RSX/GSRender.cpp @@ -7,7 +7,7 @@ // temporarily (u8 value is really CellVideoOutResolutionId, but HLE declarations shouldn't be available for the rest of emu, even indirectly) extern cfg::map_entry g_cfg_video_out_resolution; -extern const std::unordered_map g_video_out_resolution_map; +extern const std::unordered_map> g_video_out_resolution_map; draw_context_t GSFrameBase::new_context() { @@ -20,8 +20,9 @@ draw_context_t GSFrameBase::new_context() } GSRender::GSRender(frame_type type) - : m_frame(Emu.GetCallbacks().get_gs_frame(type, g_video_out_resolution_map.at(g_cfg_video_out_resolution.get())).release()) { + const auto size = g_video_out_resolution_map.at(g_cfg_video_out_resolution.get()); + m_frame = Emu.GetCallbacks().get_gs_frame(type, size.first, size.second).release(); } GSRender::~GSRender() diff --git a/rpcs3/Emu/RSX/GSRender.h b/rpcs3/Emu/RSX/GSRender.h index 6743d6391a..166641c369 100644 --- a/rpcs3/Emu/RSX/GSRender.h +++ b/rpcs3/Emu/RSX/GSRender.h @@ -37,7 +37,8 @@ public: virtual void set_current(draw_context_t ctx) = 0; virtual void flip(draw_context_t ctx) = 0; - virtual size2i client_size() = 0; + virtual int client_width() = 0; + virtual int client_height() = 0; virtual void* handle() const = 0; diff --git a/rpcs3/Emu/RSX/RSXThread.cpp b/rpcs3/Emu/RSX/RSXThread.cpp index c610b57c7d..370befbbc2 100644 --- a/rpcs3/Emu/RSX/RSXThread.cpp +++ b/rpcs3/Emu/RSX/RSXThread.cpp @@ -10,6 +10,7 @@ #include "rsx_methods.h" #include "Utilities/GSL.h" +#include "Utilities/StrUtil.h" #define CMD_DEBUG 0 diff --git a/rpcs3/Emu/RSX/RSXThread.h b/rpcs3/Emu/RSX/RSXThread.h index 1b481edd85..4f84b5a716 100644 --- a/rpcs3/Emu/RSX/RSXThread.h +++ b/rpcs3/Emu/RSX/RSXThread.h @@ -8,9 +8,9 @@ #include "RSXVertexProgram.h" #include "RSXFragmentProgram.h" -#include "Utilities/Semaphore.h" #include "Utilities/Thread.h" #include "Utilities/Timer.h" +#include "Utilities/geometry.h" extern u64 get_system_time(); @@ -54,7 +54,7 @@ namespace rsx template<> struct bijective { - static constexpr std::pair map[] + static constexpr bijective_pair map[] { { rsx::shader_language::glsl, "glsl" }, { rsx::shader_language::hlsl, "hlsl" }, @@ -281,7 +281,6 @@ namespace rsx double fps_limit = 59.94; public: - semaphore_t sem_flip; u64 last_flip_time; vm::ps3::ptr flip_handler = vm::null; vm::ps3::ptr user_handler = vm::null; diff --git a/rpcs3/Emu/RSX/VK/VKGSRender.cpp b/rpcs3/Emu/RSX/VK/VKGSRender.cpp index dfdf299ec5..0ea6ddb38f 100644 --- a/rpcs3/Emu/RSX/VK/VKGSRender.cpp +++ b/rpcs3/Emu/RSX/VK/VKGSRender.cpp @@ -376,7 +376,7 @@ VKGSRender::VKGSRender() : GSRender(frame_type::Vulkan) vk::set_current_thread_ctx(m_thread_context); vk::set_current_renderer(m_swap_chain->get_device()); - m_swap_chain->init_swapchain(m_frame->client_size().width, m_frame->client_size().height); + m_swap_chain->init_swapchain(m_frame->client_width(), m_frame->client_height()); //create command buffer... m_command_buffer_pool.create((*m_device)); @@ -582,8 +582,8 @@ void VKGSRender::end() rp_begin.framebuffer = m_framebuffer_to_clean.back()->value; rp_begin.renderArea.offset.x = 0; rp_begin.renderArea.offset.y = 0; - rp_begin.renderArea.extent.width = m_frame->client_size().width; - rp_begin.renderArea.extent.height = m_frame->client_size().height; + rp_begin.renderArea.extent.width = m_frame->client_width(); + rp_begin.renderArea.extent.height = m_frame->client_height(); vkCmdBeginRenderPass(m_command_buffer, &rp_begin, VK_SUBPASS_CONTENTS_INLINE); @@ -1106,7 +1106,7 @@ void VKGSRender::flip(int buffer) coordi aspect_ratio; if (1) //enable aspect ratio { - sizei csize = m_frame->client_size(); + sizei csize = { m_frame->client_width(), m_frame->client_height() }; sizei new_size = csize; const double aq = (double)buffer_width / buffer_height; @@ -1128,7 +1128,7 @@ void VKGSRender::flip(int buffer) } else { - aspect_ratio.size = m_frame->client_size(); + aspect_ratio.size = { m_frame->client_width(), m_frame->client_height() }; } VkSwapchainKHR swap_chain = (VkSwapchainKHR)(*m_swap_chain); diff --git a/rpcs3/Emu/RSX/rsx_methods.cpp b/rpcs3/Emu/RSX/rsx_methods.cpp index dee9342949..968589bc75 100644 --- a/rpcs3/Emu/RSX/rsx_methods.cpp +++ b/rpcs3/Emu/RSX/rsx_methods.cpp @@ -674,8 +674,6 @@ namespace rsx }); } - rsx->sem_flip.post_and_wait(); - if (double limit = g_cfg_rsx_frame_limit.get()) { if (limit < 0) limit = rsx->fps_limit; // TODO diff --git a/rpcs3/Emu/System.cpp b/rpcs3/Emu/System.cpp index 710bb82596..e49240a652 100644 --- a/rpcs3/Emu/System.cpp +++ b/rpcs3/Emu/System.cpp @@ -17,6 +17,8 @@ #include "Loader/PSF.h" #include "Loader/ELF.h" +#include "Utilities/StrUtil.h" + #include "../Crypto/unself.h" cfg::bool_entry g_cfg_autostart(cfg::root.misc, "Always start after boot"); @@ -31,6 +33,8 @@ extern atomic_t g_thread_count; extern u64 get_system_time(); +fs::file g_tty; + namespace rpcs3 { event& on_run() { static event on_run; return on_run; } @@ -48,6 +52,11 @@ Emulator::Emulator() void Emulator::Init() { + if (!g_tty) + { + g_tty.open(fs::get_config_dir() + "TTY.log", fs::rewrite + fs::append); + } + idm::init(); fxm::init(); @@ -424,7 +433,7 @@ DECLARE(fxm::g_map); DECLARE(fxm::g_mutex); #ifndef _MSC_VER -constexpr std::pair bijective::map[]; -constexpr std::pair<_log::level, const char*> bijective<_log::level, const char*>::map[]; -constexpr std::pair bijective::map[]; +constexpr DECLARE(bijective::map); +constexpr DECLARE(bijective<_log::level, const char*>::map); +constexpr DECLARE(bijective::map); #endif diff --git a/rpcs3/Emu/System.h b/rpcs3/Emu/System.h index 5a655b4c36..48fbb8f44a 100644 --- a/rpcs3/Emu/System.h +++ b/rpcs3/Emu/System.h @@ -14,7 +14,7 @@ struct EmuCallbacks std::function()> get_kb_handler; std::function()> get_mouse_handler; std::function()> get_pad_handler; - std::function(frame_type, size2i)> get_gs_frame; + std::function(frame_type, int, int)> get_gs_frame; std::function()> get_gs_render; std::function()> get_audio; std::function()> get_msg_dialog; diff --git a/rpcs3/Emu/VFS.cpp b/rpcs3/Emu/VFS.cpp index a278da8e45..32e54511ed 100644 --- a/rpcs3/Emu/VFS.cpp +++ b/rpcs3/Emu/VFS.cpp @@ -4,6 +4,8 @@ #include "VFS.h" +#include "Utilities/StrUtil.h" + cfg::string_entry g_cfg_vfs_emulator_dir(cfg::root.vfs, "$(EmulatorDir)"); // Default (empty): taken from fs::get_executable_dir() cfg::string_entry g_cfg_vfs_dev_hdd0(cfg::root.vfs, "/dev_hdd0/", "$(EmulatorDir)dev_hdd0/"); cfg::string_entry g_cfg_vfs_dev_hdd1(cfg::root.vfs, "/dev_hdd1/", "$(EmulatorDir)dev_hdd1/"); diff --git a/rpcs3/Gui/ConLogFrame.cpp b/rpcs3/Gui/ConLogFrame.cpp index 55535b0758..c8296bf0b1 100644 --- a/rpcs3/Gui/ConLogFrame.cpp +++ b/rpcs3/Gui/ConLogFrame.cpp @@ -169,7 +169,7 @@ void LogFrame::OnTimer(wxTimerEvent& event) const auto start = std::chrono::high_resolution_clock::now(); // Check TTY logs - while (const u64 size = std::min(sizeof(buf), _log::g_tty_file.size() - m_tty_file.pos())) + while (const u64 size = std::min(sizeof(buf), m_tty_file.size() - m_tty_file.pos())) { const wxString& text = get_utf8(m_tty_file, size); diff --git a/rpcs3/Gui/GLGSFrame.cpp b/rpcs3/Gui/GLGSFrame.cpp index f0e09833f6..d2de2936d0 100644 --- a/rpcs3/Gui/GLGSFrame.cpp +++ b/rpcs3/Gui/GLGSFrame.cpp @@ -7,8 +7,8 @@ extern cfg::bool_entry g_cfg_rsx_debug_output; -GLGSFrame::GLGSFrame(size2i size) - : GSFrame("OpenGL", size) +GLGSFrame::GLGSFrame(int w, int h) + : GSFrame("OpenGL", w, h) { const int context_attrs[] = { @@ -26,7 +26,7 @@ GLGSFrame::GLGSFrame(size2i size) 0 }; - m_canvas = new wxGLCanvas(this, wxID_ANY, context_attrs, wxDefaultPosition, { size.width, size.height }); + m_canvas = new wxGLCanvas(this, wxID_ANY, context_attrs, wxDefaultPosition, { w, h }); m_canvas->Bind(wxEVT_LEFT_DCLICK, &GSFrame::OnLeftDclick, this); } diff --git a/rpcs3/Gui/GLGSFrame.h b/rpcs3/Gui/GLGSFrame.h index 09d5720426..a9ab969951 100644 --- a/rpcs3/Gui/GLGSFrame.h +++ b/rpcs3/Gui/GLGSFrame.h @@ -8,7 +8,7 @@ class GLGSFrame : public GSFrame wxGLCanvas* m_canvas; public: - GLGSFrame(size2i); + GLGSFrame(int w, int h); void* make_context() override; void set_current(draw_context_t context) override; diff --git a/rpcs3/Gui/GSFrame.cpp b/rpcs3/Gui/GSFrame.cpp index 41a0554f77..81aa2e5686 100644 --- a/rpcs3/Gui/GSFrame.cpp +++ b/rpcs3/Gui/GSFrame.cpp @@ -12,12 +12,12 @@ BEGIN_EVENT_TABLE(GSFrame, wxFrame) EVT_SIZE(GSFrame::OnSize) END_EVENT_TABLE() -GSFrame::GSFrame(const wxString& title, size2i size) +GSFrame::GSFrame(const wxString& title, int w, int h) : wxFrame(nullptr, wxID_ANY, "GSFrame[" + title + "]") { SetIcon(wxGetApp().m_MainFrame->GetIcon()); - SetClientSize(size.width, size.height); + SetClientSize(w, h); wxGetApp().Bind(wxEVT_KEY_DOWN, &GSFrame::OnKeyDown, this); Bind(wxEVT_CLOSE_WINDOW, &GSFrame::OnClose, this); Bind(wxEVT_LEFT_DCLICK, &GSFrame::OnLeftDclick, this); @@ -86,10 +86,14 @@ void GSFrame::delete_context(void* ctx) { } -size2i GSFrame::client_size() +int GSFrame::client_width() { - wxSize size = GetClientSize(); - return{ size.GetWidth(), size.GetHeight() }; + return GetClientSize().GetWidth(); +} + +int GSFrame::client_height() +{ + return GetClientSize().GetHeight(); } void GSFrame::flip(draw_context_t) diff --git a/rpcs3/Gui/GSFrame.h b/rpcs3/Gui/GSFrame.h index f13f46c648..ff01b3d52f 100644 --- a/rpcs3/Gui/GSFrame.h +++ b/rpcs3/Gui/GSFrame.h @@ -7,7 +7,7 @@ class GSFrame : public wxFrame, public GSFrameBase u64 m_frames = 0; public: - GSFrame(const wxString& title, size2i); + GSFrame(const wxString& title, int w, int h); protected: virtual void OnPaint(wxPaintEvent& event); @@ -28,7 +28,8 @@ protected: void set_current(draw_context_t context) override; void delete_context(void* context) override; void flip(draw_context_t context) override; - size2i client_size() override; + int client_width() override; + int client_height() override; public: void OnLeftDclick(wxMouseEvent&) diff --git a/rpcs3/Gui/InterpreterDisAsm.cpp b/rpcs3/Gui/InterpreterDisAsm.cpp index 7f218da646..e28e1c60d9 100644 --- a/rpcs3/Gui/InterpreterDisAsm.cpp +++ b/rpcs3/Gui/InterpreterDisAsm.cpp @@ -453,7 +453,7 @@ void InterpreterDisAsmFrame::DoStep(wxCommandEvent& WXUNUSED(event)) { if (cpu) { - if (cpu->state.atomic_op([](mset& state) -> bool + if (cpu->state.atomic_op([](bitset_t& state) -> bool { state += cpu_state::dbg_step; return state.test_and_reset(cpu_state::dbg_pause); diff --git a/rpcs3/Loader/ELF.h b/rpcs3/Loader/ELF.h index 3430fc1d2d..71e2cfde76 100644 --- a/rpcs3/Loader/ELF.h +++ b/rpcs3/Loader/ELF.h @@ -157,7 +157,7 @@ enum class elf_error template<> struct bijective { - static constexpr std::pair map[] + static constexpr bijective_pair map[] { { elf_error::ok, "" }, diff --git a/rpcs3/Loader/TRP.cpp b/rpcs3/Loader/TRP.cpp index 28cfc3b108..2f59b9b2b1 100644 --- a/rpcs3/Loader/TRP.cpp +++ b/rpcs3/Loader/TRP.cpp @@ -16,7 +16,7 @@ bool TRPLoader::Install(const std::string& dest, bool show) const std::string& local_path = vfs::get(dest); - if (!fs::create_dir(local_path) && errno != EEXIST) + if (!fs::create_dir(local_path) && fs::error != EEXIST) { return false; } diff --git a/rpcs3/emucore.vcxproj b/rpcs3/emucore.vcxproj index 91dda91d51..f63cba175f 100644 --- a/rpcs3/emucore.vcxproj +++ b/rpcs3/emucore.vcxproj @@ -74,7 +74,9 @@ - + + NotUsing + NotUsing @@ -227,6 +229,7 @@ + @@ -357,7 +360,9 @@ + + @@ -369,6 +374,7 @@ + diff --git a/rpcs3/emucore.vcxproj.filters b/rpcs3/emucore.vcxproj.filters index 4766e6cb2a..d7baae4115 100644 --- a/rpcs3/emucore.vcxproj.filters +++ b/rpcs3/emucore.vcxproj.filters @@ -851,6 +851,9 @@ Emu\Memory + + Emu + @@ -1606,5 +1609,14 @@ Emu\Cell\lv2 + + Utilities + + + Utilities + + + Utilities + \ No newline at end of file diff --git a/rpcs3/rpcs3.cpp b/rpcs3/rpcs3.cpp index 3151972d08..814391fb26 100644 --- a/rpcs3/rpcs3.cpp +++ b/rpcs3/rpcs3.cpp @@ -164,14 +164,14 @@ bool Rpcs3App::OnInit() callbacks.get_pad_handler = PURE_EXPR(g_cfg_pad_handler.get()()); - callbacks.get_gs_frame = [](frame_type type, size2i size) -> std::unique_ptr + callbacks.get_gs_frame = [](frame_type type, int w, int h) -> std::unique_ptr { switch (type) { - case frame_type::OpenGL: return std::make_unique(size); - case frame_type::DX12: return std::make_unique("DirectX 12", size); - case frame_type::Null: return std::make_unique("Null", size); - case frame_type::Vulkan: return std::make_unique("Vulkan", size); + case frame_type::OpenGL: return std::make_unique(w, h); + case frame_type::DX12: return std::make_unique("DirectX 12", w, h); + case frame_type::Null: return std::make_unique("Null", w, h); + case frame_type::Vulkan: return std::make_unique("Vulkan", w, h); } throw EXCEPTION("Invalid Frame Type (0x%x)", type); diff --git a/rpcs3/stdafx.h b/rpcs3/stdafx.h index 0ab9cd9215..7148a0c127 100644 --- a/rpcs3/stdafx.h +++ b/rpcs3/stdafx.h @@ -19,16 +19,12 @@ #pragma warning( disable : 4351 ) -#include #include -#include #include #include -#include -#include +#include #include #include -#include #include #include #include @@ -54,6 +50,5 @@ using namespace std::chrono_literals; #include "Utilities/BEType.h" #include "Utilities/Atomic.h" #include "Utilities/StrFmt.h" -#include "Utilities/BitField.h" #include "Utilities/File.h" #include "Utilities/Log.h"