#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; }