mirror of
https://github.com/libretro/bsnes-libretro.git
synced 2024-11-23 08:59:40 +00:00
50420e3dd2
byuu says: Changelog: - added nall/bit-field.hpp - updated all CPU cores (sans LR35902 due to some complexities) to use BitFields instead of bools - updated as many CPU cores as I could to use BitFields instead of union { struct { uint8_t ... }; }; pairs The speed changes are mostly a wash for this. In some instances, I noticed a ~2-3% speedup (eg SNES emulation), and in others a 2-3% slowdown (eg Famicom emulation.) It's within the margin of error, so it's safe to say it has no impact. This does give us a lot of new useful things, however: - no more manual reconstruction of flag values from lots of left shifts and ORs - no more manual deconstruction of flag values from lots of ANDs - ability to get completely free aliases to flag groups (eg GSU can provide alt2, alt1 and also alt (which is alt2,alt1 combined) - removes the need for the nasty order_lsbN macro hack (eventually will make higan 100% endian independent) - saves us from insane compilers that try and do nasty things with alignment on union-structs - saves us from insane compilers that try to store bit-field bits in reverse order - will allow some really novel new use cases (I'm planning an instant-decode ARM opcode function, for instance.) - reduces code size (we can serialize flag registers in one line instead of one for each flag) However, I probably won't use it for super critical code that's constantly reading out register values (eg PPU MMIO registers.) I think there we would end up with a performance penalty.
116 lines
2.9 KiB
C++
116 lines
2.9 KiB
C++
#pragma once
|
|
|
|
#include <nall/memory.hpp>
|
|
|
|
namespace nall {
|
|
|
|
struct bitvector {
|
|
bitvector() = default;
|
|
bitvector(uint size) { resize(size); }
|
|
bitvector(const bitvector& source) { operator=(source); }
|
|
bitvector(bitvector&& source) { operator=(move(source)); }
|
|
~bitvector() { reset(); }
|
|
|
|
auto operator=(const bitvector& source) -> bitvector& {
|
|
bits = source.bits;
|
|
pool = (uint8_t*)memory::resize(pool, bytes());
|
|
memory::copy(pool, source.pool, bytes());
|
|
return *this;
|
|
}
|
|
|
|
auto operator=(bitvector&& source) -> bitvector& {
|
|
pool = source.pool;
|
|
bits = source.bits;
|
|
source.pool = nullptr;
|
|
source.bits = 0;
|
|
return *this;
|
|
}
|
|
|
|
explicit operator bool() const { return bits > 0; }
|
|
auto size() const -> uint { return bits; }
|
|
auto bytes() const -> uint { return (bits + 7) / 8; }
|
|
auto data() -> uint8_t* { return pool; }
|
|
auto data() const -> const uint8_t* { return pool; }
|
|
|
|
auto reset() -> void {
|
|
if(pool) free(pool);
|
|
pool = nullptr;
|
|
bits = 0;
|
|
}
|
|
|
|
auto resize(uint size) -> void {
|
|
uint from = bits;
|
|
bits = size;
|
|
for(uint n = size; n < from; n++) clear(n); //on reduce
|
|
pool = (uint8_t*)memory::resize(pool, bytes());
|
|
for(uint n = from; n < size; n++) clear(n); //on expand
|
|
}
|
|
|
|
auto get(uint position) const -> bool {
|
|
return pool[position >> 3] & (0x80 >> (position & 7));
|
|
}
|
|
|
|
auto clear() -> void {
|
|
memory::fill(pool, bytes(), 0x00);
|
|
}
|
|
|
|
auto set() -> void {
|
|
memory::fill(pool, bytes(), 0xff);
|
|
for(uint n = bits; n < bytes() * 8; n++) clear(n);
|
|
}
|
|
|
|
auto clear(uint position) -> void {
|
|
pool[position >> 3] &= ~(0x80 >> (position & 7));
|
|
}
|
|
|
|
auto set(uint position) -> void {
|
|
pool[position >> 3] |= (0x80 >> (position & 7));
|
|
}
|
|
|
|
auto invert(uint position) -> void {
|
|
get(position) ? clear(position) : set(position);
|
|
}
|
|
|
|
auto set(uint position, bool value) -> void {
|
|
value ? set(position) : clear(position);
|
|
}
|
|
|
|
struct reference {
|
|
reference(bitvector& self, uint position) : self(self), position(position) {}
|
|
operator bool() const { return self.get(position); }
|
|
auto operator=(bool value) -> reference& { self.set(position, value); return *this; }
|
|
|
|
protected:
|
|
bitvector& self;
|
|
uint position;
|
|
};
|
|
|
|
auto operator[](uint position) -> reference {
|
|
return reference(*this, position);
|
|
}
|
|
|
|
auto operator[](uint position) const -> bool {
|
|
return get(position);
|
|
}
|
|
|
|
struct iterator {
|
|
iterator(bitvector& self, uint position) : self(self), position(position) {}
|
|
auto operator!=(const iterator& source) const -> bool { return position != source.position; }
|
|
auto operator++() -> iterator& { position++; return *this; }
|
|
auto operator*() -> reference { return self.operator[](position); }
|
|
|
|
protected:
|
|
bitvector& self;
|
|
uint position;
|
|
};
|
|
|
|
auto begin() -> iterator { return iterator(*this, 0); }
|
|
auto end() -> iterator { return iterator(*this, bits); }
|
|
|
|
protected:
|
|
uint8_t* pool = nullptr;
|
|
uint bits = 0;
|
|
};
|
|
|
|
}
|