sol2/tests/runtime_tests/source/container_shims.cpp

322 lines
8.3 KiB
C++
Raw Normal View History

// sol3
// The MIT License (MIT)
2020-08-13 22:42:37 +08:00
// Copyright (c) 2013-2020 Rapptz, ThePhD and contributors
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#include "sol_test.hpp"
#include <catch.hpp>
#include <iterator>
#include <vector>
#include <list>
#include <forward_list>
#include <map>
#include <deque>
#include <array>
#include <unordered_map>
#include <set>
#include <unordered_set>
class int_shim {
public:
int_shim() = default;
int_shim(int x) : x_(x) {
}
int val() const {
return x_;
}
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;
}
}
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;
}
else {
++n_;
}
value_ = n_;
return *this;
}
bool operator==(const input_it& i) const {
return n_ == i.n_ && m_ == i.m_;
}
bool operator!=(const input_it& i) const {
return !(*this == i);
}
private:
int n_ = -1;
int m_ = -1;
int_shim value_;
};
class not_really_a_container {
public:
using value_type = int_shim;
using iterator = input_it;
using const_iterator = input_it;
const_iterator begin() const {
return iterator(0, 100);
}
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;
};
namespace sol {
template <>
struct is_container<my_vec> : std::true_type { };
template <>
struct usertype_container<my_vec> {
// Hooks Lua's syntax for #c
static int size(lua_State* L) {
my_vec& v = sol::stack::get<my_vec&>(L, 1);
return stack::push(L, v.size());
}
// Used by default implementation
static auto begin(lua_State*, my_vec& self) {
return self.begin();
}
static auto end(lua_State*, my_vec& self) {
return self.end();
}
static std::ptrdiff_t index_adjustment(lua_State*, my_vec&) {
return 0;
}
};
} // 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;
lua.open_libraries(sol::lib::base, sol::lib::package);
lua.new_usertype<int_shim>("int_shim", "new", sol::no_constructor, "val", &int_shim::val);
not_really_a_container c;
lua["c"] = &c;
#if SOL_LUA_VERSION > 502
auto result0 = lua.safe_script(R"lua(
for k, v in pairs(c) do
assert((k - 1) == v:val())
end
)lua",
sol::script_pass_on_error);
REQUIRE(result0.valid());
#endif
auto result1 = lua.safe_script(R"lua(
for k=1,#c do
v = c[k]
assert((k - 1) == v:val())
end
)lua",
sol::script_pass_on_error);
REQUIRE(result1.valid());
}
TEST_CASE("containers/custom indexing", "allow containers to set a custom indexing offset") {
sol::state lua;
lua.open_libraries(sol::lib::base);
lua["c"] = my_vec { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
auto result1 = lua.safe_script("for i=0,9 do assert(i == c[i]) end", sol::script_pass_on_error);
REQUIRE(result1.valid());
auto result2 = lua.safe_script("assert(c[10] == nil)", sol::script_pass_on_error);
REQUIRE(result2.valid());
auto result3 = lua.safe_script("assert(c[-1] == nil)", sol::script_pass_on_error);
REQUIRE(result3.valid());
auto result4 = lua.safe_script("assert(#c == 10)", sol::script_pass_on_error);
REQUIRE(result4.valid());
}
TEST_CASE("containers/containers of pointers", "containers of pointers shouldn't have their value_type's overly stripped") {
sol::state lua;
class MyContainer {
public:
typedef int** iterator;
typedef int* value_type;
std::vector<value_type> m_vec;
inline iterator begin() {
return m_vec.data();
}
inline iterator end() {
return m_vec.data() + m_vec.size();
}
inline void push_back(value_type v) {
m_vec.push_back(v);
}
};
int a = 500;
int b = 600;
MyContainer ctr;
ctr.push_back(&a);
ctr.push_back(&b);
lua["c"] = ctr;
{
auto result1 = lua.safe_script("ap = c[1]", sol::script_pass_on_error);
REQUIRE(result1.valid());
auto result2 = lua.safe_script("bp = c[2]", sol::script_pass_on_error);
REQUIRE(result2.valid());
int* ap = lua["ap"];
int* bp = lua["bp"];
REQUIRE(ap == &a);
REQUIRE(bp == &b);
REQUIRE(*ap == 500);
REQUIRE(*bp == 600);
}
std::unordered_map<int, int*> ptrs;
ptrs[5] = &a;
ptrs[6] = &b;
lua["c2"] = ptrs;
{
auto result1 = lua.safe_script("ap = c2[5]", sol::script_pass_on_error);
REQUIRE(result1.valid());
auto result2 = lua.safe_script("bp = c2[6]", sol::script_pass_on_error);
REQUIRE(result2.valid());
int* ap = lua["ap"];
int* bp = lua["bp"];
REQUIRE(ap == &a);
REQUIRE(bp == &b);
REQUIRE(*ap == 500);
REQUIRE(*bp == 600);
}
}
TEST_CASE("containers/pair container in usertypes", "make sure containers that use pairs in usertypes do not trigger compiler errors") {
sol::state lua;
lua.open_libraries(sol::lib::base);
auto orderSuit = lua.new_usertype<order_suit>("order_suit", sol::constructors<order_suit(int)>());
#define SET_PROP(__PROP__) orderSuit.set(#__PROP__, &order_suit::__PROP__)
SET_PROP(objs);
SET_PROP(objs2);
#undef SET_PROP
auto result1 = lua.safe_script("osobj = order_suit.new(5)", sol::script_pass_on_error);
REQUIRE(result1.valid());
auto result2 = lua.safe_script("pvec = osobj.objs", sol::script_pass_on_error);
REQUIRE(result2.valid());
auto result3 = lua.safe_script("pvec2 = osobj.objs2", sol::script_pass_on_error);
REQUIRE(result3.valid());
using vec_t = std::remove_reference_t<decltype(std::declval<order_suit>().objs)>;
using vec2_t = std::remove_reference_t<decltype(std::declval<order_suit>().objs2)>;
vec_t& pvec = lua["pvec"];
vec2_t& pvec2 = lua["pvec2"];
REQUIRE(pvec.size() == 5);
REQUIRE(pvec2.size() == 10);
REQUIRE(pvec[0].first == 0);
REQUIRE(pvec[0].second == 0);
REQUIRE(pvec[1].first == 1);
REQUIRE(pvec[1].second == 10);
REQUIRE(pvec[2].first == 2);
REQUIRE(pvec[2].second == 20);
REQUIRE(pvec2[0].first == 10);
REQUIRE(pvec2[0].second == 0);
REQUIRE(pvec2[1].first == 11);
REQUIRE(pvec2[1].second == 50);
REQUIRE(pvec2[2].first == 12);
REQUIRE(pvec2[2].second == 100);
REQUIRE(pvec2[3].first == 13);
REQUIRE(pvec2[3].second == 150);
}