成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

Emscripten教程之C++和JavaScript綁定(三)

warkiz / 4336人閱讀

摘要:支持綁定大多數(shù)的結構,包括和中引入的。枚舉支持枚舉和枚舉類。雖然還有進一步優(yōu)化的空間,但到目前為止,它在實際應用程序中的性能已經(jīng)被證明是完全可以接受的。

翻譯:云荒杯傾

Embind用于綁定C++函數(shù)和類到JavaScript,這樣編譯代碼就能在js中以一種很自然的方式來使用。Embind也支持從C++調(diào)JavaScript的class。

Embind支持綁定大多數(shù)C++的結構,包括C++11和C++14中引入的。它只有一個明顯的限制就是目前還不支持raw pointers with complicated lifetime semantics。

本文展示了如何使用EMSCRIPTEN_BINDINGS()塊來創(chuàng)建函數(shù)、類、值類型、指針(包括原始和智能指針)、枚舉和常量的綁定,以及如何為抽象類創(chuàng)建綁定,這些抽象類可以在JavaScript中被重寫。它還簡要介紹了如何管理傳遞給JavaScript的c++對象句柄的內(nèi)存。

note:
Embind的靈感來自 Boost.Python,他們使用非常相似的方法定義綁定。
一個簡單例子

下面的代碼使用EMSCRIPTEN_BINDINGS()暴露了C++ lerp()函數(shù)給JavaScript。

    // quick_example.cpp
    #include 

    using namespace emscripten;

    float lerp(float a, float b, float t) {
        return (1 - t) * a + t * b;
    }

    EMSCRIPTEN_BINDINGS(my_module) {
        function("lerp", &lerp);
    }

為了使用embind編譯上例,請調(diào)用emcc的bing選項:

emcc --bind -o quick_example.js quick_example.cpp

生成的quick_example.js文件可以作為node模塊加載,也可以使用

當quick_example.js文件初始化加載后, EMSCRIPTEN_BINDINGS()中代碼會運行。

所有通過Embind暴露的symblols都可以在Module對象獲取。

暴露一個類給JavaScript需要比較復雜的綁定語句,比如:

    class MyClass {
    public:
      MyClass(int x, std::string y)
        : x(x)
        , y(y)
      {}

      void incrementX() {
        ++x;
      }

      int getX() const { return x; }
      void setX(int x_) { x = x_; }

      static std::string getStringFromInstance(const MyClass& instance) {
        return instance.y;
      }

    private:
      int x;
      std::string y;
    };

    // Binding code
    EMSCRIPTEN_BINDINGS(my_class_example) {
      class_("MyClass")
        .constructor()
        .function("incrementX", &MyClass::incrementX)
        .property("x", &MyClass::getX, &MyClass::setX)
        .class_function("getStringFromInstance", &MyClass::getStringFromInstance)
        ;
    }

綁定塊在一個臨時class_對象上定義了成員函數(shù)調(diào)用鏈(Boost.Python也是同樣風格)。

note:
你應該只綁定那些你實際需要的項(將它作為一個規(guī)則或原則),因為每個綁定會增加代碼大小。比如,內(nèi)部方法和私有變量可以很少綁定。

在JavaScript中定義和使用MyClass實例的代碼如下:

    var instance = new Module.MyClass(10, "hello");
    instance.incrementX();
    instance.x; // 12
    instance.x = 20; // 20
    Module.MyClass.getStringFromInstance(instance); // "hello"
    instance.delete();
內(nèi)存管理

因為JavaScript,尤其是ECMA-262 Edition 5.1,不支持 finalizers or weak references with callbacks,因此Emscripten沒有辦法調(diào)用C++對象的析構函數(shù)。

警告:
JavaScript代碼必須明確刪除C++對象的句柄,否則Emscripten堆會無限增長。
    var x = new Module.MyClass;
    x.method();
    x.delete();

    var y = Module.myFunctionThatReturnsClassInstance();
    y.method();
    y.delete();
值類型

對基本類型進行手動內(nèi)存管理是麻煩的,所以embind對值類型提供了支持。包括Value arrays和 value objects,分別對應js的array和object。

示例:

    struct Point2f {
        float x;
        float y;
    };

    struct PersonRecord {
        std::string name;
        int age;
    };

    PersonRecord findPersonAtLocation(Point2f);

    EMSCRIPTEN_BINDINGS(my_value_example) {
        value_array("Point2f")
            .element(&Point2f::x)
            .element(&Point2f::y)
            ;

        value_object("PersonRecord")
            .field("name", &PersonRecord::name)
            .field("age", &PersonRecord::age)
            ;

        function("findPersonAtLocation", &findPersonAtLocation);
    }

