Skip to content

Commit

Permalink
Fix issue #62
Browse files Browse the repository at this point in the history
Cast pointers to class member (variable, function, property getter/setter)
to the real class type in addition to 4974a8b

Added constructors and copy-constructors for `property_` template in order
to use them in `class_::set()` for casting to the real class type.

Added tests for binding classes with multiple inheritance.
  • Loading branch information
pmed committed Aug 27, 2017
1 parent 922c194 commit 2d1f89a
Show file tree
Hide file tree
Showing 3 changed files with 113 additions and 15 deletions.
79 changes: 79 additions & 0 deletions test/test_class.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -207,8 +207,87 @@ void test_class_()
1 + 2 * use_shared_ptr); // y1 + (y2 + y3 when use_shared_ptr)
}

template<bool use_shared_ptr>
void test_multiple_inheritance()
{
struct A
{
int x;
A() : x(1) {}
int f() { return x; }
void set_f(int v) { x = v; }

int z() const { return x; }
};

struct B
{
int x;
B() : x(2) {}
int g() { return x; }
void set_g(int v) { x = v; }

int z() const { return x; }
};

struct C : A, B
{
int x;
C() : x(3) {}
int h() { return x; }
void set_h(int v) { x = v; }

int z() const { return x; }
};

v8pp::context context;
v8::Isolate* isolate = context.isolate();
v8::HandleScope scope(isolate);

v8pp::class_<C, use_shared_ptr> C_class(isolate);
C_class
.ctor<>()
.set("xA", &A::x)
.set("xB", &B::x)
.set("xC", &C::x)

.set("zA", &A::z)
.set("zB", &B::z)
.set("zC", &C::z)

.set("f", &A::f)
.set("g", &B::g)
.set("h", &C::h)

.set("rF", v8pp::property(&C::f))
.set("rG", v8pp::property(&C::g))
.set("rH", v8pp::property(&C::h))

.set("F", v8pp::property(&C::f, &C::set_f))
.set("G", v8pp::property(&C::g, &C::set_g))
.set("H", v8pp::property(&C::h, &C::set_h))
;


context.set("C", C_class);
check_eq("get attributes", run_script<int>(context, "c = new C(); c.xA + c.xB + c.xC"), 1 + 2 + 3);
check_eq("set attributes", run_script<int>(context,
"c = new C(); c.xA = 10; c.xB = 20; c.xC = 30; c.xA + c.xB + c.xC"), 10 + 20 + 30);

check_eq("functions", run_script<int>(context, "c = new C(); c.f() + c.g() + c.h()"), 1 + 2 + 3);
check_eq("z functions", run_script<int>(context, "c = new C(); c.zA() + c.zB() + c.zC()"), 1 + 2 + 3);

check_eq("rproperties", run_script<int>(context,
"c = new C(); c.rF + c.rG + c.rH"), 1 + 2 + 3);
check_eq("rwproperties", run_script<int>(context,
"c = new C(); c.F = 100; c.G = 200; c.H = 300; c.F + c.G + c.H"), 100 + 200 + 300);
}

void test_class()
{
test_class_<false>();
test_class_<true>();

test_multiple_inheritance<false>();
test_multiple_inheritance<true>();
}
16 changes: 8 additions & 8 deletions v8pp/class.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -621,11 +621,11 @@ class class_
{
using mem_func_type =
typename detail::function_traits<Method>::template pointer_type<T>;

mem_func_type mf(mem_func);
class_info_.class_function_template()->PrototypeTemplate()->Set(
isolate(), name, v8::FunctionTemplate::New(isolate(),
&detail::forward_function<mem_func_type, use_shared_ptr>,
detail::set_external_data(isolate(), std::forward<Method>(mem_func))));
detail::set_external_data(isolate(), std::forward<mem_func_type>(mf))));
return *this;
}

Expand Down Expand Up @@ -653,6 +653,7 @@ class class_

using attribute_type = typename
detail::function_traits<Attribute>::template pointer_type<T>;
attribute_type attr(attribute);
v8::AccessorGetterCallback getter = &member_get<attribute_type>;
v8::AccessorSetterCallback setter = &member_set<attribute_type>;
if (readonly)
Expand All @@ -663,7 +664,7 @@ class class_
class_info_.class_function_template()->PrototypeTemplate()
->SetAccessor(v8pp::to_v8(isolate(), name), getter, setter,
detail::set_external_data(isolate(),
std::forward<Attribute>(attribute)), v8::DEFAULT,
std::forward<attribute_type>(attr)), v8::DEFAULT,
v8::PropertyAttribute(v8::DontDelete | (setter? 0 : v8::ReadOnly)));
return *this;
}
Expand All @@ -674,25 +675,24 @@ class class_
&& std::is_member_function_pointer<SetMethod>::value, class_&>::type
set(char const *name, property_<GetMethod, SetMethod>&& property)
{
using prop_type = property_<GetMethod, SetMethod>;

v8::HandleScope scope(isolate());

using property_type = property_<
typename detail::function_traits<GetMethod>::template pointer_type<T>,
typename detail::function_traits<SetMethod>::template pointer_type<T>
>;
property_type prop(property);
v8::AccessorGetterCallback getter = property_type::template get<use_shared_ptr>;
v8::AccessorSetterCallback setter = property_type::template set<use_shared_ptr>;
if (prop_type::is_readonly)
if (prop.is_readonly)
{
setter = nullptr;
}

class_info_.class_function_template()->PrototypeTemplate()
->SetAccessor(v8pp::to_v8(isolate(), name),getter, setter,
->SetAccessor(v8pp::to_v8(isolate(), name), getter, setter,
detail::set_external_data(isolate(),
std::forward<prop_type>(property)), v8::DEFAULT,
std::forward<property_type>(prop)), v8::DEFAULT,
v8::PropertyAttribute(v8::DontDelete | (setter ? 0 : v8::ReadOnly)));
return *this;
}
Expand Down
33 changes: 26 additions & 7 deletions v8pp/property.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,19 @@ struct property_
Set setter;

enum { is_readonly = false };

property_(Get getter, Set setter)
: getter(getter)
, setter(setter)
{
}

template<typename OtherGet, typename OtherSet>
property_(property_<OtherGet, OtherSet> const& other)
: getter(other.getter)
, setter(other.setter)
{
}
};

/// Read-only property class specialization for get only method
Expand All @@ -362,25 +375,31 @@ struct property_<Get, Get>
Get getter;

enum { is_readonly = true };

explicit property_(Get getter)
: getter(getter)
{
}

template<typename OtherGet>
explicit property_(property_<OtherGet, OtherGet> const& other)
: getter(other.getter)
{
}
};

/// Create read/write property from get and set member functions
template<typename Get, typename Set>
property_<Get, Set> property(Get get, Set set)
{
property_<Get, Set> prop;
prop.getter = get;
prop.setter = set;
return prop;
return property_<Get, Set>(get, set);
}

/// Create read-only property from a get function
template<typename Get>
property_<Get, Get> property(Get get)
{
property_<Get, Get> prop;
prop.getter = get;
return prop;
return property_<Get, Get>(get);
}

} // namespace v8pp
Expand Down

0 comments on commit 2d1f89a

Please sign in to comment.