-
-
Save Mellnik/fb7227b76a32719d453cc694d97fba2a to your computer and use it in GitHub Desktop.
LuaBridge type alignment
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
template<class T> | |
class UserdataValue : public Userdata | |
{ | |
private: | |
UserdataValue(UserdataValue<T> const&); | |
UserdataValue<T> operator=(UserdataValue<T> const&); | |
#if LUABRIDGE_SUPPORTS_USERALIGNEDTYPES | |
using AlignType = typename std::conditional<alignof(T) <= alignof(double), T, void*>::type; | |
static constexpr int MAX_PADDING = alignof(T) <= alignof(AlignType) ? 0 : alignof(T) - alignof(AlignType) + 1; | |
alignas(AlignType) unsigned char m_storage[sizeof(T) + MAX_PADDING]; | |
#else | |
char m_storage[sizeof(T)]; | |
#endif | |
private: | |
/** | |
Used for placement construction. | |
*/ | |
UserdataValue() | |
{ | |
#if LUABRIDGE_SUPPORTS_USERALIGNEDTYPES | |
if (MAX_PADDING > 0) | |
{ | |
uintptr_t offset = reinterpret_cast<uintptr_t>(&m_storage[0]) % alignof(T); | |
if (offset > 0) offset = alignof(T) - offset; | |
assert(offset < MAX_PADDING); | |
m_storage[sizeof(m_storage) - 1] = static_cast<unsigned char>(offset); | |
} | |
#endif | |
m_p = 0; | |
} | |
~UserdataValue() | |
{ | |
if (getPointer() != 0) | |
{ | |
getObject()->~T(); | |
} | |
} | |
public: | |
/** | |
Push a T via placement new. | |
The caller is responsible for calling placement new using the | |
returned uninitialized storage. | |
@param L A Lua state. | |
@returns An object referring to the newly created userdata value. | |
*/ | |
static UserdataValue<T>* place(lua_State* const L) | |
{ | |
UserdataValue<T>* const ud = | |
new (lua_newuserdata(L, sizeof(UserdataValue<T>))) UserdataValue<T>(); | |
lua_rawgetp(L, LUA_REGISTRYINDEX, detail::getClassRegistryKey<T>()); | |
if (!lua_istable(L, -1)) | |
{ | |
throw std::logic_error("The class is not registered in LuaBridge"); | |
} | |
lua_setmetatable(L, -2); | |
return ud; | |
} | |
/** | |
Push T via copy construction from U. | |
@tparam U A container type. | |
@param L A Lua state. | |
@param u A container object reference. | |
*/ | |
template<class U> | |
static inline void push(lua_State* const L, U const& u) | |
{ | |
UserdataValue<T>* ud = place(L); | |
new (ud->getObject()) U(u); | |
ud->commit(); | |
} | |
/** | |
Confirm object construction. | |
*/ | |
void commit() { m_p = getObject(); } | |
private: | |
inline void* __storagePtr() | |
{ | |
#if LUABRIDGE_SUPPORTS_USERALIGNEDTYPES | |
if (MAX_PADDING == 0) | |
{ | |
return &m_storage[0]; | |
} | |
return &m_storage[0] + m_storage[sizeof(m_storage) - 1]; | |
#else | |
return &m_storage[0]; | |
#endif | |
} | |
public: | |
T* getObject() | |
{ | |
// If this fails to compile it means you forgot to provide | |
// a Container specialization for your container! | |
// | |
return reinterpret_cast<T*>(__storagePtr()); | |
} | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment