Created
June 30, 2020 19:48
-
-
Save carlopi/73825f9915dfcd00847f37d93eded97c to your computer and use it in GitHub Desktop.
Wrapper via pimpl_with_deleter of arbitrary Wasm classes
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
///////////////////////////////////////////////////////////////////////////////// | |
//---------------------- BOILERPLATE TO PUT IN A SEPARATE HEADER -----/// | |
///////////////////////////////////////////////////////////////////////////////// | |
#include <memory> | |
class [[cheerp::genericjs]][[cheerp::jsexport]] CounterAlive { | |
public: | |
CounterAlive() | |
{ | |
++counter; | |
} | |
// ~CounterAlive() | |
void deleter() //current limitation on the destructor | |
{ | |
--counter; | |
} | |
[[cheerp::jsexport]] | |
static int numberAlive() | |
{ | |
return counter; | |
} | |
[[cheerp::jsexport]] | |
void placeholder() | |
{ | |
} | |
private: | |
static int counter; | |
}; | |
int CounterAlive::counter = 0; | |
namespace cheerp_pimpl | |
{ | |
template<typename T> | |
class [[cheerp::genericjs]] pimpl_with_deleter { | |
private: | |
T* m; | |
CounterAlive counter; | |
public: | |
pimpl_with_deleter() : m(new T()) {} | |
template<typename ...Args> pimpl_with_deleter( Args&& ... args) : m( new T(args...)) {} | |
/* current limitations on member of [[cheerp::jsexport]]-ed classes impose deleting the destructor | |
~pimpl_with_deleter() | |
{ | |
deleter(); | |
}*/ | |
void deleter() | |
{ | |
counter.deleter(); | |
//Since for now we have to do without destructor | |
//we declare a class deleter that is manually called and implement the destructor | |
delete m; | |
} | |
T* operator->() | |
{ | |
return m; | |
} | |
T& operator*() | |
{ | |
return *m; | |
} | |
}; | |
} //end namespace cheerp_pimpl | |
//////////////////////////////////////////////////////////////// | |
///----------------- END BOILERPLATE -------------/// | |
//////////////////////////////////////////////////////////////// | |
#include <vector> | |
#include <set> | |
#include <iostream> | |
//EXAMPLE OF ARBITRARY WASM CLASS WITH NON-TRIVIAL DESTRUCTOR | |
class [[cheerp::wasm]] WasmClass | |
{ | |
//Arbitrary class, have no restrictions of sort, can be used both in arbitrary code AND inside a JSExported wrapper | |
public: | |
WasmClass(int X) | |
{ | |
std::cout << "ImplWasm instantiated with value " << X << "\n"; | |
} | |
void insert(int N) | |
{ | |
//Insert N both in the set and the vector | |
V.push_back(N); | |
bool f = S.insert(N).second; | |
std::cout << N << " inserted"; | |
if (!f) | |
std::cout << " but was already present"; | |
std::cout << "\n"; | |
} | |
int totalNum() const | |
{ | |
return V.size(); | |
} | |
int numDifferentItems() const | |
{ | |
return S.size(); | |
} | |
~WasmClass() | |
{ | |
std::cout << "Destructor called....\n"; | |
} | |
private: | |
std::vector<int> V; | |
std::set<int> S; | |
}; | |
//JSEXPORTED WRAPPER TO DECLARE | |
class [[cheerp::jsexport]][[cheerp::genericjs]] GenericjsWrapperWithDeleter | |
{ | |
cheerp_pimpl::pimpl_with_deleter<WasmClass> m; | |
public: | |
GenericjsWrapperWithDeleter(int N) : m(N) | |
{ | |
std::cout << "GenericjsWrapperWithDeleter constructor\n"; | |
} | |
void insert(int N) | |
{ | |
m->insert(N); | |
} | |
// ~GenericjsWrapperWithDeleter() //Also here, we can't have the destructor... for now we are forced to call deleter | |
void deleter() | |
{ | |
{ | |
m.deleter(); | |
std::cout << "GenericjsWrapperWithDeleter \"destructor\" called\n"; | |
} | |
}; | |
//USE OF THE WASM CLASS FROM C++ CODE | |
void someWasmFunction() | |
{ | |
std::cout << "\nCalling someWasmFunction\n"; | |
WasmClass W(23); | |
W.insert(45); | |
W.insert(45); | |
std::cout << "Done calling someWasmFunction\n\n"; | |
//W destructor called... | |
} | |
//USE OF THE JSEXPORTED CLASS FROM JAVASCRIPT CODE | |
void [[cheerp::genericjs]] someOtherGenerericjsFunction() | |
{ | |
std::cout << "\nCalling someOtherGenericjsFunction\n"; | |
//__asm__ is a way of directing calling JavaScript arbitrary code, but in principle similar code should be on the user side | |
__asm__("\ | |
var instance = new GenericjsWrapperWithDeleter(100);\ | |
instance.insert(45);\ | |
instance.insert(12334);\ | |
instance.deleter();\ | |
console.log(CounterAlive.numberAlive());\ | |
"); | |
//IN JS WE NEED TO CALL THE DELETER | |
std::cout << "Done calling someOtherGenericjsFunction\n\n"; | |
} | |
int main() | |
{ | |
someWasmFunction(); | |
someOtherGenerericjsFunction(); | |
assert(CounterAlive::numberAlive() == 0); | |
// You might be willing to create some objects and leave them alive, but be conscious with memory leaks | |
return 0; | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment