Skip to content

Commit

Permalink
Add intrusive_ptr_converter.
Browse files Browse the repository at this point in the history
intrusive_ptr_converter can be used for all smart pointer types where
construction of multiple smart pointers from a single raw pointer is not a
problem, such as boost::intrusive_ptr (for which specializations of
luabind::default_converter are provided).

Includes test.
  • Loading branch information
Oberon00 committed Aug 6, 2013
1 parent 5bd863e commit 39d6e3c
Show file tree
Hide file tree
Showing 4 changed files with 172 additions and 0 deletions.
64 changes: 64 additions & 0 deletions luabind/intrusive_ptr_converter.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
// Copyright Chsritian Neumüller 2013. Use, modification and distribution is
// subject to the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

#ifndef LUABIND_INTRUSIVE_PTR_CONVERTER_HPP_INCLUDED
#define LUABIND_INTRUSIVE_PTR_CONVERTER_HPP_INCLUDED

#include <luabind/config.hpp>
#include <luabind/detail/decorate_type.hpp>
#include <luabind/detail/policy.hpp>

#include <boost/mpl/bool.hpp>
#include <boost/smart_ptr/intrusive_ptr.hpp>

namespace luabind {
namespace detail {
template <class P>
struct intrusive_ptr_converter
: default_converter<typename P::element_type*>
{
private:
typedef P ptr_t;
typedef typename ptr_t::element_type* rawptr_t;

public:
typedef mpl::false_ is_native;

template <class U>
int match(lua_State* L, U, int index)
{
return default_converter<rawptr_t>::match(
L, LUABIND_DECORATE_TYPE(rawptr_t), index);
}

template <class U>
ptr_t apply(lua_State* L, U, int index)
{
rawptr_t raw_ptr = default_converter<rawptr_t>::apply(
L, LUABIND_DECORATE_TYPE(rawptr_t), index);
return ptr_t(raw_ptr);
}

void apply(lua_State* L, ptr_t const& p)
{
detail::value_converter().apply(L, p);
}

template <class U>
void converter_postcall(lua_State*, U const&, int)
{}
};
} // namespace detail

template <typename T>
struct default_converter<boost::intrusive_ptr<T> >:
detail::intrusive_ptr_converter<boost::intrusive_ptr<T> > {};

template <typename T>
struct default_converter<boost::intrusive_ptr<T> const&>:
detail::intrusive_ptr_converter<boost::intrusive_ptr<T> > {};

} // namespace luabind

#endif // LUABIND_INTRUSIVE_PTR_CONVERTER_HPP_INCLUDED
1 change: 1 addition & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ set(luabind_HDRS
../luabind/get_main_thread.hpp
../luabind/get_pointer.hpp
../luabind/handle.hpp
../luabind/intrusive_ptr_converter.hpp
../luabind/iterator_policy.hpp
../luabind/luabind.hpp
../luabind/lua_state_fwd.hpp
Expand Down
1 change: 1 addition & 0 deletions test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ set(TESTS
"held_type"
"implicit_cast"
"implicit_raw"
"intrusive_ptr"
"iterator"
"lua_classes"
"null_pointer"
Expand Down
106 changes: 106 additions & 0 deletions test/test_intrusive_ptr.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
// Copyright Chsritian Neumüller 2013. Use, modification and distribution is
// subject to the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

#include "test.hpp"

#include <luabind/intrusive_ptr_converter.hpp>
#include <luabind/luabind.hpp>

#include <boost/noncopyable.hpp>

using boost::intrusive_ptr;

namespace {

struct B: private boost::noncopyable, counted_type<B>
{
B(int val_): ref_cnt(0), val(val_) {}
virtual ~B() {
std::cout << "~B\n";
TEST_CHECK(ref_cnt == 0);
}

int ref_cnt;
int val;
};

COUNTER_GUARD(B);

struct D: B
{
D(int val_): B(val_) {}
};

void intrusive_ptr_add_ref(B* b)
{
++b->ref_cnt;
}

void intrusive_ptr_release(B* b)
{
if (!--b->ref_cnt)
delete b;
}

void needs_b(intrusive_ptr<B> pb, int expected_rc)
{
TEST_CHECK(pb->ref_cnt == expected_rc);
}

void needs_d(intrusive_ptr<D> pd)
{
TEST_CHECK(pd->ref_cnt == 2);
}

intrusive_ptr<B> filter_b(intrusive_ptr<B> pb)
{
TEST_CHECK(pb->ref_cnt == 2);
return pb;
}

} // namespace unnamed

void test_main(lua_State* L)
{
using namespace luabind;

module(L) [
class_<B, intrusive_ptr<B> >("B")
.def(constructor<int>())
.def_readonly("val", &B::val)
.def_readonly("ref_cnt", &B::ref_cnt),
class_<D, B, intrusive_ptr<D> >("D")
.def(constructor<int>()),
def("needs_b", &needs_b),
def("needs_d", &needs_d),
def("filter_b", &filter_b)
];

DOSTRING(L,
"d = D(1)\n"
"print(d.val, d.ref_cnt)\n"
"assert(d.val == 1)\n"
"assert(d.ref_cnt == 1)\n"
);

DOSTRING(L,
"needs_d(d)\n"
"needs_b(d, 2)\n"
);

DOSTRING(L,
"bd = filter_b(d)\n"
"assert(bd.val == 1)\n"
"assert(bd.ref_cnt == 2)\n"
"needs_b(bd, 3)\n"
"assert(bd.ref_cnt == 2)\n"
);

DOSTRING(L,
"d = nil\n"
"collectgarbage()\n"
"collectgarbage()\n"
"assert(bd.ref_cnt == 1)\n"
);
}

0 comments on commit 39d6e3c

Please sign in to comment.