以下代碼就不需要擔心手動生命周期管理。

    var person = Module.findPersonAtLocation([10.2, 156.5]);
    console.log("Found someone! Their name is " + person.name + " and they are " + person.age + " years old");
高級類概念(todo) 重載函數(shù)

構造函數(shù)和函數(shù)可以根據(jù)參數(shù)數(shù)量重載,但embind不支持根據(jù)參數(shù)類型重載。當你指定一個重載,請使用select_overload()幫助函數(shù)選中合適的簽名。

    struct HasOverloadedMethods {
        void foo();
        void foo(int i);
        void foo(float f) const;
    };

    EMSCRIPTEN_BINDING(overloads) {
        class_("HasOverloadedMethods")
            .function("foo", select_overload(&HasOverloadedMethods::foo))
            .function("foo_int", select_overload(&HasOverloadedMethods::foo))
            .function("foo_float", select_overload(&HasOverloadedMethods::foo))
            ;
    }
枚舉

embind支持C++98枚舉和C++11枚舉類。

    enum OldStyle {
        OLD_STYLE_ONE,
        OLD_STYLE_TWO
    };

    enum class NewStyle {
        ONE,
        TWO
    };

    EMSCRIPTEN_BINDINGS(my_enum_example) {
        enum_("OldStyle")
            .value("ONE", OLD_STYLE_ONE)
            .value("TWO", OLD_STYLE_TWO)
            ;
        enum_("NewStyle")
            .value("ONE", NewStyle::ONE)
            .value("TWO", NewStyle::TWO)
            ;
    }

JavaScript調(diào)用方式如下:

    Module.OldStyle.ONE;
    Module.NewStyle.TWO;
常量

向JavaScript暴露一個常量:

    EMSCRIPTEN_BINDINGS(my_constant_example) {
        constant("SOME_CONSTANT", SOME_CONSTANT);
    }
內(nèi)存視圖

在某些情況下,將原始二進制數(shù)據(jù)以一個類型化數(shù)組的形式直接暴露給JavaScript代碼是有價值的。這對于直接從堆上上傳大型WebGL紋理非常有用。

內(nèi)存視圖應該像指針一樣對待;生命周期和有效性不由運行時管理的,如果底層對象被修改或重新分配,則很容易損壞數(shù)據(jù)。

    #include 
    #include 

    using namespace emscripten;

    unsigned char *byteBuffer = /* ... */;
    size_t bufferLength = /* ... */;

    val getBytes() {
        return val(typed_memory_view(bufferLength, byteBuffer));
    }

    EMSCRIPTEN_BINDINGS(memory_view_example) {
        function("getBytes", &getBytes);
    }

下面JavaScript代碼接收類型數(shù)組視圖

    var myUint8Array = Module.getBytes()
    var xhr = new XMLHttpRequest();
    xhr.open("POST", /* ... */);
    xhr.send(myUint8Array);
使用val將JavaScript翻譯為C++

Embind提供了一個c++類,emscripten::val,您可以使用它將JavaScript代碼轉(zhuǎn)換為c++。使用val,可以在c++中調(diào)用JavaScript對象,讀取和寫入它們的屬性,或者強制它們成為c++值,比如bool、int或std::string。

下面代碼展示了你可以通過val在C++中調(diào)用JavaScript的 Web Audio API。
首先看一下js的代碼,展示js怎么用這個API:

    // Get web audio api context
    var AudioContext = window.AudioContext || window.webkitAudioContext;

    // Got an AudioContext: Create context and OscillatorNode
    var context = new AudioContext();
    var oscillator = context.createOscillator();

    // Configuring oscillator: set OscillatorNode type and frequency
    oscillator.type = "triangle";
    oscillator.frequency.value = 261.63; // value in hertz - middle C

    // Playing
    oscillator.connect(context.destination);
    oscillator.start();

    // All done!

