mirror of
https://github.com/ThePhD/sol2.git
synced 2024-03-22 13:10:44 +08:00
bitfield example and link in docs
This commit is contained in:
parent
4aec055004
commit
57c933cc9b
|
@ -24,3 +24,6 @@ The examples folder also has a number of really great examples for you to see. T
|
||||||
- Work on a copy by taking or returning a copy by value.
|
- Work on a copy by taking or returning a copy by value.
|
||||||
* The actual metatable associated with the usertype has a long name and is defined to be opaque by the Sol implementation.
|
* The actual metatable associated with the usertype has a long name and is defined to be opaque by the Sol implementation.
|
||||||
* Containers get pushed as special usertypes, but can be disabled if problems arising as detailed :doc:`here<api/containers>`.
|
* Containers get pushed as special usertypes, but can be disabled if problems arising as detailed :doc:`here<api/containers>`.
|
||||||
|
* You can use bitfields but it requires some finesse on your part. We have an example to help you get started `here that uses a few tricks`_.
|
||||||
|
|
||||||
|
.. _here that uses a few tricks: https://github.com/ThePhD/sol2/blob/develop/examples/usertype_bitfields.cpp
|
||||||
|
|
164
examples/usertype_bitfields.cpp
Normal file
164
examples/usertype_bitfields.cpp
Normal file
|
@ -0,0 +1,164 @@
|
||||||
|
#define SOL_CHECK_ARGUMENTS
|
||||||
|
#include <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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
#if defined(_MSC_VER) || defined(__MINGW32__)
|
||||||
|
#pragma pack(1)
|
||||||
|
struct flags_t {
|
||||||
|
#else
|
||||||
|
struct __attribute__((packed, aligned(1))) 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{};
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
std::cout << "=== usertype_bitfields example ===" << 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;
|
||||||
|
|
||||||
|
assert(C);
|
||||||
|
assert(N);
|
||||||
|
assert(D == 0xDF);
|
||||||
|
|
||||||
|
std::cout << std::endl;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -20,8 +20,8 @@
|
||||||
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
// This file was generated with a script.
|
// This file was generated with a script.
|
||||||
// Generated 2016-11-15 09:39:55.397287 UTC
|
// Generated 2016-11-16 03:43:41.504038 UTC
|
||||||
// This header was generated with sol v2.15.1 (revision fe162b9)
|
// This header was generated with sol v2.15.1 (revision 4aec055)
|
||||||
// https://github.com/ThePhD/sol2
|
// https://github.com/ThePhD/sol2
|
||||||
|
|
||||||
#ifndef SOL_SINGLE_INCLUDE_HPP
|
#ifndef SOL_SINGLE_INCLUDE_HPP
|
||||||
|
@ -6986,14 +6986,17 @@ namespace sol {
|
||||||
return call_into_lua(returns_list(), args_list(), L, start, std::forward<Fx>(fx), std::forward<FxArgs>(fxargs)...);
|
return call_into_lua(returns_list(), args_list(), L, start, std::forward<Fx>(fx), std::forward<FxArgs>(fxargs)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline call_syntax get_call_syntax(lua_State* L, const std::string& key, int index = -2) {
|
inline call_syntax get_call_syntax(lua_State* L, const std::string& key, int index) {
|
||||||
|
if (lua_gettop(L) == 0) {
|
||||||
|
return call_syntax::dot;
|
||||||
|
}
|
||||||
luaL_getmetatable(L, key.c_str());
|
luaL_getmetatable(L, key.c_str());
|
||||||
auto pn = pop_n(L, 1);
|
auto pn = pop_n(L, 1);
|
||||||
if (lua_compare(L, -1, index, LUA_OPEQ) == 1) {
|
if (lua_compare(L, -1, index, LUA_OPEQ) != 1) {
|
||||||
return call_syntax::colon;
|
|
||||||
}
|
|
||||||
return call_syntax::dot;
|
return call_syntax::dot;
|
||||||
}
|
}
|
||||||
|
return call_syntax::colon;
|
||||||
|
}
|
||||||
|
|
||||||
inline void script(lua_State* L, const std::string& code) {
|
inline void script(lua_State* L, const std::string& code) {
|
||||||
if (luaL_dostring(L, code.c_str())) {
|
if (luaL_dostring(L, code.c_str())) {
|
||||||
|
@ -7882,7 +7885,7 @@ namespace sol {
|
||||||
};
|
};
|
||||||
|
|
||||||
static int call(lua_State* L, F& f) {
|
static int call(lua_State* L, F& f) {
|
||||||
call_syntax syntax = stack::get_call_syntax(L, &usertype_traits<T>::user_metatable()[0]);
|
call_syntax syntax = stack::get_call_syntax(L, &usertype_traits<T>::user_metatable()[0], 1);
|
||||||
int syntaxval = static_cast<int>(syntax);
|
int syntaxval = static_cast<int>(syntax);
|
||||||
int argcount = lua_gettop(L) - syntaxval;
|
int argcount = lua_gettop(L) - syntaxval;
|
||||||
return construct_match<T, meta::pop_front_type_t<meta::function_args_t<Cxs>>...>(onmatch(), L, argcount, 1 + syntaxval, f);
|
return construct_match<T, meta::pop_front_type_t<meta::function_args_t<Cxs>>...>(onmatch(), L, argcount, 1 + syntaxval, f);
|
||||||
|
|
|
@ -443,7 +443,7 @@ namespace sol {
|
||||||
};
|
};
|
||||||
|
|
||||||
static int call(lua_State* L, F& f) {
|
static int call(lua_State* L, F& f) {
|
||||||
call_syntax syntax = stack::get_call_syntax(L, &usertype_traits<T>::user_metatable()[0]);
|
call_syntax syntax = stack::get_call_syntax(L, &usertype_traits<T>::user_metatable()[0], 1);
|
||||||
int syntaxval = static_cast<int>(syntax);
|
int syntaxval = static_cast<int>(syntax);
|
||||||
int argcount = lua_gettop(L) - syntaxval;
|
int argcount = lua_gettop(L) - syntaxval;
|
||||||
return construct_match<T, meta::pop_front_type_t<meta::function_args_t<Cxs>>...>(onmatch(), L, argcount, 1 + syntaxval, f);
|
return construct_match<T, meta::pop_front_type_t<meta::function_args_t<Cxs>>...>(onmatch(), L, argcount, 1 + syntaxval, f);
|
||||||
|
|
|
@ -181,14 +181,17 @@ namespace sol {
|
||||||
return call_into_lua(returns_list(), args_list(), L, start, std::forward<Fx>(fx), std::forward<FxArgs>(fxargs)...);
|
return call_into_lua(returns_list(), args_list(), L, start, std::forward<Fx>(fx), std::forward<FxArgs>(fxargs)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline call_syntax get_call_syntax(lua_State* L, const std::string& key, int index = -2) {
|
inline call_syntax get_call_syntax(lua_State* L, const std::string& key, int index) {
|
||||||
|
if (lua_gettop(L) == 0) {
|
||||||
|
return call_syntax::dot;
|
||||||
|
}
|
||||||
luaL_getmetatable(L, key.c_str());
|
luaL_getmetatable(L, key.c_str());
|
||||||
auto pn = pop_n(L, 1);
|
auto pn = pop_n(L, 1);
|
||||||
if (lua_compare(L, -1, index, LUA_OPEQ) == 1) {
|
if (lua_compare(L, -1, index, LUA_OPEQ) != 1) {
|
||||||
return call_syntax::colon;
|
|
||||||
}
|
|
||||||
return call_syntax::dot;
|
return call_syntax::dot;
|
||||||
}
|
}
|
||||||
|
return call_syntax::colon;
|
||||||
|
}
|
||||||
|
|
||||||
inline void script(lua_State* L, const std::string& code) {
|
inline void script(lua_State* L, const std::string& code) {
|
||||||
if (luaL_dostring(L, code.c_str())) {
|
if (luaL_dostring(L, code.c_str())) {
|
||||||
|
|
|
@ -1423,3 +1423,26 @@ TEST_CASE("usertype/destruction-test", "make sure usertypes are properly destruc
|
||||||
lua["testCrash"]();
|
lua["testCrash"]();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE("usertype/call-initializers", "Ensure call constructors with initializers work well") {
|
||||||
|
struct A {
|
||||||
|
double f = 25.5;
|
||||||
|
|
||||||
|
static void init(A& x, double f) {
|
||||||
|
x.f = f;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
sol::state lua;
|
||||||
|
lua.open_libraries();
|
||||||
|
|
||||||
|
lua.new_usertype<A>("A",
|
||||||
|
sol::call_constructor, sol::initializers(&A::init)
|
||||||
|
);
|
||||||
|
|
||||||
|
lua.script(R"(
|
||||||
|
a = A(24.3)
|
||||||
|
)");
|
||||||
|
A& a = lua["a"];
|
||||||
|
REQUIRE(a.f == 24.3);
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user