register_smart_ptr changed to .shared_ptr (mod to class definition) -- shared_ptr (outside of class definition) is still allowed
shared pointers passed by reference can be modified by the called code -- the change is now reflected at the Javascript calling level other minor clean-up and small syntactic changes
This commit is contained in:
Родитель
8a12d4c1c4
Коммит
e5fca2885b
|
@ -5,7 +5,6 @@
|
|||
/*global Pointer_stringify, writeStringToMemory*/
|
||||
/*global __emval_register, _emval_handle_array, __emval_decref*/
|
||||
/*global ___getDynamicPointerType: false*/
|
||||
/*global ___dynamicPointerCast: false*/
|
||||
/*global ___typeName:false*/
|
||||
/*global ___staticPointerCast: false*/
|
||||
|
||||
|
@ -308,6 +307,12 @@ function runDestructors(destructors) {
|
|||
}
|
||||
}
|
||||
|
||||
function refreshSmartPointee(handle) {
|
||||
if (handle && handle.smartPointer) {
|
||||
handle.ptr = handle.type.smartPointerType.getPointee(handle.smartPointer);
|
||||
}
|
||||
}
|
||||
|
||||
function makeInvoker(name, argCount, argTypes, invoker, fn) {
|
||||
if (!FUNCTION_TABLE[fn]) {
|
||||
throw new BindingError('function '+name+' is not defined');
|
||||
|
@ -329,6 +334,9 @@ function makeInvoker(name, argCount, argTypes, invoker, fn) {
|
|||
rv = argTypes[0].fromWireType(rv);
|
||||
}
|
||||
runDestructors(destructors);
|
||||
for (i = 1; i < argCount; i++) {
|
||||
refreshSmartPointee(arguments[i-1]);
|
||||
}
|
||||
return rv;
|
||||
};
|
||||
}
|
||||
|
@ -537,21 +545,21 @@ RegisteredPointer.prototype.toWireType = function(destructors, handle) {
|
|||
if (!handle) {
|
||||
return null;
|
||||
}
|
||||
if (handle.pointeeType.isPolymorphic) {
|
||||
fromRawType = handle.pointeeType.getDynamicRawPointerType(handle.ptr);
|
||||
if (handle.type.isPolymorphic) {
|
||||
fromRawType = handle.type.getDynamicRawPointerType(handle.ptr);
|
||||
} else {
|
||||
fromRawType = handle.pointeeType.rawType;
|
||||
fromRawType = handle.type.rawType;
|
||||
}
|
||||
if (fromRawType === this.pointeeType.rawType) {
|
||||
if (fromRawType === this.type.rawType) {
|
||||
return this.isSmartPointer ? handle.smartPointer : handle.ptr;
|
||||
}
|
||||
var ptr = staticPointerCast(handle.ptr, fromRawType, this.pointeeType.rawType);
|
||||
var ptr = staticPointerCast(handle.ptr, fromRawType, this.type.rawType);
|
||||
if (this.isSmartPointer) {
|
||||
// todo: if ptr == handle.ptr, there's no need to allocate a new smartPtr!
|
||||
var smartPtr = _malloc(16);
|
||||
handle.pointeeType.smartPointerType.rawConstructor(smartPtr, ptr, handle.smartPointer);
|
||||
var smartPtr = _malloc(16); // todo: can we get C++ to tell us the size of the pointer?
|
||||
handle.type.smartPointerType.rawConstructor(smartPtr, ptr, handle.smartPointer);
|
||||
ptr = smartPtr;
|
||||
destructors.push(handle.pointeeType.smartPointerType.rawDestructor);
|
||||
destructors.push(handle.type.smartPointerType.rawDestructor);
|
||||
destructors.push(ptr);
|
||||
}
|
||||
return ptr;
|
||||
|
@ -582,7 +590,7 @@ RegisteredPointer.prototype.fromWireType = function(ptr) {
|
|||
RegisteredPointer.prototype.getDynamicRawPointerType = function(ptr) {
|
||||
var type = null;
|
||||
if (this.isPolymorphic) {
|
||||
if (this.rawGetPointee) {
|
||||
if (this.rawGetPointee) { // todo: did you mean isSmartPtr?
|
||||
type = ___getDynamicPointerType(this.rawGetPointee(ptr));
|
||||
} else {
|
||||
type = ___getDynamicPointerType(ptr);
|
||||
|
@ -594,8 +602,8 @@ RegisteredPointer.prototype.getDynamicRawPointerType = function(ptr) {
|
|||
RegisteredPointer.prototype.getDynamicDowncastType = function(ptr) {
|
||||
var downcastType = null;
|
||||
var type = this.getDynamicRawPointerType(ptr);
|
||||
if (type && type !== this.pointeeType.rawType) {
|
||||
var derivation = Module.__getDerivationPath(type, this.pointeeType.rawType);
|
||||
if (type && type !== this.type.rawType) {
|
||||
var derivation = Module.__getDerivationPath(type, this.type.rawType);
|
||||
for (var i = 0; i < derivation.size(); i++) {
|
||||
downcastType = typeRegistry[derivation.at(i)];
|
||||
if (downcastType) {
|
||||
|
@ -615,7 +623,7 @@ RegisteredPointer.prototype.fromWireTypeAutoDowncast = function(ptr) { // ptr is
|
|||
}
|
||||
var toType = this.getDynamicDowncastType(ptr);
|
||||
if (toType) {
|
||||
var fromType = this.pointeeType;
|
||||
var fromType = this.type;
|
||||
if (this.isSmartPointer) {
|
||||
handle = toType.smartPointerType.fromWireType(ptr);
|
||||
} else {
|
||||
|
@ -641,12 +649,16 @@ function __embind_register_smart_ptr(
|
|||
rawConstructor = FUNCTION_TABLE[rawConstructor];
|
||||
rawDestructor = FUNCTION_TABLE[rawDestructor];
|
||||
rawGetPointee = FUNCTION_TABLE[rawGetPointee];
|
||||
|
||||
|
||||
if (name == "") {
|
||||
name = pointeeType.name + "Ptr";
|
||||
}
|
||||
|
||||
var Handle = createNamedFunction(name, function(ptr) {
|
||||
this.count = {value: 1};
|
||||
this.smartPointer = ptr; // std::shared_ptr<T>*
|
||||
this.ptr = rawGetPointee(ptr); // T*
|
||||
this.pointeeType = pointeeType;
|
||||
this.type = pointeeType;
|
||||
});
|
||||
|
||||
// TODO: test for SmartPtr.prototype.constructor property?
|
||||
|
@ -680,7 +692,7 @@ function __embind_register_smart_ptr(
|
|||
this.ptr = undefined;
|
||||
};
|
||||
var registeredPointer = new RegisteredPointer(Handle, pointeeType.isPolymorphic, true, rawGetPointee, rawConstructor, rawDestructor);
|
||||
registeredPointer.pointeeType = pointeeType;
|
||||
registeredPointer.type = pointeeType;
|
||||
pointeeType.smartPointerType = registerType(rawType, name, registeredPointer);
|
||||
}
|
||||
|
||||
|
@ -828,11 +840,13 @@ function __embind_register_class(
|
|||
|
||||
h.count = {value: 1, ptr: ptr };
|
||||
h.ptr = ptr;
|
||||
h.pointeeType = type; // set below
|
||||
h.type = type; // set below
|
||||
|
||||
for(var prop in Handle.prototype) {
|
||||
var dp = Object.getOwnPropertyDescriptor(Handle.prototype, prop);
|
||||
Object.defineProperty(h, prop, dp);
|
||||
if (Handle.prototype.hasOwnProperty(prop)) {
|
||||
var dp = Object.getOwnPropertyDescriptor(Handle.prototype, prop);
|
||||
Object.defineProperty(h, prop, dp);
|
||||
}
|
||||
}
|
||||
|
||||
return h;
|
||||
|
@ -875,15 +889,15 @@ function __embind_register_class(
|
|||
// todo: clean this up!
|
||||
var registeredClass = new RegisteredPointer(Handle, isPolymorphic, false);
|
||||
var type = registerType(rawType, name, registeredClass);
|
||||
registeredClass.pointeeType = type;
|
||||
registeredClass.type = type;
|
||||
|
||||
var registeredClass = new RegisteredPointer(Handle, isPolymorphic, false);
|
||||
registeredClass = new RegisteredPointer(Handle, isPolymorphic, false);
|
||||
registerType(rawPointerType, name + '*', registeredClass);
|
||||
registeredClass.pointeeType = type;
|
||||
registeredClass.type = type;
|
||||
// todo: implement const pointers (no modification Javascript side)
|
||||
var registeredClass = new RegisteredPointer(Handle, isPolymorphic, false);
|
||||
registeredClass = new RegisteredPointer(Handle, isPolymorphic, false);
|
||||
registerType(rawConstPointerType, name + ' const*', registeredClass);
|
||||
registeredClass.pointeeType = type;
|
||||
registeredClass.type = type;
|
||||
|
||||
type.constructor = createNamedFunction(type.name, function() {
|
||||
var body = type.constructor.body;
|
||||
|
@ -965,26 +979,32 @@ function __embind_register_class_method(
|
|||
rv = argTypes[0].fromWireType(rv);
|
||||
}
|
||||
runDestructors(destructors);
|
||||
for (i = 1; i < argCount; i++) {
|
||||
refreshSmartPointee(arguments[i-1]);
|
||||
}
|
||||
return rv;
|
||||
};
|
||||
classType.Handle.memberType[methodName] = "method";
|
||||
});
|
||||
}
|
||||
|
||||
// todo: cast methods should require binding of their target types
|
||||
function __embind_register_raw_cast_method(
|
||||
function __embind_register_cast_method(
|
||||
rawClassType,
|
||||
isPolymorphic,
|
||||
methodName,
|
||||
rawReturnType,
|
||||
rawInvoker
|
||||
rawRawReturnType,
|
||||
rawSharedReturnType,
|
||||
rawRawCaster,
|
||||
rawSharedCaster
|
||||
) {
|
||||
requestDeferredRegistration(function() {
|
||||
var classType = requireRegisteredType(rawClassType, 'class');
|
||||
methodName = Pointer_stringify(methodName);
|
||||
var humanName = classType.name + '.' + methodName;
|
||||
var returnType = requireRegisteredType(rawReturnType, 'method ' + humanName + ' return value');
|
||||
rawInvoker = FUNCTION_TABLE[rawInvoker];
|
||||
var rawReturnType = requireRegisteredType(rawRawReturnType, 'method ' + humanName + ' return value');
|
||||
var sharedReturnType = requireRegisteredType(rawSharedReturnType, 'method ' + humanName + ' shared pointer return value');
|
||||
var rawCaster = FUNCTION_TABLE[rawRawCaster];
|
||||
var sharedCaster = FUNCTION_TABLE[rawSharedCaster];
|
||||
classType.Handle.prototype[methodName] = function() {
|
||||
if (!this.ptr) {
|
||||
throw new BindingError('cannot call emscripten binding method ' + humanName + ' on deleted object');
|
||||
|
@ -995,11 +1015,11 @@ function __embind_register_raw_cast_method(
|
|||
if (isPolymorphic) {
|
||||
// todo: this is all only to validate the cast -- cache the result
|
||||
var runtimeType = ___getDynamicPointerType(this.ptr);
|
||||
var derivation = Module.__getDerivationPath(rawReturnType, runtimeType); // downcast is valid
|
||||
var derivation = Module.__getDerivationPath(rawRawReturnType, runtimeType); // downcast is valid
|
||||
var size = derivation.size();
|
||||
derivation.delete();
|
||||
if (size === 0) {
|
||||
derivation = Module.__getDerivationPath(runtimeType, rawReturnType); // upcast is valid
|
||||
derivation = Module.__getDerivationPath(runtimeType, rawRawReturnType); // upcast is valid
|
||||
size = derivation.size();
|
||||
derivation.delete();
|
||||
if (size === 0) {
|
||||
|
@ -1007,64 +1027,29 @@ function __embind_register_raw_cast_method(
|
|||
}
|
||||
}
|
||||
}
|
||||
var args = new Array(1);
|
||||
args[0] = this.ptr;
|
||||
var ptr = rawInvoker.apply(null, args);
|
||||
var rv = returnType.fromWireType(ptr);
|
||||
rv.count = this.count;
|
||||
this.count.value ++;
|
||||
var args;
|
||||
var ptr;
|
||||
var rv;
|
||||
if (this.smartPointer) {
|
||||
args = new Array(2);
|
||||
ptr = _malloc(8);
|
||||
args[0] = ptr;
|
||||
args[1] = this.smartPointer;
|
||||
sharedCaster.apply(null,args); // need a smart pointer raw invoker
|
||||
rv = sharedReturnType.fromWireType(ptr);
|
||||
} else {
|
||||
args = new Array(1);
|
||||
args[0] = this.ptr;
|
||||
ptr = rawCaster.apply(null, args);
|
||||
rv = rawReturnType.fromWireType(ptr);
|
||||
rv.count = this.count;
|
||||
this.count.value ++;
|
||||
}
|
||||
return rv;
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
// todo: cast methods should not be passed from the smart ptr to the contained object!!
|
||||
function __embind_register_smart_cast_method(
|
||||
rawPointerType,
|
||||
rawReturnType,
|
||||
returnPointeeType,
|
||||
isPolymorphic,
|
||||
methodName,
|
||||
rawInvoker
|
||||
) {
|
||||
requestDeferredRegistration(function() {
|
||||
var pointerType = requireRegisteredType(rawPointerType, 'smart pointer class');
|
||||
methodName = Pointer_stringify(methodName);
|
||||
var humanName = pointerType.name + '.' + methodName;
|
||||
var returnType = requireRegisteredType(rawReturnType, 'method ' + humanName + ' return value');
|
||||
rawInvoker = FUNCTION_TABLE[rawInvoker];
|
||||
pointerType.Handle.prototype[methodName] = function() {
|
||||
if (!this.ptr) {
|
||||
throw new BindingError('cannot call emscripten binding method ' + humanName + ' on deleted object');
|
||||
}
|
||||
if (arguments.length !== 0) {
|
||||
throw new BindingError('emscripten binding method ' + humanName + ' called with arguments, none expected');
|
||||
}
|
||||
if (isPolymorphic) {
|
||||
// todo: just validating the cast -- cache the result
|
||||
var runtimeType = ___getDynamicPointerType(this.ptr);
|
||||
var derivation = Module.__getDerivationPath(returnPointeeType, runtimeType); // downcast is valid
|
||||
var size = derivation.size();
|
||||
derivation.delete();
|
||||
if (size === 0) {
|
||||
derivation = Module.__getDerivationPath(runtimeType, returnPointeeType); // upcast is valid
|
||||
size = derivation.size();
|
||||
derivation.delete();
|
||||
if (size === 0) {
|
||||
throw new CastError("Pointer conversion is not available");
|
||||
}
|
||||
}
|
||||
}
|
||||
var args = new Array(2);
|
||||
var ptr = _malloc(8);
|
||||
args[0] = ptr;
|
||||
args[1] = this.smartPointer;
|
||||
rawInvoker.apply(null,args);
|
||||
return returnType.fromWireType(ptr);
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
function __embind_register_class_classmethod(
|
||||
rawClassType,
|
||||
methodName,
|
||||
|
|
|
@ -124,20 +124,14 @@ namespace emscripten {
|
|||
size_t memberFunctionSize,
|
||||
void* memberFunction);
|
||||
|
||||
void _embind_register_raw_cast_method(
|
||||
void _embind_register_cast_method(
|
||||
TYPEID classType,
|
||||
bool isPolymorphic,
|
||||
const char* methodName,
|
||||
TYPEID returnType,
|
||||
GenericFunction invoker);
|
||||
|
||||
void _embind_register_smart_cast_method(
|
||||
TYPEID pointerType,
|
||||
TYPEID returnType,
|
||||
TYPEID returnPointeeType,
|
||||
bool isPolymorphic,
|
||||
const char* methodName,
|
||||
GenericFunction invoker);
|
||||
TYPEID sharedReturnType,
|
||||
GenericFunction rawInvoker,
|
||||
GenericFunction sharedInvoker);
|
||||
|
||||
void _embind_register_class_field(
|
||||
TYPEID classType,
|
||||
|
@ -274,7 +268,6 @@ namespace emscripten {
|
|||
|
||||
extern "C" {
|
||||
int __getDynamicPointerType(int p);
|
||||
int __dynamicPointerCast(int p, int to);
|
||||
}
|
||||
|
||||
template<typename FromType, typename ToType>
|
||||
|
@ -283,14 +276,14 @@ namespace emscripten {
|
|||
};
|
||||
|
||||
template<typename FromRawType, typename ToRawType, bool isPolymorphic>
|
||||
struct performShared {
|
||||
struct performSharedCast {
|
||||
static std::shared_ptr<ToRawType> cast(std::shared_ptr<FromRawType> from) {
|
||||
return std::dynamic_pointer_cast<ToRawType>(from);
|
||||
};
|
||||
};
|
||||
|
||||
template<typename FromRawType, typename ToRawType>
|
||||
struct performShared<FromRawType, ToRawType, false> {
|
||||
struct performSharedCast<FromRawType, ToRawType, false> {
|
||||
static std::shared_ptr<ToRawType> cast(std::shared_ptr<FromRawType> from) {
|
||||
return std::shared_ptr<ToRawType>(from, static_cast<ToRawType*>(from.get()));
|
||||
};
|
||||
|
@ -300,7 +293,7 @@ namespace emscripten {
|
|||
void function(const char* name, ReturnType (fn)(Args...), Policies...) {
|
||||
using namespace internal;
|
||||
|
||||
registerStandardTypes();
|
||||
registerStandardTypes(); // todo: remove all
|
||||
|
||||
typename WithPolicies<Policies...>::template ArgTypeList<ReturnType, Args...> args;
|
||||
_embind_register_function(
|
||||
|
@ -625,21 +618,12 @@ namespace emscripten {
|
|||
reinterpret_cast<GenericFunction>(&get_pointee<PointerType>));
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
template<typename ReturnType>
|
||||
register_smart_ptr& cast(const char* methodName) {
|
||||
using namespace internal;
|
||||
typedef typename ReturnType::element_type ReturnPointeeType;
|
||||
typedef typename PointerType::element_type PointeeType;
|
||||
_embind_register_smart_cast_method(
|
||||
TypeID<PointerType>::get(),
|
||||
TypeID<ReturnType>::get(),
|
||||
TypeID<ReturnPointeeType>::get(),
|
||||
std::is_polymorphic<PointeeType>::value,
|
||||
methodName,
|
||||
reinterpret_cast<GenericFunction>(&performShared<PointeeType, ReturnPointeeType, std::is_polymorphic<PointeeType>::value>::cast));
|
||||
return *this;
|
||||
}
|
||||
template<typename PointeeType>
|
||||
class shared_ptr: public register_smart_ptr<std::shared_ptr<PointeeType>> {
|
||||
public:
|
||||
shared_ptr(const char* name): register_smart_ptr<std::shared_ptr<PointeeType>>(name) {};
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -777,13 +761,31 @@ namespace emscripten {
|
|||
template<typename ReturnType>
|
||||
class_& cast(const char* methodName) {
|
||||
using namespace internal;
|
||||
//typedef typename std::shared_ptr<ClassType> PointerType;
|
||||
typedef typename std::shared_ptr<ReturnType> SharedReturnType;
|
||||
|
||||
_embind_register_raw_cast_method(
|
||||
_embind_register_cast_method(
|
||||
TypeID<ClassType>::get(),
|
||||
std::is_polymorphic<ClassType>::value,
|
||||
methodName,
|
||||
TypeID<ReturnType>::get(),
|
||||
reinterpret_cast<GenericFunction>(&performRawStaticCast<ClassType,ReturnType>));
|
||||
TypeID<SharedReturnType>::get(),
|
||||
reinterpret_cast<GenericFunction>(&performRawStaticCast<ClassType, ReturnType>),
|
||||
reinterpret_cast<GenericFunction>(&performSharedCast<ClassType, ReturnType, std::is_polymorphic<ClassType>::value>::cast));
|
||||
return *this;
|
||||
}
|
||||
|
||||
class_& shared_ptr(const char* ptrName = "") {
|
||||
using namespace internal;
|
||||
typedef typename std::shared_ptr<ClassType> PointerType;
|
||||
|
||||
_embind_register_smart_ptr(
|
||||
TypeID<PointerType>::get(),
|
||||
TypeID<ClassType>::get(),
|
||||
ptrName,
|
||||
reinterpret_cast<GenericFunction>(&raw_smart_pointer_constructor<ClassType*>),
|
||||
reinterpret_cast<GenericFunction>(&raw_destructor<PointerType>),
|
||||
reinterpret_cast<GenericFunction>(&get_pointee<PointerType>));
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -101,7 +101,7 @@ namespace emscripten {
|
|||
// __getDerivationPath returns an array of type_info pointers describing the derivation chain starting with
|
||||
// the derived type and proceeding toward (and ending with) the base type. Types are only included if they
|
||||
// appear on all possible derivation paths.
|
||||
std::vector<int> __getDerivationPath(int dv, const int bs) {
|
||||
std::vector<int> __getDerivationPath(int dv, const int bs) { // todo: use emval array to pass return value??
|
||||
std::vector<std::vector<const __cxxabiv1::__class_type_info*>> paths;
|
||||
|
||||
const std::type_info* dv1 = (std::type_info*)dv;
|
||||
|
@ -176,27 +176,11 @@ namespace emscripten {
|
|||
|
||||
// __getDynamicPointerType returns (for polymorphic types only!) the type of the instance actually
|
||||
// pointed to.
|
||||
int EMSCRIPTEN_KEEPALIVE __getDynamicPointerType(int p) {
|
||||
int EMSCRIPTEN_KEEPALIVE __getDynamicPointerType(int p) { // use size_t
|
||||
void** vtable = *(void***)p;
|
||||
return (int)static_cast<const std::type_info*>(vtable[-1]);
|
||||
}
|
||||
|
||||
// Calls to __dynamic_cast are generated by the compiler to implement dynamic_cast<>() -- its prototype is
|
||||
// not available through any header file. It is called directly here because it allows run-time
|
||||
// specification of the target pointer type (which can only be specified at compile time when using
|
||||
// dynamic_cast<>().
|
||||
void* __dynamic_cast(void*, const std::type_info*, const std::type_info*, int);
|
||||
|
||||
// __dynamicPointerCast performs a C++ dynamic_cast<>() operation, but allowing run-time specification of
|
||||
// the from and to pointer types.
|
||||
int EMSCRIPTEN_KEEPALIVE __dynamicPointerCast(int p, int to) {
|
||||
int ret = (int)__staticPointerCast((void *)p, __getDynamicPointerType(p), to);
|
||||
if (ret < 0) {
|
||||
return 0;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
const char* EMSCRIPTEN_KEEPALIVE __typeName(int p) {
|
||||
const std::type_info* ti = (const std::type_info*)p;
|
||||
size_t nameLen = std::min(strlen(ti->name()), (unsigned int)1024);
|
||||
|
|
Загрузка…
Ссылка в новой задаче