2

これには簡単な答えがあるに違いないと確信していますが、ドキュメントやいくつかの最初のグーグル検索で参照を見つけることができませんでした.

基本的に、次のようなクラスがあります。

#define NX 65
#define NY 65

class myclass{
    // other stuff
    public:
        //other stuff.. more functions and more variables
        // a function I want to call every so often with a few different cases
        void solve(int case);
        // a 2D double array that I want to access in JS
        double ux[NX+1][NY+1];
}

他にも関数や変数が使用されていますが、JavaScript で直接呼び出されるものはありません。

ここで、オブジェクトを作成して次のようなことができるように、組み込みたいと思います。

x = new Module.myclass();
x.solve(2); // parameter is irrelevant
for (i=0; i<x.ux.length; i++) {
    for (j=0; j<x.ux[i].length; j++) {
        // do something with the data
        console.log(x.ux[i][j]);
    }
}

だから、当然、私は次のようなことをします:

EMSCRIPTEN_BINDINGS(myclass) {
    class_<myclass>("myclass")
        .function("solve", &myclass::solve)
        .property("ux", &LBM::getux, &LBM::setux)
        ;
}

これらは私のゲッターとセッターです

void setux(double uxnew[NX+1][NY+1]) {
        for (int i=0; i<NX+1; i++) {
                for (int j=0; j<NY+1; j++) {
                        ux[i][j] = uxnew[i][j];
                }
        }
};
double getux() { return **ux; };

次に、これらのエラーがあります。

In file included from ../../lbm.cpp:10:
/home/vagrant/src/emscripten/system/include/emscripten/bind.h:1043:33: error: implicit instantiation of undefined template 'emscripten::internal::GetterPolicy<double (LBM::*)()>'
                TypeID<typename GP::ReturnType>::get(),
                                ^
../../lbm.cpp:1264:18: note: in instantiation of function template specialization 'emscripten::class_<LBM, emscripten::internal::NoBaseClass>::property<double (LBM::*)(), void (LBM::*)(double (*)[66])>' requested here
                .property("p", &LBM::getp, &LBM::setp)
                 ^
/home/vagrant/src/emscripten/system/include/emscripten/bind.h:428:16: note: template is declared here
        struct GetterPolicy;

emscriptenで二重配列を処理する方法を知っている人はいますか? ドキュメントの一部を見逃していなかったことを本当に願っています。私がそうしなかった場合、これは組み込みページに含める必要があります。

また、不手際がありましたことをお詫び申し上げます。それは(表面的には)複雑な問題ではありません。どうすればいいのかわからない。

4

1 に答える 1

4

おそらくきれいではありませんが、いくつかのオプションがあると思います...

この例では、ダイレクト メモリ アクセスの例 2 に int の配列を使用していますが、javascript 側でダイレクト メモリ サイズを適切にマップする限り、double などを使用できます。

test.cpp:

#include <emscripten/bind.h>
#include <stdlib.h>
#include <iostream>

#define NX 65
#define NY 65

class myclass{
    // other stuff
    public:
        myclass() {
            //Just initializing some values to see:
            ux2[0][0] = 3;
            ux2[0][1] = 5;
            ux2[1][0] = 7;
            ux2[1][1] = 9;
        }

        //Example 1: only the  setux seems to work, not getux:
        std::vector<std::vector<double>> ux;
        std::vector<std::vector<double>> getux() { return ux; }
        void setux(std::vector<std::vector<double>> uxnew) {
            for (int i=0; i<NX+1; i++) {
                    for (int j=0; j<NY+1; j++) {
                            std::cout << uxnew[i][j] << std::endl;
                            ux[i][j] = uxnew[i][j];
                    }
            }
        }

        //Example 2: But if we know the address of ux2, then we can get
        // the values and set them, no need for vector overhead:
        int ux2[NX+1][NY+1];
        int getux2() {
            return (int)&ux2;
        };

};


// Required for example 1:
EMSCRIPTEN_BINDINGS(stl_wrappers) {
    emscripten::register_vector<double>("VectorDouble");
    emscripten::register_vector<std::vector<double>>("VectorVectorDouble");
}