然后使用val將代碼翻譯成c++,如下:

    #include 
    #include 
    #include 

    using namespace emscripten;

    int main() {
      val AudioContext = val::global("AudioContext");
      if (!AudioContext.as()) {
        printf("No global AudioContext, trying webkitAudioContext
");
        AudioContext = val::global("webkitAudioContext");
      }

      printf("Got an AudioContext
");
      val context = AudioContext.new_();
      val oscillator = context.call("createOscillator");

      printf("Configuring oscillator
");
      oscillator.set("type", val("triangle"));
      oscillator["frequency"].set("value", val(261.63)); // Middle C

      printf("Playing
");
      oscillator.call("connect", context["destination"]);
      oscillator.call("start", 0);

      printf("All done!
");
    }

首先使用global()取全局AudioContext對象(如果不存在就取webkitAudioContext對象),然后使用new_()創(chuàng)建實例,從實例我們可以創(chuàng)建oscillator,設置set()它的屬性,然后播放。

內(nèi)建類型轉(zhuǎn)換

embind為許多標準C++類型提供類型轉(zhuǎn)換

C++類型 JavaScript類型
void undefined
bool true or false
char number
signed char number
unsigned char number
short number
ungigned short number
int number
unsigned int number
log number
unsigned long number
float number
double number
std::string ArrayBuffer, Uint8Array, Uint8ClampedArray, Int8Array, or String
std::wstring String (UTF-16 code units)
emscripten::val anything

為了方便,embind還提供了工廠函數(shù)用來注冊std::vector(register_vector())和std::map(register_map())類型。

    EMSCRIPTEN_BINDINGS(stl_wrappers) {
        register_vector("VectorInt");
        register_map("MapIntInt");
    }
性能

在撰寫本文時,還沒有對標準基準測試或相對于WebIDL Binder的全面的embind性能測試。

簡單函數(shù)的調(diào)用開銷在200ns左右。雖然還有進一步優(yōu)化的空間,但到目前為止,它在實際應用程序中的性能已經(jīng)被證明是完全可以接受的。

Emscripten代碼移植系列文章

Emscripten代碼移植主題系列文章是emscripten中文站點的一部分內(nèi)容。
本文是第三個主題第二篇文章。
第一個主題介紹代碼可移植性與限制
第二個主題介紹Emscripten的運行時環(huán)境
第三個主題第一篇文章介紹連接C++和JavaScript
第三個主題第二篇文章介紹embind
第四個主題介紹文件和文件系統(tǒng)

文章版權歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/91911.html

相關文章

  • Emscripten教程連接C++JavaScript

    摘要:用具體的參數(shù)和返回值調(diào)用一個編譯的函數(shù),而是一個編譯的函數(shù)的包裹,調(diào)用它會返回一個可以調(diào)用的函數(shù)。如果返回值是或你要指定不同宏,是還是。返回值用于傳給數(shù)據(jù)。對庫文件的限制調(diào)用函數(shù)作為中的函數(shù)指針使用返回一個整數(shù)來表示一個函數(shù)指針。 翻譯:云荒杯傾本文是Emscripten-WebAssembly專欄系列文章之一,更多文章請查看專欄。也可以去作者的博客閱讀文章。歡迎加入Wasm和emsc...

    gyl_coder 評論0 收藏0
  • Emscripten教程Emscripten的運行時環(huán)境(二)

    摘要:運行時環(huán)境與大多數(shù)應用程序所期望的環(huán)境不同。不過程序是要手動交換緩沖區(qū)的。第一個主題介紹代碼可移植性與限制第二個主題介紹的運行時環(huán)境第三個主題第一篇文章介紹連接和第三個主題第二篇文章介紹第四個主題介紹文件和文件系統(tǒng)第六個主題介紹如何調(diào)試代碼 翻譯:云荒杯傾本文是Emscripten-WebAssembly專欄系列文章之一,更多文章請查看專欄。也可以去作者的博客閱讀文章。 Emscrip...

    VishKozus 評論0 收藏0
  • Emscripten教程優(yōu)化你的代碼

    摘要:優(yōu)化項也會引發(fā)一些問題。檢查你的代碼是否工作并修復問題。從起,及以上的優(yōu)化級別默認啟動了這項設置。目前正在進行改進。代碼移植系列文章代碼移植主題系列文章是中文站點的一部分內(nèi)容。 作者:云荒杯傾歡迎加入Wasm和emscripten技術交流群,群聊號碼:939206522。 這是關于Emscripten的系列文章,更多文章請看下面鏈接。 Emscripten代碼移植系列文章 Emscr...

    Jokcy 評論0 收藏0
  • Emscripten教程優(yōu)化你的代碼

    摘要:優(yōu)化項也會引發(fā)一些問題。檢查你的代碼是否工作并修復問題。從起,及以上的優(yōu)化級別默認啟動了這項設置。目前正在進行改進。代碼移植系列文章代碼移植主題系列文章是中文站點的一部分內(nèi)容。 作者:云荒杯傾歡迎加入Wasm和emscripten技術交流群,群聊號碼:939206522。 這是關于Emscripten的系列文章,更多文章請看下面鏈接。 Emscripten代碼移植系列文章 Emscr...

    bladefury 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<