Skip to content
Merged
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
2 changes: 1 addition & 1 deletion VERSION.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.20260529.1
0.20260604.0
6 changes: 0 additions & 6 deletions src/api/libopencor/seduniformtimecourse.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,6 @@ class LIBOPENCOR_EXPORT SedUniformTimeCourse: public SedSimulation
* Return the initial time used by this simulation.
*
* @return The initial time used by this simulation.
*
* @warning ---GRY--- The initial time of a simulation is currently ignored. We currently assume that the initial
* time is always the same as the output start time.
*/

double initialTime() const;
Expand All @@ -81,9 +78,6 @@ class LIBOPENCOR_EXPORT SedUniformTimeCourse: public SedSimulation
* Set the initial time to be used by this simulation.
*
* @param pInitialTime The initial time to be used by this simulation.
*
* @warning ---GRY--- The initial time of a simulation is currently ignored. We currently assume that the initial
* time is always the same as the output start time.
*/

void setInitialTime(double pInitialTime);
Expand Down
71 changes: 38 additions & 33 deletions src/bindings/javascript/file.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,57 +32,62 @@ void fileApi()
.property("fileName", &libOpenCOR::File::fileName)
.property("url", &libOpenCOR::File::url)
.property("path", &libOpenCOR::File::path)
// clang-format off
.function("contents", emscripten::optional_override([](const libOpenCOR::FilePtr &pThis) {
const auto &contents {pThis->contents()};
auto size = contents.size();

if (size == 0) {
return emscripten::val::global("Uint8Array").new_(0);
}

// Note: we avoid using emscripten::typed_memory_view() as an intermediate step since it creates a
// JavaScript's TypedArray view directly backed by wasmMemory.buffer. This is fragile and
// would break if ALLOW_MEMORY_GROWTH was to be enabled or if pthreads/SharedArrayBuffer
// support were to be added. By performing the copy entirely within a single EM_ASM() block,
// HEAPU8 is fetched and used atomically.

return emscripten::val::take_ownership(
static_cast<emscripten::EM_VAL>(EM_ASM_PTR({
var jsArray = new Uint8Array(HEAPU8.subarray($0, $0 + $1));

return Emval.toHandle(jsArray); }, contents.data(), size)));
}))
const auto &contents {pThis->contents()};
auto size = contents.size();

if (size == 0) {
return emscripten::val::global("Uint8Array").new_(0);
}

// Note: we avoid using emscripten::typed_memory_view() as an intermediate step since it creates a
// JavaScript's TypedArray view directly backed by wasmMemory.buffer. This is fragile and would break
// if ALLOW_MEMORY_GROWTH was to be enabled or if pthreads/SharedArrayBuffer support were to be added.
// By performing the copy entirely within a single EM_ASM() block, HEAPU8 is fetched and used
// atomically.

return emscripten::val::take_ownership(static_cast<emscripten::EM_VAL>(
EM_ASM_PTR({
let jsArray = new Uint8Array(HEAPU8.subarray($0, $0 + $1));

return Emval.toHandle(jsArray);
}, contents.data(), size)));
}))
.function("setContents", emscripten::optional_override([](const libOpenCOR::FilePtr &pThis, emscripten::val pContents) {
if (pContents.isNull() || pContents.isUndefined()) {
pThis->setContents(libOpenCOR::UnsignedChars {});
if (pContents.isNull() || pContents.isUndefined()) {
pThis->setContents(libOpenCOR::UnsignedChars {});

return;
}
return;
}

// Note: avoid using emscripten::vecFromJSArray() since it internally uses typed_memory_view (see
// the note in the contents() binding above).
// Note: avoid using emscripten::vecFromJSArray() since it internally uses typed_memory_view (see the note
// in the contents() binding above).

auto length = pContents["length"].as<size_t>();
libOpenCOR::UnsignedChars contents(length);
auto length = pContents["length"].as<size_t>();
libOpenCOR::UnsignedChars contents(length);

if (length > 0) {
EM_ASM({ HEAPU8.set(Emval.toValue($0).subarray(0, $2), $1); }, pContents.as_handle(), contents.data(), length);
}
if (length > 0) {
EM_ASM({
HEAPU8.set(Emval.toValue($0).subarray(0, $2), $1);
}, pContents.as_handle(), contents.data(), length);
}

pThis->setContents(std::move(contents));
}))
pThis->setContents(std::move(contents));
})) // clang-format on
.property("hasChildFiles", &libOpenCOR::File::hasChildFiles)
.property("childFileCount", &libOpenCOR::File::childFileCount)
.property("childFileNames", &libOpenCOR::File::childFileNames)
.property("childFiles", &libOpenCOR::File::childFiles)
.function("childFile", &libOpenCOR::File::childFile)
.function("childFileFromFileName", &libOpenCOR::File::childFileFromFileName);

// clang-format off
EM_ASM({
Module["File"]["Type"] = Module["File.Type"];

delete Module["File.Type"];
});
}); // clang-format on

// FileManager API.

Expand Down
6 changes: 3 additions & 3 deletions src/bindings/javascript/logger.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,14 +46,14 @@ void loggerApi()
.property("typeAsString", &libOpenCOR::Issue::typeAsString)
.property("description", &libOpenCOR::Issue::description);

