Skip to content
This repository has been archived by the owner on Dec 15, 2022. It is now read-only.

Commit

Permalink
Adds asm.js support
Browse files Browse the repository at this point in the history
  • Loading branch information
arcanis committed Jan 15, 2017
1 parent b9b7a06 commit 6ff35dc
Show file tree
Hide file tree
Showing 22 changed files with 645 additions and 47 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,5 @@ node_modules
build
.DS_Store
.clang_complete

/browser.js
12 changes: 8 additions & 4 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
try {
module.exports = require('./build/Release/superstring.node')
} catch (e) {
module.exports = require('./build/Debug/superstring.node')
if (process.env.FORCE_BROWSER_FALLBACK) {
module.exports = require('./browser');
} else {
try {
module.exports = require('./build/Release/superstring.node')
} catch (e) {
module.exports = require('./build/Debug/superstring.node')
}
}
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@
"name": "superstring",
"version": "1.0.5",
"description": "A data structure to efficiently represent the results of applying patches.",
"main": "./index",
"browser": "./browser",
"scripts": {
"build:browser": "em++ --bind -o browser.js -O3 -std=c++14 -I src/bindings/em -I src/core -include iostream src/core/*.cc src/bindings/em/*.cc -s TOTAL_MEMORY=134217728 --memory-init-file 0",
"test-native": "script/test-native.js",
"test": "mocha test/js/*.js",
"benchmark": "node benchmark/marker-index.benchmark.js",
Expand Down
2 changes: 2 additions & 0 deletions src/bindings/buffer-offset-index-wrapper.cc
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include "buffer-offset-index-wrapper.h"
#include "noop.h"
#include "point-wrapper.h"

using namespace v8;
Expand All @@ -8,6 +9,7 @@ void BufferOffsetIndexWrapper::init(Local<Object> exports) {
constructor_template->SetClassName(Nan::New<String>("BufferOffsetIndex").ToLocalChecked());
constructor_template->InstanceTemplate()->SetInternalFieldCount(1);
const auto &prototype_template = constructor_template->PrototypeTemplate();
prototype_template->Set(Nan::New<String>("delete").ToLocalChecked(), Nan::New<FunctionTemplate>(noop));
prototype_template->Set(Nan::New<String>("splice").ToLocalChecked(), Nan::New<FunctionTemplate>(splice));
prototype_template->Set(Nan::New<String>("position_for_character_index").ToLocalChecked(), Nan::New<FunctionTemplate>(position_for_character_index));
prototype_template->Set(Nan::New<String>("character_index_for_position").ToLocalChecked(), Nan::New<FunctionTemplate>(character_index_for_position));
Expand Down
348 changes: 348 additions & 0 deletions src/bindings/em/auto-wrap.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,348 @@
#pragma once

#include <memory>
#include <type_traits>
#include <unordered_map>
#include <vector>

#include <emscripten/val.h>

#include "flat_set.h"
#include "marker-index.h"
#include "optional.h"
#include "point-wrapper.h"
#include "point.h"
#include "text.h"

/********** **********/

template <typename LocalTypeTpl, typename WireTypeTpl>
struct em_wrap_type_base {

using LocalType = LocalTypeTpl;
using WireType = WireTypeTpl;

};

template <typename LocalType, typename WireType>
struct em_wrap_type_simple : public em_wrap_type_base<LocalType, WireType> {

static LocalType receive(WireType data) { return data; }
static WireType transmit(LocalType data) { return data; }

};

/********** **********/

template <typename LocalType>
struct em_wrap_type : public em_wrap_type_simple<LocalType, LocalType> {};

/********** **********/

template <typename LocalType>
LocalType em_receive(typename em_wrap_type<typename std::decay<LocalType>::type>::WireType data)
{
return em_wrap_type<typename std::decay<LocalType>::type>::receive(data);
}

template <typename LocalType>
typename em_wrap_type<typename std::decay<LocalType>::type>::WireType em_transmit(LocalType data)
{
return em_wrap_type<typename std::decay<LocalType>::type>::transmit(data);
}

/********** **********/

template <>
struct em_wrap_type<void> : public em_wrap_type_base<void, void> {};

template <>
struct em_wrap_type<Point> : public em_wrap_type_simple<Point, PointWrapper> {};

template <typename ValueType>
struct em_wrap_type<std::vector<ValueType>> : public em_wrap_type_base<std::vector<ValueType>, emscripten::val> {

static std::vector<ValueType> receive(emscripten::val const & val)
{
std::vector<ValueType> vec;

for (auto t = 0u, T = val["length"].as<unsigned>(); t < T; ++t)
vec.push_back(val[t].as<ValueType>());

return vec;
}

static emscripten::val transmit(std::vector<ValueType> const & vec)
{
auto array = emscripten::val::array();

for (auto const & t : vec)
array.call<void>("push", em_transmit(t));

return array;
}

};

template <typename ValueType>
struct em_wrap_type<optional<ValueType>> : public em_wrap_type_base<optional<ValueType>, emscripten::val> {

static optional<ValueType> receive(emscripten::val const & val)
{
if (!val.as<bool>())
return optional<ValueType>();

return optional<ValueType>(val.as<ValueType>());
}

static emscripten::val transmit(optional<ValueType> const & opt)
{
if (!opt)
return emscripten::val::undefined();

return emscripten::val(em_transmit(*opt));
}

};

template <typename KeyType, typename ValueType>
struct em_wrap_type<std::unordered_map<KeyType, ValueType>> : public em_wrap_type_base<std::unordered_map<KeyType, ValueType>, emscripten::val> {

static std::unordered_map<KeyType, ValueType> receive(emscripten::val const & val)
{
throw std::runtime_error("Unimplemented");
}

static emscripten::val transmit(std::unordered_map<KeyType, ValueType> const & map)
{
auto object = emscripten::val::object();

for (auto const & t : map)
object.set(em_transmit(t.first), em_transmit(t.second));

return object;
}

};

template <typename ValueType>
struct em_wrap_type<flat_set<ValueType>> : public em_wrap_type_base<flat_set<ValueType>, emscripten::val> {

static flat_set<ValueType> receive(emscripten::val const & val)
{
throw std::runtime_error("Unimplemented");
}

static emscripten::val transmit(flat_set<ValueType> const & set)
{
auto object = emscripten::val::global("Set").new_();

for (auto const & t : set)
object.call<void>("add", em_transmit(t));

return object;
}

};

template <>
struct em_wrap_type<MarkerIndex::SpliceResult> : public em_wrap_type_base<MarkerIndex::SpliceResult, emscripten::val> {

static MarkerIndex::SpliceResult receive(emscripten::val const & val)
{
throw std::runtime_error("Unimplemented");
}

static emscripten::val transmit(MarkerIndex::SpliceResult const & spliceResult)
{
auto object = emscripten::val::object();

object.set("touch", em_transmit(spliceResult.touch));
object.set("inside", em_transmit(spliceResult.inside));
object.set("overlap", em_transmit(spliceResult.overlap));
object.set("surround", em_transmit(spliceResult.surround));

return object;
}

};

template <>
struct em_wrap_type<Text> : public em_wrap_type_base<Text, std::string> {

static Text receive(std::string const & str)
{
return Text(str.begin(), str.end());
}

static std::string transmit(Text const & text)
{
return std::string(text.begin(), text.end());
}

};

template <>
struct em_wrap_type<std::unique_ptr<Text>> : public em_wrap_type_base<std::unique_ptr<Text>, emscripten::val> {

static std::unique_ptr<Text> receive(emscripten::val const & val)
{
return std::make_unique<Text>(em_wrap_type<Text>::receive(val.as<std::string>()));
}

static emscripten::val transmit(std::unique_ptr<Text> const & text)
{
if (!text)
return emscripten::val::undefined();

return emscripten::val(em_wrap_type<Text>::transmit(*text));
}

};

template <>
struct em_wrap_type<Text *> : public em_wrap_type_base<Text *, emscripten::val> {

static Text * receive(emscripten::val const & val)
{
return new Text(em_wrap_type<Text>::receive(val.as<std::string>()));
}

static emscripten::val transmit(Text * text)
{
if (!text)
return emscripten::val::undefined();

return emscripten::val(em_wrap_type<Text>::transmit(*text));
}

};

/********** **********/

template <typename T, T>
struct em_wrap_fn;

template <typename T, typename ... Args, void (T::*fn)(Args ...)>
struct em_wrap_fn<void (T::*)(Args ...), fn>
{
static void wrap(T & t, typename em_wrap_type<typename std::decay<Args>::type>::WireType ... args)
{
return (t.*fn)(em_wrap_type<typename std::decay<Args>::type>::receive(args) ...);
}
};

template <typename T, typename ... Args, void (T::*fn)(Args ...) const>
struct em_wrap_fn<void (T::*)(Args ...) const, fn>
{
static void wrap(T const & t, typename em_wrap_type<typename std::decay<Args>::type>::WireType ... args)
{
return (t.*fn)(em_wrap_type<typename std::decay<Args>::type>::receive(args) ...);
}
};

template <typename T, typename Ret, typename ... Args, Ret (T::*fn)(Args ...)>
struct em_wrap_fn<Ret (T::*)(Args ...), fn>
{
static typename em_wrap_type<typename std::decay<Ret>::type>::WireType wrap(T & t, typename em_wrap_type<typename std::decay<Args>::type>::WireType ... args)
{
return em_wrap_type<typename std::decay<Ret>::type>::transmit((t.*fn)(em_wrap_type<typename std::decay<Args>::type>::receive(args) ...));
}
};

template <typename T, typename Ret, typename ... Args, Ret (T::*fn)(Args ...) const>
struct em_wrap_fn<Ret (T::*)(Args ...) const, fn>
{
static typename em_wrap_type<typename std::decay<Ret>::type>::WireType wrap(T const & t, typename em_wrap_type<typename std::decay<Args>::type>::WireType ... args)
{
return em_wrap_type<typename std::decay<Ret>::type>::transmit((t.*fn)(em_wrap_type<typename std::decay<Args>::type>::receive(args) ...));
}
};

template <typename T, typename ... Args, void (*fn)(T &, Args ...)>
struct em_wrap_fn<void (*)(T &, Args ...), fn>
{
static void wrap(T & t, typename em_wrap_type<typename std::decay<Args>::type>::WireType ... args)
{
return fn(t, em_wrap_type<typename std::decay<Args>::type>::receive(args) ...);
}
};

template <typename T, typename ... Args, void (*fn)(T const &, Args ...)>
struct em_wrap_fn<void (*)(T const &, Args ...), fn>
{
static void wrap(T const & t, typename em_wrap_type<typename std::decay<Args>::type>::WireType ... args)
{
return fn(t, em_wrap_type<typename std::decay<Args>::type>::receive(args) ...);
}
};

template <typename T, typename Ret, typename ... Args, Ret (*fn)(T &, Args ...)>
struct em_wrap_fn<Ret (*)(T &, Args ...), fn>
{
static typename em_wrap_type<typename std::decay<Ret>::type>::WireType wrap(T & t, typename em_wrap_type<typename std::decay<Args>::type>::WireType ... args)
{
return em_wrap_type<typename std::decay<Ret>::type>::transmit(fn(t, em_wrap_type<typename std::decay<Args>::type>::receive(args) ...));
}
};

template <typename T, typename Ret, typename ... Args, Ret (*fn)(T const &, Args ...)>
struct em_wrap_fn<Ret (*)(T const &, Args ...), fn>
{
static typename em_wrap_type<typename std::decay<Ret>::type>::WireType wrap(T const & t, typename em_wrap_type<typename std::decay<Args>::type>::WireType ... args)
{
return em_wrap_type<typename std::decay<Ret>::type>::transmit(fn(t, em_wrap_type<typename std::decay<Args>::type>::receive(args) ...));
}
};

/********** **********/

template <typename T, T>
struct em_wrap_static_fn;

template <typename ... Args, void (*fn)(Args ...)>
struct em_wrap_static_fn<void (*)(Args ...), fn>
{
static void wrap(typename em_wrap_type<typename std::decay<Args>::type>::WireType ... args)
{
return fn(em_wrap_type<typename std::decay<Args>::type>::receive(args) ...);
}
};

template <typename Ret, typename ... Args, Ret (*fn)(Args ...)>
struct em_wrap_static_fn<Ret (*)(Args ...), fn>
{
static typename em_wrap_type<typename std::decay<Ret>::type>::WireType wrap(typename em_wrap_type<typename std::decay<Args>::type>::WireType ... args)
{
return em_wrap_type<typename std::decay<Ret>::type>::transmit(fn(em_wrap_type<typename std::decay<Args>::type>::receive(args) ...));
}
};

/********** **********/

template <typename T, T>
struct em_wrap_property;

template <typename T, typename PropertyType, PropertyType T::*property>
struct em_wrap_property<PropertyType T::*, property>
{
static typename em_wrap_type<typename std::decay<PropertyType>::type>::WireType get(T const & t)
{
return em_transmit(t.*property);
}

static void set(T & t, typename em_wrap_type<typename std::decay<PropertyType>::type>::WireType wire)
{
t.*property = em_receive<PropertyType>(wire);
}
};

/********** **********/

#define WRAP(FN) WRAP_OVERLOAD((FN), decltype(FN))
#define WRAP_OVERLOAD(FN, ...) &em_wrap_fn<__VA_ARGS__, (FN)>::wrap

#define WRAP_STATIC(FN) WRAP_STATIC_OVERLOAD((FN), decltype(FN))
#define WRAP_STATIC_OVERLOAD(FN, ...) &em_wrap_static_fn<__VA_ARGS__, (FN)>::wrap

#define WRAP_FIELD(CLASS, FIELD) &em_wrap_property<decltype(&CLASS::FIELD), &CLASS::FIELD>::get, &em_wrap_property<decltype(&CLASS::FIELD), &CLASS::FIELD>::set
Loading

0 comments on commit 6ff35dc

Please sign in to comment.