diff --git a/kernel/cellos/include/cellos/sys_fs.h b/kernel/cellos/include/cellos/sys_fs.h index 890c9db3f..1c8804966 100644 --- a/kernel/cellos/include/cellos/sys_fs.h +++ b/kernel/cellos/include/cellos/sys_fs.h @@ -124,7 +124,7 @@ enum class lv2_mp_flag { strict_get_block_size, cache, - __bitset_enum_max + bitset_last = cache, }; enum class lv2_file_type { @@ -140,7 +140,7 @@ struct lv2_fs_mount_point { const u32 sector_size = 512; const u64 sector_count = 256; const u32 block_size = 4096; - const bs_t flags{}; + const rx::EnumBitSet flags{}; lv2_fs_mount_point *const next = nullptr; mutable shared_mutex mutex; diff --git a/kernel/cellos/include/cellos/sys_net.h b/kernel/cellos/include/cellos/sys_net.h index 132fea706..f3b4131f7 100644 --- a/kernel/cellos/include/cellos/sys_net.h +++ b/kernel/cellos/include/cellos/sys_net.h @@ -1,16 +1,8 @@ #pragma once -#include "util/bit_set.h" -#include "util/mutex.h" - #include "Emu/Cell/ErrorCodes.h" #include "Emu/Memory/vm_ptr.h" -#include -#include -#include -#include - // Error codes enum sys_net_error : s32 { SYS_NET_ENOENT = 2, @@ -54,7 +46,7 @@ enum sys_net_error : s32 { }; static constexpr sys_net_error operator-(sys_net_error v) { - return sys_net_error{-+v}; + return sys_net_error{-static_cast(v)}; } // Socket types (prefixed with SYS_NET_) diff --git a/kernel/cellos/include/cellos/sys_net/lv2_socket.h b/kernel/cellos/include/cellos/sys_net/lv2_socket.h index cd426dc30..481dd7d53 100644 --- a/kernel/cellos/include/cellos/sys_net/lv2_socket.h +++ b/kernel/cellos/include/cellos/sys_net/lv2_socket.h @@ -6,6 +6,8 @@ #include "Emu/IdManager.h" #include "Emu/NP/ip_address.h" #include "cellos/sys_net.h" +#include "rx/EnumBitSet.hpp" +#include "util/atomic_bit_set.h" #include "util/mutex.h" #ifdef _WIN32 @@ -32,7 +34,7 @@ public: write, error, - __bitset_enum_max + bitset_last }; union sockopt_data { @@ -62,10 +64,10 @@ public: std::unique_lock lock(); void set_lv2_id(u32 id); - bs_t get_events() const; - void set_poll_event(bs_t event); - void poll_queue(shared_ptr ppu, bs_t event, - std::function)> poll_cb); + rx::EnumBitSet get_events() const; + void set_poll_event(rx::EnumBitSet event); + void poll_queue(shared_ptr ppu, rx::EnumBitSet event, + std::function)> poll_cb); u32 clear_queue(ppu_thread *); void handle_events(const pollfd &native_fd, bool unset_connecting = false); void queue_wake(ppu_thread *ppu); @@ -110,7 +112,7 @@ public: virtual s32 shutdown(s32 how) = 0; virtual s32 poll(sys_net_pollfd &sn_pfd, pollfd &native_pfd) = 0; - virtual std::tuple select(bs_t selected, + virtual std::tuple select(rx::EnumBitSet selected, pollfd &native_pfd) = 0; error_code abort_socket(s32 flags); @@ -137,8 +139,8 @@ protected: atomic_bs_t events{}; // Event processing workload (pair of thread id and the processing function) - std::vector< - std::pair, std::function)>>> + std::vector, + std::function)>>> queue; // Socket options value keepers diff --git a/kernel/cellos/include/cellos/sys_net/lv2_socket_native.h b/kernel/cellos/include/cellos/sys_net/lv2_socket_native.h index b8d7f2e74..f8d7d0509 100644 --- a/kernel/cellos/include/cellos/sys_net/lv2_socket_native.h +++ b/kernel/cellos/include/cellos/sys_net/lv2_socket_native.h @@ -58,7 +58,7 @@ public: bool is_lock = true) override; s32 poll(sys_net_pollfd &sn_pfd, pollfd &native_pfd) override; - std::tuple select(bs_t selected, + std::tuple select(rx::EnumBitSet selected, pollfd &native_pfd) override; bool is_socket_connected(); diff --git a/kernel/cellos/include/cellos/sys_net/lv2_socket_p2p.h b/kernel/cellos/include/cellos/sys_net/lv2_socket_p2p.h index dc98edb50..9c24e19d7 100644 --- a/kernel/cellos/include/cellos/sys_net/lv2_socket_p2p.h +++ b/kernel/cellos/include/cellos/sys_net/lv2_socket_p2p.h @@ -1,6 +1,7 @@ #pragma once #include "lv2_socket.h" +#include class lv2_socket_p2p : public lv2_socket { public: @@ -38,7 +39,7 @@ public: s32 shutdown(s32 how) override; s32 poll(sys_net_pollfd &sn_pfd, pollfd &native_pfd) override; - std::tuple select(bs_t selected, + std::tuple select(rx::EnumBitSet selected, pollfd &native_pfd) override; void handle_new_data(sys_net_sockaddr_in_p2p p2p_addr, diff --git a/kernel/cellos/include/cellos/sys_net/lv2_socket_p2ps.h b/kernel/cellos/include/cellos/sys_net/lv2_socket_p2ps.h index 1cb1e5e2e..d156f6aca 100644 --- a/kernel/cellos/include/cellos/sys_net/lv2_socket_p2ps.h +++ b/kernel/cellos/include/cellos/sys_net/lv2_socket_p2ps.h @@ -1,5 +1,6 @@ #pragma once +#include #ifdef _WIN32 #include #include @@ -101,7 +102,7 @@ public: s32 shutdown(s32 how) override; s32 poll(sys_net_pollfd &sn_pfd, pollfd &native_pfd) override; - std::tuple select(bs_t selected, + std::tuple select(rx::EnumBitSet selected, pollfd &native_pfd) override; private: diff --git a/kernel/cellos/include/cellos/sys_net/lv2_socket_raw.h b/kernel/cellos/include/cellos/sys_net/lv2_socket_raw.h index 65cf35348..cd32ce5e6 100644 --- a/kernel/cellos/include/cellos/sys_net/lv2_socket_raw.h +++ b/kernel/cellos/include/cellos/sys_net/lv2_socket_raw.h @@ -40,6 +40,6 @@ public: s32 shutdown(s32 how) override; s32 poll(sys_net_pollfd &sn_pfd, pollfd &native_pfd) override; - std::tuple select(bs_t selected, + std::tuple select(rx::EnumBitSet selected, pollfd &native_pfd) override; }; diff --git a/kernel/cellos/src/lv2.cpp b/kernel/cellos/src/lv2.cpp index 8dab3e7ee..ef8a010d7 100644 --- a/kernel/cellos/src/lv2.cpp +++ b/kernel/cellos/src/lv2.cpp @@ -53,6 +53,7 @@ #include "sys_usbd.h" #include "sys_vm.h" +#include "util/atomic_bit_set.h" #include "util/init_mutex.hpp" #include "util/sysinfo.hpp" #include "util/tsc.hpp" @@ -1762,17 +1763,18 @@ bool lv2_obj::sleep_unlocked(cpu_thread &thread, u64 timeout, return_val = false; } - const auto [_, ok] = ppu->state.fetch_op([&](bs_t &val) { - if (!(val & cpu_flag::signal)) { - val += cpu_flag::suspend; + const auto [_, ok] = + ppu->state.fetch_op([&](rx::EnumBitSet &val) { + if (!(val & cpu_flag::signal)) { + val += cpu_flag::suspend; - // Flag used for forced timeout notification - ensure(!timeout || !(val & cpu_flag::notify)); - return true; - } + // Flag used for forced timeout notification + ensure(!timeout || !(val & cpu_flag::notify)); + return true; + } - return false; - }); + return false; + }); if (!ok) { ppu_log.fatal("sleep() failed (signaled) (%s)", ppu->current_function); @@ -2075,7 +2077,7 @@ void lv2_obj::schedule_all(u64 current_time) { ppu_log.trace("schedule(): %s", target->id); // Remove yield if it was sleeping until now - const bs_t remove_yield = + const rx::EnumBitSet remove_yield = target->start_time == 0 ? +cpu_flag::suspend : (cpu_flag::yield + cpu_flag::preempt); diff --git a/kernel/cellos/src/sys_fs.cpp b/kernel/cellos/src/sys_fs.cpp index 1eff5ddc3..a0907463d 100644 --- a/kernel/cellos/src/sys_fs.cpp +++ b/kernel/cellos/src/sys_fs.cpp @@ -740,7 +740,7 @@ lv2_file::open_raw_result_t lv2_file::open_raw(const std::string &local_path, return {CELL_EISDIR}; } - bs_t open_mode{}; + rx::EnumBitSet open_mode{}; switch (flags & CELL_FS_O_ACCMODE) { case CELL_FS_O_RDONLY: diff --git a/kernel/cellos/src/sys_net.cpp b/kernel/cellos/src/sys_net.cpp index 337318e88..c74b7edf8 100644 --- a/kernel/cellos/src/sys_net.cpp +++ b/kernel/cellos/src/sys_net.cpp @@ -403,7 +403,7 @@ error_code sys_net_bnet_accept(ppu_thread &ppu, s32 s, sock.poll_queue(idm::get_unlocked>(ppu.id), lv2_socket::poll_t::read, - [&](bs_t events) -> bool { + [&](rx::EnumBitSet events) -> bool { if (events & lv2_socket::poll_t::read) { auto [success, res, res_socket, res_addr] = sock.accept(false); @@ -554,7 +554,7 @@ error_code sys_net_bnet_connect(ppu_thread &ppu, s32 s, sock.poll_queue(idm::get_unlocked>(ppu.id), lv2_socket::poll_t::write, - [&](bs_t events) -> bool { + [&](rx::EnumBitSet events) -> bool { if (events & lv2_socket::poll_t::write) { result = sock.connect_followup(); @@ -819,7 +819,7 @@ error_code sys_net_bnet_recvfrom(ppu_thread &ppu, s32 s, vm::ptr buf, sock.poll_queue( idm::get_unlocked>(ppu.id), lv2_socket::poll_t::read, - [&](bs_t events) -> bool { + [&](rx::EnumBitSet events) -> bool { if (events & lv2_socket::poll_t::read) { const auto success = sock.recvfrom(flags, len, false); @@ -929,7 +929,7 @@ error_code sys_net_bnet_sendmsg(ppu_thread &ppu, s32 s, sock.poll_queue(idm::get_unlocked>(ppu.id), lv2_socket::poll_t::write, - [&](bs_t events) -> bool { + [&](rx::EnumBitSet events) -> bool { if (events & lv2_socket::poll_t::write) { const auto success = sock.sendmsg(flags, *netmsg, false); @@ -1023,7 +1023,7 @@ error_code sys_net_bnet_sendto(ppu_thread &ppu, s32 s, vm::cptr buf, // Enable write event sock.poll_queue(idm::get_unlocked>(ppu.id), lv2_socket::poll_t::write, - [&](bs_t events) -> bool { + [&](rx::EnumBitSet events) -> bool { if (events & lv2_socket::poll_t::write) { auto success = sock.sendto(flags, buf_copy, sn_addr, false); @@ -1336,7 +1336,7 @@ error_code sys_net_bnet_poll(ppu_thread &ppu, vm::ptr fds, sock->set_connecting(connecting[i]); #endif - bs_t selected = +lv2_socket::poll_t::error; + rx::EnumBitSet selected = +lv2_socket::poll_t::error; if (fds_buf[i].events & SYS_NET_POLLIN) selected += lv2_socket::poll_t::read; @@ -1348,7 +1348,7 @@ error_code sys_net_bnet_poll(ppu_thread &ppu, vm::ptr fds, sock->poll_queue(idm::get_unlocked>(ppu.id), selected, [sock, selected, &fds_buf, i, &signaled, - &ppu](bs_t events) { + &ppu](rx::EnumBitSet events) { if (events & selected) { if (events & selected & lv2_socket::poll_t::read) fds_buf[i].revents |= SYS_NET_POLLIN; @@ -1457,7 +1457,7 @@ error_code sys_net_bnet_select(ppu_thread &ppu, s32 nfds, for (s32 i = 0; i < nfds; i++) { _fds[i].fd = -1; - bs_t selected{}; + rx::EnumBitSet selected{}; if (readfds && _readfds.bit(i)) selected += lv2_socket::poll_t::read; @@ -1529,7 +1529,7 @@ error_code sys_net_bnet_select(ppu_thread &ppu, s32 nfds, } for (s32 i = 0; i < nfds; i++) { - bs_t selected{}; + rx::EnumBitSet selected{}; if (readfds && _readfds.bit(i)) selected += lv2_socket::poll_t::read; @@ -1554,7 +1554,7 @@ error_code sys_net_bnet_select(ppu_thread &ppu, s32 nfds, sock->poll_queue( idm::get_unlocked>(ppu.id), selected, [sock, selected, i, &rread, &rwrite, &rexcept, &signaled, - &ppu](bs_t events) { + &ppu](rx::EnumBitSet events) { if (events & selected) { if (selected & lv2_socket::poll_t::read && events & diff --git a/kernel/cellos/src/sys_net/lv2_socket.cpp b/kernel/cellos/src/sys_net/lv2_socket.cpp index 3ecbc47d3..26ba231b6 100644 --- a/kernel/cellos/src/sys_net/lv2_socket.cpp +++ b/kernel/cellos/src/sys_net/lv2_socket.cpp @@ -32,17 +32,17 @@ void lv2_socket::set_connecting(bool connecting) { void lv2_socket::set_lv2_id(u32 id) { lv2_id = id; } -bs_t lv2_socket::get_events() const { +rx::EnumBitSet lv2_socket::get_events() const { return events.load(); } -void lv2_socket::set_poll_event(bs_t event) { +void lv2_socket::set_poll_event(rx::EnumBitSet event) { events += event; } void lv2_socket::poll_queue( - shared_ptr ppu, bs_t event, - std::function)> poll_cb) { + shared_ptr ppu, rx::EnumBitSet event, + std::function)> poll_cb) { set_poll_event(event); queue.emplace_back(std::move(ppu), poll_cb); @@ -88,7 +88,7 @@ u32 lv2_socket::clear_queue(ppu_thread *ppu) { void lv2_socket::handle_events(const pollfd &native_pfd, [[maybe_unused]] bool unset_connecting) { - bs_t events_happening{}; + rx::EnumBitSet events_happening{}; if (native_pfd.revents & (POLLIN | POLLHUP) && events.test_and_reset(lv2_socket::poll_t::read)) diff --git a/kernel/cellos/src/sys_net/lv2_socket_native.cpp b/kernel/cellos/src/sys_net/lv2_socket_native.cpp index c58c35c36..0a8b557be 100644 --- a/kernel/cellos/src/sys_net/lv2_socket_native.cpp +++ b/kernel/cellos/src/sys_net/lv2_socket_native.cpp @@ -260,7 +260,7 @@ std::optional lv2_socket_native::connect(const sys_net_sockaddr &addr) { #endif this->poll_queue( null_ptr, lv2_socket::poll_t::write, - [this](bs_t events) -> bool { + [this](rx::EnumBitSet events) -> bool { if (events & lv2_socket::poll_t::write) { int native_error; ::socklen_t size = sizeof(native_error); @@ -1101,7 +1101,7 @@ s32 lv2_socket_native::poll(sys_net_pollfd &sn_pfd, pollfd &native_pfd) { } std::tuple -lv2_socket_native::select(bs_t selected, +lv2_socket_native::select(rx::EnumBitSet selected, pollfd &native_pfd) { native_pfd.fd = native_socket; if (selected & lv2_socket::poll_t::read) { diff --git a/kernel/cellos/src/sys_net/lv2_socket_p2p.cpp b/kernel/cellos/src/sys_net/lv2_socket_p2p.cpp index 85b2fa4ef1..0db2b3d65 100644 --- a/kernel/cellos/src/sys_net/lv2_socket_p2p.cpp +++ b/kernel/cellos/src/sys_net/lv2_socket_p2p.cpp @@ -4,6 +4,7 @@ #include "sys_net/lv2_socket_p2p.h" #include "sys_net/network_context.h" #include "sys_net/sys_net_helpers.h" +#include LOG_CHANNEL(sys_net); @@ -54,7 +55,7 @@ void lv2_socket_p2p::handle_new_data(sys_net_sockaddr_in_p2p p2p_addr, // Check if poll is happening if (events.test_and_reset(lv2_socket::poll_t::read)) { - bs_t read_event = lv2_socket::poll_t::read; + rx::EnumBitSet read_event = lv2_socket::poll_t::read; for (auto it = queue.begin(); it != queue.end();) { if (it->second(read_event)) { it = queue.erase(it); @@ -378,7 +379,7 @@ s32 lv2_socket_p2p::poll(sys_net_pollfd &sn_pfd, } std::tuple -lv2_socket_p2p::select(bs_t selected, +lv2_socket_p2p::select(rx::EnumBitSet selected, [[maybe_unused]] pollfd &native_pfd) { std::lock_guard lock(mutex); diff --git a/kernel/cellos/src/sys_net/lv2_socket_p2ps.cpp b/kernel/cellos/src/sys_net/lv2_socket_p2ps.cpp index ba5438144..f93f4ba24 100644 --- a/kernel/cellos/src/sys_net/lv2_socket_p2ps.cpp +++ b/kernel/cellos/src/sys_net/lv2_socket_p2ps.cpp @@ -332,7 +332,7 @@ bool lv2_socket_p2ps::handle_connected(p2ps_encapsulated_tcp *tcp_header, // check if polling is happening if (data_available && events.test_and_reset(lv2_socket::poll_t::read)) { - bs_t read_event = lv2_socket::poll_t::read; + rx::EnumBitSet read_event = lv2_socket::poll_t::read; for (auto it = queue.begin(); it != queue.end();) { if (it->second(read_event)) { it = queue.erase(it); @@ -479,7 +479,7 @@ bool lv2_socket_p2ps::handle_listening(p2ps_encapsulated_tcp *tcp_header, backlog.push_back(new_sock_id); if (events.test_and_reset(lv2_socket::poll_t::read)) { - bs_t read_event = lv2_socket::poll_t::read; + rx::EnumBitSet read_event = lv2_socket::poll_t::read; for (auto it = queue.begin(); it != queue.end();) { if (it->second(read_event)) { it = queue.erase(it); @@ -983,7 +983,7 @@ s32 lv2_socket_p2ps::poll(sys_net_pollfd &sn_pfd, } std::tuple -lv2_socket_p2ps::select(bs_t selected, +lv2_socket_p2ps::select(rx::EnumBitSet selected, [[maybe_unused]] pollfd &native_pfd) { std::lock_guard lock(mutex); diff --git a/kernel/cellos/src/sys_net/lv2_socket_raw.cpp b/kernel/cellos/src/sys_net/lv2_socket_raw.cpp index ab408a0b9..42e0476d9 100644 --- a/kernel/cellos/src/sys_net/lv2_socket_raw.cpp +++ b/kernel/cellos/src/sys_net/lv2_socket_raw.cpp @@ -130,7 +130,7 @@ s32 lv2_socket_raw::poll([[maybe_unused]] sys_net_pollfd &sn_pfd, } std::tuple -lv2_socket_raw::select([[maybe_unused]] bs_t selected, +lv2_socket_raw::select([[maybe_unused]] rx::EnumBitSet selected, [[maybe_unused]] pollfd &native_pfd) { LOG_ONCE(raw_select, "lv2_socket_raw::select"); return {}; diff --git a/kernel/cellos/src/sys_spu.cpp b/kernel/cellos/src/sys_spu.cpp index 8a963fe6c..b12c88cd9 100644 --- a/kernel/cellos/src/sys_spu.cpp +++ b/kernel/cellos/src/sys_spu.cpp @@ -1295,7 +1295,7 @@ error_code sys_spu_thread_group_terminate(ppu_thread &ppu, u32 id, s32 value) { for (auto &thread : group->threads) { if (thread) { - thread->state.fetch_op([](bs_t &flags) { + thread->state.fetch_op([](rx::EnumBitSet &flags) { if (flags & cpu_flag::stop) { // In case the thread raised the ret flag itself at some point do not // raise it again diff --git a/ps3fw/cellGame.cpp b/ps3fw/cellGame.cpp index 27b1f0048..9086355c0 100644 --- a/ps3fw/cellGame.cpp +++ b/ps3fw/cellGame.cpp @@ -1612,7 +1612,7 @@ enum class strkey_flag : u32 // set_other, // writing is allowed for other types of PARAM.SFO (not // possible) - __bitset_enum_max + bitset_last }; struct string_key_info @@ -1620,7 +1620,7 @@ struct string_key_info public: string_key_info() = default; string_key_info(std::string_view _name, u32 _max_size, - bs_t _flags) + rx::EnumBitSet _flags) : name(_name), max_size(_max_size), flags(_flags) {} std::string_view name; @@ -1653,7 +1653,7 @@ public: } private: - bs_t flags{}; // allowed operations + rx::EnumBitSet flags{}; // allowed operations }; static string_key_info get_param_string_key(s32 id) diff --git a/rpcs3/Crypto/utils.cpp b/rpcs3/Crypto/utils.cpp index 3098422c9..242b04d77 100644 --- a/rpcs3/Crypto/utils.cpp +++ b/rpcs3/Crypto/utils.cpp @@ -8,8 +8,9 @@ #include "sha256.h" #include "key_vault.h" #include -#include -#include +#include +#include +#include "util/StrFmt.h" #include "util/StrUtil.h" #include "util/File.h" diff --git a/rpcs3/Emu/CPU/CPUThread.cpp b/rpcs3/Emu/CPU/CPUThread.cpp index 4eb39457d..d7a34a068 100644 --- a/rpcs3/Emu/CPU/CPUThread.cpp +++ b/rpcs3/Emu/CPU/CPUThread.cpp @@ -64,7 +64,7 @@ void fmt_class_string::format(std::string& out, u64 arg) case cpu_flag::dbg_global_pause: return "G-PAUSE"; case cpu_flag::dbg_pause: return "PAUSE"; case cpu_flag::dbg_step: return "STEP"; - case cpu_flag::__bitset_enum_max: break; + case cpu_flag::bitset_last: break; } return unknown; @@ -72,7 +72,7 @@ void fmt_class_string::format(std::string& out, u64 arg) } template <> -void fmt_class_string>::format(std::string& out, u64 arg) +void fmt_class_string>::format(std::string& out, u64 arg) { format_bitset(out, arg, "[", "|", "]", &fmt_class_string::format); } @@ -799,7 +799,7 @@ cpu_thread::cpu_thread(u32 id) } } -void cpu_thread::cpu_wait(bs_t old) +void cpu_thread::cpu_wait(rx::EnumBitSet old) { state.wait(old); } @@ -816,8 +816,8 @@ bool cpu_thread::check_state() noexcept while (true) { // Process all flags in a single atomic op - bs_t state1; - auto state0 = state.fetch_op([&](bs_t& flags) + rx::EnumBitSet state1; + auto state0 = state.fetch_op([&](rx::EnumBitSet& flags) { bool store = false; @@ -1168,9 +1168,9 @@ cpu_thread& cpu_thread::operator=(thread_state) return *this; } -void cpu_thread::add_remove_flags(bs_t to_add, bs_t to_remove) +void cpu_thread::add_remove_flags(rx::EnumBitSet to_add, rx::EnumBitSet to_remove) { - bs_t result{}; + rx::EnumBitSet result{}; if (!to_remove) { @@ -1183,7 +1183,7 @@ void cpu_thread::add_remove_flags(bs_t to_add, bs_t to_remov } else { - result = state.atomic_op([&](bs_t& v) + result = state.atomic_op([&](rx::EnumBitSet& v) { v += to_add; v -= to_remove; diff --git a/rpcs3/Emu/CPU/CPUThread.h b/rpcs3/Emu/CPU/CPUThread.h index 176a8f86a..661e8b997 100644 --- a/rpcs3/Emu/CPU/CPUThread.h +++ b/rpcs3/Emu/CPU/CPUThread.h @@ -1,7 +1,8 @@ #pragma once #include "util/Thread.h" -#include "util/bit_set.h" +#include "rx/EnumBitSet.hpp" +#include "util/atomic_bit_set.h" #include #include @@ -33,17 +34,17 @@ enum class cpu_flag : u32 dbg_pause, // Thread paused dbg_step, // Thread forced to pause after one step (one instruction, etc) - __bitset_enum_max + bitset_last }; // Test stopped state -constexpr bool is_stopped(bs_t state) +constexpr bool is_stopped(rx::EnumBitSet state) { return !!(state & (cpu_flag::stop + cpu_flag::exit + cpu_flag::again)); } // Test paused state -constexpr bool is_paused(bs_t state) +constexpr bool is_paused(rx::EnumBitSet state) { return !!(state & (cpu_flag::suspend + cpu_flag::dbg_global_pause + cpu_flag::dbg_pause)) && !is_stopped(state); } @@ -87,12 +88,12 @@ public: } // Wrappers - static constexpr bool is_stopped(bs_t s) + static constexpr bool is_stopped(rx::EnumBitSet s) { return ::is_stopped(s); } - static constexpr bool is_paused(bs_t s) + static constexpr bool is_paused(rx::EnumBitSet s) { return ::is_paused(s); } @@ -155,7 +156,7 @@ public: cpu_thread& operator=(thread_state); // Add/remove CPU state flags in an atomic operations, notifying if required - void add_remove_flags(bs_t to_add, bs_t to_remove); + void add_remove_flags(rx::EnumBitSet to_add, rx::EnumBitSet to_remove); // Thread stats for external observation static atomic_t g_threads_created, g_threads_deleted, g_suspend_counter; @@ -194,7 +195,7 @@ public: virtual void cpu_return() {} // Callback for thread_ctrl::wait or RSX wait - virtual void cpu_wait(bs_t old); + virtual void cpu_wait(rx::EnumBitSet old); // Callback for function abortion stats on Emu.Kill() virtual void cpu_on_stop() {} diff --git a/rpcs3/Emu/Cell/PPUAnalyser.cpp b/rpcs3/Emu/Cell/PPUAnalyser.cpp index 8d5d3c679..824c478a6 100644 --- a/rpcs3/Emu/Cell/PPUAnalyser.cpp +++ b/rpcs3/Emu/Cell/PPUAnalyser.cpp @@ -25,7 +25,7 @@ void fmt_class_string::format(std::string& out, u64 arg) case ppu_attr::no_return: return "no_return"; case ppu_attr::no_size: return "no_size"; case ppu_attr::has_mfvscr: return "has_mfvscr"; - case ppu_attr::__bitset_enum_max: break; + case ppu_attr::bitset_last: break; } return unknown; @@ -33,7 +33,7 @@ void fmt_class_string::format(std::string& out, u64 arg) } template <> -void fmt_class_string>::format(std::string& out, u64 arg) +void fmt_class_string>::format(std::string& out, u64 arg) { format_bitset(out, arg, "[", ",", "]", &fmt_class_string::format); } @@ -857,7 +857,7 @@ bool ppu_module::analyse(u32 lib_toc, u32 entry, const u32 sec_end, con // u32 stack_frame = 0; u32 single_target = 0; u32 trampoline = 0; - bs_t attr{}; + rx::EnumBitSet attr{}; std::set callers{}; }; diff --git a/rpcs3/Emu/Cell/PPUAnalyser.h b/rpcs3/Emu/Cell/PPUAnalyser.h index 9ce0a4b17..cd8e68c23 100644 --- a/rpcs3/Emu/Cell/PPUAnalyser.h +++ b/rpcs3/Emu/Cell/PPUAnalyser.h @@ -8,7 +8,7 @@ #include "util/asm.hpp" #include "util/to_endian.hpp" -#include "util/bit_set.h" +#include "rx/EnumBitSet.hpp" #include "PPUOpcodes.h" // PPU Function Attributes @@ -19,7 +19,7 @@ enum class ppu_attr : u8 no_size, has_mfvscr, - __bitset_enum_max + bitset_last }; // PPU Function Information @@ -131,7 +131,7 @@ struct ppu_module : public Type std::string name{}; // Filename std::string path{}; // Filepath s64 offset = 0; // Offset of file - mutable bs_t attr{}; // Shared module attributes + mutable rx::EnumBitSet attr{}; // Shared module attributes std::string cache{}; // Cache file path std::vector relocs{}; // Relocations std::vector segs{}; // Segments diff --git a/rpcs3/Emu/Cell/PPUInterpreter.cpp b/rpcs3/Emu/Cell/PPUInterpreter.cpp index a84bf21c4..f05b49703 100644 --- a/rpcs3/Emu/Cell/PPUInterpreter.cpp +++ b/rpcs3/Emu/Cell/PPUInterpreter.cpp @@ -70,7 +70,7 @@ enum class ppu_exec_bit : u64 set_call_history, use_feed_data, - __bitset_enum_max + bitset_last }; using enum ppu_exec_bit; @@ -80,7 +80,7 @@ template struct ppu_exec_select { template - static ppu_intrp_func_t select(bs_t selected, F func) + static ppu_intrp_func_t select(rx::EnumBitSet selected, F func) { // Make sure there is no flag duplication, otherwise skip flag if constexpr (((Flags0 != Flag) && ...)) @@ -97,7 +97,7 @@ struct ppu_exec_select } template - static ppu_intrp_func_t select(bs_t, F func) + static ppu_intrp_func_t select(rx::EnumBitSet, F func) { // Instantiate interpreter function with required set of flags return func.template operator()(); @@ -107,7 +107,7 @@ struct ppu_exec_select static auto select() { #ifndef __INTELLISENSE__ - return [](bs_t selected, auto func) + return [](rx::EnumBitSet selected, auto func) { return ppu_exec_select::select(selected, func); }; @@ -2350,7 +2350,7 @@ template struct VSLDOI { template - static auto select(bs_t selected, auto func) + static auto select(rx::EnumBitSet selected, auto func) { return ppu_exec_select<>::select(selected, func); } @@ -3891,7 +3891,7 @@ template struct MFOCRF { template - static auto select(bs_t selected, auto func) + static auto select(rx::EnumBitSet selected, auto func) { return ppu_exec_select<>::select(selected, func); } @@ -7547,7 +7547,7 @@ struct ppu_interpreter_t ppu_interpreter_rt_base::ppu_interpreter_rt_base() noexcept { // Obtain required set of flags from settings - bs_t selected{}; + rx::EnumBitSet selected{}; if (g_cfg.core.ppu_set_sat_bit) selected += set_sat; if (g_cfg.core.ppu_use_nj_bit) diff --git a/rpcs3/Emu/Cell/PPUModule.cpp b/rpcs3/Emu/Cell/PPUModule.cpp index 33e46ed2a..65c3ff0b6 100644 --- a/rpcs3/Emu/Cell/PPUModule.cpp +++ b/rpcs3/Emu/Cell/PPUModule.cpp @@ -3254,7 +3254,7 @@ bool ppu_load_rel_exec(const ppu_rel_object& elf) std::stable_sort(shdrs.begin(), shdrs.end(), [](auto& a, auto& b) -> bool { - const bs_t flags_a_has = a->sh_flags() - b->sh_flags(); + const rx::EnumBitSet flags_a_has = a->sh_flags() - b->sh_flags(); return flags_a_has.all_of(sh_flag::shf_execinstr); }); diff --git a/rpcs3/Emu/Cell/PPUThread.cpp b/rpcs3/Emu/Cell/PPUThread.cpp index 6854e299c..5226a97cb 100644 --- a/rpcs3/Emu/Cell/PPUThread.cpp +++ b/rpcs3/Emu/Cell/PPUThread.cpp @@ -1261,7 +1261,7 @@ static void ppu_break(ppu_thread& ppu, ppu_opcode_t, be_t* this_op, ppu_int ppu.cia = old_cia; // Pause - ppu.state.atomic_op([&](bs_t& state) + ppu.state.atomic_op([&](rx::EnumBitSet& state) { if (pause_all) state += cpu_flag::dbg_global_pause; @@ -2423,7 +2423,7 @@ void ppu_thread::cpu_on_stop() } } -void ppu_thread::cpu_wait(bs_t old) +void ppu_thread::cpu_wait(rx::EnumBitSet old) { // Meanwhile while waiting, notify SPU waiters if (u32 addr = res_notify) @@ -2781,7 +2781,7 @@ ppu_thread::ppu_thread(utils::serial& ar) void ppu_thread::save(utils::serial& ar) { // For debugging purposes, load this as soon as this function enters - const bs_t state_flags = state; + const rx::EnumBitSet state_flags = state; USING_SERIALIZATION_VERSION(ppu); @@ -5421,10 +5421,10 @@ bool ppu_initialize(const ppu_module& info, bool check_only, u64 file_s accurate_nj_mode, contains_symbol_resolver, - __bitset_enum_max + bitset_last }; - be_t> settings{}; + be_t> settings{}; #if !defined(_WIN32) && !defined(__APPLE__) settings += ppu_settings::platform_bit; diff --git a/rpcs3/Emu/Cell/PPUThread.h b/rpcs3/Emu/Cell/PPUThread.h index 341a89dd9..3ed7d5806 100644 --- a/rpcs3/Emu/Cell/PPUThread.h +++ b/rpcs3/Emu/Cell/PPUThread.h @@ -151,7 +151,7 @@ public: virtual void cpu_task() override final; virtual void cpu_sleep() override; virtual void cpu_on_stop() override; - virtual void cpu_wait(bs_t old) override; + virtual void cpu_wait(rx::EnumBitSet old) override; virtual ~ppu_thread() override; SAVESTATE_INIT_POS(3); diff --git a/rpcs3/Emu/Cell/PPUTranslator.h b/rpcs3/Emu/Cell/PPUTranslator.h index bb0c54d19..a5338da5a 100644 --- a/rpcs3/Emu/Cell/PPUTranslator.h +++ b/rpcs3/Emu/Cell/PPUTranslator.h @@ -34,7 +34,7 @@ class PPUTranslator final : public cpu_translator u64 m_addr = 0; // Function attributes - bs_t m_attr{}; + rx::EnumBitSet m_attr{}; // Relocation info const ppu_segment* m_reloc = nullptr; diff --git a/rpcs3/Emu/Cell/SPUCommonRecompiler.cpp b/rpcs3/Emu/Cell/SPUCommonRecompiler.cpp index 0a26b572d..9657d6d4e 100644 --- a/rpcs3/Emu/Cell/SPUCommonRecompiler.cpp +++ b/rpcs3/Emu/Cell/SPUCommonRecompiler.cpp @@ -2920,7 +2920,7 @@ spu_program spu_recompiler_base::analyse(const be_t* ls, u32 entry_point, s } // Weak constant propagation context (for guessing branch targets) - std::array, 128> vflags{}; + std::array, 128> vflags{}; // Associated constant values for 32-bit preferred slot std::array values; @@ -5596,7 +5596,7 @@ spu_program spu_recompiler_base::analyse(const be_t* ls, u32 entry_point, s pos = ra.origin; } - const bs_t flag = (ra.flag & rb.flag) - vf::is_null; + const rx::EnumBitSet flag = (ra.flag & rb.flag) - vf::is_null; vregs[reg] = reg_state_t{flag, value, flag & vf::is_const ? u32{umax} : reg_state_t::alloc_tag(), 0, 0, pos}; }; diff --git a/rpcs3/Emu/Cell/SPUInterpreter.cpp b/rpcs3/Emu/Cell/SPUInterpreter.cpp index b1e76b01b..86be410df 100644 --- a/rpcs3/Emu/Cell/SPUInterpreter.cpp +++ b/rpcs3/Emu/Cell/SPUInterpreter.cpp @@ -34,7 +34,7 @@ enum class spu_exec_bit : u64 { use_dfma, - __bitset_enum_max + bitset_last }; using enum spu_exec_bit; @@ -43,7 +43,7 @@ template struct spu_exec_select { template - static spu_intrp_func_t select(bs_t selected, F func) + static spu_intrp_func_t select(rx::EnumBitSet selected, F func) { // Make sure there is no flag duplication, otherwise skip flag if constexpr (((Flags0 != Flag) && ...)) @@ -60,7 +60,7 @@ struct spu_exec_select } template - static spu_intrp_func_t select(bs_t, F func) + static spu_intrp_func_t select(rx::EnumBitSet, F func) { // Instantiate interpreter function with required set of flags return func.template operator()(); @@ -3131,7 +3131,7 @@ struct spu_interpreter_t spu_interpreter_rt_base::spu_interpreter_rt_base() noexcept { // Obtain required set of flags from settings - bs_t selected{}; + rx::EnumBitSet selected{}; if (g_cfg.core.use_accurate_dfma) selected += use_dfma; diff --git a/rpcs3/Emu/Cell/SPURecompiler.h b/rpcs3/Emu/Cell/SPURecompiler.h index f1d205262..feb53f51d 100644 --- a/rpcs3/Emu/Cell/SPURecompiler.h +++ b/rpcs3/Emu/Cell/SPURecompiler.h @@ -198,12 +198,12 @@ public: is_rel, is_null, - __bitset_enum_max + bitset_last }; struct reg_state_t { - bs_t flag{+vf::is_null}; + rx::EnumBitSet flag{+vf::is_null}; u32 value{}; u32 tag = umax; u32 known_ones{}; diff --git a/rpcs3/Emu/Cell/SPUThread.cpp b/rpcs3/Emu/Cell/SPUThread.cpp index a9fd8ff28..c9b724572 100644 --- a/rpcs3/Emu/Cell/SPUThread.cpp +++ b/rpcs3/Emu/Cell/SPUThread.cpp @@ -2027,7 +2027,7 @@ void spu_thread::cpu_work() if (!work_left) { // No more pending work - state.atomic_op([](bs_t& flags) + state.atomic_op([](rx::EnumBitSet& flags) { if (flags & cpu_flag::pending_recheck) { @@ -7010,7 +7010,7 @@ bool spu_thread::stop_and_signal(u32 code) { if (thread) { - thread->state.fetch_op([](bs_t& flags) + thread->state.fetch_op([](rx::EnumBitSet& flags) { if (flags & cpu_flag::stop) { diff --git a/rpcs3/Emu/GDB.cpp b/rpcs3/Emu/GDB.cpp index 4cdff6437..a4c080821 100644 --- a/rpcs3/Emu/GDB.cpp +++ b/rpcs3/Emu/GDB.cpp @@ -1,7 +1,7 @@ #include "stdafx.h" #include "GDB.h" -#include "util/bit_set.h" +#include "rx/EnumBitSet.hpp" #include "util/logs.hpp" #include "util/StrUtil.h" #include "Emu/Memory/vm.h" @@ -823,7 +823,7 @@ bool gdb_thread::cmd_vcont(gdb_cmd& cmd) if (ppu) { - bs_t add_flags{}; + rx::EnumBitSet add_flags{}; if (cmd.data[1] == 's') { diff --git a/rpcs3/Emu/Memory/vm.cpp b/rpcs3/Emu/Memory/vm.cpp index 66585f440..df398e6bc 100644 --- a/rpcs3/Emu/Memory/vm.cpp +++ b/rpcs3/Emu/Memory/vm.cpp @@ -435,7 +435,7 @@ namespace vm bool temporary_unlock(cpu_thread& cpu) noexcept { - bs_t add_state = cpu_flag::wait; + rx::EnumBitSet add_state = cpu_flag::wait; if (g_tls_locked && g_tls_locked->compare_and_swap_test(&cpu, nullptr)) { diff --git a/rpcs3/Emu/RSX/RSXThread.cpp b/rpcs3/Emu/RSX/RSXThread.cpp index 653a9e5cf..3a8a45f8a 100644 --- a/rpcs3/Emu/RSX/RSXThread.cpp +++ b/rpcs3/Emu/RSX/RSXThread.cpp @@ -850,7 +850,7 @@ namespace rsx on_exit(); } - void thread::cpu_wait(bs_t old) + void thread::cpu_wait(rx::EnumBitSet old) { if (external_interrupt_lock) { diff --git a/rpcs3/Emu/RSX/RSXThread.h b/rpcs3/Emu/RSX/RSXThread.h index 6284a3694..313f606aa 100644 --- a/rpcs3/Emu/RSX/RSXThread.h +++ b/rpcs3/Emu/RSX/RSXThread.h @@ -188,7 +188,7 @@ namespace rsx u32 get_fifo_cmd() const; void dump_regs(std::string&, std::any& custom_data) const override; - void cpu_wait(bs_t old) override; + void cpu_wait(rx::EnumBitSet old) override; static constexpr u32 id_base = 0x5555'5555; // See get_current_cpu_thread() diff --git a/rpcs3/Emu/System.cpp b/rpcs3/Emu/System.cpp index a7864ffb0..127839852 100644 --- a/rpcs3/Emu/System.cpp +++ b/rpcs3/Emu/System.cpp @@ -2654,7 +2654,7 @@ void Emulator::FinalizeRunRequest() { const bool autostart = !m_ar || !!g_cfg.misc.autostart; - bs_t add_flags = cpu_flag::dbg_global_pause; + rx::EnumBitSet add_flags = cpu_flag::dbg_global_pause; if (autostart) { @@ -2663,7 +2663,7 @@ void Emulator::FinalizeRunRequest() auto spu_select = [&](u32, spu_thread& spu) { - bs_t sub_flags = cpu_flag::stop; + rx::EnumBitSet sub_flags = cpu_flag::stop; if (spu.group && spu.index == spu.group->waiter_spu_index) { @@ -3605,7 +3605,7 @@ void Emulator::Kill(bool allow_autoexit, bool savestate, savestate_stage* save_s set_progress_message("Finalizing File"); - bs_t extension_flags{SaveStateExtentionFlags1::SupportsMenuOpenResume}; + rx::EnumBitSet extension_flags{SaveStateExtentionFlags1::SupportsMenuOpenResume}; if (g_fxo->get().active) { diff --git a/rpcs3/Emu/System.h b/rpcs3/Emu/System.h index b77e92085..9e9149195 100644 --- a/rpcs3/Emu/System.h +++ b/rpcs3/Emu/System.h @@ -4,7 +4,7 @@ #include "util/types.hpp" #include "util/atomic.hpp" #include "util/shared_ptr.hpp" -#include "util/bit_set.h" +#include "rx/EnumBitSet.hpp" #include "config_mode.h" #include "games_config.h" #include @@ -188,10 +188,10 @@ class Emulator final SupportsMenuOpenResume, ShouldCloseMenu, - __bitset_enum_max, + bitset_last, }; - bs_t m_savestate_extension_flags1{}; + rx::EnumBitSet m_savestate_extension_flags1{}; public: static constexpr std::string_view game_id_boot_prefix = "%RPCS3_GAMEID%:"; diff --git a/rpcs3/Loader/ELF.h b/rpcs3/Loader/ELF.h index 6ccd4bbd6..d37acdeec 100644 --- a/rpcs3/Loader/ELF.h +++ b/rpcs3/Loader/ELF.h @@ -2,7 +2,7 @@ #include "util/types.hpp" #include "util/File.h" -#include "util/bit_set.h" +#include "rx/EnumBitSet.hpp" #include "util/endian.hpp" #include @@ -56,10 +56,10 @@ enum class sh_flag : u32 shf_alloc, shf_execinstr, - __bitset_enum_max + bitset_last }; -constexpr bool is_memorizable_section(sec_type type, bs_t flags) +constexpr bool is_memorizable_section(sec_type type, rx::EnumBitSet flags) { switch (type) { @@ -184,9 +184,9 @@ struct elf_shdr en_t sh_addralign; en_t sh_entsize; - bs_t sh_flags() const + rx::EnumBitSet sh_flags() const { - return std::bit_cast>(static_cast(+_sh_flags)); + return std::bit_cast>(static_cast(+_sh_flags)); } }; @@ -218,7 +218,7 @@ enum class elf_opt : u32 no_sections, // Don't load shdrs no_data, // Load phdrs without data - __bitset_enum_max + bitset_last }; // ELF loading error @@ -266,12 +266,12 @@ public: public: elf_object() = default; - elf_object(const fs::file& stream, u64 offset = 0, bs_t opts = {}) + elf_object(const fs::file& stream, u64 offset = 0, rx::EnumBitSet opts = {}) { open(stream, offset, opts); } - elf_error open(const fs::file& stream, u64 offset = 0, bs_t opts = {}) + elf_error open(const fs::file& stream, u64 offset = 0, rx::EnumBitSet opts = {}) { highest_offset = 0; diff --git a/rpcs3/dev/iso.cpp b/rpcs3/dev/iso.cpp index a2e50e9f9..4303403e8 100644 --- a/rpcs3/dev/iso.cpp +++ b/rpcs3/dev/iso.cpp @@ -146,7 +146,7 @@ bool iso_dev::statfs(const std::string& path, fs::device_stat& info) return true; } -std::unique_ptr iso_dev::open(const std::string& path, bs_t mode) +std::unique_ptr iso_dev::open(const std::string& path, rx::EnumBitSet mode) { if (mode & fs::write) { diff --git a/rpcs3/dev/iso.hpp b/rpcs3/dev/iso.hpp index 019bbdc35..7879252f7 100644 --- a/rpcs3/dev/iso.hpp +++ b/rpcs3/dev/iso.hpp @@ -230,7 +230,7 @@ public: bool stat(const std::string& path, fs::stat_t& info) override; bool statfs(const std::string& path, fs::device_stat& info) override; - std::unique_ptr open(const std::string& path, bs_t mode) override; + std::unique_ptr open(const std::string& path, rx::EnumBitSet mode) override; std::unique_ptr open_dir(const std::string& path) override; private: diff --git a/rpcs3/util/File.cpp b/rpcs3/util/File.cpp index 709c26db1..c93c4a007 100644 --- a/rpcs3/util/File.cpp +++ b/rpcs3/util/File.cpp @@ -1635,7 +1635,7 @@ void fs::sync() fmt::throw_exception("Stream overflow."); } -fs::file::file(const std::string& path, bs_t mode) +fs::file::file(const std::string& path, rx::EnumBitSet mode) { if (path.empty()) { diff --git a/rpcs3/util/File.h b/rpcs3/util/File.h index d768a27ee..145453630 100644 --- a/rpcs3/util/File.h +++ b/rpcs3/util/File.h @@ -3,7 +3,7 @@ #include "util/serialization.hpp" #include "util/types.hpp" #include "util/shared_ptr.hpp" -#include "bit_set.h" +#include "rx/EnumBitSet.hpp" #include #include @@ -35,7 +35,7 @@ namespace fs unread, isfile, - __bitset_enum_max + bitset_last }; constexpr auto read = +open_mode::read; // Enable reading @@ -174,7 +174,7 @@ namespace fs virtual bool trunc(const std::string& path, u64 length); virtual bool utime(const std::string& path, s64 atime, s64 mtime); - virtual std::unique_ptr open(const std::string& path, bs_t mode) = 0; + virtual std::unique_ptr open(const std::string& path, rx::EnumBitSet mode) = 0; virtual std::unique_ptr open_dir(const std::string& path) = 0; }; @@ -258,7 +258,7 @@ namespace fs file() = default; // Open file with specified mode - explicit file(const std::string& path, bs_t mode = ::fs::read); + explicit file(const std::string& path, rx::EnumBitSet mode = ::fs::read); static file from_native_handle(native_handle handle); @@ -903,7 +903,7 @@ namespace fs } template - bool write_file(const std::string& path, bs_t mode, const Args&... args) + bool write_file(const std::string& path, rx::EnumBitSet mode, const Args&... args) { // Always use write flag, remove read flag if (fs::file f{path, mode + fs::write - fs::read}) diff --git a/rpcs3/util/atomic_bit_set.h b/rpcs3/util/atomic_bit_set.h new file mode 100644 index 000000000..ae5b9f591 --- /dev/null +++ b/rpcs3/util/atomic_bit_set.h @@ -0,0 +1,175 @@ +#pragma once + +/* +This header implements bs_t<> class for scoped enum types (enum class). +To enable bs_t<>, enum scope must contain `bitset_last` entry. + +enum class flagzz : u32 +{ + flag1, // Bit indices start from zero + flag2, + + bitset_last // It must be the last value +}; + +This also enables helper operators for this enum type. + +Examples: +`+flagzz::flag1` - unary `+` operator convert flagzz value to bs_t +`flagzz::flag1 + flagzz::flag2` - bitset union +`flagzz::flag1 - flagzz::flag2` - bitset difference +Intersection (&) and symmetric difference (^) is also available. +*/ + +#include "rx/EnumBitSet.hpp" +#include "util/atomic.hpp" +#include "util/StrFmt.h" + +template +concept BitSetEnum = std::is_enum_v && requires(T x) { + T::bitset_last; +}; + +// Atomic bitset specialization with optimized operations +template +class atomic_bs_t : public atomic_t> +{ + // Corresponding bitset type + using bs_t = rx::EnumBitSet; + + // Base class + using base = atomic_t>; + + // Use underlying m_data + using base::m_data; + +public: + // Underlying type + using underlying_type = typename bs_t::underlying_type; + + atomic_bs_t() = default; + + atomic_bs_t(const atomic_bs_t&) = delete; + + atomic_bs_t& operator=(const atomic_bs_t&) = delete; + + explicit constexpr atomic_bs_t(bs_t value) + : base(value) + { + } + + explicit constexpr atomic_bs_t(T bit) + : base(bit) + { + } + + using base::operator bs_t; + + explicit operator bool() const + { + return static_cast(base::load()); + } + + explicit operator underlying_type() const + { + return static_cast(base::load()); + } + + bs_t operator+() const + { + return base::load(); + } + + bs_t fetch_add(const bs_t& rhs) + { + return bs_t::fromUnderlying(atomic_storage::fetch_or(m_data.raw(), rhs.toUnderlying())); + } + + bs_t add_fetch(const bs_t& rhs) + { + return bs_t::fromUnderlying(atomic_storage::or_fetch(m_data.raw(), rhs.toUnderlying())); + } + + bs_t operator+=(const bs_t& rhs) + { + return add_fetch(rhs); + } + + bs_t fetch_sub(const bs_t& rhs) + { + return bs_t::fromUnderlying(atomic_storage::fetch_and(m_data.raw(), ~rhs.toUnderlying())); + } + + bs_t sub_fetch(const bs_t& rhs) + { + return bs_t::fromUnderlying(atomic_storage::and_fetch(m_data.raw(), ~rhs.toUnderlying())); + } + + bs_t operator-=(const bs_t& rhs) + { + return sub_fetch(rhs); + } + + bs_t fetch_and(const bs_t& rhs) + { + return bs_t::fromUnderlying(atomic_storage::fetch_and(m_data.raw(), rhs.toUnderlying())); + } + + bs_t and_fetch(const bs_t& rhs) + { + return bs_t::fromUnderlying(atomic_storage::and_fetch(m_data.raw(), rhs.toUnderlying())); + } + + bs_t operator&=(const bs_t& rhs) + { + return and_fetch(rhs); + } + + bs_t fetch_xor(const bs_t& rhs) + { + return bs_t::fromUnderlying(atomic_storage::fetch_xor(m_data.raw(), rhs.toUnderlying())); + } + + bs_t xor_fetch(const bs_t& rhs) + { + return bs_t::fromUnderlying(atomic_storage::xor_fetch(m_data.raw(), rhs.toUnderlying())); + } + + bs_t operator^=(const bs_t& rhs) + { + return xor_fetch(rhs); + } + + auto fetch_or(const bs_t&) = delete; + auto or_fetch(const bs_t&) = delete; + auto operator|=(const bs_t&) = delete; + + bool test_and_set(T rhs) + { + return atomic_storage::bts(m_data.raw(), static_cast(static_cast(rhs))); + } + + bool test_and_reset(T rhs) + { + return atomic_storage::btr(m_data.raw(), static_cast(static_cast(rhs))); + } + + bool test_and_invert(T rhs) + { + return atomic_storage::btc(m_data.raw(), static_cast(static_cast(rhs))); + } + + bool bit_test_set(uint bit) = delete; + bool bit_test_reset(uint bit) = delete; + bool bit_test_invert(uint bit) = delete; + + bool all_of(bs_t arg) const + { + return base::load().all_of(arg); + } + + bool none_of(bs_t arg) const + { + return base::load().none_of(arg); + } +}; diff --git a/rpcs3/util/bit_set.h b/rpcs3/util/bit_set.h deleted file mode 100644 index 919210175..000000000 --- a/rpcs3/util/bit_set.h +++ /dev/null @@ -1,404 +0,0 @@ -#pragma once - -/* -This header implements bs_t<> class for scoped enum types (enum class). -To enable bs_t<>, enum scope must contain `__bitset_enum_max` entry. - -enum class flagzz : u32 -{ - flag1, // Bit indices start from zero - flag2, - - __bitset_enum_max // It must be the last value -}; - -This also enables helper operators for this enum type. - -Examples: -`+flagzz::flag1` - unary `+` operator convert flagzz value to bs_t -`flagzz::flag1 + flagzz::flag2` - bitset union -`flagzz::flag1 - flagzz::flag2` - bitset difference -Intersection (&) and symmetric difference (^) is also available. -*/ - -#include "util/types.hpp" -#include "util/atomic.hpp" -#include "util/StrFmt.h" - -template -concept BitSetEnum = std::is_enum_v && requires(T x) { - T::__bitset_enum_max; -}; - -template -class atomic_bs_t; - -// Bitset type for enum class with available bits [0, T::__bitset_enum_max) -template -class bs_t final -{ -public: - // Underlying type - using under = std::underlying_type_t; - - ENABLE_BITWISE_SERIALIZATION; - -private: - // Underlying value - under m_data; - - friend class atomic_bs_t; - - // Value constructor - constexpr explicit bs_t(int, under data) noexcept - : m_data(data) - { - } - -public: - static constexpr usz bitmax = sizeof(T) * 8; - static constexpr usz bitsize = static_cast(T::__bitset_enum_max); - - static_assert(std::is_enum_v, "bs_t<> error: invalid type (must be enum)"); - static_assert(bitsize <= bitmax, "bs_t<> error: invalid __bitset_enum_max"); - static_assert(bitsize != bitmax || std::is_unsigned_v, "bs_t<> error: invalid __bitset_enum_max (sign bit)"); - - // Helper function - static constexpr under shift(T value) - { - return static_cast(1) << static_cast(value); - } - - bs_t() = default; - - // Construct from a single bit - constexpr bs_t(T bit) noexcept - : m_data(shift(bit)) - { - } - - // Test for empty bitset - constexpr explicit operator bool() const noexcept - { - return m_data != 0; - } - - // Extract underlying data - constexpr explicit operator under() const noexcept - { - return m_data; - } - - // Copy - constexpr bs_t operator+() const - { - return *this; - } - - constexpr bs_t& operator+=(bs_t rhs) - { - m_data |= static_cast(rhs); - return *this; - } - - constexpr bs_t& operator-=(bs_t rhs) - { - m_data &= ~static_cast(rhs); - return *this; - } - - constexpr bs_t& operator&=(bs_t rhs) - { - m_data &= static_cast(rhs); - return *this; - } - - constexpr bs_t& operator^=(bs_t rhs) - { - m_data ^= static_cast(rhs); - return *this; - } - - friend constexpr bs_t operator+(bs_t lhs, bs_t rhs) - { - return bs_t(0, lhs.m_data | rhs.m_data); - } - - friend constexpr bs_t operator-(bs_t lhs, bs_t rhs) - { - return bs_t(0, lhs.m_data & ~rhs.m_data); - } - - friend constexpr bs_t operator&(bs_t lhs, bs_t rhs) - { - return bs_t(0, lhs.m_data & rhs.m_data); - } - - friend constexpr bs_t operator^(bs_t lhs, bs_t rhs) - { - return bs_t(0, lhs.m_data ^ rhs.m_data); - } - - constexpr bool operator==(bs_t rhs) const noexcept - { - return m_data == rhs.m_data; - } - - constexpr bool test_and_set(T bit) - { - bool r = (m_data & shift(bit)) != 0; - m_data |= shift(bit); - return r; - } - - constexpr bool test_and_reset(T bit) - { - bool r = (m_data & shift(bit)) != 0; - m_data &= ~shift(bit); - return r; - } - - constexpr bool test_and_complement(T bit) - { - bool r = (m_data & shift(bit)) != 0; - m_data ^= shift(bit); - return r; - } - - constexpr bool all_of(bs_t arg) const - { - return (m_data & arg.m_data) == arg.m_data; - } - - constexpr bool none_of(bs_t arg) const - { - return (m_data & arg.m_data) == 0; - } -}; - -// Unary '+' operator: promote plain enum value to bitset value -template -constexpr bs_t operator+(T bit) -{ - return bs_t(bit); -} - -// Binary '+' operator: bitset union -template - requires(std::is_constructible_v, U>) -constexpr bs_t operator+(T lhs, const U& rhs) -{ - return bs_t(lhs) + bs_t(rhs); -} - -// Binary '+' operator: bitset union -template - requires(std::is_constructible_v, U> && !std::is_enum_v) -constexpr bs_t operator+(const U& lhs, T rhs) -{ - return bs_t(lhs) + bs_t(rhs); -} - -// Binary '-' operator: bitset difference -template - requires(std::is_constructible_v, U>) -constexpr bs_t operator-(T lhs, const U& rhs) -{ - return bs_t(lhs) - bs_t(rhs); -} - -// Binary '-' operator: bitset difference -template - requires(std::is_constructible_v, U> && !std::is_enum_v) -constexpr bs_t operator-(const U& lhs, T rhs) -{ - return bs_t(lhs) - bs_t(rhs); -} - -// Binary '&' operator: bitset intersection -template - requires(std::is_constructible_v, U>) -constexpr bs_t operator&(T lhs, const U& rhs) -{ - return bs_t(lhs) & bs_t(rhs); -} - -// Binary '&' operator: bitset intersection -template - requires(std::is_constructible_v, U> && !std::is_enum_v) -constexpr bs_t operator&(const U& lhs, T rhs) -{ - return bs_t(lhs) & bs_t(rhs); -} - -// Binary '^' operator: bitset symmetric difference -template - requires(std::is_constructible_v, U>) -constexpr bs_t operator^(T lhs, const U& rhs) -{ - return bs_t(lhs) ^ bs_t(rhs); -} - -// Binary '^' operator: bitset symmetric difference -template - requires(std::is_constructible_v, U> && !std::is_enum_v) -constexpr bs_t operator^(const U& lhs, T rhs) -{ - return bs_t(lhs) ^ bs_t(rhs); -} - -// Atomic bitset specialization with optimized operations -template -class atomic_bs_t : public atomic_t<::bs_t> -{ - // Corresponding bitset type - using bs_t = ::bs_t; - - // Base class - using base = atomic_t<::bs_t>; - - // Use underlying m_data - using base::m_data; - -public: - // Underlying type - using under = typename bs_t::under; - - atomic_bs_t() = default; - - atomic_bs_t(const atomic_bs_t&) = delete; - - atomic_bs_t& operator=(const atomic_bs_t&) = delete; - - explicit constexpr atomic_bs_t(bs_t value) - : base(value) - { - } - - explicit constexpr atomic_bs_t(T bit) - : base(bit) - { - } - - using base::operator bs_t; - - explicit operator bool() const - { - return static_cast(base::load()); - } - - explicit operator under() const - { - return static_cast(base::load()); - } - - bs_t operator+() const - { - return base::load(); - } - - bs_t fetch_add(const bs_t& rhs) - { - return bs_t(0, atomic_storage::fetch_or(m_data.m_data, rhs.m_data)); - } - - bs_t add_fetch(const bs_t& rhs) - { - return bs_t(0, atomic_storage::or_fetch(m_data.m_data, rhs.m_data)); - } - - bs_t operator+=(const bs_t& rhs) - { - return add_fetch(rhs); - } - - bs_t fetch_sub(const bs_t& rhs) - { - return bs_t(0, atomic_storage::fetch_and(m_data.m_data, ~rhs.m_data)); - } - - bs_t sub_fetch(const bs_t& rhs) - { - return bs_t(0, atomic_storage::and_fetch(m_data.m_data, ~rhs.m_data)); - } - - bs_t operator-=(const bs_t& rhs) - { - return sub_fetch(rhs); - } - - bs_t fetch_and(const bs_t& rhs) - { - return bs_t(0, atomic_storage::fetch_and(m_data.m_data, rhs.m_data)); - } - - bs_t and_fetch(const bs_t& rhs) - { - return bs_t(0, atomic_storage::and_fetch(m_data.m_data, rhs.m_data)); - } - - bs_t operator&=(const bs_t& rhs) - { - return and_fetch(rhs); - } - - bs_t fetch_xor(const bs_t& rhs) - { - return bs_t(0, atomic_storage::fetch_xor(m_data.m_data, rhs.m_data)); - } - - bs_t xor_fetch(const bs_t& rhs) - { - return bs_t(0, atomic_storage::xor_fetch(m_data.m_data, rhs.m_data)); - } - - bs_t operator^=(const bs_t& rhs) - { - return xor_fetch(rhs); - } - - auto fetch_or(const bs_t&) = delete; - auto or_fetch(const bs_t&) = delete; - auto operator|=(const bs_t&) = delete; - - bool test_and_set(T rhs) - { - return atomic_storage::bts(m_data.m_data, static_cast(static_cast(rhs))); - } - - bool test_and_reset(T rhs) - { - return atomic_storage::btr(m_data.m_data, static_cast(static_cast(rhs))); - } - - bool test_and_invert(T rhs) - { - return atomic_storage::btc(m_data.m_data, static_cast(static_cast(rhs))); - } - - bool bit_test_set(uint bit) = delete; - bool bit_test_reset(uint bit) = delete; - bool bit_test_invert(uint bit) = delete; - - bool all_of(bs_t arg) const - { - return base::load().all_of(arg); - } - - bool none_of(bs_t arg) const - { - return base::load().none_of(arg); - } -}; - -template -struct fmt_unveil> -{ - // Format as is - using type = bs_t; - - static inline u64 get(const bs_t& bitset) - { - return static_cast>(bitset); - } -}; diff --git a/rx/include/rx/BitSet.h b/rx/include/rx/BitSet.h deleted file mode 100644 index 55fe47ab1..000000000 --- a/rx/include/rx/BitSet.h +++ /dev/null @@ -1,268 +0,0 @@ -#pragma once - -/* -This header implements bs_t<> class for scoped enum types (enum class). -To enable bs_t<>, enum scope must contain `__bitset_enum_max` entry. - -enum class flagzz : u32 -{ - flag1, // Bit indices start from zero - flag2, -}; - -This also enables helper operators for this enum type. - -Examples: -`flagzz::flag1 | flagzz::flag2` - bitset union -`flagzz::flag1 & ~flagzz::flag2` - bitset difference -Intersection (&) and symmetric difference (^) is also available. -*/ - -#include "refl.hpp" -#include "types.hpp" - -namespace rx { -template -concept BitSetEnum = - std::is_enum_v && requires(T x) { rx::fieldCount > 0; }; - -template class BitSet; - -namespace detail { -template class InvertedBitSet final { - using underlying_type = std::underlying_type_t; - underlying_type m_data; - constexpr InvertedBitSet(underlying_type data) : m_data(data) {} - friend BitSet; -}; -} // namespace detail - -// Bitset type for enum class with available bits [0, fieldCount) -template class BitSet final { -public: - // Underlying type - using underlying_type = std::underlying_type_t; - -private: - // Underlying value - underlying_type m_data; - - // Value constructor - constexpr explicit BitSet(int, underlying_type data) noexcept - : m_data(data) {} - -public: - static constexpr usz bitmax = sizeof(T) * 8; - static constexpr usz bitsize = - static_cast(rx::fieldCount); - - static_assert(std::is_enum_v, - "BitSet<> error: invalid type (must be enum)"); - static_assert(bitsize <= bitmax, - "BitSet<> error: failed to determine enum field count"); - static_assert(bitsize != bitmax || std::is_unsigned_v, - "BitSet<> error: invalid field count (sign bit)"); - - // Helper function - static constexpr underlying_type shift(T value) { - return static_cast(1) - << static_cast(value); - } - - BitSet() = default; - - // Construct from a single bit - constexpr BitSet(T bit) noexcept : m_data(shift(bit)) {} - - // Test for empty bitset - constexpr explicit operator bool() const noexcept { return m_data != 0; } - - // Extract underlying data - constexpr explicit operator underlying_type() const noexcept { - return m_data; - } - - constexpr detail::InvertedBitSet operator~() const { return {m_data}; } - - constexpr BitSet &operator+=(BitSet rhs) { - m_data |= static_cast(rhs); - return *this; - } - - constexpr BitSet &operator-=(BitSet rhs) { - m_data &= ~static_cast(rhs); - return *this; - } - - constexpr BitSet without(BitSet rhs) const { - BitSet result = *this; - result.m_data &= ~static_cast(rhs); - return result; - } - - constexpr BitSet with(BitSet rhs) const { - BitSet result = *this; - result.m_data |= static_cast(rhs); - return result; - } - - constexpr BitSet &operator&=(BitSet rhs) { - m_data &= static_cast(rhs); - return *this; - } - - constexpr BitSet &operator^=(BitSet rhs) { - m_data ^= static_cast(rhs); - return *this; - } - - [[deprecated("Use operator|")]] friend constexpr BitSet - operator+(BitSet lhs, BitSet rhs) { - return BitSet(0, lhs.m_data | rhs.m_data); - } - - friend constexpr BitSet operator-(BitSet lhs, BitSet rhs) { - return BitSet(0, lhs.m_data & ~rhs.m_data); - } - - friend constexpr BitSet operator|(BitSet lhs, BitSet rhs) { - return BitSet(0, lhs.m_data | rhs.m_data); - } - - friend constexpr BitSet operator&(BitSet lhs, BitSet rhs) { - return BitSet(0, lhs.m_data & rhs.m_data); - } - - friend constexpr BitSet operator&(BitSet lhs, detail::InvertedBitSet rhs) { - return BitSet(0, lhs.m_data & rhs.m_data); - } - - friend constexpr BitSet operator^(BitSet lhs, BitSet rhs) { - return BitSet(0, lhs.m_data ^ rhs.m_data); - } - - constexpr bool operator==(BitSet rhs) const noexcept { - return m_data == rhs.m_data; - } - - constexpr bool test_and_set(T bit) { - bool r = (m_data & shift(bit)) != 0; - m_data |= shift(bit); - return r; - } - - constexpr bool test_and_reset(T bit) { - bool r = (m_data & shift(bit)) != 0; - m_data &= ~shift(bit); - return r; - } - - constexpr bool test_and_complement(T bit) { - bool r = (m_data & shift(bit)) != 0; - m_data ^= shift(bit); - return r; - } - - constexpr bool any_of(BitSet arg) const { return (m_data & arg.m_data) != 0; } - - constexpr bool all_of(BitSet arg) const { - return (m_data & arg.m_data) == arg.m_data; - } - - constexpr bool none_of(BitSet arg) const { - return (m_data & arg.m_data) == 0; - } -}; - -namespace bitset { -// Unary '+' operator: promote plain enum value to bitset value -template -[[deprecated("Use toBitSet(bit)")]] constexpr BitSet operator+(T bit) { - return BitSet(bit); -} - -template constexpr BitSet toBitSet(T bit) { - return BitSet(bit); -} - -// Binary '+' operator: bitset union -template - requires(std::is_constructible_v, U>) -[[deprecated("Use operator|")]] constexpr BitSet operator+(T lhs, - const U &rhs) { - return BitSet(lhs) | BitSet(rhs); -} - -// Binary '+' operator: bitset union -template - requires(std::is_constructible_v, U> && !std::is_enum_v) -[[deprecated("Use operator|")]] constexpr BitSet operator+(const U &lhs, - T rhs) { - return BitSet(lhs) | BitSet(rhs); -} - -// Binary '|' operator: bitset union -template - requires(std::is_constructible_v, U>) -constexpr BitSet operator|(T lhs, const U &rhs) { - return BitSet(lhs) | BitSet(rhs); -} - -// Binary '|' operator: bitset union -template - requires(std::is_constructible_v, U> && !std::is_enum_v) -constexpr BitSet operator|(const U &lhs, T rhs) { - return BitSet(lhs) | BitSet(rhs); -} - -// Binary '-' operator: bitset difference -template - requires(std::is_constructible_v, U>) -constexpr BitSet operator-(T lhs, const U &rhs) { - return BitSet(lhs) - BitSet(rhs); -} - -// Binary '-' operator: bitset difference -template - requires(std::is_constructible_v, U> && !std::is_enum_v) -constexpr BitSet operator-(const U &lhs, T rhs) { - return BitSet(lhs) - BitSet(rhs); -} - -// Binary '&' operator: bitset intersection -template - requires(std::is_constructible_v, U>) -constexpr BitSet operator&(T lhs, const U &rhs) { - return BitSet(lhs) & BitSet(rhs); -} - -// Binary '&' operator: bitset intersection -template - requires(std::is_constructible_v, U> && !std::is_enum_v) -constexpr BitSet operator&(const U &lhs, T rhs) { - return BitSet(lhs) & BitSet(rhs); -} - -// Binary '&' operator: bitset intersection -template -constexpr BitSet operator&(T lhs, detail::InvertedBitSet rhs) { - return BitSet(lhs) & rhs; -} - -// Binary '^' operator: bitset symmetric difference -template - requires(std::is_constructible_v, U>) -constexpr BitSet operator^(T lhs, const U &rhs) { - return BitSet(lhs) ^ BitSet(rhs); -} - -// Binary '^' operator: bitset symmetric difference -template - requires(std::is_constructible_v, U> && !std::is_enum_v) -constexpr BitSet operator^(const U &lhs, T rhs) { - return BitSet(lhs) ^ BitSet(rhs); -} -} // namespace bitset -} // namespace rx - -using namespace rx::bitset; diff --git a/rx/include/rx/EnumBitSet.hpp b/rx/include/rx/EnumBitSet.hpp new file mode 100644 index 000000000..e98e6dba6 --- /dev/null +++ b/rx/include/rx/EnumBitSet.hpp @@ -0,0 +1,287 @@ +#pragma once + +/* +This header implements EnumBitSet<> class for scoped enum types (enum class). +To enable EnumBitSet<>, enum scope must contain `bitset_last` entry. + +enum class flagzz : u32 +{ + flag1, // Bit indices start from zero + flag2, + + bitset_last = flag2 +}; + +This also enables helper operators for this enum type. + +Examples: +`flagzz::flag1 | flagzz::flag2` - bitset union +`flagzz::flag1 & ~flagzz::flag2` - bitset difference +Intersection (&) and symmetric difference (^) is also available. +*/ + +#include "types.hpp" + +namespace rx { +template +concept BitSetEnum = std::is_enum_v && requires { T::bitset_last; }; + +template class EnumBitSet; + +namespace detail { +template class InvertedEnumBitSet final { + using underlying_type = std::underlying_type_t; + underlying_type m_data; + constexpr InvertedEnumBitSet(underlying_type data) : m_data(data) {} + friend EnumBitSet; +}; +} // namespace detail + +// Bitset type for enum class with available bits [0, fieldCount) +template class EnumBitSet final { +public: + // Underlying type + using underlying_type = std::underlying_type_t; + +private: + // Underlying value + underlying_type m_data; + + // Value constructor + constexpr explicit EnumBitSet(int, underlying_type data) noexcept + : m_data(data) {} + +public: + static constexpr usz bitmax = sizeof(T) * 8; + static constexpr usz bitsize = + static_cast(T::bitset_last) + 1; + + static_assert(std::is_enum_v, + "BitSet<> error: invalid type (must be enum)"); + static_assert(bitsize <= bitmax, + "BitSet<> error: failed to determine enum field count"); + static_assert(bitsize != bitmax || std::is_unsigned_v, + "BitSet<> error: invalid field count (sign bit)"); + + // Helper function + static constexpr underlying_type shift(T value) { + return static_cast(1) + << static_cast(value); + } + + EnumBitSet() = default; + + // Construct from a single bit + constexpr EnumBitSet(T bit) noexcept : m_data(shift(bit)) {} + + [[nodiscard]] constexpr underlying_type toUnderlying() const { + return m_data; + } + + [[nodiscard]] static constexpr EnumBitSet + fromUnderlying(underlying_type raw) { + return EnumBitSet(0, raw); + } + + // Test for empty bitset + constexpr explicit operator bool() const noexcept { return m_data != 0; } + + // Extract underlying data + constexpr explicit operator underlying_type() const noexcept { + return m_data; + } + + constexpr detail::InvertedEnumBitSet operator~() const { return {m_data}; } + + [[deprecated("Use operator|=")]] constexpr EnumBitSet & + operator+=(EnumBitSet rhs) { + m_data |= static_cast(rhs); + return *this; + } + + constexpr EnumBitSet &operator|=(EnumBitSet rhs) { + m_data |= static_cast(rhs); + return *this; + } + + constexpr EnumBitSet &operator-=(EnumBitSet rhs) { + m_data &= ~static_cast(rhs); + return *this; + } + + constexpr EnumBitSet without(EnumBitSet rhs) const { + EnumBitSet result = *this; + result.m_data &= ~static_cast(rhs); + return result; + } + + constexpr EnumBitSet with(EnumBitSet rhs) const { + EnumBitSet result = *this; + result.m_data |= static_cast(rhs); + return result; + } + + constexpr EnumBitSet &operator&=(EnumBitSet rhs) { + m_data &= static_cast(rhs); + return *this; + } + + constexpr EnumBitSet &operator^=(EnumBitSet rhs) { + m_data ^= static_cast(rhs); + return *this; + } + + [[deprecated("Use operator|")]] friend constexpr EnumBitSet + operator+(EnumBitSet lhs, EnumBitSet rhs) { + return EnumBitSet(0, lhs.m_data | rhs.m_data); + } + + friend constexpr EnumBitSet operator-(EnumBitSet lhs, EnumBitSet rhs) { + return EnumBitSet(0, lhs.m_data & ~rhs.m_data); + } + + friend constexpr EnumBitSet operator|(EnumBitSet lhs, EnumBitSet rhs) { + return EnumBitSet(0, lhs.m_data | rhs.m_data); + } + + friend constexpr EnumBitSet operator&(EnumBitSet lhs, EnumBitSet rhs) { + return EnumBitSet(0, lhs.m_data & rhs.m_data); + } + + friend constexpr EnumBitSet operator&(EnumBitSet lhs, + detail::InvertedEnumBitSet rhs) { + return EnumBitSet(0, lhs.m_data & rhs.m_data); + } + + friend constexpr EnumBitSet operator^(EnumBitSet lhs, EnumBitSet rhs) { + return EnumBitSet(0, lhs.m_data ^ rhs.m_data); + } + + constexpr bool operator==(EnumBitSet rhs) const noexcept { + return m_data == rhs.m_data; + } + + constexpr bool test_and_set(T bit) { + bool r = (m_data & shift(bit)) != 0; + m_data |= shift(bit); + return r; + } + + constexpr bool test_and_reset(T bit) { + bool r = (m_data & shift(bit)) != 0; + m_data &= ~shift(bit); + return r; + } + + constexpr bool test_and_complement(T bit) { + bool r = (m_data & shift(bit)) != 0; + m_data ^= shift(bit); + return r; + } + + constexpr bool any_of(EnumBitSet arg) const { + return (m_data & arg.m_data) != 0; + } + + constexpr bool all_of(EnumBitSet arg) const { + return (m_data & arg.m_data) == arg.m_data; + } + + constexpr bool none_of(EnumBitSet arg) const { + return (m_data & arg.m_data) == 0; + } + + underlying_type &raw() { return m_data; } +}; + +template constexpr EnumBitSet toBitSet(T bit) { + return EnumBitSet(bit); +} + +namespace bitset { +// Unary '+' operator: promote plain enum value to bitset value +template +[[deprecated("Use toBitSet(bit)")]] constexpr EnumBitSet operator+(T bit) { + return EnumBitSet(bit); +} +// Binary '+' operator: bitset union +template + requires(std::is_constructible_v, U>) +[[deprecated("Use operator|")]] constexpr EnumBitSet +operator+(T lhs, const U &rhs) { + return EnumBitSet(lhs) | EnumBitSet(rhs); +} + +// Binary '+' operator: bitset union +template + requires(std::is_constructible_v, U> && !std::is_enum_v) +[[deprecated("Use operator|")]] constexpr EnumBitSet operator+(const U &lhs, + T rhs) { + return EnumBitSet(lhs) | EnumBitSet(rhs); +} + +// Binary '|' operator: bitset union +template + requires(std::is_constructible_v, U>) +constexpr EnumBitSet operator|(T lhs, const U &rhs) { + return EnumBitSet(lhs) | EnumBitSet(rhs); +} + +// Binary '|' operator: bitset union +template + requires(std::is_constructible_v, U> && !std::is_enum_v) +constexpr EnumBitSet operator|(const U &lhs, T rhs) { + return EnumBitSet(lhs) | EnumBitSet(rhs); +} + +// Binary '-' operator: bitset difference +template + requires(std::is_constructible_v, U>) +constexpr EnumBitSet operator-(T lhs, const U &rhs) { + return EnumBitSet(lhs) - EnumBitSet(rhs); +} + +// Binary '-' operator: bitset difference +template + requires(std::is_constructible_v, U> && !std::is_enum_v) +constexpr EnumBitSet operator-(const U &lhs, T rhs) { + return EnumBitSet(lhs) - EnumBitSet(rhs); +} + +// Binary '&' operator: bitset intersection +template + requires(std::is_constructible_v, U>) +constexpr EnumBitSet operator&(T lhs, const U &rhs) { + return EnumBitSet(lhs) & EnumBitSet(rhs); +} + +// Binary '&' operator: bitset intersection +template + requires(std::is_constructible_v, U> && !std::is_enum_v) +constexpr EnumBitSet operator&(const U &lhs, T rhs) { + return EnumBitSet(lhs) & EnumBitSet(rhs); +} + +// Binary '&' operator: bitset intersection +template +constexpr EnumBitSet operator&(T lhs, detail::InvertedEnumBitSet rhs) { + return EnumBitSet(lhs) & rhs; +} + +// Binary '^' operator: bitset symmetric difference +template + requires(std::is_constructible_v, U>) +constexpr EnumBitSet operator^(T lhs, const U &rhs) { + return EnumBitSet(lhs) ^ EnumBitSet(rhs); +} + +// Binary '^' operator: bitset symmetric difference +template + requires(std::is_constructible_v, U> && !std::is_enum_v) +constexpr EnumBitSet operator^(const U &lhs, T rhs) { + return EnumBitSet(lhs) ^ EnumBitSet(rhs); +} +} // namespace bitset +} // namespace rx + +using namespace rx::bitset;