Harden bitset access
This commit is contained in:
@@ -2,7 +2,6 @@
|
||||
#include "Emu/System.h"
|
||||
#include "Emu/Cell/PPUModule.h"
|
||||
|
||||
#include <bitset>
|
||||
#include "cellPamf.h"
|
||||
|
||||
LOG_CHANNEL(cellPamf);
|
||||
@@ -500,7 +499,7 @@ error_code pamfVerify(vm::cptr<PamfHeader> pAddr, u64 fileSize, vm::ptr<CellPamf
|
||||
|
||||
const auto streams = &pAddr->seq_info.grouping_periods.groups.streams;
|
||||
|
||||
std::bitset<16> channels_used[6]{};
|
||||
std::array<bit_set<16>, 6> channels_used{};
|
||||
|
||||
u32 end_of_streams_addr = 0;
|
||||
u32 next_ep_table_addr = 0;
|
||||
@@ -516,14 +515,16 @@ error_code pamfVerify(vm::cptr<PamfHeader> pAddr, u64 fileSize, vm::ptr<CellPamf
|
||||
return CELL_PAMF_ERROR_UNKNOWN_STREAM;
|
||||
}
|
||||
|
||||
bit_set<16>& used_channels = ::at32(channels_used, *type);
|
||||
|
||||
// Every channel may only be used once per type
|
||||
if (channels_used[*type].test(*ch))
|
||||
if (used_channels.test(*ch))
|
||||
{
|
||||
return { CELL_PAMF_ERROR_INVALID_PAMF, "pamfVerify() failed: invalid channel" };
|
||||
}
|
||||
|
||||
// Mark channel as used
|
||||
channels_used[*type].set(*ch);
|
||||
used_channels.set(*ch, true);
|
||||
|
||||
const u32 ep_offset = streams[stream_idx].ep_offset;
|
||||
const u32 ep_num = streams[stream_idx].ep_num;
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#include "stdafx.h"
|
||||
|
||||
#include <bitset>
|
||||
#include <string>
|
||||
|
||||
#include "cellSsl.h"
|
||||
@@ -92,7 +91,7 @@ std::string getCert(const std::string& certPath, const int certID, const bool is
|
||||
newID = certID - 1;
|
||||
}
|
||||
|
||||
std::string filePath = fmt::format("%sCA%02d.cer", certPath, newID);
|
||||
const std::string filePath = fmt::format("%sCA%02d.cer", certPath, newID);
|
||||
|
||||
if (!fs::exists(filePath))
|
||||
{
|
||||
@@ -106,7 +105,7 @@ error_code cellSslCertificateLoader(u64 flag, vm::ptr<char> buffer, u32 size, vm
|
||||
{
|
||||
cellSsl.trace("cellSslCertificateLoader(flag=%llu, buffer=*0x%x, size=%zu, required=*0x%x)", flag, buffer, size, required);
|
||||
|
||||
const std::bitset<58> flagBits(flag);
|
||||
const bit_set<58> flagBits(flag);
|
||||
const std::string certPath = vfs::get("/dev_flash/data/cert/");
|
||||
|
||||
if (required)
|
||||
@@ -114,10 +113,11 @@ error_code cellSslCertificateLoader(u64 flag, vm::ptr<char> buffer, u32 size, vm
|
||||
*required = 0;
|
||||
for (uint i = 1; i <= flagBits.size(); i++)
|
||||
{
|
||||
if (!flagBits[i-1])
|
||||
if (!flagBits.test(i - 1))
|
||||
continue;
|
||||
|
||||
// If we're loading cert 6 (the baltimore cert), then we need set that we're loading the 'normal' set of certs.
|
||||
*required += ::size32(getCert(certPath, i, flagBits[BaltimoreCert-1]));
|
||||
*required += ::size32(getCert(certPath, i, flagBits.test(BaltimoreCert - 1)));
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -125,14 +125,15 @@ error_code cellSslCertificateLoader(u64 flag, vm::ptr<char> buffer, u32 size, vm
|
||||
std::string final;
|
||||
for (uint i = 1; i <= flagBits.size(); i++)
|
||||
{
|
||||
if (!flagBits[i-1])
|
||||
if (!flagBits.test(i - 1))
|
||||
continue;
|
||||
|
||||
// If we're loading cert 6 (the baltimore cert), then we need set that we're loading the 'normal' set of certs.
|
||||
final.append(getCert(certPath, i, flagBits[BaltimoreCert-1]));
|
||||
final.append(getCert(certPath, i, flagBits.test(BaltimoreCert - 1)));
|
||||
}
|
||||
|
||||
memset(buffer.get_ptr(), '\0', size - 1);
|
||||
memcpy(buffer.get_ptr(), final.c_str(), final.size());
|
||||
std::memset(buffer.get_ptr(), '\0', size - 1);
|
||||
std::memcpy(buffer.get_ptr(), final.c_str(), final.size());
|
||||
}
|
||||
|
||||
return CELL_OK;
|
||||
|
||||
@@ -2905,7 +2905,7 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
||||
// Check for redundancy
|
||||
if (!m_block_info[target / 4])
|
||||
{
|
||||
m_block_info[target / 4] = true;
|
||||
m_block_info.set(target / 4, true);
|
||||
workload.push_back(target);
|
||||
}
|
||||
|
||||
@@ -3080,7 +3080,7 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
||||
}
|
||||
else
|
||||
{
|
||||
m_entry_info[target / 4] = true;
|
||||
m_entry_info.set(target / 4, true);
|
||||
add_block(target);
|
||||
}
|
||||
}
|
||||
@@ -3091,8 +3091,8 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
||||
|
||||
if (!is_no_return && sl && g_cfg.core.spu_block_size != spu_block_size_type::safe)
|
||||
{
|
||||
m_ret_info[pos / 4 + 1] = true;
|
||||
m_entry_info[pos / 4 + 1] = true;
|
||||
m_ret_info.set(pos / 4 + 1, true);
|
||||
m_entry_info.set(pos / 4 + 1, true);
|
||||
m_targets[pos].push_back(pos + 4);
|
||||
add_block(pos + 4);
|
||||
}
|
||||
@@ -3307,8 +3307,8 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
||||
}
|
||||
else
|
||||
{
|
||||
m_ret_info[pos / 4 + 1] = true;
|
||||
m_entry_info[pos / 4 + 1] = true;
|
||||
m_ret_info.set(pos / 4 + 1, true);
|
||||
m_entry_info.set(pos / 4 + 1, true);
|
||||
m_targets[pos].push_back(pos + 4);
|
||||
add_block(pos + 4);
|
||||
}
|
||||
@@ -3375,15 +3375,15 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
||||
|
||||
if (!is_no_return && g_cfg.core.spu_block_size != spu_block_size_type::safe)
|
||||
{
|
||||
m_ret_info[pos / 4 + 1] = true;
|
||||
m_entry_info[pos / 4 + 1] = true;
|
||||
m_ret_info.set(pos / 4 + 1, true);
|
||||
m_entry_info.set(pos / 4 + 1, true);
|
||||
m_targets[pos].push_back(pos + 4);
|
||||
add_block(pos + 4);
|
||||
}
|
||||
|
||||
if (!is_no_return && g_cfg.core.spu_block_size == spu_block_size_type::giga && !sync)
|
||||
{
|
||||
m_entry_info[target / 4] = true;
|
||||
m_entry_info.set(target / 4, true);
|
||||
add_block(target);
|
||||
}
|
||||
else
|
||||
@@ -3409,7 +3409,7 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
||||
|
||||
if (g_cfg.core.spu_block_size == spu_block_size_type::giga && !sync)
|
||||
{
|
||||
m_entry_info[target / 4] = true;
|
||||
m_entry_info.set(target / 4, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -3714,7 +3714,7 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
||||
|
||||
// Bit array used to deduplicate workload list
|
||||
workload.push_back(pair.first);
|
||||
m_bits[pair.first / 4] = true;
|
||||
m_bits.set(pair.first / 4, true);
|
||||
|
||||
for (usz i = 0; !reachable && i < workload.size(); i++)
|
||||
{
|
||||
@@ -3746,7 +3746,7 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
||||
if (new_pred >= lsa && new_pred < limit && !m_bits[new_pred / 4])
|
||||
{
|
||||
workload.push_back(new_pred);
|
||||
m_bits[new_pred / 4] = true;
|
||||
m_bits.set(new_pred / 4, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3769,7 +3769,7 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
||||
|
||||
for (u32 pred : workload)
|
||||
{
|
||||
m_bits[pred / 4] = false;
|
||||
m_bits.set(pred / 4, false);
|
||||
}
|
||||
|
||||
if (!reachable && pair.first < limit)
|
||||
@@ -3828,9 +3828,9 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
||||
|
||||
if (addr < lsa || addr >= limit || !result.data[(addr - lsa) / 4])
|
||||
{
|
||||
m_block_info[addr / 4] = false;
|
||||
m_entry_info[addr / 4] = false;
|
||||
m_ret_info[addr / 4] = false;
|
||||
m_block_info.set(addr / 4, false);
|
||||
m_entry_info.set(addr / 4, false);
|
||||
m_ret_info.set(addr / 4, false);
|
||||
m_preds.erase(addr);
|
||||
}
|
||||
}
|
||||
@@ -3856,7 +3856,7 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
||||
if (it->second.empty() && !m_entry_info[it->first / 4])
|
||||
{
|
||||
// If not an entry point, remove the block completely
|
||||
m_block_info[it->first / 4] = false;
|
||||
m_block_info.set(it->first / 4, false);
|
||||
it = m_preds.erase(it);
|
||||
continue;
|
||||
}
|
||||
@@ -3964,7 +3964,7 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
||||
if (type == spu_itype::STQD && op.ra == s_reg_sp && !block.reg_mod[op.rt] && !block.reg_use[op.rt])
|
||||
{
|
||||
// Register saved onto the stack before use
|
||||
block.reg_save_dom[op.rt] = true;
|
||||
block.reg_save_dom.set(op.rt, true);
|
||||
|
||||
reg_save = op.rt;
|
||||
}
|
||||
@@ -3994,7 +3994,7 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
||||
if (reg_save != reg && block.reg_save_dom[reg])
|
||||
{
|
||||
// Register is still used after saving; probably not eligible for optimization
|
||||
block.reg_save_dom[reg] = false;
|
||||
block.reg_save_dom.set(reg, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4065,7 +4065,7 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
||||
if (!is_tail)
|
||||
{
|
||||
block.reg_mod.set(i);
|
||||
block.reg_mod_xf[i] = false;
|
||||
block.reg_mod_xf.set(i, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4106,8 +4106,8 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
||||
{
|
||||
const u32 addr = emp.first->first;
|
||||
spu_log.error("[0x%05x] Fixed first function at 0x%05x", entry_point, addr);
|
||||
m_entry_info[addr / 4] = true;
|
||||
m_ret_info[addr / 4] = false;
|
||||
m_entry_info.set(addr / 4, true);
|
||||
m_ret_info.set(addr / 4, false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4146,9 +4146,9 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
||||
if (!m_entry_info[target / 4] || m_ret_info[target / 4])
|
||||
{
|
||||
// Create new function entry (likely a tail call)
|
||||
m_entry_info[target / 4] = true;
|
||||
m_entry_info.set(target / 4, true);
|
||||
|
||||
m_ret_info[target / 4] = false;
|
||||
m_ret_info.set(target / 4, false);
|
||||
|
||||
m_funcs.try_emplace(target);
|
||||
|
||||
@@ -4246,10 +4246,10 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
||||
|
||||
for (u32 entry : new_entries)
|
||||
{
|
||||
m_entry_info[entry / 4] = true;
|
||||
m_entry_info.set(entry / 4, true);
|
||||
|
||||
// Acknowledge artificial (reversible) chunk entry point
|
||||
m_ret_info[entry / 4] = true;
|
||||
m_ret_info.set(entry / 4, true);
|
||||
}
|
||||
|
||||
for (auto& bb : m_bbs)
|
||||
@@ -4435,7 +4435,7 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
||||
if (orig < 0x40000)
|
||||
{
|
||||
auto& src = ::at32(m_bbs, orig);
|
||||
bb.reg_const[i] = src.reg_const[i];
|
||||
bb.reg_const.set(i, src.reg_const[i]);
|
||||
bb.reg_val32[i] = src.reg_val32[i];
|
||||
}
|
||||
|
||||
@@ -4474,25 +4474,25 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
||||
{
|
||||
case spu_itype::IL:
|
||||
{
|
||||
bb.reg_const[op.rt] = true;
|
||||
bb.reg_const.set(op.rt, true);
|
||||
bb.reg_val32[op.rt] = op.si16;
|
||||
break;
|
||||
}
|
||||
case spu_itype::ILA:
|
||||
{
|
||||
bb.reg_const[op.rt] = true;
|
||||
bb.reg_const.set(op.rt, true);
|
||||
bb.reg_val32[op.rt] = op.i18;
|
||||
break;
|
||||
}
|
||||
case spu_itype::ILHU:
|
||||
{
|
||||
bb.reg_const[op.rt] = true;
|
||||
bb.reg_const.set(op.rt, true);
|
||||
bb.reg_val32[op.rt] = op.i16 << 16;
|
||||
break;
|
||||
}
|
||||
case spu_itype::ILH:
|
||||
{
|
||||
bb.reg_const[op.rt] = true;
|
||||
bb.reg_const.set(op.rt, true);
|
||||
bb.reg_val32[op.rt] = op.i16 << 16 | op.i16;
|
||||
break;
|
||||
}
|
||||
@@ -4503,37 +4503,37 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
||||
}
|
||||
case spu_itype::ORI:
|
||||
{
|
||||
bb.reg_const[op.rt] = bb.reg_const[op.ra];
|
||||
bb.reg_const.set(op.rt, bb.reg_const[op.ra]);
|
||||
bb.reg_val32[op.rt] = bb.reg_val32[op.ra] | op.si10;
|
||||
break;
|
||||
}
|
||||
case spu_itype::OR:
|
||||
{
|
||||
bb.reg_const[op.rt] = bb.reg_const[op.ra] && bb.reg_const[op.rb];
|
||||
bb.reg_const.set(op.rt, bb.reg_const[op.ra] && bb.reg_const[op.rb]);
|
||||
bb.reg_val32[op.rt] = bb.reg_val32[op.ra] | bb.reg_val32[op.rb];
|
||||
break;
|
||||
}
|
||||
case spu_itype::AI:
|
||||
{
|
||||
bb.reg_const[op.rt] = bb.reg_const[op.ra];
|
||||
bb.reg_const.set(op.rt, bb.reg_const[op.ra]);
|
||||
bb.reg_val32[op.rt] = bb.reg_val32[op.ra] + op.si10;
|
||||
break;
|
||||
}
|
||||
case spu_itype::A:
|
||||
{
|
||||
bb.reg_const[op.rt] = bb.reg_const[op.ra] && bb.reg_const[op.rb];
|
||||
bb.reg_const.set(op.rt, bb.reg_const[op.ra] && bb.reg_const[op.rb]);
|
||||
bb.reg_val32[op.rt] = bb.reg_val32[op.ra] + bb.reg_val32[op.rb];
|
||||
break;
|
||||
}
|
||||
case spu_itype::SFI:
|
||||
{
|
||||
bb.reg_const[op.rt] = bb.reg_const[op.ra];
|
||||
bb.reg_const.set(op.rt, bb.reg_const[op.ra]);
|
||||
bb.reg_val32[op.rt] = op.si10 - bb.reg_val32[op.ra];
|
||||
break;
|
||||
}
|
||||
case spu_itype::SF:
|
||||
{
|
||||
bb.reg_const[op.rt] = bb.reg_const[op.ra] && bb.reg_const[op.rb];
|
||||
bb.reg_const.set(op.rt, bb.reg_const[op.ra] && bb.reg_const[op.rb]);
|
||||
bb.reg_val32[op.rt] = bb.reg_val32[op.rb] - bb.reg_val32[op.ra];
|
||||
break;
|
||||
}
|
||||
@@ -4566,14 +4566,14 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
||||
}
|
||||
|
||||
// Clear const
|
||||
bb.reg_const[op.rt] = false;
|
||||
bb.reg_const.set(op.rt, false);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
// Clear const if reg is modified here
|
||||
if (u8 reg = m_regmod[ia / 4]; reg < s_reg_max)
|
||||
bb.reg_const[reg] = false;
|
||||
bb.reg_const.set(reg, false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -6103,17 +6103,17 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
||||
|
||||
u32 ra = s_reg_max, rb = s_reg_max, rc = s_reg_max;
|
||||
|
||||
if (::at32(m_use_ra, pos / 4))
|
||||
if (m_use_ra.test(pos / 4))
|
||||
{
|
||||
ra = op.ra;
|
||||
}
|
||||
|
||||
if (::at32(m_use_rb, pos / 4))
|
||||
if (m_use_rb.test(pos / 4))
|
||||
{
|
||||
rb = op.rb;
|
||||
}
|
||||
|
||||
if (::at32(m_use_rc, pos / 4))
|
||||
if (m_use_rc.test(pos / 4))
|
||||
{
|
||||
rc = op.rc;
|
||||
}
|
||||
@@ -6373,8 +6373,8 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
||||
}
|
||||
|
||||
std::array<u32, s_reg_max> reg_use{};
|
||||
std::bitset<s_reg_max> reg_maybe_float{};
|
||||
std::bitset<s_reg_max> reg_mod{};
|
||||
bit_set<s_reg_max> reg_maybe_float{};
|
||||
bit_set<s_reg_max> reg_mod{};
|
||||
|
||||
for (auto it = m_bbs.find(reduced_loop->loop_pc); it != m_bbs.end() && it->first <= bpc; it++)
|
||||
{
|
||||
@@ -6398,7 +6398,7 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
||||
|
||||
for (u32 i = 0; i < s_reg_max; i++)
|
||||
{
|
||||
if (!::at32(reduced_loop->loop_dicts, i))
|
||||
if (!reduced_loop->loop_dicts.test(i))
|
||||
{
|
||||
if (reg_use[i] && reg_mod[i])
|
||||
{
|
||||
@@ -6662,7 +6662,7 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
||||
|
||||
for (u32 i = 0; i < reg->regs.size() && reduced_loop->active; i++)
|
||||
{
|
||||
if (::at32(reg->regs, i))
|
||||
if (reg->regs.test(i))
|
||||
{
|
||||
if (0) if (i == op_rt || reg->modified == 0)
|
||||
{
|
||||
@@ -6708,11 +6708,11 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
||||
auto reg_org = reduced_loop->find_reg(i);
|
||||
u32 reg_index = i;
|
||||
|
||||
if (reg_org && !cond_val_incr_before_cond && reg_org->modified == 0 && reg_org->regs.count() - 1u <= 1u && !::at32(reg_org->regs, i))
|
||||
if (reg_org && !cond_val_incr_before_cond && reg_org->modified == 0 && reg_org->regs.count() - 1u <= 1u && !reg_org->regs.test(i))
|
||||
{
|
||||
for (u32 j = 0; j <= s_reg_127; j++)
|
||||
{
|
||||
if (::at32(reg_org->regs, j))
|
||||
if (reg_org->regs.test(j))
|
||||
{
|
||||
if (const auto reg_found = reduced_loop->find_reg(j))
|
||||
{
|
||||
@@ -6781,7 +6781,7 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
||||
break;
|
||||
}
|
||||
|
||||
if (reg_index != i && ::at32(reg->regs, reg_index))
|
||||
if (reg_index != i && reg->regs.test(reg_index))
|
||||
{
|
||||
// Unimplemented
|
||||
break_reduced_loop_pattern(30, reduced_loop->discard());
|
||||
@@ -7104,8 +7104,8 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
||||
}
|
||||
|
||||
std::array<u32, s_reg_max> reg_use{};
|
||||
std::bitset<s_reg_max> reg_maybe_float{};
|
||||
std::bitset<s_reg_max> reg_mod{};
|
||||
bit_set<s_reg_max> reg_maybe_float{};
|
||||
bit_set<s_reg_max> reg_mod{};
|
||||
|
||||
for (auto it = m_bbs.find(reduced_loop->loop_pc); it != m_bbs.end() && it->first <= bpc; it++)
|
||||
{
|
||||
@@ -7129,7 +7129,7 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
||||
|
||||
for (u32 i = 0; i < s_reg_max; i++)
|
||||
{
|
||||
if (!::at32(reduced_loop->loop_dicts, i))
|
||||
if (!reduced_loop->loop_dicts.test(i))
|
||||
{
|
||||
if (reg_use[i] && reg_mod[i])
|
||||
{
|
||||
@@ -8412,17 +8412,17 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
||||
|
||||
u32 ra = s_reg_max, rb = s_reg_max, rc = s_reg_max;
|
||||
|
||||
if (::at32(m_use_ra, pos / 4))
|
||||
if (m_use_ra.test(pos / 4))
|
||||
{
|
||||
ra = op.ra;
|
||||
}
|
||||
|
||||
if (::at32(m_use_rb, pos / 4))
|
||||
if (m_use_rb.test(pos / 4))
|
||||
{
|
||||
rb = op.rb;
|
||||
}
|
||||
|
||||
if (::at32(m_use_rc, pos / 4))
|
||||
if (m_use_rc.test(pos / 4))
|
||||
{
|
||||
rc = op.rc;
|
||||
}
|
||||
@@ -8693,7 +8693,7 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
||||
|
||||
for (u32 i = 0; i < s_reg_max; i++)
|
||||
{
|
||||
if (::at32(pattern.loop_writes, i))
|
||||
if (pattern.loop_writes.test(i))
|
||||
{
|
||||
if (regs.size() != 1)
|
||||
{
|
||||
@@ -8703,7 +8703,7 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
||||
fmt::append(regs, " r%u-w", i);
|
||||
}
|
||||
|
||||
if (::at32(pattern.loop_args, i))
|
||||
if (pattern.loop_args.test(i))
|
||||
{
|
||||
if (regs.size() != 1)
|
||||
{
|
||||
@@ -8713,7 +8713,7 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
||||
fmt::append(regs, " r%u-r", i);
|
||||
}
|
||||
|
||||
if (::at32(pattern.loop_may_update, i))
|
||||
if (pattern.loop_may_update.test(i))
|
||||
{
|
||||
if (regs.size() != 1)
|
||||
{
|
||||
|
||||
@@ -7148,8 +7148,8 @@ public:
|
||||
{
|
||||
const value_t<f32[4]> ab[2]{a, b};
|
||||
|
||||
std::bitset<2> safe_int_compare(0);
|
||||
std::bitset<2> safe_finite_compare(0);
|
||||
bit_set<2> safe_int_compare(0);
|
||||
bit_set<2> safe_finite_compare(0);
|
||||
|
||||
for (u32 i = 0; i < 2; i++)
|
||||
{
|
||||
@@ -7192,12 +7192,12 @@ public:
|
||||
return eval(sext<s32[4]>(bitcast<s32[4]>(a) > bitcast<s32[4]>(b)));
|
||||
}
|
||||
|
||||
if (safe_finite_compare.test(1))
|
||||
if (safe_finite_compare.test(1u))
|
||||
{
|
||||
return eval(sext<s32[4]>(fcmp_uno(clamp_negative_smax(a) > b)));
|
||||
}
|
||||
|
||||
if (safe_finite_compare.test(0))
|
||||
if (safe_finite_compare.test(0u))
|
||||
{
|
||||
return eval(sext<s32[4]>(fcmp_ord(a > clamp_smax(b))));
|
||||
}
|
||||
@@ -7247,7 +7247,7 @@ public:
|
||||
|
||||
const value_t<f32[4]> ab[2]{a, b};
|
||||
|
||||
std::bitset<2> safe_int_compare(0);
|
||||
bit_set<2> safe_int_compare(0);
|
||||
|
||||
for (u32 i = 0; i < 2; i++)
|
||||
{
|
||||
@@ -7521,8 +7521,8 @@ public:
|
||||
|
||||
const value_t<f32[4]> ab[2]{a, b};
|
||||
|
||||
std::bitset<2> safe_float_compare(0);
|
||||
std::bitset<2> safe_int_compare(0);
|
||||
bit_set<2> safe_float_compare(0);
|
||||
bit_set<2> safe_int_compare(0);
|
||||
|
||||
for (u32 i = 0; i < 2; i++)
|
||||
{
|
||||
@@ -7595,8 +7595,8 @@ public:
|
||||
|
||||
const value_t<f32[4]> ab[2]{a, b};
|
||||
|
||||
std::bitset<2> safe_float_compare(0);
|
||||
std::bitset<2> safe_int_compare(0);
|
||||
bit_set<2> safe_float_compare(0);
|
||||
bit_set<2> safe_int_compare(0);
|
||||
|
||||
for (u32 i = 0; i < 2; i++)
|
||||
{
|
||||
|
||||
@@ -6,22 +6,10 @@
|
||||
#include "SPUThread.h"
|
||||
#include "SPUAnalyser.h"
|
||||
#include <vector>
|
||||
#include <bitset>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <deque>
|
||||
|
||||
// std::bitset
|
||||
template <typename CT, typename T>
|
||||
requires requires(std::remove_cvref_t<CT>& x, T&& y) { x.count(); x.test(y); x.flip(y); }
|
||||
[[nodiscard]] constexpr bool at32(CT&& container, T&& index, std::source_location src_loc = std::source_location::current())
|
||||
{
|
||||
const usz csv = container.size();
|
||||
if (csv <= std::forward<T>(index)) [[unlikely]]
|
||||
fmt::raw_range_error(src_loc, format_object_simplified(index), csv);
|
||||
return container[std::forward<T>(index)];
|
||||
}
|
||||
|
||||
// Helper class
|
||||
class spu_cache
|
||||
{
|
||||
@@ -358,15 +346,15 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
std::bitset<s_reg_max> loop_args;
|
||||
std::bitset<s_reg_max> loop_dicts;
|
||||
std::bitset<s_reg_max> loop_writes;
|
||||
std::bitset<s_reg_max> loop_may_update;
|
||||
std::bitset<s_reg_max> gpr_not_nans;
|
||||
bit_set<s_reg_max> loop_args;
|
||||
bit_set<s_reg_max> loop_dicts;
|
||||
bit_set<s_reg_max> loop_writes;
|
||||
bit_set<s_reg_max> loop_may_update;
|
||||
bit_set<s_reg_max> gpr_not_nans;
|
||||
|
||||
struct origin_t
|
||||
{
|
||||
std::bitset<s_reg_max + 1> regs{};
|
||||
bit_set<s_reg_max + 1> regs{};
|
||||
u32 modified = 0;
|
||||
spu_itype_t mod1_type = spu_itype::UNK;
|
||||
spu_itype_t mod2_type = spu_itype::UNK;
|
||||
@@ -434,7 +422,7 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
return regs.count() == 1 && ::at32(regs, reg_val);
|
||||
return regs.count() == 1 && regs.test(reg_val);
|
||||
}
|
||||
|
||||
bool is_loop_dictator(u32 reg_val, bool test_predictable = false, bool should_predictable = true) const
|
||||
@@ -444,7 +432,7 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
if (regs.count() >= 1 && ::at32(regs, reg_val))
|
||||
if (regs.count() >= 1 && regs.test(reg_val))
|
||||
{
|
||||
if (!test_predictable)
|
||||
{
|
||||
@@ -503,7 +491,7 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
if (regs.count() - (::at32(regs, reg_val) ? 1 : 0))
|
||||
if (regs.count() - (regs.test(reg_val) ? 1 : 0))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -686,7 +674,7 @@ public:
|
||||
|
||||
bool is_gpr_not_NaN_hint(u32 i) const noexcept
|
||||
{
|
||||
return ::at32(gpr_not_nans, i);
|
||||
return gpr_not_nans.test(i);
|
||||
}
|
||||
|
||||
origin_t get_reg(u32 reg_val) noexcept
|
||||
@@ -714,14 +702,14 @@ protected:
|
||||
u64 m_hash_start;
|
||||
|
||||
// Bit indicating start of the block
|
||||
std::bitset<SPU_LS_SIZE / 4> m_block_info;
|
||||
bit_set<SPU_LS_SIZE / 4> m_block_info;
|
||||
|
||||
// GPR modified by the instruction (-1 = not set)
|
||||
std::array<u8, SPU_LS_SIZE / 4> m_regmod;
|
||||
|
||||
std::bitset<SPU_LS_SIZE / 4> m_use_ra;
|
||||
std::bitset<SPU_LS_SIZE / 4> m_use_rb;
|
||||
std::bitset<SPU_LS_SIZE / 4> m_use_rc;
|
||||
bit_set<SPU_LS_SIZE / 4> m_use_ra;
|
||||
bit_set<SPU_LS_SIZE / 4> m_use_rb;
|
||||
bit_set<SPU_LS_SIZE / 4> m_use_rc;
|
||||
|
||||
// List of possible targets for the instruction (entry shouldn't exist for simple instructions)
|
||||
std::unordered_map<u32, std::vector<u32>, value_hash<u32, 2>> m_targets;
|
||||
@@ -730,10 +718,10 @@ protected:
|
||||
std::unordered_map<u32, std::vector<u32>, value_hash<u32, 2>> m_preds;
|
||||
|
||||
// List of function entry points and return points (set after BRSL, BRASL, BISL, BISLED)
|
||||
std::bitset<SPU_LS_SIZE / 4> m_entry_info;
|
||||
bit_set<SPU_LS_SIZE / 4> m_entry_info;
|
||||
|
||||
// Set after return points and disjoint chunks
|
||||
std::bitset<SPU_LS_SIZE / 4> m_ret_info;
|
||||
bit_set<SPU_LS_SIZE / 4> m_ret_info;
|
||||
|
||||
// Basic block information
|
||||
struct block_info
|
||||
@@ -751,28 +739,28 @@ protected:
|
||||
term_type terminator;
|
||||
|
||||
// Bit mask of the registers modified in the block
|
||||
std::bitset<s_reg_max> reg_mod{};
|
||||
bit_set<s_reg_max> reg_mod{};
|
||||
|
||||
// Set if last modifying instruction produces xfloat
|
||||
std::bitset<s_reg_max> reg_mod_xf{};
|
||||
bit_set<s_reg_max> reg_mod_xf{};
|
||||
|
||||
// Set if the initial register value in this block may be xfloat
|
||||
std::bitset<s_reg_max> reg_maybe_xf{};
|
||||
bit_set<s_reg_max> reg_maybe_xf{};
|
||||
|
||||
// Set if register is used in floating pont instruction
|
||||
std::bitset<s_reg_max> reg_maybe_float{};
|
||||
bit_set<s_reg_max> reg_maybe_float{};
|
||||
|
||||
// Set if register is used as shuffle mask
|
||||
std::bitset<s_reg_max> reg_maybe_shuffle_mask{};
|
||||
bit_set<s_reg_max> reg_maybe_shuffle_mask{};
|
||||
|
||||
// Number of times registers are used (before modified)
|
||||
std::array<u32, s_reg_max> reg_use{};
|
||||
|
||||
// Bit mask of the trivial (u32 x 4) constant value resulting in this block
|
||||
std::bitset<s_reg_max> reg_const{};
|
||||
bit_set<s_reg_max> reg_const{};
|
||||
|
||||
// Bit mask of register saved onto the stack before use
|
||||
std::bitset<s_reg_max> reg_save_dom{};
|
||||
bit_set<s_reg_max> reg_save_dom{};
|
||||
|
||||
// Address of the function
|
||||
u32 func = 0x40000;
|
||||
@@ -850,7 +838,7 @@ protected:
|
||||
|
||||
private:
|
||||
// For private use
|
||||
std::bitset<0x10000> m_bits;
|
||||
bit_set<0x10000> m_bits;
|
||||
|
||||
// For private use
|
||||
std::vector<u32> workload;
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
#include "sys_rsxaudio.h"
|
||||
|
||||
#include <cmath>
|
||||
#include <bitset>
|
||||
#include <optional>
|
||||
|
||||
#ifdef __linux__
|
||||
@@ -1651,13 +1650,13 @@ void rsxaudio_backend_thread::set_mute_state(avport_bit muted_avports)
|
||||
|
||||
u8 rsxaudio_backend_thread::gen_mute_state(avport_bit avports)
|
||||
{
|
||||
std::bitset<SYS_RSXAUDIO_AVPORT_CNT> mute_state{0};
|
||||
bit_set<SYS_RSXAUDIO_AVPORT_CNT> mute_state{0};
|
||||
|
||||
if (avports.hdmi_0) mute_state[static_cast<u8>(RsxaudioAvportIdx::HDMI_0)] = true;
|
||||
if (avports.hdmi_1) mute_state[static_cast<u8>(RsxaudioAvportIdx::HDMI_1)] = true;
|
||||
if (avports.avmulti) mute_state[static_cast<u8>(RsxaudioAvportIdx::AVMULTI)] = true;
|
||||
if (avports.spdif_0) mute_state[static_cast<u8>(RsxaudioAvportIdx::SPDIF_0)] = true;
|
||||
if (avports.spdif_1) mute_state[static_cast<u8>(RsxaudioAvportIdx::SPDIF_1)] = true;
|
||||
if (avports.hdmi_0) mute_state.set(static_cast<u8>(RsxaudioAvportIdx::HDMI_0), true);
|
||||
if (avports.hdmi_1) mute_state.set(static_cast<u8>(RsxaudioAvportIdx::HDMI_1), true);
|
||||
if (avports.avmulti) mute_state.set(static_cast<u8>(RsxaudioAvportIdx::AVMULTI), true);
|
||||
if (avports.spdif_0) mute_state.set(static_cast<u8>(RsxaudioAvportIdx::SPDIF_0), true);
|
||||
if (avports.spdif_1) mute_state.set(static_cast<u8>(RsxaudioAvportIdx::SPDIF_1), true);
|
||||
|
||||
return static_cast<u8>(mute_state.to_ulong());
|
||||
}
|
||||
@@ -1832,7 +1831,7 @@ u32 rsxaudio_backend_thread::write_data_callback(u32 bytes, void* buf)
|
||||
return val;
|
||||
});
|
||||
|
||||
const std::bitset<SYS_RSXAUDIO_AVPORT_CNT> mute_state{cb_cfg.mute_state};
|
||||
const bit_set<SYS_RSXAUDIO_AVPORT_CNT> mute_state{cb_cfg.mute_state};
|
||||
|
||||
if (cb_cfg.ready && !mute_state[static_cast<u8>(cb_cfg.avport_idx)] && Emu.IsRunning())
|
||||
{
|
||||
|
||||
@@ -2,12 +2,11 @@
|
||||
|
||||
#include "util/atomic.hpp"
|
||||
#include <util/types.hpp>
|
||||
#include <bitset>
|
||||
|
||||
namespace rsx
|
||||
{
|
||||
template <int N>
|
||||
void unpack_bitset(const std::bitset<N>& block, u64* values)
|
||||
void unpack_bitset(const bit_set<N>& block, u64* values)
|
||||
{
|
||||
for (int bit = 0, n = -1, shift = 0; bit < N; ++bit, ++shift)
|
||||
{
|
||||
@@ -25,11 +24,11 @@ namespace rsx
|
||||
}
|
||||
|
||||
template <int N>
|
||||
void pack_bitset(std::bitset<N>& block, u64* values)
|
||||
void pack_bitset(bit_set<N>& block, u64* values)
|
||||
{
|
||||
for (int n = 0, shift = 0; shift < N; ++n, shift += 64)
|
||||
{
|
||||
std::bitset<N> tmp = values[n];
|
||||
bit_set<N> tmp = values[n];
|
||||
tmp <<= shift;
|
||||
block |= tmp;
|
||||
}
|
||||
|
||||
@@ -140,7 +140,7 @@ vertex_program_utils::vertex_program_metadata vertex_program_utils::analyse_vert
|
||||
//u32 last_instruction_address = 0;
|
||||
//u32 first_instruction_address = entry;
|
||||
|
||||
std::bitset<rsx::max_vertex_program_instructions> instructions_to_patch;
|
||||
bit_set<rsx::max_vertex_program_instructions> instructions_to_patch;
|
||||
std::pair<u32, u32> instruction_range{ umax, 0 };
|
||||
bool has_branch_instruction = false;
|
||||
std::stack<u32> call_stack;
|
||||
@@ -178,7 +178,7 @@ vertex_program_utils::vertex_program_metadata vertex_program_utils::analyse_vert
|
||||
d3.HEX = instruction._u32[3];
|
||||
|
||||
// Touch current instruction
|
||||
result.instruction_mask[current_instruction] = true;
|
||||
result.instruction_mask.set(current_instruction, true);
|
||||
instruction_range.first = std::min(current_instruction, instruction_range.first);
|
||||
instruction_range.second = std::max(current_instruction, instruction_range.second);
|
||||
|
||||
@@ -258,7 +258,7 @@ vertex_program_utils::vertex_program_metadata vertex_program_utils::analyse_vert
|
||||
case RSX_SCA_OPCODE_CLB:
|
||||
{
|
||||
// Need to patch the jump address to be consistent wherever the program is located
|
||||
instructions_to_patch[current_instruction] = true;
|
||||
instructions_to_patch.set(current_instruction, true);
|
||||
has_branch_instruction = true;
|
||||
|
||||
d0.HEX = instruction._u32[0];
|
||||
|
||||
@@ -24,7 +24,7 @@ namespace program_hash_util
|
||||
{
|
||||
struct vertex_program_metadata
|
||||
{
|
||||
std::bitset<rsx::max_vertex_program_instructions> instruction_mask;
|
||||
bit_set<rsx::max_vertex_program_instructions> instruction_mask;
|
||||
u32 ucode_length;
|
||||
u32 referenced_textures_mask;
|
||||
u16 referenced_inputs_mask;
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
#include "program_util.h"
|
||||
|
||||
#include <vector>
|
||||
#include <bitset>
|
||||
#include <set>
|
||||
|
||||
enum vp_reg_type
|
||||
@@ -227,7 +226,7 @@ struct RSXVertexProgram
|
||||
u32 output_mask = 0;
|
||||
u32 base_address = 0;
|
||||
u32 entry = 0;
|
||||
std::bitset<rsx::max_vertex_program_instructions> instruction_mask;
|
||||
bit_set<rsx::max_vertex_program_instructions> instruction_mask;
|
||||
std::set<u32> jump_table;
|
||||
|
||||
rsx::texture_dimension_extended get_texture_dimension(u8 id) const
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
#include "util/asm.hpp"
|
||||
|
||||
#include <thread>
|
||||
#include <bitset>
|
||||
|
||||
using spu_rdata_t = std::byte[128];
|
||||
|
||||
@@ -689,7 +688,7 @@ namespace rsx
|
||||
}
|
||||
|
||||
// Check for flow control
|
||||
if (std::bitset<2> jump_type; jump_type
|
||||
if (bit_set<2> jump_type; jump_type
|
||||
.set(0, (cmd & RSX_METHOD_OLD_JUMP_CMD_MASK) == RSX_METHOD_OLD_JUMP_CMD)
|
||||
.set(1, (cmd & RSX_METHOD_NEW_JUMP_CMD_MASK) == RSX_METHOD_NEW_JUMP_CMD)
|
||||
.any())
|
||||
|
||||
@@ -40,7 +40,7 @@ log_viewer::log_viewer(std::shared_ptr<gui_settings> gui_settings)
|
||||
m_path_last = m_gui_settings->GetValue(gui::fd_log_viewer).toString();
|
||||
m_show_timestamps = m_gui_settings->GetValue(gui::lv_show_timestamps).toBool();
|
||||
m_show_threads = m_gui_settings->GetValue(gui::lv_show_threads).toBool();
|
||||
m_log_levels = std::bitset<32>(m_gui_settings->GetValue(gui::lv_log_levels).toUInt());
|
||||
m_log_levels = bit_set<32>(m_gui_settings->GetValue(gui::lv_log_levels).toUInt());
|
||||
|
||||
m_log_text = new QPlainTextEdit(this);
|
||||
m_log_text->setReadOnly(true);
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#include "find_dialog.h"
|
||||
#include "util/types.hpp"
|
||||
|
||||
#include <QPlainTextEdit>
|
||||
#include <QDropEvent>
|
||||
|
||||
#include <bitset>
|
||||
#include <memory>
|
||||
|
||||
class LogHighlighter;
|
||||
@@ -37,7 +37,7 @@ private:
|
||||
QPlainTextEdit* m_log_text;
|
||||
LogHighlighter* m_log_highlighter;
|
||||
std::unique_ptr<find_dialog> m_find_dialog;
|
||||
std::bitset<32> m_log_levels = std::bitset<32>(0b11111111u);
|
||||
bit_set<32> m_log_levels = bit_set<32>(0b11111111u);
|
||||
bool m_show_timestamps = true;
|
||||
bool m_show_threads = true;
|
||||
bool m_last_actions_only = false;
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <compare>
|
||||
#include <memory>
|
||||
#include <bit>
|
||||
#include <bitset>
|
||||
#include <string>
|
||||
#include <source_location>
|
||||
#include <new>
|
||||
@@ -1064,6 +1065,144 @@ template <typename CT, typename T> requires requires (CT&& x, T&& y) { x.count(y
|
||||
return found->second;
|
||||
}
|
||||
|
||||
// Exception friendly std::bitset
|
||||
template <usz Bits>
|
||||
struct bit_set
|
||||
{
|
||||
public:
|
||||
constexpr bit_set() noexcept : m_bitset() {}
|
||||
constexpr bit_set(usz val) noexcept : m_bitset(val) {}
|
||||
|
||||
[[nodiscard]] bool test(usz pos, std::source_location src_loc = std::source_location::current()) const
|
||||
{
|
||||
if (pos >= Bits) [[unlikely]]
|
||||
fmt::raw_range_error(src_loc, format_object_simplified(pos), Bits);
|
||||
|
||||
return m_bitset[pos];
|
||||
}
|
||||
|
||||
bit_set& set(usz pos, bool val = true, std::source_location src_loc = std::source_location::current())
|
||||
{
|
||||
if (pos >= Bits) [[unlikely]]
|
||||
fmt::raw_range_error(src_loc, format_object_simplified(pos), Bits);
|
||||
|
||||
m_bitset[pos] = val;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bit_set& reset(usz pos, std::source_location src_loc = std::source_location::current())
|
||||
{
|
||||
if (pos >= Bits) [[unlikely]]
|
||||
fmt::raw_range_error(src_loc, format_object_simplified(pos), Bits);
|
||||
|
||||
m_bitset[pos] = false;
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr bit_set& reset() noexcept
|
||||
{
|
||||
m_bitset.reset();
|
||||
return *this;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr unsigned long to_ulong() const noexcept requires(Bits <= 32)
|
||||
{
|
||||
return m_bitset.to_ulong();
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr unsigned long long to_ullong() const noexcept requires(Bits <= 64)
|
||||
{
|
||||
return m_bitset.to_ullong();
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr bool any() const noexcept
|
||||
{
|
||||
return m_bitset.any();
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr bool none() const noexcept
|
||||
{
|
||||
return m_bitset.none();
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr bool all() const noexcept
|
||||
{
|
||||
return m_bitset.all();
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr usz count() const noexcept
|
||||
{
|
||||
return m_bitset.count();
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr usz size() const noexcept
|
||||
{
|
||||
return Bits;
|
||||
}
|
||||
|
||||
// Helps us getting the source location when using the [] operator
|
||||
struct location_index
|
||||
{
|
||||
template <typename T> requires std::convertible_to<T, usz>
|
||||
location_index(T&& pos, std::source_location src_loc = std::source_location::current())
|
||||
: index(static_cast<usz>(std::forward<T>(pos))), loc(src_loc)
|
||||
{}
|
||||
|
||||
usz index;
|
||||
std::source_location loc;
|
||||
};
|
||||
|
||||
[[nodiscard]] constexpr bool operator[](location_index index) const
|
||||
{
|
||||
return test(index.index, index.loc);
|
||||
}
|
||||
|
||||
constexpr bit_set& operator&=(const bit_set& r) noexcept
|
||||
{
|
||||
m_bitset &= r.m_bitset;
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr bit_set& operator|=(const bit_set& r) noexcept
|
||||
{
|
||||
m_bitset |= r.m_bitset;
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr bit_set& operator^=(const bit_set& r) noexcept
|
||||
{
|
||||
m_bitset ^= r.m_bitset;
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr bit_set& operator<<=(usz pos) noexcept
|
||||
{
|
||||
m_bitset <<= pos;
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr bit_set& operator>>=(usz pos) noexcept
|
||||
{
|
||||
m_bitset >>= pos;
|
||||
return *this;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr bit_set operator<<(const usz pos) const noexcept
|
||||
{
|
||||
return m_bitset << pos;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr bit_set operator>>(const usz pos) const noexcept
|
||||
{
|
||||
return m_bitset >> pos;
|
||||
}
|
||||
|
||||
private:
|
||||
constexpr bit_set(std::bitset<Bits>&& set) noexcept : m_bitset(set) {}
|
||||
|
||||
std::bitset<Bits> m_bitset;
|
||||
};
|
||||
|
||||
// Simplified hash algorithm. May be used in std::unordered_(map|set).
|
||||
template <typename T, usz Shift = 0>
|
||||
struct value_hash
|
||||
|
||||
Reference in New Issue
Block a user