diff options
author | Chad Austin <chad@imvu.com> | 2013-04-03 19:50:50 -0700 |
---|---|---|
committer | Jukka Jylänki <jujjyl@gmail.com> | 2013-04-12 14:27:19 +0300 |
commit | f508d6306ff0be4966d3f26b99a26c46f7c2c1ef (patch) | |
tree | 352dd1ce42319b225794db40ee510dc86743e36b | |
parent | d4bf6fbe297ea7e5720b49bfa6fc58b696540144 (diff) |
Allow value_tuple and value_struct to be registered as global constants. This involved reworking how value_struct and value_tuple are registered.
-rwxr-xr-x | src/embind/embind.js | 248 | ||||
-rwxr-xr-x | system/include/emscripten/bind.h | 26 | ||||
-rwxr-xr-x | tests/embind/embind.test.js | 3 | ||||
-rw-r--r-- | tests/embind/embind_test.cpp | 7 |
4 files changed, 173 insertions, 111 deletions
diff --git a/src/embind/embind.js b/src/embind/embind.js index 46fdeee4..37439912 100755 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -407,37 +407,15 @@ function __embind_register_function(name, argCount, rawArgTypesAddr, rawInvoker, }); } +var tupleRegistrations = {}; + function __embind_register_tuple(rawType, name, rawConstructor, rawDestructor) { - name = Pointer_stringify(name); - rawConstructor = FUNCTION_TABLE[rawConstructor]; - rawDestructor = FUNCTION_TABLE[rawDestructor]; - registerType(rawType, { - name: name, - rawConstructor: rawConstructor, - rawDestructor: rawDestructor, + tupleRegistrations[rawType] = { + name: Pointer_stringify(name), + rawConstructor: FUNCTION_TABLE[rawConstructor], + rawDestructor: FUNCTION_TABLE[rawDestructor], elements: [], - fromWireType: function(ptr) { - var len = this.elements.length; - var rv = new Array(len); - for (var i = 0; i < len; ++i) { - rv[i] = this.elements[i].read(ptr); - } - this.rawDestructor(ptr); - return rv; - }, - toWireType: function(destructors, o) { - var len = this.elements.length; - if (len !== o.length) { - throw new TypeError("Incorrect number of tuple elements"); - } - var ptr = this.rawConstructor(); - for (var i = 0; i < len; ++i) { - this.elements[i].write(ptr, o[i]); - } - destructors.push(rawDestructor, ptr); - return ptr; - }, - }); + }; } function __embind_register_tuple_element( @@ -449,78 +427,84 @@ function __embind_register_tuple_element( setter, setterContext ) { - var tupleType = requireRegisteredType(rawTupleType, 'tuple'); - getter = FUNCTION_TABLE[getter]; - setter = FUNCTION_TABLE[setter]; + tupleRegistrations[rawTupleType].elements.push({ + getterReturnType: getterReturnType, + getter: FUNCTION_TABLE[getter], + getterContext: getterContext, + setterArgumentType: setterArgumentType, + setter: FUNCTION_TABLE[setter], + setterContext: setterContext, + }); +} - var index = tupleType.elements.length; - tupleType.elements.push(undefined); - - // TODO: test incomplete registration of value tuples - whenDependentTypesAreResolved([], [getterReturnType, setterArgumentType], function(types) { - var getterReturnType = types[0]; - var setterArgumentType = types[1]; - tupleType.elements[index] = { - read: function(ptr) { - return getterReturnType.fromWireType( - getter( - getterContext, - ptr)); - }, - write: function(ptr, o) { +function __embind_finalize_tuple(rawTupleType) { + var reg = tupleRegistrations[rawTupleType]; + delete tupleRegistrations[rawTupleType]; + var elements = reg.elements; + var elementsLength = elements.length; + var elementTypes = elements.map(function(elt) { return elt.getterReturnType; }). + concat(elements.map(function(elt) { return elt.setterArgumentType; })); + + var rawConstructor = reg.rawConstructor; + var rawDestructor = reg.rawDestructor; + + whenDependentTypesAreResolved([rawTupleType], elementTypes, function(elementTypes) { + elements.forEach(function(elt, i) { + var getterReturnType = elementTypes[i]; + var getter = elt.getter; + var getterContext = elt.getterContext; + var setterArgumentType = elementTypes[i + elementsLength]; + var setter = elt.setter; + var setterContext = elt.setterContext; + elt.read = function(ptr) { + return getterReturnType.fromWireType(getter(getterContext, ptr)); + }; + elt.write = function(ptr, o) { var destructors = []; - setter( - setterContext, - ptr, - setterArgumentType.toWireType(destructors, o)); + setter(setterContext, ptr, setterArgumentType.toWireType(destructors, o)); runDestructors(destructors); - } - }; - return []; + }; + }); + + return [{ + name: reg.name, + fromWireType: function(ptr) { + var rv = new Array(elementsLength); + for (var i = 0; i < elementsLength; ++i) { + rv[i] = elements[i].read(ptr); + } + rawDestructor(ptr); + return rv; + }, + toWireType: function(destructors, o) { + if (elementsLength !== o.length) { + throw new TypeError("Incorrect number of tuple elements"); + } + var ptr = rawConstructor(); + for (var i = 0; i < elementsLength; ++i) { + elements[i].write(ptr, o[i]); + } + destructors.push(rawDestructor, ptr); + return ptr; + }, + }]; }); } +var structRegistrations = {}; + function __embind_register_struct( rawType, name, rawConstructor, rawDestructor ) { - name = Pointer_stringify(name); - rawConstructor = FUNCTION_TABLE[rawConstructor]; - rawDestructor = FUNCTION_TABLE[rawDestructor]; - - registerType(rawType, { - name: name, - rawConstructor: rawConstructor, - rawDestructor: rawDestructor, - fields: {}, - fromWireType: function(ptr) { - var fields = this.fields; - var rv = {}; - for (var i in fields) { - rv[i] = fields[i].read(ptr); - } - this.rawDestructor(ptr); - return rv; - }, - toWireType: function(destructors, o) { - var fields = this.fields; - // todo: Here we have an opportunity for -O3 level "unsafe" optimizations: - // assume all fields are present without checking. - for (var fieldName in fields) { - if (!(fieldName in o)) { - throw new TypeError('Missing field'); - } - } - var ptr = this.rawConstructor(); - for (fieldName in fields) { - fields[fieldName].write(ptr, o[fieldName]); - } - destructors.push(rawDestructor, ptr); - return ptr; - }, - }); + structRegistrations[rawType] = { + name: Pointer_stringify(name), + rawConstructor: FUNCTION_TABLE[rawConstructor], + rawDestructor: FUNCTION_TABLE[rawDestructor], + fields: [], + }; } function __embind_register_struct_field( @@ -533,27 +517,75 @@ function __embind_register_struct_field( setter, setterContext ) { - structType = requireRegisteredType(structType, 'struct'); - fieldName = Pointer_stringify(fieldName); - getter = FUNCTION_TABLE[getter]; - setter = FUNCTION_TABLE[setter]; + structRegistrations[structType].fields.push({ + fieldName: Pointer_stringify(fieldName), + getterReturnType: getterReturnType, + getter: FUNCTION_TABLE[getter], + getterContext: getterContext, + setterArgumentType: setterArgumentType, + setter: FUNCTION_TABLE[setter], + setterContext: setterContext, + }); +} + +function __embind_finalize_struct(structType) { + var reg = structRegistrations[structType]; + delete structRegistrations[structType]; + + var rawConstructor = reg.rawConstructor; + var rawDestructor = reg.rawDestructor; + var fieldRecords = reg.fields; + var fieldTypes = fieldRecords.map(function(field) { return field.getterReturnType; }). + concat(fieldRecords.map(function(field) { return field.setterArgumentType; })); + whenDependentTypesAreResolved([structType], fieldTypes, function(fieldTypes) { + var fields = {}; + fieldRecords.forEach(function(field, i) { + var fieldName = field.fieldName; + var getterReturnType = fieldTypes[i]; + var getter = field.getter; + var getterContext = field.getterContext; + var setterArgumentType = fieldTypes[i + fieldRecords.length]; + var setter = field.setter; + var setterContext = field.setterContext; + fields[fieldName] = { + read: function(ptr) { + return getterReturnType.fromWireType( + getter(getterContext, ptr)); + }, + write: function(ptr, o) { + var destructors = []; + setter(setterContext, ptr, setterArgumentType.toWireType(destructors, o)); + runDestructors(destructors); + } + }; + }); - // TODO: test incomplete registration of value structs - whenDependentTypesAreResolved([], [getterReturnType, setterArgumentType], function(types) { - var getterReturnType = types[0]; - var setterArgumentType = types[1]; - structType.fields[fieldName] = { - read: function(ptr) { - return getterReturnType.fromWireType( - getter(getterContext, ptr)); + return [{ + name: reg.name, + fromWireType: function(ptr) { + var rv = {}; + for (var i in fields) { + rv[i] = fields[i].read(ptr); + } + rawDestructor(ptr); + return rv; }, - write: function(ptr, o) { - var destructors = []; - setter(setterContext, ptr, setterArgumentType.toWireType(destructors, o)); - runDestructors(destructors); - } - }; - return []; + toWireType: function(destructors, o) { + // todo: Here we have an opportunity for -O3 level "unsafe" optimizations: + // assume all fields are present without checking. + for (var fieldName in fields) { + if (!(fieldName in o)) { + throw new TypeError('Missing field'); + } + } + var ptr = rawConstructor(); + for (fieldName in fields) { + fields[fieldName].write(ptr, o[fieldName]); + } + destructors.push(rawDestructor, ptr); + return ptr; + }, + }]; }); } diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index e767afaa..bd170dea 100755 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -77,6 +77,8 @@ namespace emscripten { GenericFunction setter, void* setterContext); + void _embind_finalize_tuple(TYPEID tupleType); + void _embind_register_struct( TYPEID structType, const char* fieldName, @@ -93,6 +95,8 @@ namespace emscripten { GenericFunction setter, void* setterContext); + void _embind_finalize_struct(TYPEID structType); + void _embind_register_smart_ptr( TYPEID pointerType, TYPEID pointeeType, @@ -458,6 +462,15 @@ namespace emscripten { return internal::getContext(context); } }; + + class noncopyable { + protected: + noncopyable() {} + ~noncopyable() {} + private: + noncopyable(const noncopyable&) = delete; + const noncopyable& operator=(const noncopyable&) = delete; + }; } //////////////////////////////////////////////////////////////////////////////// @@ -465,7 +478,7 @@ namespace emscripten { //////////////////////////////////////////////////////////////////////////////// template<typename ClassType> - class value_tuple { + class value_tuple : public internal::noncopyable { public: value_tuple(const char* name) { using namespace internal; @@ -476,6 +489,11 @@ namespace emscripten { reinterpret_cast<GenericFunction>(&raw_destructor<ClassType>)); } + ~value_tuple() { + using namespace internal; + _embind_finalize_tuple(TypeID<ClassType>::get()); + } + template<typename InstanceType, typename ElementType> value_tuple& element(ElementType InstanceType::*field) { using namespace internal; @@ -516,7 +534,7 @@ namespace emscripten { //////////////////////////////////////////////////////////////////////////////// template<typename ClassType> - class value_struct { + class value_struct : public internal::noncopyable { public: value_struct(const char* name) { using namespace internal; @@ -527,6 +545,10 @@ namespace emscripten { reinterpret_cast<GenericFunction>(&raw_destructor<ClassType>)); } + ~value_struct() { + _embind_finalize_struct(internal::TypeID<ClassType>::get()); + } + template<typename InstanceType, typename FieldType> value_struct& field(const char* fieldName, FieldType InstanceType::*field) { using namespace internal; diff --git a/tests/embind/embind.test.js b/tests/embind/embind.test.js index 7bb3985f..11746214 100755 --- a/tests/embind/embind.test.js +++ b/tests/embind/embind.test.js @@ -1519,7 +1519,8 @@ module({ BaseFixture.extend("constants", function() { assert.equal(10, cm.INT_CONSTANT); assert.equal("some string", cm.STRING_CONSTANT); - //assert.deepEqual([1, 2, 3], cm.VALUE_TUPLE_CONSTANT); + assert.deepEqual([1, 2, 3], cm.VALUE_TUPLE_CONSTANT); + assert.deepEqual({x:1,y:2,z:3}, cm.VALUE_STRUCT_CONSTANT); }); }); diff --git a/tests/embind/embind_test.cpp b/tests/embind/embind_test.cpp index 4d1b376b..be089f9f 100644 --- a/tests/embind/embind_test.cpp +++ b/tests/embind/embind_test.cpp @@ -1355,11 +1355,18 @@ int overloaded_function(int i, int j) EMSCRIPTEN_BINDINGS(constants) {
constant("INT_CONSTANT", 10);
constant("STRING_CONSTANT", std::string("some string"));
+
TupleVector tv;
tv.x = 1;
tv.y = 2;
tv.z = 3;
constant("VALUE_TUPLE_CONSTANT", tv);
+
+ StructVector sv;
+ sv.x = 1;
+ sv.y = 2;
+ sv.z = 3;
+ constant("VALUE_STRUCT_CONSTANT", sv);
}
EMSCRIPTEN_BINDINGS(tests) {
|