1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210
|
#define SOL_ALL_SAFETIES_ON 1
#include <sol/sol.hpp>
#include <cstddef>
#include <cstdint>
#include <climits>
#include <type_traits>
namespace itsy_bitsy {
template <std::size_t sz, typename C = void>
struct bit_type {
typedef uint64_t type;
};
template <std::size_t sz>
struct bit_type<sz, std::enable_if_t<(sz <= 1)>> {
typedef bool type;
};
template <std::size_t sz>
struct bit_type<sz,
std::enable_if_t<(sz > 2 && sz <= 16)>> {
typedef uint16_t type;
};
template <std::size_t sz>
struct bit_type<sz,
std::enable_if_t<(sz > 16 && sz <= 32)>> {
typedef uint32_t type;
};
template <std::size_t sz>
struct bit_type<sz,
std::enable_if_t<(sz > 32 && sz <= 64)>> {
typedef uint64_t type;
};
template <std::size_t sz>
using bit_type_t = typename bit_type<sz>::type;
template <typename T, typename V>
bool vcxx_warning_crap(std::true_type, V val) {
return val != 0;
}
template <typename T, typename V>
T vcxx_warning_crap(std::false_type, V val) {
return static_cast<T>(val);
}
template <typename T, typename V>
auto vcxx_warning_crap(V val) {
return vcxx_warning_crap<T>(
std::is_same<bool, T>(), val);
}
template <typename Base, std::size_t bit_target = 0x0,
std::size_t size = 0x1>
void write(Base& b, bit_type_t<size> bits) {
typedef bit_type_t<sizeof(Base) * CHAR_BIT>
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<aligned_type>(
bit_target - aligned_target);
const aligned_type shifted_mask
= ((static_cast<aligned_type>(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<aligned_type*>(
static_cast<void*>(&b));
jumper += aligned_target;
aligned_type& aligned = *jumper;
aligned &= compl_shifted_mask;
aligned
|= (static_cast<aligned_type>(bits) << bits_left);
}
template <typename Base, std::size_t bit_target = 0x0,
std::size_t size = 0x1>
bit_type_t<size> read(Base& b) {
typedef bit_type_t<sizeof(Base) * CHAR_BIT>
aligned_type;
typedef bit_type_t<size> 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<aligned_type>(
bit_target - aligned_target);
const aligned_type mask
= (static_cast<aligned_type>(1) << size) - 1;
// Jump by native size of a pointer to target
// then OR the bits
aligned_type* jumper = static_cast<aligned_type*>(
static_cast<void*>(&b));
jumper += aligned_target;
const aligned_type& aligned = *jumper;
aligned_type field_bits
= (aligned >> bits_left) & mask;
field_type bits
= vcxx_warning_crap<field_type>(field_bits);
return bits;
}
} // namespace itsy_bitsy
#include <iostream>
#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>("flags_t",
"C",
sol::property(itsy_bitsy::read<flags_t, 0>,
itsy_bitsy::write<flags_t, 0>),
"N",
sol::property(itsy_bitsy::read<flags_t, 1>,
itsy_bitsy::write<flags_t, 1>),
"D",
sol::property(itsy_bitsy::read<flags_t, 8, 14>,
itsy_bitsy::write<flags_t, 8, 14>));
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_ASSERT(C);
SOL_ASSERT(N);
SOL_ASSERT(D == 0xDF);
std::cout << std::endl;
return 0;
}
|