Implement better insert-with-no-iterator support

- reorder constructor values to match class order
- Fix up compilation related to GCC
- Add new shim tests to confirm insertion works properly
- regenerate single
This commit is contained in:
ThePhD 2021-01-22 01:32:42 -05:00
parent a9ff1d4187
commit d363ccd759
No known key found for this signature in database
GPG Key ID: 1509DB1C0F702BFA
8 changed files with 379 additions and 194 deletions

View File

@ -65,9 +65,9 @@ namespace sol {
: m_L(nullptr)
, m_next_function_ref(lua_nil)
, m_table_ref(lua_nil)
, m_cached_key_value_pair({ lua_nil, lua_nil })
, m_key_index(empty_key_index)
, m_iteration_index(0)
, m_cached_key_value_pair({ lua_nil, lua_nil }) {
, m_iteration_index(0) {
}
pairs_iterator(const pairs_iterator&) = delete;
@ -77,9 +77,9 @@ namespace sol {
: m_L(right.m_L)
, m_next_function_ref(std::move(right.m_next_function_ref))
, m_table_ref(std::move(right.m_table_ref))
, m_cached_key_value_pair(std::move(right.m_cached_key_value_pair))
, m_key_index(right.m_key_index)
, m_iteration_index(right.m_iteration_index)
, m_cached_key_value_pair(std::move(right.m_cached_key_value_pair)) {
, m_iteration_index(right.m_iteration_index) {
right.m_key_index = empty_key_index;
}
@ -87,10 +87,11 @@ namespace sol {
m_L = right.m_L;
m_next_function_ref = std::move(right.m_next_function_ref);
m_table_ref = std::move(right.m_table_ref);
m_cached_key_value_pair = std::move(right.m_cached_key_value_pair);
m_key_index = right.m_key_index;
m_iteration_index = right.m_iteration_index;
m_cached_key_value_pair = std::move(right.m_cached_key_value_pair);
right.m_key_index = empty_key_index;
return *this;
}
template <typename Source>
@ -105,8 +106,9 @@ namespace sol {
lua_remove(m_L, abs_source_index);
if (metatable_exists == 1) {
// just has a metatable, but does it have __pairs ?
stack_lua_table metatable(m_L, abs_source_index);
optional<protected_function> maybe_pairs_function = metatable.raw_get<optional<function>>(meta_function::pairs);
stack_reference metatable(m_L, raw_index(abs_source_index));
stack::get_field<is_global_table_v<Source>, true>(m_L, meta_function::pairs, metatable.stack_index());
optional<protected_function> maybe_pairs_function = stack::pop<optional<function>>(m_L);
if (maybe_pairs_function.has_value()) {
function& pairs_function = *maybe_pairs_function;
protected_function_result next_fn_and_table_and_first_key = pairs_function(source_);

View File

@ -401,16 +401,28 @@ namespace sol { namespace meta {
};
template <typename T>
struct has_insert_test {
struct has_insert_with_iterator_test {
private:
template <typename C>
static sfinae_yes_t test(decltype(std::declval<C>().insert(std::declval<std::add_rvalue_reference_t<typename C::const_iterator>>(),
std::declval<std::add_rvalue_reference_t<typename C::value_type>>()))*);
static sfinae_yes_t test(decltype(std::declval<C>().insert(
std::declval<std::add_rvalue_reference_t<typename C::iterator>>(), std::declval<std::add_rvalue_reference_t<typename C::value_type>>()))*);
template <typename C>
static sfinae_no_t test(...);
public:
static constexpr bool value = std::is_same_v<decltype(test<T>(0)), sfinae_yes_t>;
static constexpr bool value = !std::is_same_v<decltype(test<T>(0)), sfinae_no_t>;
};
template <typename T>
struct has_insert_test {
private:
template <typename C>
static sfinae_yes_t test(decltype(std::declval<C>().insert(std::declval<std::add_rvalue_reference_t<typename C::value_type>>()))*);
template <typename C>
static sfinae_no_t test(...);
public:
static constexpr bool value = !std::is_same_v<decltype(test<T>(0)), sfinae_no_t>;
};
template <typename T>
@ -562,6 +574,9 @@ namespace sol { namespace meta {
template <typename T>
using has_insert = meta::boolean<meta_detail::has_insert_test<T>::value>;
template <typename T>
using has_insert_with_iterator = meta::boolean<meta_detail::has_insert_with_iterator_test<T>::value>;
template <typename T>
using has_insert_after = meta::boolean<meta_detail::has_insert_after_test<T>::value>;

View File

@ -719,10 +719,14 @@ namespace sol {
template <typename Iter>
static detail::error_result set_associative_insert(std::true_type, lua_State*, T& self, Iter& it, K& key, stack_object value) {
if constexpr (meta::has_insert<T>::value) {
if constexpr (meta::has_insert_with_iterator<T>::value) {
self.insert(it, value_type(key, value.as<V>()));
return {};
}
else if constexpr (meta::has_insert<T>::value) {
self.insert(value_type(key, value.as<V>()));
return {};
}
else {
(void)self;
(void)it;
@ -734,10 +738,14 @@ namespace sol {
template <typename Iter>
static detail::error_result set_associative_insert(std::false_type, lua_State*, T& self, Iter& it, K& key, stack_object) {
if constexpr (meta::has_insert<T>::value) {
if constexpr (meta::has_insert_with_iterator<T>::value) {
self.insert(it, key);
return {};
}
else if constexpr (meta::has_insert<T>::value) {
self.insert(key);
return {};
}
else {
(void)self;
(void)it;
@ -917,19 +925,25 @@ namespace sol {
template <typename Iter>
static detail::error_result add_push_back(std::false_type, lua_State* L, T& self, stack_object value, Iter& pos) {
return add_insert(meta::has_insert<T>(), L, self, value, pos);
return add_insert(
std::integral_constant < bool, meta::has_insert<T>::value || meta::has_insert_with_iterator<T>::value > (), L, self, value, pos);
}
static detail::error_result add_push_back(std::false_type, lua_State* L, T& self, stack_object value) {
return add_insert(meta::has_insert<T>(), L, self, value);
return add_insert(
std::integral_constant < bool, meta::has_insert<T>::value || meta::has_insert_with_iterator<T>::value > (), L, self, value);
}
template <typename Iter>
static detail::error_result add_associative(std::true_type, lua_State* L, T& self, stack_object key, Iter& pos) {
if constexpr (meta::has_insert<T>::value) {
if constexpr (meta::has_insert_with_iterator<T>::value) {
self.insert(pos, value_type(key.as<K>(), stack::unqualified_get<V>(L, 3)));
return {};
}
else if constexpr (meta::has_insert<T>::value) {
self.insert(value_type(key.as<K>(), stack::unqualified_get<V>(L, 3)));
return {};
}
else {
(void)L;
(void)self;
@ -1016,7 +1030,12 @@ namespace sol {
}
static detail::error_result insert_copyable(std::true_type, lua_State* L, T& self, stack_object key, stack_object value) {
return insert_has(meta::has_insert<T>(), L, self, std::move(key), std::move(value));
return insert_has(std::integral_constant < bool,
meta::has_insert<T>::value || meta::has_insert_with_iterator<T>::value > (),
L,
self,
std::move(key),
std::move(value));
}
static detail::error_result insert_copyable(std::false_type, lua_State*, T&, stack_object, stack_object) {

View File

@ -657,12 +657,6 @@ namespace sol { namespace u_detail {
inline void set(lua_State* L, Key&& key, Value&& value);
};
template <typename T>
inline int destroy_usertype_storage(lua_State* L) noexcept {
clear_usertype_registry_names<T>(L);
return detail::user_alloc_destroy<usertype_storage<T>>(L);
}
template <typename T, typename Key, typename Value>
void usertype_storage_base::set(lua_State* L, Key&& key, Value&& value) {
using ValueU = meta::unwrap_unqualified_t<Value>;
@ -804,6 +798,34 @@ namespace sol { namespace u_detail {
static_cast<usertype_storage_base&>(*this).set<T>(L, std::forward<Key>(key), std::forward<Value>(value));
}
template <typename T>
inline void clear_usertype_registry_names(lua_State* L) {
using u_traits = usertype_traits<T>;
using u_const_traits = usertype_traits<const T>;
using u_unique_traits = usertype_traits<d::u<T>>;
using u_ref_traits = usertype_traits<T*>;
using u_const_ref_traits = usertype_traits<T const*>;
stack_reference registry(L, raw_index(LUA_REGISTRYINDEX));
registry.push();
// eliminate all named entries for this usertype
// in the registry (luaL_newmetatable does
// [name] = new table
// in registry upon creation
stack::set_field(L, &u_traits::metatable()[0], lua_nil, registry.stack_index());
stack::set_field(L, &u_const_traits::metatable()[0], lua_nil, registry.stack_index());
stack::set_field(L, &u_const_ref_traits::metatable()[0], lua_nil, registry.stack_index());
stack::set_field(L, &u_ref_traits::metatable()[0], lua_nil, registry.stack_index());
stack::set_field(L, &u_unique_traits::metatable()[0], lua_nil, registry.stack_index());
registry.pop();
}
template <typename T>
inline int destroy_usertype_storage(lua_State* L) noexcept {
clear_usertype_registry_names<T>(L);
return detail::user_alloc_destroy<usertype_storage<T>>(L);
}
template <typename T>
inline usertype_storage<T>& create_usertype_storage(lua_State* L) {
const char* gcmetakey = &usertype_traits<T>::gc_table()[0];
@ -900,28 +922,6 @@ namespace sol { namespace u_detail {
return target_umt;
}
template <typename T>
inline void clear_usertype_registry_names(lua_State* L) {
using u_traits = usertype_traits<T>;
using u_const_traits = usertype_traits<const T>;
using u_unique_traits = usertype_traits<d::u<T>>;
using u_ref_traits = usertype_traits<T*>;
using u_const_ref_traits = usertype_traits<T const*>;
stack_reference registry(L, raw_index(LUA_REGISTRYINDEX));
registry.push();
// eliminate all named entries for this usertype
// in the registry (luaL_newmetatable does
// [name] = new table
// in registry upon creation
stack::set_field(L, &u_traits::metatable()[0], lua_nil, registry.stack_index());
stack::set_field(L, &u_const_traits::metatable()[0], lua_nil, registry.stack_index());
stack::set_field(L, &u_const_ref_traits::metatable()[0], lua_nil, registry.stack_index());
stack::set_field(L, &u_ref_traits::metatable()[0], lua_nil, registry.stack_index());
stack::set_field(L, &u_unique_traits::metatable()[0], lua_nil, registry.stack_index());
registry.pop();
}
template <typename T>
inline void clear_usertype_storage(lua_State* L) {
using u_traits = usertype_traits<T>;

View File

@ -20,8 +20,8 @@
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// This file was generated with a script.
// Generated 2021-01-21 20:56:50.106258 UTC
// This header was generated with sol v3.2.3 (revision c032cda5)
// Generated 2021-01-22 06:17:28.820224 UTC
// This header was generated with sol v3.2.3 (revision a9ff1d41)
// https://github.com/ThePhD/sol2
#ifndef SOL_SINGLE_CONFIG_HPP

View File

@ -20,8 +20,8 @@
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// This file was generated with a script.
// Generated 2021-01-21 20:56:50.090246 UTC
// This header was generated with sol v3.2.3 (revision c032cda5)
// Generated 2021-01-22 06:17:28.815225 UTC
// This header was generated with sol v3.2.3 (revision a9ff1d41)
// https://github.com/ThePhD/sol2
#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.
// This file was generated with a script.
// Generated 2021-01-21 20:56:49.214244 UTC
// This header was generated with sol v3.2.3 (revision c032cda5)
// Generated 2021-01-22 06:17:28.072111 UTC
// This header was generated with sol v3.2.3 (revision a9ff1d41)
// https://github.com/ThePhD/sol2
#ifndef SOL_SINGLE_INCLUDE_HPP
@ -2118,16 +2118,28 @@ namespace sol { namespace meta {
};
template <typename T>
struct has_insert_test {
struct has_insert_with_iterator_test {
private:
template <typename C>
static sfinae_yes_t test(decltype(std::declval<C>().insert(std::declval<std::add_rvalue_reference_t<typename C::const_iterator>>(),
std::declval<std::add_rvalue_reference_t<typename C::value_type>>()))*);
static sfinae_yes_t test(decltype(std::declval<C>().insert(
std::declval<std::add_rvalue_reference_t<typename C::iterator>>(), std::declval<std::add_rvalue_reference_t<typename C::value_type>>()))*);
template <typename C>
static sfinae_no_t test(...);
public:
static constexpr bool value = std::is_same_v<decltype(test<T>(0)), sfinae_yes_t>;
static constexpr bool value = !std::is_same_v<decltype(test<T>(0)), sfinae_no_t>;
};
template <typename T>
struct has_insert_test {
private:
template <typename C>
static sfinae_yes_t test(decltype(std::declval<C>().insert(std::declval<std::add_rvalue_reference_t<typename C::value_type>>()))*);
template <typename C>
static sfinae_no_t test(...);
public:
static constexpr bool value = !std::is_same_v<decltype(test<T>(0)), sfinae_no_t>;
};
template <typename T>
@ -2279,6 +2291,9 @@ namespace sol { namespace meta {
template <typename T>
using has_insert = meta::boolean<meta_detail::has_insert_test<T>::value>;
template <typename T>
using has_insert_with_iterator = meta::boolean<meta_detail::has_insert_with_iterator_test<T>::value>;
template <typename T>
using has_insert_after = meta::boolean<meta_detail::has_insert_after_test<T>::value>;
@ -21366,10 +21381,14 @@ namespace sol {
template <typename Iter>
static detail::error_result set_associative_insert(std::true_type, lua_State*, T& self, Iter& it, K& key, stack_object value) {
if constexpr (meta::has_insert<T>::value) {
if constexpr (meta::has_insert_with_iterator<T>::value) {
self.insert(it, value_type(key, value.as<V>()));
return {};
}
else if constexpr (meta::has_insert<T>::value) {
self.insert(value_type(key, value.as<V>()));
return {};
}
else {
(void)self;
(void)it;
@ -21381,10 +21400,14 @@ namespace sol {
template <typename Iter>
static detail::error_result set_associative_insert(std::false_type, lua_State*, T& self, Iter& it, K& key, stack_object) {
if constexpr (meta::has_insert<T>::value) {
if constexpr (meta::has_insert_with_iterator<T>::value) {
self.insert(it, key);
return {};
}
else if constexpr (meta::has_insert<T>::value) {
self.insert(key);
return {};
}
else {
(void)self;
(void)it;
@ -21564,19 +21587,25 @@ namespace sol {
template <typename Iter>
static detail::error_result add_push_back(std::false_type, lua_State* L, T& self, stack_object value, Iter& pos) {
return add_insert(meta::has_insert<T>(), L, self, value, pos);
return add_insert(
std::integral_constant < bool, meta::has_insert<T>::value || meta::has_insert_with_iterator<T>::value > (), L, self, value, pos);
}
static detail::error_result add_push_back(std::false_type, lua_State* L, T& self, stack_object value) {
return add_insert(meta::has_insert<T>(), L, self, value);
return add_insert(
std::integral_constant < bool, meta::has_insert<T>::value || meta::has_insert_with_iterator<T>::value > (), L, self, value);
}
template <typename Iter>
static detail::error_result add_associative(std::true_type, lua_State* L, T& self, stack_object key, Iter& pos) {
if constexpr (meta::has_insert<T>::value) {
if constexpr (meta::has_insert_with_iterator<T>::value) {
self.insert(pos, value_type(key.as<K>(), stack::unqualified_get<V>(L, 3)));
return {};
}
else if constexpr (meta::has_insert<T>::value) {
self.insert(value_type(key.as<K>(), stack::unqualified_get<V>(L, 3)));
return {};
}
else {
(void)L;
(void)self;
@ -21663,7 +21692,12 @@ namespace sol {
}
static detail::error_result insert_copyable(std::true_type, lua_State* L, T& self, stack_object key, stack_object value) {
return insert_has(meta::has_insert<T>(), L, self, std::move(key), std::move(value));
return insert_has(std::integral_constant < bool,
meta::has_insert<T>::value || meta::has_insert_with_iterator<T>::value > (),
L,
self,
std::move(key),
std::move(value));
}
static detail::error_result insert_copyable(std::false_type, lua_State*, T&, stack_object, stack_object) {
@ -23392,12 +23426,6 @@ namespace sol { namespace u_detail {
inline void set(lua_State* L, Key&& key, Value&& value);
};
template <typename T>
inline int destroy_usertype_storage(lua_State* L) noexcept {
clear_usertype_registry_names<T>(L);
return detail::user_alloc_destroy<usertype_storage<T>>(L);
}
template <typename T, typename Key, typename Value>
void usertype_storage_base::set(lua_State* L, Key&& key, Value&& value) {
using ValueU = meta::unwrap_unqualified_t<Value>;
@ -23539,6 +23567,34 @@ namespace sol { namespace u_detail {
static_cast<usertype_storage_base&>(*this).set<T>(L, std::forward<Key>(key), std::forward<Value>(value));
}
template <typename T>
inline void clear_usertype_registry_names(lua_State* L) {
using u_traits = usertype_traits<T>;
using u_const_traits = usertype_traits<const T>;
using u_unique_traits = usertype_traits<d::u<T>>;
using u_ref_traits = usertype_traits<T*>;
using u_const_ref_traits = usertype_traits<T const*>;
stack_reference registry(L, raw_index(LUA_REGISTRYINDEX));
registry.push();
// eliminate all named entries for this usertype
// in the registry (luaL_newmetatable does
// [name] = new table
// in registry upon creation
stack::set_field(L, &u_traits::metatable()[0], lua_nil, registry.stack_index());
stack::set_field(L, &u_const_traits::metatable()[0], lua_nil, registry.stack_index());
stack::set_field(L, &u_const_ref_traits::metatable()[0], lua_nil, registry.stack_index());
stack::set_field(L, &u_ref_traits::metatable()[0], lua_nil, registry.stack_index());
stack::set_field(L, &u_unique_traits::metatable()[0], lua_nil, registry.stack_index());
registry.pop();
}
template <typename T>
inline int destroy_usertype_storage(lua_State* L) noexcept {
clear_usertype_registry_names<T>(L);
return detail::user_alloc_destroy<usertype_storage<T>>(L);
}
template <typename T>
inline usertype_storage<T>& create_usertype_storage(lua_State* L) {
const char* gcmetakey = &usertype_traits<T>::gc_table()[0];
@ -23634,28 +23690,6 @@ namespace sol { namespace u_detail {
return target_umt;
}
template <typename T>
inline void clear_usertype_registry_names(lua_State* L) {
using u_traits = usertype_traits<T>;
using u_const_traits = usertype_traits<const T>;
using u_unique_traits = usertype_traits<d::u<T>>;
using u_ref_traits = usertype_traits<T*>;
using u_const_ref_traits = usertype_traits<T const*>;
stack_reference registry(L, raw_index(LUA_REGISTRYINDEX));
registry.push();
// eliminate all named entries for this usertype
// in the registry (luaL_newmetatable does
// [name] = new table
// in registry upon creation
stack::set_field(L, &u_traits::metatable()[0], lua_nil, registry.stack_index());
stack::set_field(L, &u_const_traits::metatable()[0], lua_nil, registry.stack_index());
stack::set_field(L, &u_const_ref_traits::metatable()[0], lua_nil, registry.stack_index());
stack::set_field(L, &u_ref_traits::metatable()[0], lua_nil, registry.stack_index());
stack::set_field(L, &u_unique_traits::metatable()[0], lua_nil, registry.stack_index());
registry.pop();
}
template <typename T>
inline void clear_usertype_storage(lua_State* L) {
using u_traits = usertype_traits<T>;
@ -24493,9 +24527,9 @@ namespace sol {
: m_L(nullptr)
, m_next_function_ref(lua_nil)
, m_table_ref(lua_nil)
, m_cached_key_value_pair({ lua_nil, lua_nil })
, m_key_index(empty_key_index)
, m_iteration_index(0)
, m_cached_key_value_pair({ lua_nil, lua_nil }) {
, m_iteration_index(0) {
}
pairs_iterator(const pairs_iterator&) = delete;
@ -24505,9 +24539,9 @@ namespace sol {
: m_L(right.m_L)
, m_next_function_ref(std::move(right.m_next_function_ref))
, m_table_ref(std::move(right.m_table_ref))
, m_cached_key_value_pair(std::move(right.m_cached_key_value_pair))
, m_key_index(right.m_key_index)
, m_iteration_index(right.m_iteration_index)
, m_cached_key_value_pair(std::move(right.m_cached_key_value_pair)) {
, m_iteration_index(right.m_iteration_index) {
right.m_key_index = empty_key_index;
}
@ -24515,10 +24549,11 @@ namespace sol {
m_L = right.m_L;
m_next_function_ref = std::move(right.m_next_function_ref);
m_table_ref = std::move(right.m_table_ref);
m_cached_key_value_pair = std::move(right.m_cached_key_value_pair);
m_key_index = right.m_key_index;
m_iteration_index = right.m_iteration_index;
m_cached_key_value_pair = std::move(right.m_cached_key_value_pair);
right.m_key_index = empty_key_index;
return *this;
}
template <typename Source>
@ -24533,8 +24568,9 @@ namespace sol {
lua_remove(m_L, abs_source_index);
if (metatable_exists == 1) {
// just has a metatable, but does it have __pairs ?
stack_lua_table metatable(m_L, abs_source_index);
optional<protected_function> maybe_pairs_function = metatable.raw_get<optional<function>>(meta_function::pairs);
stack_reference metatable(m_L, raw_index(abs_source_index));
stack::get_field<is_global_table_v<Source>, true>(m_L, meta_function::pairs, metatable.stack_index());
optional<protected_function> maybe_pairs_function = stack::pop<optional<function>>(m_L);
if (maybe_pairs_function.has_value()) {
function& pairs_function = *maybe_pairs_function;
protected_function_result next_fn_and_table_and_first_key = pairs_function(source_);

View File

@ -36,111 +36,193 @@
#include <set>
#include <unordered_set>
class int_shim {
public:
int_shim() = default;
int_shim(int x) : x_(x) {
}
inline namespace sol2_test_container_shims {
int val() const {
return x_;
}
class int_shim {
public:
int_shim() = default;
private:
int x_ = -1;
};
class input_it {
public:
typedef std::input_iterator_tag iterator_category;
typedef int_shim value_type;
typedef value_type& reference;
typedef const value_type& const_reference;
typedef value_type* pointer;
typedef std::ptrdiff_t difference_type;
input_it() = default;
input_it(int n, int m) : n_(n), m_(m), value_(n_) {
assert(n_ >= 0);
assert(m_ >= 0);
assert(n_ <= m_);
if (!n_ && !m_) {
n_ = -1;
m_ = -1;
value_ = -1;
int_shim(int x) : x_(x) {
}
}
const int_shim& operator*() const {
return value_;
}
const int_shim* operator->() const {
return &value_;
}
input_it& operator++() {
assert(n_ >= 0);
assert(m_ >= 0);
if (n_ == m_ - 1) {
n_ = m_ = -1;
int val() const {
return x_;
}
else {
++n_;
private:
int x_ = -1;
};
class input_it {
public:
typedef std::input_iterator_tag iterator_category;
typedef int_shim value_type;
typedef value_type& reference;
typedef const value_type& const_reference;
typedef value_type* pointer;
typedef std::ptrdiff_t difference_type;
input_it() = default;
input_it(int n, int m) : n_(n), m_(m), value_(n_) {
assert(n_ >= 0);
assert(m_ >= 0);
assert(n_ <= m_);
if (!n_ && !m_) {
n_ = -1;
m_ = -1;
value_ = -1;
}
}
value_ = n_;
return *this;
}
bool operator==(const input_it& i) const {
return n_ == i.n_ && m_ == i.m_;
}
const int_shim& operator*() const {
return value_;
}
bool operator!=(const input_it& i) const {
return !(*this == i);
}
const int_shim* operator->() const {
return &value_;
}
private:
int n_ = -1;
int m_ = -1;
int_shim value_;
};
input_it& operator++() {
assert(n_ >= 0);
assert(m_ >= 0);
if (n_ == m_ - 1) {
n_ = m_ = -1;
}
else {
++n_;
}
value_ = n_;
return *this;
}
class not_really_a_container {
public:
using value_type = int_shim;
using iterator = input_it;
using const_iterator = input_it;
bool operator==(const input_it& i) const {
return n_ == i.n_ && m_ == i.m_;
}
const_iterator begin() const {
return iterator(0, 100);
}
bool operator!=(const input_it& i) const {
return !(*this == i);
}
const_iterator end() const {
return iterator();
}
private:
int n_ = -1;
int m_ = -1;
int_shim value_;
};
value_type gcc_warning_block() {
return int_shim();
}
class not_really_a_container {
public:
using value_type = int_shim;
using iterator = input_it;
using const_iterator = input_it;
std::size_t size() const {
return 100;
}
};
const_iterator begin() const {
return iterator(0, 100);
}
struct my_vec : public std::vector<int> {
typedef std::vector<int> base_t;
using base_t::base_t;
};
const_iterator end() const {
return iterator();
}
value_type gcc_warning_block() {
return int_shim();
}
std::size_t size() const {
return 100;
}
};
struct my_vec : public std::vector<int> {
typedef std::vector<int> base_t;
using base_t::base_t;
};
struct order_suit {
std::vector<std::pair<int, int64_t>> objs;
std::vector<std::pair<int64_t, int>> objs2;
order_suit(int pairs) {
objs.reserve(static_cast<std::size_t>(pairs));
objs2.reserve(static_cast<std::size_t>(pairs * 2));
for (int i = 0; i < pairs; ++i) {
objs.push_back({ i, i * 10 });
objs2.push_back({ (i + pairs) * 2, (i * 2) * 50 });
objs2.push_back({ ((i + pairs) * 2) + 1, (i * 2 + 1) * 50 });
}
}
};
class map_number_storage {
private:
std::unordered_map<std::string, int> data; // changed to map
public:
map_number_storage(int i) {
data[std::to_string(i)] = i;
}
int accumulate() const // changed for map
{
std::size_t sum = 0;
for (const auto& [k, v] : data) {
sum += v;
}
return static_cast<int>(sum);
}
public:
typedef std::string key_type;
typedef int mapped_type;
using value_type = decltype(data)::value_type;
using iterator = decltype(data)::iterator;
using const_iterator = decltype(data)::const_iterator;
using size_type = decltype(data)::size_type;
// ADDED
iterator find(const key_type& key) {
return data.find(key);
}
auto insert(value_type kv) {
return data.insert(kv);
}
auto insert(const key_type k, mapped_type v) {
return data.insert({ k, v });
}
mapped_type& set(key_type k, mapped_type v) {
return data[k] = v;
}
iterator begin() {
return iterator(data.begin());
}
iterator end() {
return iterator(data.end());
}
size_type size() const noexcept {
return data.size();
}
size_type max_size() const noexcept {
return data.max_size();
}
// void push_back(int value) { data.push_back(value); } NOT APPLICABLE TO MAP
bool empty() const noexcept {
return data.empty();
}
};
} // namespace sol2_test_container_shims
namespace sol {
template <>
struct is_container<my_vec> : std::true_type { };
template <>
struct is_container<map_number_storage> : std::false_type { };
template <>
struct usertype_container<my_vec> {
// Hooks Lua's syntax for #c
@ -164,20 +246,6 @@ namespace sol {
} // namespace sol
struct order_suit {
std::vector<std::pair<int, int64_t>> objs;
std::vector<std::pair<int64_t, int>> objs2;
order_suit(int pairs) {
objs.reserve(static_cast<std::size_t>(pairs));
objs2.reserve(static_cast<std::size_t>(pairs * 2));
for (int i = 0; i < pairs; ++i) {
objs.push_back({ i, i * 10 });
objs2.push_back({ (i + pairs) * 2, (i * 2) * 50 });
objs2.push_back({ ((i + pairs) * 2) + 1, (i * 2 + 1) * 50 });
}
}
};
TEST_CASE("containers/input iterators", "test shitty input iterators that are all kinds of B L E H") {
sol::state lua;
@ -319,3 +387,48 @@ TEST_CASE("containers/pair container in usertypes", "make sure containers that u
REQUIRE(pvec2[3].first == 13);
REQUIRE(pvec2[3].second == 150);
}
TEST_CASE("containers/as_container usertype", "A usertype should be able to mark itself as a container explicitly and work with BOTH kinds of insert types") {
sol::state lua;
lua.open_libraries(sol::lib::base);
lua.new_usertype<map_number_storage>("map_number_storage",
sol::constructors<map_number_storage(int)>(),
"accumulate",
&map_number_storage::accumulate,
"iterable",
[](map_number_storage& ns) {
return sol::as_container(ns); // treat like a container, despite is_container specialization
});
sol::optional<sol::error> maybe_error0 = lua.safe_script(R"(
ns = map_number_storage.new(23)
assert(ns:accumulate() == 23)
-- reference original usertype like a container
ns_container = ns:iterable()
ns_container["24"]=24
-- now print to show effect
assert(ns:accumulate() == 47)
assert(#ns == 2)
)",
&sol::script_pass_on_error);
REQUIRE_FALSE(maybe_error0.has_value());
map_number_storage& ns = lua["ns"];
map_number_storage& ns_container = lua["ns_container"];
ns.insert({ "33", 33 });
sol::optional<sol::error> maybe_error1 = lua.safe_script(R"(
assert(ns:accumulate() == 80)
assert(#ns == 3)
assert(ns_container['33'] == 33)
)",
&sol::script_pass_on_error);
REQUIRE_FALSE(maybe_error1.has_value());
REQUIRE(&ns == &ns_container);
REQUIRE(ns.size() == 3);
}