国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

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

warkiz / 4308人閱讀

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

翻譯:云荒杯傾

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

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

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

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

下面的代碼使用EMSCRIPTEN_BINDINGS()暴露了C++ lerp()函數給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編譯上例,請調用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_對象上定義了成員函數調用鏈(Boost.Python也是同樣風格)。

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

在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();
內存管理

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

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

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

對基本類型進行手動內存管理是麻煩的,所以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) 重載函數

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

    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調用方式如下:

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

向JavaScript暴露一個常量:

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

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

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

    #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代碼接收類型數組視圖

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

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

下面代碼展示了你可以通過val在C++中調用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_()創建實例,從實例我們可以創建oscillator,設置set()它的屬性,然后播放。

內建類型轉換

embind為許多標準C++類型提供類型轉換

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還提供了工廠函數用來注冊std::vector(register_vector())和std::map(register_map())類型。

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

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

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

Emscripten代碼移植系列文章

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

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/91911.html

相關文章

  • Emscripten教程連接C++JavaScript

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

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

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

    VishKozus 評論0 收藏0
  • Emscripten教程優化你的代碼

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

    Jokcy 評論0 收藏0
  • Emscripten教程優化你的代碼

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

    bladefury 評論0 收藏0

發表評論

0條評論

warkiz

|高級講師

TA的文章

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