EMSCRIPTEN_BINDINGS(myclass) {
    emscripten::class_<myclass>("myclass")
        .constructor()
        //// I could not seem to get properties to work with Vector or pointers:
        //.property("ux", &myclass::getux, &myclass::setux)

        //// So fell back to functions:
        //// Example 1:
        .function("setux",&myclass::setux)
        .function("getux",&myclass::getux) // returns undefined?
        //// Example 2: just work with pointers on JS side (note the allow_raw_pointers here)
        .function("getux2",&myclass::getux2,emscripten::allow_raw_pointers())
        ;
};

test.js:

var M = require('./test.js');

var vdd = new M.VectorVectorDouble();

var doublearray = [];
for(var i=0; i<66; ++i){
    var vd = new M.VectorDouble();
    for(var j=0; j<66; ++j){
        vd.push_back(i+j);
    }
    vdd.push_back(vd);
}

var testclass = new M.myclass();
//This works:
testclass.setux(vdd);
var noworkie = testclass.getux();
//But this does not: (?)
console.log(noworkie.get(0));


// Direct memory access:
var sz = 4;
var ln = 66;
var ind0 = 0;
var ind1 = 1;
var t = new M.myclass();
var ux2ptr = t.getux2();
console.log(M.getValue(ux2ptr+(0*ln + ind0)*sz,'i8*'));
console.log(M.getValue(ux2ptr+(0*ln + ind1)*sz,'i8*'));
console.log(M.getValue(ux2ptr+(1*ln + ind0)*sz,'i8*'));
console.log(M.getValue(ux2ptr+(1*ln + ind1)*sz,'i8*'));
M.setValue(ux2ptr+(0*ln + ind0)*sz,10,'i8*');
console.log(M.getValue(ux2ptr+(0*ln + ind0)*sz,'i8*'));
console.log(M.getValue(ux2ptr+(0*ln + ind1)*sz,'i8*'));
console.log(M.getValue(ux2ptr+(1*ln + ind0)*sz,'i8*'));
console.log(M.getValue(ux2ptr+(1*ln + ind1)*sz,'i8*'));

emcc test.cpp -o test.js -std=c++11 --bind

ベクトルは、メモリへの直接アクセスよりも面倒でオーバーヘッドが増えるように見えるので、直接アクセスを使用して必要な型に変換し、C++ 関数からポインタを返すいくつかの JavaScript ポインタ算術関数を提供して、使用する。あなたができるように:

var dimension1 = NX+1, dimension2 = NY+1;
var blah = doubleptrptr(ux2ptr, dimension1, dimension2);
var first = blah[0][0];  // so you can use the way you expect on the js side.

あっ、そういえば:

emcc -v
emcc (Emscripten GCC-like replacement + linker emulating GNU ld ) 2.0
clang version 3.2 (tags/RELEASE_32/final)
Target: i386-pc-linux-gnu
Thread model: posix

アップデート

int ではなく double の 2 次元配列を使用した例。ただし、関数の戻り値の型は依然として int です。これは、アンパサンド演算子を介してモノのアドレスを返しているためです。そのデータ型とは関係ありません。すべてのデータ型は同じサイズのポインターになります。emscripten がこのポインターの概念全体をどのようにエミュレートするかは興味深いことです。JS コードでそれを考えるのはちょっとしたことでした :) とにかく、それが何であれ、いつでも int として返すことができます。

//Example 2: If we know the address of ux2, then we can get
// the values and set them, no need for vector overhead:
double p[NX+1][NY+1];
int getp() {
    return (int)&p;
};

したがって、変更されるのは ux2 の宣言でのデータ型だけです。ux2 のアドレスを取得して int として返します。おそらくキャストも必要ありませんが、問題はありません。

emscripten バインディングでallow_raw_pointersを必ず実行してください。

.function("getp",&myclass::getp,emscripten::allow_raw_pointers())

前述したように、例のようにプロパティである場合に allow_raw_pointers を実行するように指示する方法がわかりませんでした。そのため、上記の例に示すように関数を使用しました。

于 2013-06-23T23:29:19.047 に答える