// clang-format off
EM_ASM({
Module["Issue"]["Type"] = Module["Issue.Type"];

delete Module["Issue.Type"];

Module["Issue"].prototype.toString = function()
{
Module["Issue"].prototype.toString = function() {
return this.description;
};
});
}); // clang-format on
}
78 changes: 49 additions & 29 deletions src/bindings/javascript/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,39 +55,59 @@ EMSCRIPTEN_BINDINGS(libOpenCOR)
// those commas can get interpreted as macro argument separators by the C++ preprocessor, which causes
// compilation errors.

// clang-format off
EM_ASM({
let vectorNames = 'Doubles|FilePtrs|IssuePtrs|SedAbstractTaskPtrs|SedChangePtrs|SedDataDescriptionPtrs|SedDataGeneratorPtrs|SedInstanceTaskPtrs|SedModelPtrs|SedOutputPtrs|SedSimulationPtrs|SedStylePtrs|Strings'.split('|');

vectorNames.forEach(function(name) {
vectorNames.forEach((name) => {
let prototype = Module[name].prototype;

Object.defineProperty(prototype, 'length', {
get: function() { return this.size(); }
});

prototype[Symbol.iterator] = function()
{
let i = 0;
let n = this.size();
let iterator = {};

iterator.next = () =>
{
let result = {};

if (i < n) {
result.value = this.get(i++);
result.done = false;
} else {
result.value = undefined;
result.done = true;
}

return result;
};

return iterator;
};
});
});
get: function() {
return this.size();
}
});

prototype[Symbol.iterator] = function() {
let i = 0;
let n = this.size();
let iterator = {};

iterator.next = () => {
let result = {};

if (i < n) {
result.value = this.get(i++);
result.done = false;
} else {
result.value = undefined;
result.done = true;
}

return result;
};

return iterator;
};

Object.setPrototypeOf(prototype, new Proxy(Object.getPrototypeOf(prototype), {
get: (target, prop, receiver) => {
if (typeof prop === 'string' && /^[0-9]+$/.test(prop)) {
return receiver.get(parseInt(prop));
}

return Reflect.get(target, prop, receiver);
},
set: (target, prop, value, receiver) => {
if (typeof prop === 'string' && /^[0-9]+$/.test(prop)) {
receiver.set(parseInt(prop), value);

return true;
}

return Reflect.set(target, prop, value, receiver);
}
}));
});
}); // clang-format on
}
15 changes: 9 additions & 6 deletions src/bindings/javascript/solver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,16 +31,16 @@ void solverApi()
.property("id", &libOpenCOR::Solver::id)
.property("name", &libOpenCOR::Solver::name);

// clang-format off
EM_ASM({
Module["Solver"]["Type"] = Module["Solver.Type"];

delete Module["Solver.Type"];

Module["Solver"].prototype.toString = function()
{
Module["Solver"].prototype.toString = function() {
return this.name;
};
});
}); // clang-format on

// SolverOde API.

Expand All @@ -59,9 +59,10 @@ void solverApi()
reinterpret_cast<double *>(pU), pN, reinterpret_cast<void *>(pData));
}));

// clang-format off
EM_ASM({
Module["nlaSolve"] = Module["nlaSolve"];
});
}); // clang-format on

emscripten::class_<libOpenCOR::SolverNla, emscripten::base<libOpenCOR::Solver>>("SolverNla")
.smart_ptr<libOpenCOR::SolverNlaPtr>("SolverNla");
Expand Down Expand Up @@ -102,6 +103,7 @@ void solverApi()
.property("absoluteTolerance", &libOpenCOR::SolverCvode::absoluteTolerance, &libOpenCOR::SolverCvode::setAbsoluteTolerance)
.property("interpolateSolution", &libOpenCOR::SolverCvode::interpolateSolution, &libOpenCOR::SolverCvode::setInterpolateSolution);

// clang-format off
EM_ASM({
Module["SolverCvode"]["IntegrationMethod"] = Module["SolverCvode.IntegrationMethod"];
Module["SolverCvode"]["IterationType"] = Module["SolverCvode.IterationType"];
Expand All @@ -112,7 +114,7 @@ void solverApi()
delete Module["SolverCvode.IterationType"];
delete Module["SolverCvode.LinearSolver"];
delete Module["SolverCvode.Preconditioner"];
});
}); // clang-format on

// SolverForwardEuler API.

Expand Down Expand Up @@ -145,11 +147,12 @@ void solverApi()
.property("upperHalfBandwidth", &libOpenCOR::SolverKinsol::upperHalfBandwidth, &libOpenCOR::SolverKinsol::setUpperHalfBandwidth)
.property("lowerHalfBandwidth", &libOpenCOR::SolverKinsol::lowerHalfBandwidth, &libOpenCOR::SolverKinsol::setLowerHalfBandwidth);

// clang-format off
EM_ASM({
Module["SolverKinsol"]["LinearSolver"] = Module["SolverKinsol.LinearSolver"];

delete Module["SolverKinsol.LinearSolver"];
});
}); // clang-format on

// SolverSecondOrderRungeKutta API.

Expand Down
Loading
Loading