Skip to content

Fix constructor embind #12973

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions system/include/emscripten/bind.h
Original file line number Diff line number Diff line change
Expand Up @@ -1475,6 +1475,24 @@ namespace emscripten {
return *this;
}

template<typename... Args, typename ReturnType, typename... Policies>
EMSCRIPTEN_ALWAYS_INLINE const class_& constructor(ReturnType (*factory)(Args...), Policies...) const {
using namespace internal;

// TODO: allows all raw pointers... policies need a rethink
typename WithPolicies<allow_raw_pointers, Policies...>::template ArgTypeList<ReturnType, Args...> args;
auto invoke = &Invoker<ReturnType, Args...>::invoke;
_embind_register_class_constructor(
TypeID<ClassType>::get(),
args.getCount(),
args.getTypes(),
getSignature(invoke),
reinterpret_cast<GenericFunction>(invoke),
reinterpret_cast<GenericFunction>(factory));

return *this;
}

template<typename SmartPtr, typename... Args, typename... Policies>
EMSCRIPTEN_ALWAYS_INLINE const class_& smart_ptr_constructor(const char* smartPtrName, SmartPtr (*factory)(Args...), Policies...) const {
using namespace internal;
Expand Down
11 changes: 11 additions & 0 deletions tests/embind/embind.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -1277,6 +1277,17 @@ module({
b.delete();
});

test("functions as class constructors", function() {
var a = new cm.ConstructFromFunction({optionA: true});
assert.equal(true, a.optionA);

var b = new cm.ConstructFromFunction();
assert.equal(false, b.optionA);

a.delete();
b.delete();
});

test("function objects as class methods", function() {
var b = cm.ValHolder.makeValHolder("foo");

Expand Down
52 changes: 33 additions & 19 deletions tests/embind/embind_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -341,7 +341,7 @@ class SharedPtrHolder {
std::shared_ptr<StringHolder> get() const {
return ptr_;
}

void set(std::shared_ptr<StringHolder> p) {
ptr_ = p;
}
Expand Down Expand Up @@ -988,11 +988,11 @@ class UniquePtrToConstructor {
UniquePtrToConstructor(std::unique_ptr<int> p)
: value(*p)
{}

int getValue() const {
return value;
}

private:
int value;
};
Expand Down Expand Up @@ -1412,7 +1412,7 @@ EMSCRIPTEN_BINDINGS(interface_tests) {
self.AbstractClass::passVal(v);
}))
;

function("getAbstractClass", &getAbstractClass);
function("callAbstractMethod", &callAbstractMethod);
function("callOptionalMethod", &callOptionalMethod);
Expand Down Expand Up @@ -1500,7 +1500,7 @@ class CustomSmartPtr {
~CustomSmartPtr() {
verify();
std::fill(d_, d_ + N_, Deleted);

if (ptr_ && --ptr_->refcount == 0) {
delete ptr_;
}
Expand Down Expand Up @@ -1751,6 +1751,16 @@ ConstructFromFunctor<I> construct_from_functor_mixin(const val& v, int i)
return {v, i};
}

struct ConstructFromFunction {
bool optionA;
ConstructFromFunction(bool optionA_): optionA{optionA_} {};
};

ConstructFromFunction* ConstructFromFunctionConstructor(emscripten::val value) {
bool optionA = (value.as<bool>() && value["optionA"].as<bool>());
return new ConstructFromFunction(optionA);
}

EMSCRIPTEN_BINDINGS(tests) {
register_vector<int>("IntegerVector");
register_vector<char>("CharVector");
Expand Down Expand Up @@ -1873,6 +1883,10 @@ EMSCRIPTEN_BINDINGS(tests) {
.function("getA", &ConstructFromFunctor<2>::getA)
;

class_<ConstructFromFunction>("ConstructFromFunction")
.constructor<emscripten::val>(&ConstructFromFunctionConstructor)
;

class_<ValHolder>("ValHolder")
.smart_ptr<std::shared_ptr<ValHolder>>("std::shared_ptr<ValHolder>")
.constructor<val>()
Expand Down Expand Up @@ -1929,7 +1943,7 @@ EMSCRIPTEN_BINDINGS(tests) {
.function("get", &StringHolder::get)
.function("get_const_ref", &StringHolder::get_const_ref)
;

class_<SharedPtrHolder>("SharedPtrHolder")
.constructor<>()
.function("get", &SharedPtrHolder::get)
Expand Down Expand Up @@ -2002,7 +2016,7 @@ EMSCRIPTEN_BINDINGS(tests) {
.property("member", &SecondBase::member)
.property("secondBaseMember", &SecondBase::secondBaseMember)
;


class_<DerivedHolder>("DerivedHolder")
.constructor<>()
Expand All @@ -2017,7 +2031,7 @@ EMSCRIPTEN_BINDINGS(tests) {
.constructor<>()
.function("getClassName", &SiblingDerived::getClassName)
;

class_<MultiplyDerived, base<Base>>("MultiplyDerived")
.smart_ptr<std::shared_ptr<MultiplyDerived>>("shared_ptr<MultiplyDerived>")
.constructor<>()
Expand Down Expand Up @@ -2094,7 +2108,7 @@ EMSCRIPTEN_BINDINGS(tests) {
.constructor<>()
.function("getClassName", &PolyDiamondBase::getClassName)
;

class_<PolyDiamondDerived>("PolyDiamondDerived")
.smart_ptr<std::shared_ptr<PolyDiamondDerived>>("shared_ptr<PolyDiamondDerived>")
.constructor<>()
Expand Down Expand Up @@ -2339,10 +2353,10 @@ class MultipleSmartCtors {
class MultipleOverloads {
public:
MultipleOverloads() {}

int value;
static int staticValue;

int Func(int i) {
assert(i == 10);
value = 1;
Expand All @@ -2358,7 +2372,7 @@ class MultipleOverloads {
int WhichFuncCalled() const {
return value;
}

static int StaticFunc(int i) {
assert(i == 10);
staticValue = 1;
Expand All @@ -2381,7 +2395,7 @@ int MultipleOverloads::staticValue = 0;
class MultipleOverloadsDerived : public MultipleOverloads {
public:
MultipleOverloadsDerived() {}

int Func(int i, int j, int k) {
assert(i == 30);
assert(j == 30);
Expand All @@ -2397,7 +2411,7 @@ class MultipleOverloadsDerived : public MultipleOverloads {
value = 4;
return 4;
}

static int StaticFunc(int i, int j, int k) {
assert(i == 30);
assert(j == 30);
Expand Down Expand Up @@ -2476,14 +2490,14 @@ EMSCRIPTEN_BINDINGS(overloads) {
.constructor<int, int, int>()
.function("WhichCtorCalled", &MultipleCtors::WhichCtorCalled)
;

class_<MultipleSmartCtors>("MultipleSmartCtors")
.smart_ptr<std::shared_ptr<MultipleSmartCtors>>("shared_ptr<MultipleSmartCtors>")
.constructor(&std::make_shared<MultipleSmartCtors, int>)
.constructor(&std::make_shared<MultipleSmartCtors, int, int>)
.function("WhichCtorCalled", &MultipleSmartCtors::WhichCtorCalled)
;

class_<MultipleOverloads>("MultipleOverloads")
.constructor<>()
.function("Func", select_overload<int(int)>(&MultipleOverloads::Func))
Expand Down Expand Up @@ -2560,7 +2574,7 @@ EMSCRIPTEN_BINDINGS(order) {
.field("first", &OrderedStruct::first)
.field("second", &OrderedStruct::second)
;

class_<SecondElement>("SecondElement")
;

Expand Down Expand Up @@ -2644,7 +2658,7 @@ EMSCRIPTEN_BINDINGS(incomplete) {
class Noncopyable {
Noncopyable(const Noncopyable&) = delete;
Noncopyable& operator=(const Noncopyable&) = delete;

public:
Noncopyable() {}
Noncopyable(Noncopyable&& other) {
Expand Down Expand Up @@ -2709,7 +2723,7 @@ EMSCRIPTEN_BINDINGS(constants) {
constant("VALUE_OBJECT_CONSTANT", sv);
}

class DerivedWithOffset : public DummyDataToTestPointerAdjustment, public Base {
class DerivedWithOffset : public DummyDataToTestPointerAdjustment, public Base {
};

std::shared_ptr<Base> return_Base_from_DerivedWithOffset(std::shared_ptr<DerivedWithOffset> ptr) {
Expand Down