Referential transparency is important.

This commit is contained in:
ThePhD 2016-09-28 19:05:26 -04:00
parent d7b037da73
commit cbe599a901
4 changed files with 61 additions and 6 deletions

View File

@ -105,7 +105,7 @@ namespace sol {
if (k <= src.size() && k > 0) { if (k <= src.size() && k > 0) {
--k; --k;
std::advance(it, k); std::advance(it, k);
return stack::push(L, *it); return stack::push_reference(L, *it);
} }
} }
return stack::push(L, nil); return stack::push(L, nil);
@ -115,7 +115,7 @@ namespace sol {
K k = stack::get<K>(L, 2); K k = stack::get<K>(L, 2);
--k; --k;
std::advance(it, k); std::advance(it, k);
return stack::push(L, *it); return stack::push_reference(L, *it);
#endif // Safety #endif // Safety
} }
@ -164,8 +164,7 @@ namespace sol {
if (it == end(source)) { if (it == end(source)) {
return 0; return 0;
} }
int p = stack::push(L, k + 1); int p = stack::multi_push_reference(L, k + 1, *it);
p += stack::push(L, *it);
std::advance(it, 1); std::advance(it, 1);
return p; return p;
} }
@ -262,7 +261,7 @@ namespace sol {
auto it = detail::find(src, *k); auto it = detail::find(src, *k);
if (it != end(src)) { if (it != end(src)) {
auto& v = *it; auto& v = *it;
return stack::push(L, v.second); return stack::push_reference(L, v.second);
} }
} }
return stack::push(L, nil); return stack::push(L, nil);

View File

@ -282,7 +282,7 @@ namespace sol {
indexbase(&usertype_detail::simple_core_indexing_call<true>), newindexbase(&usertype_detail::simple_core_indexing_call<false>), indexbase(&usertype_detail::simple_core_indexing_call<true>), newindexbase(&usertype_detail::simple_core_indexing_call<false>),
indexbaseclasspropogation(usertype_detail::walk_all_bases<true>), newindexbaseclasspropogation(&usertype_detail::walk_all_bases<false>), indexbaseclasspropogation(usertype_detail::walk_all_bases<true>), newindexbaseclasspropogation(&usertype_detail::walk_all_bases<false>),
baseclasscheck(nullptr), baseclasscast(nullptr), baseclasscheck(nullptr), baseclasscast(nullptr),
mustindex(false), secondarymeta(false) { mustindex(true), secondarymeta(true) {
(void)detail::swallow{ 0, (void)detail::swallow{ 0,
(add(L, detail::forward_get<I * 2>(args), detail::forward_get<I * 2 + 1>(args)),0)... (add(L, detail::forward_get<I * 2>(args), detail::forward_get<I * 2 + 1>(args)),0)...
}; };

View File

@ -272,3 +272,39 @@ TEST_CASE("containers/arbitrary-creation", "userdata and tables should be usable
REQUIRE(c.get<std::string>("name") == "Rapptz"); REQUIRE(c.get<std::string>("name") == "Rapptz");
REQUIRE(c.get<std::string>("project") == "sol"); REQUIRE(c.get<std::string>("project") == "sol");
} }
TEST_CASE("containers/usertype-transparency", "Make sure containers pass their arguments through transparently and push the results as references, not new values") {
class A {
public:
int a;
A(int b = 2) : a(b) {};
void func() { }
};
struct B {
B() {
for (std::size_t i = 0; i < 20; ++i) {
a_list.emplace_back(static_cast<int>(i));
}
}
std::vector<A> a_list;
};
sol::state lua;
lua.new_usertype<B>("B",
"a_list", &B::a_list
);
lua.script(R"(
b = B.new()
a_ref = b.a_list[2]
)");
B& b = lua["b"];
A& a_ref = lua["a_ref"];
REQUIRE(&b.a_list[1] == &a_ref);
REQUIRE(b.a_list[1].a == a_ref.a);
}

View File

@ -437,3 +437,23 @@ TEST_CASE("usertype/simple-destruction-test", "make sure usertypes are properly
lua["testCrash"](); lua["testCrash"]();
} }
} }
TEST_CASE("usertype/simple-table-append", "Ensure that appending to the meta table also affects the internal function table for pointers as well") {
struct A {
int func() {
return 5000;
}
};
sol::state lua;
lua.open_libraries();
lua.new_simple_usertype<A>("A");
sol::table table = lua["A"];
table["func"] = &A::func;
A a;
lua.set("a", &a);
REQUIRE_NOTHROW(
lua.script("assert(a:func() == 5000)")
);
}