#define SOL_ALL_SAFETIES_ON 1
#include
#include
#include
#include
#include
namespace itsy_bitsy {
template <:size_t sz typename c="void">
struct bit_type {
typedef uint64_t type;
};
template <:size_t sz>
struct bit_type> {
typedef bool type;
};
template <:size_t sz>
struct bit_type 2 && sz <= 16)>> {
typedef uint16_t type;
};
template <:size_t sz>
struct bit_type 16 && sz <= 32)>> {
typedef uint32_t type;
};
template <:size_t sz>
struct bit_type 32 && sz <= 64)>> {
typedef uint64_t type;
};
template <:size_t sz>
using bit_type_t = typename bit_type::type;
template
bool vcxx_warning_crap(std::true_type, V val) {
return val != 0;
}
template
T vcxx_warning_crap(std::false_type, V val) {
return static_cast(val);
}
template
auto vcxx_warning_crap(V val) {
return vcxx_warning_crap(
std::is_same(), val);
}
template
void write(Base& b, bit_type_t bits) {
typedef bit_type_t
aligned_type;
static const std::size_t aligned_type_bit_size
= sizeof(aligned_type) * CHAR_BIT;
static_assert(
sizeof(Base) * CHAR_BIT >= (bit_target + size),
"bit offset and size are too large for the "
"desired structure.");
static_assert((bit_target % aligned_type_bit_size)
<= ((bit_target + size)
% aligned_type_bit_size),
"bit offset and size cross beyond largest "
"integral constant boundary.");
const std::size_t aligned_target
= (bit_target + size) / aligned_type_bit_size;
const aligned_type bits_left
= static_cast(
bit_target - aligned_target);
const aligned_type shifted_mask
= ((static_cast(1) << size) - 1)
<< bits_left;
const aligned_type compl_shifted_mask = ~shifted_mask;
// Jump by native size of a pointer to target
// then OR the bits
aligned_type* jumper = static_cast(
static_cast(&b));
jumper += aligned_target;
aligned_type& aligned = *jumper;
aligned &= compl_shifted_mask;
aligned
|= (static_cast(bits) << bits_left);
}
template
bit_type_t read(Base& b) {
typedef bit_type_t
aligned_type;
typedef bit_type_t field_type;
static const std::size_t aligned_type_bit_size
= sizeof(aligned_type) * CHAR_BIT;
static_assert(
sizeof(Base) * CHAR_BIT >= (bit_target + size),
"bit offset and size are too large for the "
"desired structure.");
static_assert((bit_target % aligned_type_bit_size)
<= ((bit_target + size)
% aligned_type_bit_size),
"bit offset and size cross beyond largest "
"integral constant boundary.");
const std::size_t aligned_target
= (bit_target + size) / aligned_type_bit_size;
const aligned_type bits_left
= static_cast(
bit_target - aligned_target);
const aligned_type mask
= (static_cast(1) << size) - 1;
// Jump by native size of a pointer to target
// then OR the bits
aligned_type* jumper = static_cast(
static_cast(&b));
jumper += aligned_target;
const aligned_type& aligned = *jumper;
aligned_type field_bits
= (aligned >> bits_left) & mask;
field_type bits
= vcxx_warning_crap(field_bits);
return bits;
}
} // namespace itsy_bitsy
#include
#if defined(_MSC_VER) || defined(__MINGW32__)
#pragma pack(1)
struct alignas(sizeof(uint32_t)) flags_t {
#else
struct __attribute__((packed, aligned(sizeof(uint32_t))))
flags_t {
#endif
uint8_t C : 1;
uint8_t N : 1;
uint8_t PV : 1;
uint8_t _3 : 1;
uint8_t H : 1;
uint8_t _5 : 1;
uint8_t Z : 1;
uint8_t S : 1;
uint16_t D : 14;
} flags { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
int main() {
std::cout << "=== usertype_bitfields ===" << std::endl;
#ifdef __MINGW32__
std::cout << "MinGW Detected, packing structs is broken in "
"MinGW and this test may fail"
<< std::endl;
#endif
sol::state lua;
lua.open_libraries();
lua.new_usertype("flags_t",
"C",
sol::property(itsy_bitsy::read,
itsy_bitsy::write),
"N",
sol::property(itsy_bitsy::read,
itsy_bitsy::write),
"D",
sol::property(itsy_bitsy::read,
itsy_bitsy::write));
lua["f"] = std::ref(flags);
lua.script(R"(
print(f.C)
f.C = true;
print(f.C)
print(f.N)
f.N = true;
print(f.N)
print(f.D)
f.D = 0xDF;
print(f.D)
)");
bool C = flags.C;
bool N = flags.N;
uint16_t D = flags.D;
std::cout << std::hex;
std::cout << "sizeof(flags): " << sizeof(flags)
<< std::endl;
std::cout << "C: " << C << std::endl;
std::cout << "N: " << N << std::endl;
std::cout << "D: " << D << std::endl;
sol_c_assert(C);
sol_c_assert(N);
sol_c_assert(D == 0xDF);
std::cout << std::endl;
return 0;
}