the god-tier commit-without-running-tests...

This commit is contained in:
ThePhD 2019-04-28 09:40:51 -04:00
parent 2d470857b4
commit 3426947340
No known key found for this signature in database
GPG Key ID: 1509DB1C0F702BFA
12 changed files with 548 additions and 104 deletions

View File

@ -33,23 +33,20 @@
namespace sol { namespace sol {
namespace detail { namespace detail {
struct direct_error_tag {}; struct direct_error_tag {};
const auto direct_error = direct_error_tag {}; const auto direct_error = direct_error_tag{};
struct error_result { struct error_result {
int results; int results;
const char* format_string; const char* format_string;
std::array<const char*, 4> args_strings; std::array<const char*, 4> args_strings;
error_result() error_result() : results(0), format_string(nullptr) {
: results(0), format_string(nullptr) {
} }
error_result(int results) error_result(int results) : results(results), format_string(nullptr) {
: results(results), format_string(nullptr) {
} }
error_result(const char* fmt, const char* msg) error_result(const char* fmt, const char* msg) : results(0), format_string(fmt) {
: results(0), format_string(fmt) {
args_strings[0] = msg; args_strings[0] = msg;
} }
}; };
@ -65,20 +62,16 @@ namespace sol {
class error : public std::runtime_error { class error : public std::runtime_error {
private: private:
// Because VC++ is upsetting, most of the time! // Because VC++ is upsetting, most of the time!
std::string w; std::string what_reason;
public: public:
error(const std::string& str) error(const std::string& str) : error(detail::direct_error, "lua: error: " + str) {
: error(detail::direct_error, "lua: error: " + str) {
} }
error(std::string&& str) error(std::string&& str) : error(detail::direct_error, "lua: error: " + std::move(str)) {
: error(detail::direct_error, "lua: error: " + std::move(str)) {
} }
error(detail::direct_error_tag, const std::string& str) error(detail::direct_error_tag, const std::string& str) : std::runtime_error(""), what_reason(str) {
: std::runtime_error(""), w(str) {
} }
error(detail::direct_error_tag, std::string&& str) error(detail::direct_error_tag, std::string&& str) : std::runtime_error(""), what_reason(std::move(str)) {
: std::runtime_error(""), w(std::move(str)) {
} }
error(const error& e) = default; error(const error& e) = default;
@ -87,7 +80,7 @@ namespace sol {
error& operator=(error&& e) = default; error& operator=(error&& e) = default;
virtual const char* what() const noexcept override { virtual const char* what() const noexcept override {
return w.c_str(); return what_reason.c_str();
} }
}; };

View File

@ -32,6 +32,7 @@
#include "protected_handler.hpp" #include "protected_handler.hpp"
#include "bytecode.hpp" #include "bytecode.hpp"
#include "dump_handler.hpp" #include "dump_handler.hpp"
#include <cstdint> #include <cstdint>
#include <algorithm> #include <algorithm>

View File

@ -31,31 +31,31 @@
namespace sol { namespace sol {
namespace detail {
template <typename T>
using proxy_key_t = meta::conditional_t<meta::is_specialization_of_v<meta::unqualified_t<T>, std::tuple>,
T,
std::tuple<meta::conditional_t<
std::is_array_v<meta::unqualified_t<T>>, std::remove_reference_t<T>&, meta::unqualified_t<T>
>>
>;
}
template <typename Table, typename Key> template <typename Table, typename Key>
struct proxy : public proxy_base<proxy<Table, Key>> { struct proxy : public proxy_base<proxy<Table, Key>> {
private: private:
using key_type = detail::proxy_key_t<Key>; using key_type = detail::proxy_key_t<Key>;
template <typename T, std::size_t... I> template <typename T, std::size_t... I>
decltype(auto) tuple_get(std::index_sequence<I...>) const { decltype(auto) tuple_get(std::index_sequence<I...>) const & {
return tbl.template traverse_get<T>(std::get<I>(key)...); return tbl.template traverse_get<T>(std::get<I>(key)...);
} }
template <typename T, std::size_t... I>
decltype(auto) tuple_get(std::index_sequence<I...>) && {
return tbl.template traverse_get<T>(std::get<I>(std::move(key))...);
}
template <std::size_t... I, typename T> template <std::size_t... I, typename T>
void tuple_set(std::index_sequence<I...>, T&& value) { void tuple_set(std::index_sequence<I...>, T&& value) & {
tbl.traverse_set(std::get<I>(key)..., std::forward<T>(value)); tbl.traverse_set(std::get<I>(key)..., std::forward<T>(value));
} }
template <std::size_t... I, typename T>
void tuple_set(std::index_sequence<I...>, T&& value) && {
tbl.traverse_set(std::get<I>(std::move(key))..., std::forward<T>(value));
}
auto setup_table(std::true_type) { auto setup_table(std::true_type) {
auto p = stack::probe_get_field<std::is_same_v<meta::unqualified_t<Table>, global_table>>(lua_state(), key, tbl.stack_index()); auto p = stack::probe_get_field<std::is_same_v<meta::unqualified_t<Table>, global_table>>(lua_state(), key, tbl.stack_index());
lua_pop(lua_state(), p.levels); lua_pop(lua_state(), p.levels);
@ -79,19 +79,31 @@ namespace sol {
} }
template <typename T> template <typename T>
proxy& set(T&& item) { proxy& set(T&& item) & {
tuple_set(std::make_index_sequence<std::tuple_size_v<meta::unqualified_t<key_type>>>(), std::forward<T>(item)); tuple_set(std::make_index_sequence<std::tuple_size_v<meta::unqualified_t<key_type>>>(), std::forward<T>(item));
return *this; return *this;
} }
template <typename T>
proxy&& set(T&& item) && {
tuple_set(std::make_index_sequence<std::tuple_size_v<meta::unqualified_t<key_type>>>(), std::forward<T>(item));
return std::move(*this);
}
template <typename... Args> template <typename... Args>
proxy& set_function(Args&&... args) { proxy& set_function(Args&&... args) & {
tbl.set_function(key, std::forward<Args>(args)...); tbl.set_function(key, std::forward<Args>(args)...);
return *this; return *this;
} }
template <typename... Args>
proxy&& set_function(Args&&... args) && {
tbl.set_function(std::move(key), std::forward<Args>(args)...);
return std::move(*this);
}
template <typename T> template <typename T>
proxy& operator=(T&& other) { proxy& operator=(T&& other) & {
using Tu = meta::unwrap_unqualified_t<T>; using Tu = meta::unwrap_unqualified_t<T>;
if constexpr (!is_lua_reference_or_proxy_v<Tu> && meta::is_callable_v<Tu>) { if constexpr (!is_lua_reference_or_proxy_v<Tu> && meta::is_callable_v<Tu>) {
return set_function(std::forward<T>(other)); return set_function(std::forward<T>(other));
@ -102,13 +114,36 @@ namespace sol {
} }
template <typename T> template <typename T>
proxy& operator=(std::initializer_list<T> other) { proxy&& operator=(T&& other) && {
using Tu = meta::unwrap_unqualified_t<T>;
if constexpr (!is_lua_reference_or_proxy_v<Tu> && meta::is_callable_v<Tu>) {
return std::move(*this).set_function(std::forward<T>(other));
}
else {
return std::move(*this).set(std::forward<T>(other));
}
}
template <typename T>
proxy& operator=(std::initializer_list<T> other) & {
return set(std::move(other)); return set(std::move(other));
} }
template <typename T> template <typename T>
decltype(auto) get() const { proxy&& operator=(std::initializer_list<T> other) && {
return tuple_get<T>(std::make_index_sequence<std::tuple_size<meta::unqualified_t<key_type>>::value>()); return std::move(*this).set(std::move(other));
}
template <typename T>
decltype(auto) get() const & {
using idx_seq = std::make_index_sequence<std::tuple_size_v<meta::unqualified_t<key_type>>>;
return tuple_get<T>(idx_seq());
}
template <typename T>
decltype(auto) get() && {
using idx_seq = std::make_index_sequence<std::tuple_size_v<meta::unqualified_t<key_type>>>;
return std::move(*this).template tuple_get<T>(idx_seq());
} }
template <typename T> template <typename T>

View File

@ -31,6 +31,12 @@
namespace sol { namespace sol {
struct proxy_base_tag {}; struct proxy_base_tag {};
namespace detail {
template <typename T>
using proxy_key_t = meta::conditional_t<meta::is_specialization_of_v<meta::unqualified_t<T>, std::tuple>, T,
std::tuple<meta::conditional_t<std::is_array_v<meta::unqualified_t<T>>, std::remove_reference_t<T>&, meta::unqualified_t<T>>>>;
}
template <typename Super> template <typename Super>
struct proxy_base : proxy_base_tag { struct proxy_base : proxy_base_tag {
operator std::string() const { operator std::string() const {

View File

@ -70,10 +70,14 @@ namespace sol {
template <typename base_type> template <typename base_type>
template <typename Key, typename Value> template <typename Key, typename Value>
void basic_metatable<base_type>::set(Key&& key, Value&& value) { void basic_metatable<base_type>::set(Key&& key, Value&& value) {
optional<u_detail::usertype_storage_base&> maybe_uts = u_detail::maybe_get_usertype_storage_base(this->lua_state()); this->push();
lua_State* L = this->lua_state();
int target = lua_gettop(L);
optional<u_detail::usertype_storage_base&> maybe_uts = u_detail::maybe_get_usertype_storage_base(L, target);
lua_pop(L, 1);
if (maybe_uts) { if (maybe_uts) {
u_detail::usertype_storage_base& uts = *maybe_uts; u_detail::usertype_storage_base& uts = *maybe_uts;
uts.set(std::forward<Key>(key), std::forward<Value>(value)); uts.set(L, std::forward<Key>(key), std::forward<Value>(value));
} }
else { else {
base_t::set(std::forward<Key>(key), std::forward<Value>(value)); base_t::set(std::forward<Key>(key), std::forward<Value>(value));

View File

@ -68,6 +68,10 @@ namespace sol {
friend class state; friend class state;
friend class state_view; friend class state_view;
template <typename, typename>
friend class basic_usertype;
template <typename>
friend class basic_metatable;
template <bool raw, typename... Ret, typename... Keys> template <bool raw, typename... Ret, typename... Keys>
decltype(auto) tuple_get(int table_index, Keys&&... keys) const { decltype(auto) tuple_get(int table_index, Keys&&... keys) const {
@ -116,6 +120,8 @@ namespace sol {
auto pp = stack::push_pop<global>(*this); auto pp = stack::push_pop<global>(*this);
int table_index = pp.index_of(*this); int table_index = pp.index_of(*this);
lua_State* L = base_t::lua_state(); lua_State* L = base_t::lua_state();
(void)table_index;
(void)L;
void(detail::swallow{ (stack::set_field<top_level, raw>(L, void(detail::swallow{ (stack::set_field<top_level, raw>(L,
std::get<I * 2>(std::forward<Pairs>(pairs)), std::get<I * 2>(std::forward<Pairs>(pairs)),
std::get<I * 2 + 1>(std::forward<Pairs>(pairs)), std::get<I * 2 + 1>(std::forward<Pairs>(pairs)),

View File

@ -36,6 +36,7 @@ namespace sol {
class basic_usertype : private basic_metatable<base_type> { class basic_usertype : private basic_metatable<base_type> {
private: private:
using base_t = basic_metatable<base_type>; using base_t = basic_metatable<base_type>;
using table_base_t = basic_table<base_type>;
template <typename> template <typename>
friend class basic_metatable; friend class basic_metatable;
@ -44,18 +45,23 @@ namespace sol {
friend class basic_table_core; friend class basic_table_core;
template <std::size_t... I, typename... Args> template <std::size_t... I, typename... Args>
void tuple_set(std::index_sequence<I...>, std::tuple<Args...>&& args) { void tuple_set(std::index_sequence<I...> indices, std::tuple<Args...>&& args) {
using args_tuple = std::tuple<Args...>&&; using args_tuple = std::tuple<Args...>&&;
optional<u_detail::usertype_storage<T>&> maybe_uts = u_detail::maybe_get_usertype_storage<T>(this->lua_state()); lua_State* L = this->lua_state();
optional<u_detail::usertype_storage<T>&> maybe_uts = u_detail::maybe_get_usertype_storage<T>(L);
if constexpr (sizeof...(I) > 0) { if constexpr (sizeof...(I) > 0) {
if (maybe_uts) { if (maybe_uts) {
u_detail::usertype_storage<T>& uts = *maybe_uts; u_detail::usertype_storage<T>& uts = *maybe_uts;
(void)detail::swallow{ 0, (void)detail::swallow{ 0,
(uts.set(this->lua_state(), std::get<I * 2>(std::forward<args_tuple>(args)), std::get<I * 2 + 1>(std::forward<args_tuple>(args))), (uts.set(L, std::get<I * 2>(std::forward<args_tuple>(args)), std::get<I * 2 + 1>(std::forward<args_tuple>(args))),
0)... }; 0)... };
} }
else {
table_base_t::template tuple_set<false>(indices, std::move(args));
}
} }
else { else {
(void)indices;
(void)args; (void)args;
} }
} }
@ -67,6 +73,9 @@ namespace sol {
using base_t::push; using base_t::push;
using base_t::lua_state; using base_t::lua_state;
using base_t::get; using base_t::get;
using base_t::set_function;
using base_t::traverse_set;
using base_t::traverse_get;
using base_t::unregister; using base_t::unregister;
template <typename Key, typename Value> template <typename Key, typename Value>
@ -76,6 +85,9 @@ namespace sol {
u_detail::usertype_storage<T>& uts = *maybe_uts; u_detail::usertype_storage<T>& uts = *maybe_uts;
uts.set(this->lua_state(), std::forward<Key>(key), std::forward<Value>(value)); uts.set(this->lua_state(), std::forward<Key>(key), std::forward<Value>(value));
} }
else {
base_t::set(std::forward<Key>(key), std::forward<Value>(value));
}
} }
template <typename Key> template <typename Key>

View File

@ -32,9 +32,42 @@
namespace sol { namespace sol {
template <typename Table, typename Key> template <typename Table, typename Key>
struct usertype_proxy : public proxy_base<usertype_proxy<Table, Key>> { struct usertype_proxy : public proxy_base<usertype_proxy<Table, Key>> {
private:
using key_type = detail::proxy_key_t<Key>;
template <typename T, std::size_t... I>
decltype(auto) tuple_get(std::index_sequence<I...>) const & {
return tbl.template traverse_get<T>(std::get<I>(key)...);
}
template <typename T, std::size_t... I>
decltype(auto) tuple_get(std::index_sequence<I...>) && {
return tbl.template traverse_get<T>(std::get<I>(std::move(key))...);
}
template <std::size_t... I, typename T>
void tuple_set(std::index_sequence<I...>, T&& value) & {
if constexpr (sizeof...(I) > 1) {
tbl.traverse_set(std::get<I>(key)..., std::forward<T>(value));
}
else {
tbl.set(std::get<I>(key)..., std::forward<T>(value));
}
}
template <std::size_t... I, typename T>
void tuple_set(std::index_sequence<I...>, T&& value) && {
if constexpr (sizeof...(I) > 1) {
tbl.traverse_set(std::get<I>(std::move(key))..., std::forward<T>(value));
}
else {
tbl.set(std::get<I>(std::move(key))..., std::forward<T>(value));
}
}
public: public:
Table tbl; Table tbl;
Key key; key_type key;
template <typename T> template <typename T>
usertype_proxy(Table table, T&& k) usertype_proxy(Table table, T&& k)
@ -42,21 +75,110 @@ namespace sol {
} }
template <typename T> template <typename T>
usertype_proxy& set(T&& value) { usertype_proxy& set(T&& item) & {
tbl.set(key, std::forward<T>(value)); using idx_seq = std::make_index_sequence<std::tuple_size_v<meta::unqualified_t<key_type>>>;
tuple_set(idx_seq(), std::forward<T>(item));
return *this; return *this;
} }
template <typename U> template <typename T>
usertype_proxy& operator=(U&& other) { usertype_proxy&& set(T&& item) && {
return set(std::forward<U>(other)); using idx_seq = std::make_index_sequence<std::tuple_size_v<meta::unqualified_t<key_type>>>;
std::move(*this).tuple_set(idx_seq(), std::forward<T>(item));
return std::move(*this);
} }
template <typename T> template <typename T>
usertype_proxy& operator=(std::initializer_list<T> other) { usertype_proxy& operator=(T&& other) & {
return set(std::forward<T>(other));
}
template <typename T>
usertype_proxy&& operator=(T&& other) && {
return std::move(*this).set(std::forward<T>(other));
}
template <typename T>
usertype_proxy& operator=(std::initializer_list<T> other) & {
return set(std::move(other)); return set(std::move(other));
} }
template <typename T>
usertype_proxy&& operator=(std::initializer_list<T> other) && {
return std::move(*this).set(std::move(other));
}
template <typename T>
decltype(auto) get() const& {
using idx_seq = std::make_index_sequence<std::tuple_size_v<meta::unqualified_t<key_type>>>;
return tuple_get<T>(idx_seq());
}
template <typename T>
decltype(auto) get() && {
using idx_seq = std::make_index_sequence<std::tuple_size_v<meta::unqualified_t<key_type>>>;
return std::move(*this).template tuple_get<T>(idx_seq());
}
template <typename K>
decltype(auto) operator[](K&& k) const& {
auto keys = meta::tuplefy(key, std::forward<K>(k));
return usertype_proxy<Table, decltype(keys)>(tbl, std::move(keys));
}
template <typename K>
decltype(auto) operator[](K&& k) & {
auto keys = meta::tuplefy(key, std::forward<K>(k));
return usertype_proxy<Table, decltype(keys)>(tbl, std::move(keys));
}
template <typename K>
decltype(auto) operator[](K&& k) && {
auto keys = meta::tuplefy(std::move(key), std::forward<K>(k));
return usertype_proxy<Table, decltype(keys)>(tbl, std::move(keys));
}
template <typename... Ret, typename... Args>
decltype(auto) call(Args&&... args) {
#if !defined(__clang__) && defined(_MSC_FULL_VER) && _MSC_FULL_VER >= 191200000
// MSVC is ass sometimes
return get<function>().call<Ret...>(std::forward<Args>(args)...);
#else
return get<function>().template call<Ret...>(std::forward<Args>(args)...);
#endif
}
template <typename... Args>
decltype(auto) operator()(Args&&... args) {
return call<>(std::forward<Args>(args)...);
}
bool valid() const {
auto pp = stack::push_pop(tbl);
auto p = stack::probe_get_field<std::is_same<meta::unqualified_t<Table>, global_table>::value>(lua_state(), key, lua_gettop(lua_state()));
lua_pop(lua_state(), p.levels);
return p;
}
int push() const noexcept {
return push(this->lua_state());
}
int push(lua_State* L) const noexcept {
return get<reference>().push(L);
}
type get_type() const {
type t = type::none;
auto pp = stack::push_pop(tbl);
auto p = stack::probe_get_field<std::is_same<meta::unqualified_t<Table>, global_table>::value>(lua_state(), key, lua_gettop(lua_state()));
if (p) {
t = type_of(lua_state(), -1);
}
lua_pop(lua_state(), p.levels);
return t;
}
lua_State* lua_state() const { lua_State* lua_state() const {
return tbl.lua_state(); return tbl.lua_state();
} }

View File

@ -774,17 +774,27 @@ namespace sol { namespace u_detail {
return target_umt; return target_umt;
} }
inline optional<usertype_storage_base&> maybe_get_usertype_storage_base(lua_State* L, const char* gcmetakey) { inline optional<usertype_storage_base&> maybe_get_usertype_storage_base(lua_State* L, int index) {
stack::get_field<true>(L, gcmetakey);
stack::record tracking; stack::record tracking;
if (!stack::check<user<usertype_storage_base>>(L, index)) {
return nullopt;
}
usertype_storage_base& target_umt = stack::stack_detail::unchecked_unqualified_get<user<usertype_storage_base>>(L, -1, tracking); usertype_storage_base& target_umt = stack::stack_detail::unchecked_unqualified_get<user<usertype_storage_base>>(L, -1, tracking);
return target_umt; return target_umt;
} }
inline optional<usertype_storage_base&> maybe_get_usertype_storage_base(lua_State* L, const char* gcmetakey) {
stack::get_field<true>(L, gcmetakey);
auto maybe_storage = maybe_get_usertype_storage_base(L, lua_gettop(L));
lua_pop(L, 1);
return maybe_storage;
}
inline usertype_storage_base& get_usertype_storage_base(lua_State* L, const char* gcmetakey) { inline usertype_storage_base& get_usertype_storage_base(lua_State* L, const char* gcmetakey) {
stack::get_field<true>(L, gcmetakey); stack::get_field<true>(L, gcmetakey);
stack::record tracking; stack::record tracking;
usertype_storage_base& target_umt = stack::stack_detail::unchecked_unqualified_get<user<usertype_storage_base>>(L, -1, tracking); usertype_storage_base& target_umt = stack::stack_detail::unchecked_unqualified_get<user<usertype_storage_base>>(L, -1, tracking);
lua_pop(L, 1);
return target_umt; return target_umt;
} }
@ -792,7 +802,8 @@ namespace sol { namespace u_detail {
inline optional<usertype_storage<T>&> maybe_get_usertype_storage(lua_State* L) { inline optional<usertype_storage<T>&> maybe_get_usertype_storage(lua_State* L) {
const char* gcmetakey = &usertype_traits<T>::gc_table()[0]; const char* gcmetakey = &usertype_traits<T>::gc_table()[0];
stack::get_field<true>(L, gcmetakey); stack::get_field<true>(L, gcmetakey);
if (!stack::check<user<usertype_storage<T>>>(L)) { int target = lua_gettop(L);
if (!stack::check<user<usertype_storage<T>>>(L, target)) {
return nullopt; return nullopt;
} }
usertype_storage<T>& target_umt = stack::pop<user<usertype_storage<T>>>(L); usertype_storage<T>& target_umt = stack::pop<user<usertype_storage<T>>>(L);

View File

@ -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 2019-04-23 14:29:43.918566 UTC // Generated 2019-04-28 13:40:08.826493 UTC
// This header was generated with sol v3.0.1-beta2 (revision 468ac36) // This header was generated with sol v3.0.1-beta2 (revision 2d47085)
// https://github.com/ThePhD/sol2 // https://github.com/ThePhD/sol2
#ifndef SOL_SINGLE_INCLUDE_FORWARD_HPP #ifndef SOL_SINGLE_INCLUDE_FORWARD_HPP

View File

@ -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 2019-04-23 14:29:43.637794 UTC // Generated 2019-04-28 13:40:08.534101 UTC
// This header was generated with sol v3.0.1-beta2 (revision 468ac36) // This header was generated with sol v3.0.1-beta2 (revision 2d47085)
// https://github.com/ThePhD/sol2 // https://github.com/ThePhD/sol2
#ifndef SOL_SINGLE_INCLUDE_HPP #ifndef SOL_SINGLE_INCLUDE_HPP
@ -3491,23 +3491,20 @@ namespace sol {
namespace sol { namespace sol {
namespace detail { namespace detail {
struct direct_error_tag {}; struct direct_error_tag {};
const auto direct_error = direct_error_tag {}; const auto direct_error = direct_error_tag{};
struct error_result { struct error_result {
int results; int results;
const char* format_string; const char* format_string;
std::array<const char*, 4> args_strings; std::array<const char*, 4> args_strings;
error_result() error_result() : results(0), format_string(nullptr) {
: results(0), format_string(nullptr) {
} }
error_result(int results) error_result(int results) : results(results), format_string(nullptr) {
: results(results), format_string(nullptr) {
} }
error_result(const char* fmt, const char* msg) error_result(const char* fmt, const char* msg) : results(0), format_string(fmt) {
: results(0), format_string(fmt) {
args_strings[0] = msg; args_strings[0] = msg;
} }
}; };
@ -3523,20 +3520,16 @@ namespace sol {
class error : public std::runtime_error { class error : public std::runtime_error {
private: private:
// Because VC++ is upsetting, most of the time! // Because VC++ is upsetting, most of the time!
std::string w; std::string what_reason;
public: public:
error(const std::string& str) error(const std::string& str) : error(detail::direct_error, "lua: error: " + str) {
: error(detail::direct_error, "lua: error: " + str) {
} }
error(std::string&& str) error(std::string&& str) : error(detail::direct_error, "lua: error: " + std::move(str)) {
: error(detail::direct_error, "lua: error: " + std::move(str)) {
} }
error(detail::direct_error_tag, const std::string& str) error(detail::direct_error_tag, const std::string& str) : std::runtime_error(""), what_reason(str) {
: std::runtime_error(""), w(str) {
} }
error(detail::direct_error_tag, std::string&& str) error(detail::direct_error_tag, std::string&& str) : std::runtime_error(""), what_reason(std::move(str)) {
: std::runtime_error(""), w(std::move(str)) {
} }
error(const error& e) = default; error(const error& e) = default;
@ -3545,7 +3538,7 @@ namespace sol {
error& operator=(error&& e) = default; error& operator=(error&& e) = default;
virtual const char* what() const noexcept override { virtual const char* what() const noexcept override {
return w.c_str(); return what_reason.c_str();
} }
}; };
@ -14654,6 +14647,12 @@ namespace sol {
namespace sol { namespace sol {
struct proxy_base_tag {}; struct proxy_base_tag {};
namespace detail {
template <typename T>
using proxy_key_t = meta::conditional_t<meta::is_specialization_of_v<meta::unqualified_t<T>, std::tuple>, T,
std::tuple<meta::conditional_t<std::is_array_v<meta::unqualified_t<T>>, std::remove_reference_t<T>&, meta::unqualified_t<T>>>>;
}
template <typename Super> template <typename Super>
struct proxy_base : proxy_base_tag { struct proxy_base : proxy_base_tag {
operator std::string() const { operator std::string() const {
@ -21344,17 +21343,27 @@ namespace sol { namespace u_detail {
return target_umt; return target_umt;
} }
inline optional<usertype_storage_base&> maybe_get_usertype_storage_base(lua_State* L, const char* gcmetakey) { inline optional<usertype_storage_base&> maybe_get_usertype_storage_base(lua_State* L, int index) {
stack::get_field<true>(L, gcmetakey);
stack::record tracking; stack::record tracking;
if (!stack::check<user<usertype_storage_base>>(L, index)) {
return nullopt;
}
usertype_storage_base& target_umt = stack::stack_detail::unchecked_unqualified_get<user<usertype_storage_base>>(L, -1, tracking); usertype_storage_base& target_umt = stack::stack_detail::unchecked_unqualified_get<user<usertype_storage_base>>(L, -1, tracking);
return target_umt; return target_umt;
} }
inline optional<usertype_storage_base&> maybe_get_usertype_storage_base(lua_State* L, const char* gcmetakey) {
stack::get_field<true>(L, gcmetakey);
auto maybe_storage = maybe_get_usertype_storage_base(L, lua_gettop(L));
lua_pop(L, 1);
return maybe_storage;
}
inline usertype_storage_base& get_usertype_storage_base(lua_State* L, const char* gcmetakey) { inline usertype_storage_base& get_usertype_storage_base(lua_State* L, const char* gcmetakey) {
stack::get_field<true>(L, gcmetakey); stack::get_field<true>(L, gcmetakey);
stack::record tracking; stack::record tracking;
usertype_storage_base& target_umt = stack::stack_detail::unchecked_unqualified_get<user<usertype_storage_base>>(L, -1, tracking); usertype_storage_base& target_umt = stack::stack_detail::unchecked_unqualified_get<user<usertype_storage_base>>(L, -1, tracking);
lua_pop(L, 1);
return target_umt; return target_umt;
} }
@ -21362,7 +21371,8 @@ namespace sol { namespace u_detail {
inline optional<usertype_storage<T>&> maybe_get_usertype_storage(lua_State* L) { inline optional<usertype_storage<T>&> maybe_get_usertype_storage(lua_State* L) {
const char* gcmetakey = &usertype_traits<T>::gc_table()[0]; const char* gcmetakey = &usertype_traits<T>::gc_table()[0];
stack::get_field<true>(L, gcmetakey); stack::get_field<true>(L, gcmetakey);
if (!stack::check<user<usertype_storage<T>>>(L)) { int target = lua_gettop(L);
if (!stack::check<user<usertype_storage<T>>>(L, target)) {
return nullopt; return nullopt;
} }
usertype_storage<T>& target_umt = stack::pop<user<usertype_storage<T>>>(L); usertype_storage<T>& target_umt = stack::pop<user<usertype_storage<T>>>(L);
@ -21634,9 +21644,42 @@ namespace sol { namespace u_detail {
namespace sol { namespace sol {
template <typename Table, typename Key> template <typename Table, typename Key>
struct usertype_proxy : public proxy_base<usertype_proxy<Table, Key>> { struct usertype_proxy : public proxy_base<usertype_proxy<Table, Key>> {
private:
using key_type = detail::proxy_key_t<Key>;
template <typename T, std::size_t... I>
decltype(auto) tuple_get(std::index_sequence<I...>) const & {
return tbl.template traverse_get<T>(std::get<I>(key)...);
}
template <typename T, std::size_t... I>
decltype(auto) tuple_get(std::index_sequence<I...>) && {
return tbl.template traverse_get<T>(std::get<I>(std::move(key))...);
}
template <std::size_t... I, typename T>
void tuple_set(std::index_sequence<I...>, T&& value) & {
if constexpr (sizeof...(I) > 1) {
tbl.traverse_set(std::get<I>(key)..., std::forward<T>(value));
}
else {
tbl.set(std::get<I>(key)..., std::forward<T>(value));
}
}
template <std::size_t... I, typename T>
void tuple_set(std::index_sequence<I...>, T&& value) && {
if constexpr (sizeof...(I) > 1) {
tbl.traverse_set(std::get<I>(std::move(key))..., std::forward<T>(value));
}
else {
tbl.set(std::get<I>(std::move(key))..., std::forward<T>(value));
}
}
public: public:
Table tbl; Table tbl;
Key key; key_type key;
template <typename T> template <typename T>
usertype_proxy(Table table, T&& k) usertype_proxy(Table table, T&& k)
@ -21644,21 +21687,110 @@ namespace sol {
} }
template <typename T> template <typename T>
usertype_proxy& set(T&& value) { usertype_proxy& set(T&& item) & {
tbl.set(key, std::forward<T>(value)); using idx_seq = std::make_index_sequence<std::tuple_size_v<meta::unqualified_t<key_type>>>;
tuple_set(idx_seq(), std::forward<T>(item));
return *this; return *this;
} }
template <typename U> template <typename T>
usertype_proxy& operator=(U&& other) { usertype_proxy&& set(T&& item) && {
return set(std::forward<U>(other)); using idx_seq = std::make_index_sequence<std::tuple_size_v<meta::unqualified_t<key_type>>>;
std::move(*this).tuple_set(idx_seq(), std::forward<T>(item));
return std::move(*this);
} }
template <typename T> template <typename T>
usertype_proxy& operator=(std::initializer_list<T> other) { usertype_proxy& operator=(T&& other) & {
return set(std::forward<T>(other));
}
template <typename T>
usertype_proxy&& operator=(T&& other) && {
return std::move(*this).set(std::forward<T>(other));
}
template <typename T>
usertype_proxy& operator=(std::initializer_list<T> other) & {
return set(std::move(other)); return set(std::move(other));
} }
template <typename T>
usertype_proxy&& operator=(std::initializer_list<T> other) && {
return std::move(*this).set(std::move(other));
}
template <typename T>
decltype(auto) get() const& {
using idx_seq = std::make_index_sequence<std::tuple_size_v<meta::unqualified_t<key_type>>>;
return tuple_get<T>(idx_seq());
}
template <typename T>
decltype(auto) get() && {
using idx_seq = std::make_index_sequence<std::tuple_size_v<meta::unqualified_t<key_type>>>;
return std::move(*this).template tuple_get<T>(idx_seq());
}
template <typename K>
decltype(auto) operator[](K&& k) const& {
auto keys = meta::tuplefy(key, std::forward<K>(k));
return usertype_proxy<Table, decltype(keys)>(tbl, std::move(keys));
}
template <typename K>
decltype(auto) operator[](K&& k) & {
auto keys = meta::tuplefy(key, std::forward<K>(k));
return usertype_proxy<Table, decltype(keys)>(tbl, std::move(keys));
}
template <typename K>
decltype(auto) operator[](K&& k) && {
auto keys = meta::tuplefy(std::move(key), std::forward<K>(k));
return usertype_proxy<Table, decltype(keys)>(tbl, std::move(keys));
}
template <typename... Ret, typename... Args>
decltype(auto) call(Args&&... args) {
#if !defined(__clang__) && defined(_MSC_FULL_VER) && _MSC_FULL_VER >= 191200000
// MSVC is ass sometimes
return get<function>().call<Ret...>(std::forward<Args>(args)...);
#else
return get<function>().template call<Ret...>(std::forward<Args>(args)...);
#endif
}
template <typename... Args>
decltype(auto) operator()(Args&&... args) {
return call<>(std::forward<Args>(args)...);
}
bool valid() const {
auto pp = stack::push_pop(tbl);
auto p = stack::probe_get_field<std::is_same<meta::unqualified_t<Table>, global_table>::value>(lua_state(), key, lua_gettop(lua_state()));
lua_pop(lua_state(), p.levels);
return p;
}
int push() const noexcept {
return push(this->lua_state());
}
int push(lua_State* L) const noexcept {
return get<reference>().push(L);
}
type get_type() const {
type t = type::none;
auto pp = stack::push_pop(tbl);
auto p = stack::probe_get_field<std::is_same<meta::unqualified_t<Table>, global_table>::value>(lua_state(), key, lua_gettop(lua_state()));
if (p) {
t = type_of(lua_state(), -1);
}
lua_pop(lua_state(), p.levels);
return t;
}
lua_State* lua_state() const { lua_State* lua_state() const {
return tbl.lua_state(); return tbl.lua_state();
} }
@ -21675,31 +21807,31 @@ namespace sol {
namespace sol { namespace sol {
namespace detail {
template <typename T>
using proxy_key_t = meta::conditional_t<meta::is_specialization_of_v<meta::unqualified_t<T>, std::tuple>,
T,
std::tuple<meta::conditional_t<
std::is_array_v<meta::unqualified_t<T>>, std::remove_reference_t<T>&, meta::unqualified_t<T>
>>
>;
}
template <typename Table, typename Key> template <typename Table, typename Key>
struct proxy : public proxy_base<proxy<Table, Key>> { struct proxy : public proxy_base<proxy<Table, Key>> {
private: private:
using key_type = detail::proxy_key_t<Key>; using key_type = detail::proxy_key_t<Key>;
template <typename T, std::size_t... I> template <typename T, std::size_t... I>
decltype(auto) tuple_get(std::index_sequence<I...>) const { decltype(auto) tuple_get(std::index_sequence<I...>) const & {
return tbl.template traverse_get<T>(std::get<I>(key)...); return tbl.template traverse_get<T>(std::get<I>(key)...);
} }
template <typename T, std::size_t... I>
decltype(auto) tuple_get(std::index_sequence<I...>) && {
return tbl.template traverse_get<T>(std::get<I>(std::move(key))...);
}
template <std::size_t... I, typename T> template <std::size_t... I, typename T>
void tuple_set(std::index_sequence<I...>, T&& value) { void tuple_set(std::index_sequence<I...>, T&& value) & {
tbl.traverse_set(std::get<I>(key)..., std::forward<T>(value)); tbl.traverse_set(std::get<I>(key)..., std::forward<T>(value));
} }
template <std::size_t... I, typename T>
void tuple_set(std::index_sequence<I...>, T&& value) && {
tbl.traverse_set(std::get<I>(std::move(key))..., std::forward<T>(value));
}
auto setup_table(std::true_type) { auto setup_table(std::true_type) {
auto p = stack::probe_get_field<std::is_same_v<meta::unqualified_t<Table>, global_table>>(lua_state(), key, tbl.stack_index()); auto p = stack::probe_get_field<std::is_same_v<meta::unqualified_t<Table>, global_table>>(lua_state(), key, tbl.stack_index());
lua_pop(lua_state(), p.levels); lua_pop(lua_state(), p.levels);
@ -21723,19 +21855,31 @@ namespace sol {
} }
template <typename T> template <typename T>
proxy& set(T&& item) { proxy& set(T&& item) & {
tuple_set(std::make_index_sequence<std::tuple_size_v<meta::unqualified_t<key_type>>>(), std::forward<T>(item)); tuple_set(std::make_index_sequence<std::tuple_size_v<meta::unqualified_t<key_type>>>(), std::forward<T>(item));
return *this; return *this;
} }
template <typename T>
proxy&& set(T&& item) && {
tuple_set(std::make_index_sequence<std::tuple_size_v<meta::unqualified_t<key_type>>>(), std::forward<T>(item));
return std::move(*this);
}
template <typename... Args> template <typename... Args>
proxy& set_function(Args&&... args) { proxy& set_function(Args&&... args) & {
tbl.set_function(key, std::forward<Args>(args)...); tbl.set_function(key, std::forward<Args>(args)...);
return *this; return *this;
} }
template <typename... Args>
proxy&& set_function(Args&&... args) && {
tbl.set_function(std::move(key), std::forward<Args>(args)...);
return std::move(*this);
}
template <typename T> template <typename T>
proxy& operator=(T&& other) { proxy& operator=(T&& other) & {
using Tu = meta::unwrap_unqualified_t<T>; using Tu = meta::unwrap_unqualified_t<T>;
if constexpr (!is_lua_reference_or_proxy_v<Tu> && meta::is_callable_v<Tu>) { if constexpr (!is_lua_reference_or_proxy_v<Tu> && meta::is_callable_v<Tu>) {
return set_function(std::forward<T>(other)); return set_function(std::forward<T>(other));
@ -21746,13 +21890,36 @@ namespace sol {
} }
template <typename T> template <typename T>
proxy& operator=(std::initializer_list<T> other) { proxy&& operator=(T&& other) && {
using Tu = meta::unwrap_unqualified_t<T>;
if constexpr (!is_lua_reference_or_proxy_v<Tu> && meta::is_callable_v<Tu>) {
return std::move(*this).set_function(std::forward<T>(other));
}
else {
return std::move(*this).set(std::forward<T>(other));
}
}
template <typename T>
proxy& operator=(std::initializer_list<T> other) & {
return set(std::move(other)); return set(std::move(other));
} }
template <typename T> template <typename T>
decltype(auto) get() const { proxy&& operator=(std::initializer_list<T> other) && {
return tuple_get<T>(std::make_index_sequence<std::tuple_size<meta::unqualified_t<key_type>>::value>()); return std::move(*this).set(std::move(other));
}
template <typename T>
decltype(auto) get() const & {
using idx_seq = std::make_index_sequence<std::tuple_size_v<meta::unqualified_t<key_type>>>;
return tuple_get<T>(idx_seq());
}
template <typename T>
decltype(auto) get() && {
using idx_seq = std::make_index_sequence<std::tuple_size_v<meta::unqualified_t<key_type>>>;
return std::move(*this).template tuple_get<T>(idx_seq());
} }
template <typename T> template <typename T>
@ -22060,6 +22227,10 @@ namespace sol {
friend class state; friend class state;
friend class state_view; friend class state_view;
template <typename, typename>
friend class basic_usertype;
template <typename>
friend class basic_metatable;
template <bool raw, typename... Ret, typename... Keys> template <bool raw, typename... Ret, typename... Keys>
decltype(auto) tuple_get(int table_index, Keys&&... keys) const { decltype(auto) tuple_get(int table_index, Keys&&... keys) const {
@ -22108,6 +22279,8 @@ namespace sol {
auto pp = stack::push_pop<global>(*this); auto pp = stack::push_pop<global>(*this);
int table_index = pp.index_of(*this); int table_index = pp.index_of(*this);
lua_State* L = base_t::lua_state(); lua_State* L = base_t::lua_state();
(void)table_index;
(void)L;
void(detail::swallow{ (stack::set_field<top_level, raw>(L, void(detail::swallow{ (stack::set_field<top_level, raw>(L,
std::get<I * 2>(std::forward<Pairs>(pairs)), std::get<I * 2>(std::forward<Pairs>(pairs)),
std::get<I * 2 + 1>(std::forward<Pairs>(pairs)), std::get<I * 2 + 1>(std::forward<Pairs>(pairs)),
@ -22746,6 +22919,7 @@ namespace sol {
class basic_usertype : private basic_metatable<base_type> { class basic_usertype : private basic_metatable<base_type> {
private: private:
using base_t = basic_metatable<base_type>; using base_t = basic_metatable<base_type>;
using table_base_t = basic_table<base_type>;
template <typename> template <typename>
friend class basic_metatable; friend class basic_metatable;
@ -22754,18 +22928,23 @@ namespace sol {
friend class basic_table_core; friend class basic_table_core;
template <std::size_t... I, typename... Args> template <std::size_t... I, typename... Args>
void tuple_set(std::index_sequence<I...>, std::tuple<Args...>&& args) { void tuple_set(std::index_sequence<I...> indices, std::tuple<Args...>&& args) {
using args_tuple = std::tuple<Args...>&&; using args_tuple = std::tuple<Args...>&&;
optional<u_detail::usertype_storage<T>&> maybe_uts = u_detail::maybe_get_usertype_storage<T>(this->lua_state()); lua_State* L = this->lua_state();
optional<u_detail::usertype_storage<T>&> maybe_uts = u_detail::maybe_get_usertype_storage<T>(L);
if constexpr (sizeof...(I) > 0) { if constexpr (sizeof...(I) > 0) {
if (maybe_uts) { if (maybe_uts) {
u_detail::usertype_storage<T>& uts = *maybe_uts; u_detail::usertype_storage<T>& uts = *maybe_uts;
(void)detail::swallow{ 0, (void)detail::swallow{ 0,
(uts.set(this->lua_state(), std::get<I * 2>(std::forward<args_tuple>(args)), std::get<I * 2 + 1>(std::forward<args_tuple>(args))), (uts.set(L, std::get<I * 2>(std::forward<args_tuple>(args)), std::get<I * 2 + 1>(std::forward<args_tuple>(args))),
0)... }; 0)... };
} }
else {
table_base_t::template tuple_set<false>(indices, std::move(args));
}
} }
else { else {
(void)indices;
(void)args; (void)args;
} }
} }
@ -22777,6 +22956,9 @@ namespace sol {
using base_t::push; using base_t::push;
using base_t::lua_state; using base_t::lua_state;
using base_t::get; using base_t::get;
using base_t::set_function;
using base_t::traverse_set;
using base_t::traverse_get;
using base_t::unregister; using base_t::unregister;
template <typename Key, typename Value> template <typename Key, typename Value>
@ -22786,6 +22968,9 @@ namespace sol {
u_detail::usertype_storage<T>& uts = *maybe_uts; u_detail::usertype_storage<T>& uts = *maybe_uts;
uts.set(this->lua_state(), std::forward<Key>(key), std::forward<Value>(value)); uts.set(this->lua_state(), std::forward<Key>(key), std::forward<Value>(value));
} }
else {
base_t::set(std::forward<Key>(key), std::forward<Value>(value));
}
} }
template <typename Key> template <typename Key>
@ -22917,10 +23102,14 @@ namespace sol {
template <typename base_type> template <typename base_type>
template <typename Key, typename Value> template <typename Key, typename Value>
void basic_metatable<base_type>::set(Key&& key, Value&& value) { void basic_metatable<base_type>::set(Key&& key, Value&& value) {
optional<u_detail::usertype_storage_base&> maybe_uts = u_detail::maybe_get_usertype_storage_base(this->lua_state()); this->push();
lua_State* L = this->lua_state();
int target = lua_gettop(L);
optional<u_detail::usertype_storage_base&> maybe_uts = u_detail::maybe_get_usertype_storage_base(L, target);
lua_pop(L, 1);
if (maybe_uts) { if (maybe_uts) {
u_detail::usertype_storage_base& uts = *maybe_uts; u_detail::usertype_storage_base& uts = *maybe_uts;
uts.set(std::forward<Key>(key), std::forward<Value>(value)); uts.set(L, std::forward<Key>(key), std::forward<Value>(value));
} }
else { else {
base_t::set(std::forward<Key>(key), std::forward<Value>(value)); base_t::set(std::forward<Key>(key), std::forward<Value>(value));

View File

@ -30,6 +30,28 @@
#include <iostream> #include <iostream>
#include <list> #include <list>
#include <memory> #include <memory>
#include <unordered_map>
struct special_property_object {
struct obj_hash {
std::size_t operator()(const sol::object& obj) const noexcept {
return std::hash<const void*>()(obj.pointer());
}
};
std::unordered_map<sol::object, sol::object, obj_hash> props;
sol::object get_property_lua(sol::stack_object key) const {
if (auto it = props.find(key); it != props.cend()) {
return it->second;
}
return sol::lua_nil;
}
void set_property_lua(sol::stack_object key, sol::stack_object value) {
props.insert_or_assign(key, sol::object(value));
}
};
struct new_index_test_object { struct new_index_test_object {
bool new_indexed = false; bool new_indexed = false;
@ -403,3 +425,46 @@ TEST_CASE("usertype/new_index and index", "a custom new_index and index only kic
REQUIRE(a.borf_new_indexed); REQUIRE(a.borf_new_indexed);
REQUIRE(a.new_indexed); REQUIRE(a.new_indexed);
} }
TEST_CASE("usertype/object and class extensible", "make sure that a class which override new_index and friends can still work properly") {
sol::state lua;
lua.open_libraries(sol::lib::base);
lua.new_usertype<special_property_object>("special_property_object", sol::meta_function::new_index, &special_property_object::set_property_lua, sol::meta_function::index, &special_property_object::get_property_lua);
lua["add_class_func"] = [](sol::this_state L, special_property_object&) {
sol::stack_userdata self = sol::stack::get<sol::stack_userdata>(L, 1);
sol::usertype<special_property_object> mt = self[sol::metatable_key];
std::string s = mt["__name"];
mt["additional_function"] = []() { return 24; };
};
lua["add_object_func"] = [](sol::this_state L, special_property_object&) {
sol::stack_userdata self = sol::stack::get<sol::stack_userdata>(L, 1);
self["specific_function"] = []() { return 23; };
};
sol::optional<sol::error> result0 = lua.safe_script(R"(
s = special_property_object.new()
s2 = special_property_object.new()
add_class_func(s)
add_object_func(s)
value = s:additional_function()
assert(value == 24)
value2 = s:specific_function()
assert(value2 == 23)
)",
sol::script_pass_on_error);
REQUIRE_FALSE(result0.has_value());
int value = lua["value"];
REQUIRE(value == 24);
int value2 = lua["value2"];
REQUIRE(value2 == 23);
sol::optional<sol::error> result1 = lua.safe_script(R"(
value3 = s2:specific_function()
assert(value3 == 23)
)",
sol::script_pass_on_error);
REQUIRE(result1.has_value());
}