From 6ff35dc35c179b5422d01cef93f3b33581530dba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Mon, 16 Jan 2017 00:11:18 +0100 Subject: [PATCH 01/26] Adds asm.js support --- .gitignore | 2 + index.js | 12 +- package.json | 3 + src/bindings/buffer-offset-index-wrapper.cc | 2 + src/bindings/em/auto-wrap.h | 348 ++++++++++++++++++++ src/bindings/em/buffer-offset-index.cc | 19 ++ src/bindings/em/marker-index.cc | 47 +++ src/bindings/em/patch.cc | 78 +++++ src/bindings/em/point-wrapper.h | 33 ++ src/bindings/em/point.cc | 16 + src/bindings/em/range.cc | 15 + src/bindings/marker-index-wrapper.cc | 8 +- src/bindings/noop.h | 5 + src/bindings/patch-wrapper.cc | 2 + src/core/buffer-offset-index.cc | 4 +- src/core/buffer-offset-index.h | 4 +- src/core/marker-index.h | 2 +- src/core/patch.cc | 40 +-- src/core/patch.h | 8 +- src/core/text.h | 7 +- test/js/marker-index.test.js | 6 +- test/js/patch.test.js | 31 +- 22 files changed, 645 insertions(+), 47 deletions(-) create mode 100644 src/bindings/em/auto-wrap.h create mode 100644 src/bindings/em/buffer-offset-index.cc create mode 100644 src/bindings/em/marker-index.cc create mode 100644 src/bindings/em/patch.cc create mode 100644 src/bindings/em/point-wrapper.h create mode 100644 src/bindings/em/point.cc create mode 100644 src/bindings/em/range.cc create mode 100644 src/bindings/noop.h diff --git a/.gitignore b/.gitignore index d48669b2..2e1b21f5 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,5 @@ node_modules build .DS_Store .clang_complete + +/browser.js diff --git a/index.js b/index.js index a2356884..c9933d4c 100644 --- a/index.js +++ b/index.js @@ -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') + } } diff --git a/package.json b/package.json index fa416a21..289d2005 100644 --- a/package.json +++ b/package.json @@ -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", diff --git a/src/bindings/buffer-offset-index-wrapper.cc b/src/bindings/buffer-offset-index-wrapper.cc index d6836169..d98348f1 100644 --- a/src/bindings/buffer-offset-index-wrapper.cc +++ b/src/bindings/buffer-offset-index-wrapper.cc @@ -1,4 +1,5 @@ #include "buffer-offset-index-wrapper.h" +#include "noop.h" #include "point-wrapper.h" using namespace v8; @@ -8,6 +9,7 @@ void BufferOffsetIndexWrapper::init(Local exports) { constructor_template->SetClassName(Nan::New("BufferOffsetIndex").ToLocalChecked()); constructor_template->InstanceTemplate()->SetInternalFieldCount(1); const auto &prototype_template = constructor_template->PrototypeTemplate(); + prototype_template->Set(Nan::New("delete").ToLocalChecked(), Nan::New(noop)); prototype_template->Set(Nan::New("splice").ToLocalChecked(), Nan::New(splice)); prototype_template->Set(Nan::New("position_for_character_index").ToLocalChecked(), Nan::New(position_for_character_index)); prototype_template->Set(Nan::New("character_index_for_position").ToLocalChecked(), Nan::New(character_index_for_position)); diff --git a/src/bindings/em/auto-wrap.h b/src/bindings/em/auto-wrap.h new file mode 100644 index 00000000..5c6f75e9 --- /dev/null +++ b/src/bindings/em/auto-wrap.h @@ -0,0 +1,348 @@ +#pragma once + +#include +#include +#include +#include + +#include + +#include "flat_set.h" +#include "marker-index.h" +#include "optional.h" +#include "point-wrapper.h" +#include "point.h" +#include "text.h" + +/********** **********/ + +template +struct em_wrap_type_base { + + using LocalType = LocalTypeTpl; + using WireType = WireTypeTpl; + +}; + +template +struct em_wrap_type_simple : public em_wrap_type_base { + + static LocalType receive(WireType data) { return data; } + static WireType transmit(LocalType data) { return data; } + +}; + +/********** **********/ + +template +struct em_wrap_type : public em_wrap_type_simple {}; + +/********** **********/ + +template +LocalType em_receive(typename em_wrap_type::type>::WireType data) +{ + return em_wrap_type::type>::receive(data); +} + +template +typename em_wrap_type::type>::WireType em_transmit(LocalType data) +{ + return em_wrap_type::type>::transmit(data); +} + +/********** **********/ + +template <> +struct em_wrap_type : public em_wrap_type_base {}; + +template <> +struct em_wrap_type : public em_wrap_type_simple {}; + +template +struct em_wrap_type> : public em_wrap_type_base, emscripten::val> { + + static std::vector receive(emscripten::val const & val) + { + std::vector vec; + + for (auto t = 0u, T = val["length"].as(); t < T; ++t) + vec.push_back(val[t].as()); + + return vec; + } + + static emscripten::val transmit(std::vector const & vec) + { + auto array = emscripten::val::array(); + + for (auto const & t : vec) + array.call("push", em_transmit(t)); + + return array; + } + +}; + +template +struct em_wrap_type> : public em_wrap_type_base, emscripten::val> { + + static optional receive(emscripten::val const & val) + { + if (!val.as()) + return optional(); + + return optional(val.as()); + } + + static emscripten::val transmit(optional const & opt) + { + if (!opt) + return emscripten::val::undefined(); + + return emscripten::val(em_transmit(*opt)); + } + +}; + +template +struct em_wrap_type> : public em_wrap_type_base, emscripten::val> { + + static std::unordered_map receive(emscripten::val const & val) + { + throw std::runtime_error("Unimplemented"); + } + + static emscripten::val transmit(std::unordered_map 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 +struct em_wrap_type> : public em_wrap_type_base, emscripten::val> { + + static flat_set receive(emscripten::val const & val) + { + throw std::runtime_error("Unimplemented"); + } + + static emscripten::val transmit(flat_set const & set) + { + auto object = emscripten::val::global("Set").new_(); + + for (auto const & t : set) + object.call("add", em_transmit(t)); + + return object; + } + +}; + +template <> +struct em_wrap_type : public em_wrap_type_base { + + 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 : public em_wrap_type_base { + + 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> : public em_wrap_type_base, emscripten::val> { + + static std::unique_ptr receive(emscripten::val const & val) + { + return std::make_unique(em_wrap_type::receive(val.as())); + } + + static emscripten::val transmit(std::unique_ptr const & text) + { + if (!text) + return emscripten::val::undefined(); + + return emscripten::val(em_wrap_type::transmit(*text)); + } + +}; + +template <> +struct em_wrap_type : public em_wrap_type_base { + + static Text * receive(emscripten::val const & val) + { + return new Text(em_wrap_type::receive(val.as())); + } + + static emscripten::val transmit(Text * text) + { + if (!text) + return emscripten::val::undefined(); + + return emscripten::val(em_wrap_type::transmit(*text)); + } + +}; + +/********** **********/ + +template +struct em_wrap_fn; + +template +struct em_wrap_fn +{ + static void wrap(T & t, typename em_wrap_type::type>::WireType ... args) + { + return (t.*fn)(em_wrap_type::type>::receive(args) ...); + } +}; + +template +struct em_wrap_fn +{ + static void wrap(T const & t, typename em_wrap_type::type>::WireType ... args) + { + return (t.*fn)(em_wrap_type::type>::receive(args) ...); + } +}; + +template +struct em_wrap_fn +{ + static typename em_wrap_type::type>::WireType wrap(T & t, typename em_wrap_type::type>::WireType ... args) + { + return em_wrap_type::type>::transmit((t.*fn)(em_wrap_type::type>::receive(args) ...)); + } +}; + +template +struct em_wrap_fn +{ + static typename em_wrap_type::type>::WireType wrap(T const & t, typename em_wrap_type::type>::WireType ... args) + { + return em_wrap_type::type>::transmit((t.*fn)(em_wrap_type::type>::receive(args) ...)); + } +}; + +template +struct em_wrap_fn +{ + static void wrap(T & t, typename em_wrap_type::type>::WireType ... args) + { + return fn(t, em_wrap_type::type>::receive(args) ...); + } +}; + +template +struct em_wrap_fn +{ + static void wrap(T const & t, typename em_wrap_type::type>::WireType ... args) + { + return fn(t, em_wrap_type::type>::receive(args) ...); + } +}; + +template +struct em_wrap_fn +{ + static typename em_wrap_type::type>::WireType wrap(T & t, typename em_wrap_type::type>::WireType ... args) + { + return em_wrap_type::type>::transmit(fn(t, em_wrap_type::type>::receive(args) ...)); + } +}; + +template +struct em_wrap_fn +{ + static typename em_wrap_type::type>::WireType wrap(T const & t, typename em_wrap_type::type>::WireType ... args) + { + return em_wrap_type::type>::transmit(fn(t, em_wrap_type::type>::receive(args) ...)); + } +}; + +/********** **********/ + +template +struct em_wrap_static_fn; + +template +struct em_wrap_static_fn +{ + static void wrap(typename em_wrap_type::type>::WireType ... args) + { + return fn(em_wrap_type::type>::receive(args) ...); + } +}; + +template +struct em_wrap_static_fn +{ + static typename em_wrap_type::type>::WireType wrap(typename em_wrap_type::type>::WireType ... args) + { + return em_wrap_type::type>::transmit(fn(em_wrap_type::type>::receive(args) ...)); + } +}; + +/********** **********/ + +template +struct em_wrap_property; + +template +struct em_wrap_property +{ + static typename em_wrap_type::type>::WireType get(T const & t) + { + return em_transmit(t.*property); + } + + static void set(T & t, typename em_wrap_type::type>::WireType wire) + { + t.*property = em_receive(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::get, &em_wrap_property::set diff --git a/src/bindings/em/buffer-offset-index.cc b/src/bindings/em/buffer-offset-index.cc new file mode 100644 index 00000000..4a23cfee --- /dev/null +++ b/src/bindings/em/buffer-offset-index.cc @@ -0,0 +1,19 @@ +#include "auto-wrap.h" +#include "buffer-offset-index.h" + +#include + +EMSCRIPTEN_BINDINGS(BufferOffsetIndex) { + + emscripten::class_("BufferOffsetIndex") + + .constructor<>() + + .function("splice", WRAP(&BufferOffsetIndex::splice)) + + .function("character_index_for_position", WRAP(&BufferOffsetIndex::character_index_for_position)) + .function("position_for_character_index", WRAP(&BufferOffsetIndex::position_for_character_index)) + + ; + +} diff --git a/src/bindings/em/marker-index.cc b/src/bindings/em/marker-index.cc new file mode 100644 index 00000000..17eda429 --- /dev/null +++ b/src/bindings/em/marker-index.cc @@ -0,0 +1,47 @@ +#include "auto-wrap.h" +#include "marker-index.h" + +#include + +EMSCRIPTEN_BINDINGS(MarkerIndex) { + + emscripten::class_("MarkerIndex") + + .constructor<>() + .constructor() + + .function("generateRandomNumber", WRAP(&MarkerIndex::generate_random_number)) + + .function("insert", WRAP(&MarkerIndex::insert)) + .function("setExclusive", WRAP(&MarkerIndex::set_exclusive)) + .function("delete", WRAP(&MarkerIndex::delete_marker)) + .function("splice", WRAP(&MarkerIndex::splice)) + + .function("getStart", WRAP(&MarkerIndex::get_start)) + .function("getEnd", WRAP(&MarkerIndex::get_end)) + .function("getRange", WRAP(&MarkerIndex::get_range)) + + .function("compare", WRAP(&MarkerIndex::compare)) + + .function("findIntersecting", WRAP(&MarkerIndex::find_intersecting)) + .function("findContaining", WRAP(&MarkerIndex::find_containing)) + .function("findContainedIn", WRAP(&MarkerIndex::find_contained_in)) + .function("findStartingIn", WRAP(&MarkerIndex::find_starting_in)) + .function("findStartingAt", WRAP(&MarkerIndex::find_starting_at)) + .function("findEndingIn", WRAP(&MarkerIndex::find_ending_in)) + .function("findEndingAt", WRAP(&MarkerIndex::find_ending_at)) + + .function("dump", WRAP(&MarkerIndex::dump)) + + ; + + emscripten::value_object("SpliceResult") + + .field("touch", &MarkerIndex::SpliceResult::touch) + .field("inside", &MarkerIndex::SpliceResult::inside) + .field("overlap", &MarkerIndex::SpliceResult::overlap) + .field("surround", &MarkerIndex::SpliceResult::surround) + + ; + +} diff --git a/src/bindings/em/patch.cc b/src/bindings/em/patch.cc new file mode 100644 index 00000000..2e28363a --- /dev/null +++ b/src/bindings/em/patch.cc @@ -0,0 +1,78 @@ +#include +#include + +#include "auto-wrap.h" +#include "patch.h" + +#include +#include + +Patch * constructor(emscripten::val val) +{ + bool merge_adjacent_hunks = false; + + if (val.as() && val["mergeAdjacentHunks"].as()) + merge_adjacent_hunks = true; + + return new Patch(merge_adjacent_hunks); +} + +std::vector serialize(Patch const & patch) +{ + std::vector vec; + patch.serialize(&vec); + + return vec; +} + +Patch * deserialize(std::vector const & vec) +{ + return new Patch(vec); +} + +EMSCRIPTEN_BINDINGS(Patch) { + + emscripten::class_("Patch") + + .constructor<>() + .constructor(WRAP_STATIC(&constructor), emscripten::allow_raw_pointers()) + + .function("splice", WRAP_OVERLOAD(&Patch::splice, bool (Patch::*)(Point, Point, Point))) + .function("splice", WRAP_OVERLOAD(&Patch::splice, bool (Patch::*)(Point, Point, Point, std::unique_ptr, std::unique_ptr))) + + .function("spliceOld", WRAP(&Patch::splice_old)) + + .function("copy", WRAP(&Patch::copy)) + .function("invert", WRAP(&Patch::invert)) + + .function("getHunks", WRAP(&Patch::get_hunks)) + .function("getHunksInNewRange", WRAP_OVERLOAD(&Patch::get_hunks_in_new_range, std::vector (Patch::*)(Point, Point))) + .function("getHunksInNewRange", WRAP_OVERLOAD(&Patch::get_hunks_in_new_range, std::vector (Patch::*)(Point, Point, bool))) + .function("getHunksInOldRange", WRAP(&Patch::get_hunks_in_old_range)) + .function("getHunkCount", WRAP(&Patch::get_hunk_count)) + + .function("hunkForOldPosition", WRAP(&Patch::hunk_for_old_position)) + .function("hunkForNewPosition", WRAP(&Patch::hunk_for_new_position)) + + .function("rebalance", WRAP(&Patch::rebalance)) + + .function("serialize", WRAP(&serialize)) + + .class_function("deserialize", WRAP_STATIC(&deserialize), emscripten::allow_raw_pointers()) + + ; + + emscripten::value_object("Hunk") + + .field("oldStart", WRAP_FIELD(Patch::Hunk, old_start)) + .field("oldEnd", WRAP_FIELD(Patch::Hunk, old_end)) + + .field("newStart", WRAP_FIELD(Patch::Hunk, new_start)) + .field("newEnd", WRAP_FIELD(Patch::Hunk, new_end)) + + .field("oldText", WRAP_FIELD(Patch::Hunk, old_text)) + .field("newText", WRAP_FIELD(Patch::Hunk, new_text)) + + ; + +} diff --git a/src/bindings/em/point-wrapper.h b/src/bindings/em/point-wrapper.h new file mode 100644 index 00000000..0fe2a8fc --- /dev/null +++ b/src/bindings/em/point-wrapper.h @@ -0,0 +1,33 @@ +#pragma once + +#include +#include + +#include "point.h" + +struct PointWrapper { + + double row; + double column; + + PointWrapper(void) + : row(0) + , column(0) + { + } + + PointWrapper(Point const & point) + : row(point.row) + , column(point.column) + { + } + + operator Point(void) const + { + unsigned row = std::min(this->row, static_cast(std::numeric_limits::max())); + unsigned column = std::min(this->column, static_cast(std::numeric_limits::max())); + + return Point(row, column); + } + +}; diff --git a/src/bindings/em/point.cc b/src/bindings/em/point.cc new file mode 100644 index 00000000..4c6f033d --- /dev/null +++ b/src/bindings/em/point.cc @@ -0,0 +1,16 @@ +#include "auto-wrap.h" +#include "point-wrapper.h" +#include "point.h" + +#include + +EMSCRIPTEN_BINDINGS(Point) { + + emscripten::value_object("Point") + + .field("row", WRAP_FIELD(PointWrapper, row)) + .field("column", WRAP_FIELD(PointWrapper, column)) + + ; + +} diff --git a/src/bindings/em/range.cc b/src/bindings/em/range.cc new file mode 100644 index 00000000..6f120273 --- /dev/null +++ b/src/bindings/em/range.cc @@ -0,0 +1,15 @@ +#include "auto-wrap.h" +#include "range.h" + +#include + +EMSCRIPTEN_BINDINGS(Range) { + + emscripten::value_object("Range") + + .field("start", WRAP_FIELD(Range, start)) + .field("end", WRAP_FIELD(Range, end)) + + ; + +} diff --git a/src/bindings/marker-index-wrapper.cc b/src/bindings/marker-index-wrapper.cc index 9d693935..b645cf2a 100644 --- a/src/bindings/marker-index-wrapper.cc +++ b/src/bindings/marker-index-wrapper.cc @@ -2,6 +2,7 @@ #include #include "marker-index.h" #include "nan.h" +#include "noop.h" #include "optional.h" #include "point-wrapper.h" #include "range.h" @@ -23,6 +24,7 @@ void MarkerIndexWrapper::init(Local exports) { const auto &prototype_template = constructor_template->PrototypeTemplate(); + prototype_template->Set(Nan::New("delete").ToLocalChecked(), Nan::New(noop)); prototype_template->Set(Nan::New("generateRandomNumber").ToLocalChecked(), Nan::New(generate_random_number)); prototype_template->Set(Nan::New("insert").ToLocalChecked(), Nan::New(insert)); @@ -199,9 +201,9 @@ void MarkerIndexWrapper::get_range(const Nan::FunctionCallbackInfo &info) optional id = marker_id_from_js(info[0]); if (id) { Range range = wrapper->marker_index.get_range(*id); - auto result = Nan::New(2); - result->Set(0, PointWrapper::from_point(range.start)); - result->Set(1, PointWrapper::from_point(range.end)); + auto result = Nan::New(); + result->Set(Nan::New(start_string), PointWrapper::from_point(range.start)); + result->Set(Nan::New(end_string), PointWrapper::from_point(range.end)); info.GetReturnValue().Set(result); } } diff --git a/src/bindings/noop.h b/src/bindings/noop.h new file mode 100644 index 00000000..6b446a5a --- /dev/null +++ b/src/bindings/noop.h @@ -0,0 +1,5 @@ +#pragma once + +#include "nan.h" + +static void noop(const Nan::FunctionCallbackInfo&) {} diff --git a/src/bindings/patch-wrapper.cc b/src/bindings/patch-wrapper.cc index 3a168004..189c0edb 100644 --- a/src/bindings/patch-wrapper.cc +++ b/src/bindings/patch-wrapper.cc @@ -1,3 +1,4 @@ +#include "noop.h" #include "patch-wrapper.h" #include #include @@ -129,6 +130,7 @@ void PatchWrapper::init(Local exports) { constructor_template_local->Set(Nan::New("compose").ToLocalChecked(), Nan::New(compose)); constructor_template_local->InstanceTemplate()->SetInternalFieldCount(1); const auto &prototype_template = constructor_template_local->PrototypeTemplate(); + prototype_template->Set(Nan::New("delete").ToLocalChecked(), Nan::New(noop)); prototype_template->Set(Nan::New("splice").ToLocalChecked(), Nan::New(splice)); prototype_template->Set(Nan::New("spliceOld").ToLocalChecked(), Nan::New(splice_old)); prototype_template->Set(Nan::New("copy").ToLocalChecked(), Nan::New(copy)); diff --git a/src/core/buffer-offset-index.cc b/src/core/buffer-offset-index.cc index abdd628f..96ba6147 100644 --- a/src/core/buffer-offset-index.cc +++ b/src/core/buffer-offset-index.cc @@ -54,7 +54,7 @@ BufferOffsetIndex::~BufferOffsetIndex() { } } -void BufferOffsetIndex::splice(unsigned start_row, unsigned deleted_lines_count, std::vector &new_line_lengths) { +void BufferOffsetIndex::splice(unsigned start_row, unsigned deleted_lines_count, std::vector const &new_line_lengths) { auto start_node = find_and_bubble_node_up_to_root(start_row - 1); auto end_node = find_and_bubble_node_up_to_root(start_row + deleted_lines_count); @@ -251,7 +251,7 @@ void BufferOffsetIndex::rotate_node_right(LineNode * pivot, LineNode * root, Lin pivot->compute_subtree_extents(); } -LineNode *BufferOffsetIndex::build_node_tree_from_line_lengths(std::vector &line_lengths, unsigned start, unsigned end, unsigned min_priority) { +LineNode *BufferOffsetIndex::build_node_tree_from_line_lengths(std::vector const &line_lengths, unsigned start, unsigned end, unsigned min_priority) { if (start == end) { return nullptr; } else { diff --git a/src/core/buffer-offset-index.h b/src/core/buffer-offset-index.h index d3087115..7d0c747a 100644 --- a/src/core/buffer-offset-index.h +++ b/src/core/buffer-offset-index.h @@ -11,7 +11,7 @@ class BufferOffsetIndex { public: BufferOffsetIndex(); ~BufferOffsetIndex(); - void splice(unsigned, unsigned, std::vector&); + void splice(unsigned, unsigned, std::vector const&); unsigned character_index_for_position(Point) const; Point position_for_character_index(unsigned) const; @@ -20,7 +20,7 @@ class BufferOffsetIndex { void bubble_node_down(LineNode *, LineNode *); void rotate_node_left(LineNode *, LineNode *, LineNode *); void rotate_node_right(LineNode *, LineNode *, LineNode *); - LineNode *build_node_tree_from_line_lengths(std::vector&, unsigned, unsigned, unsigned); + LineNode *build_node_tree_from_line_lengths(std::vector const&, unsigned, unsigned, unsigned); LineNode *root; std::default_random_engine rng_engine; diff --git a/src/core/marker-index.h b/src/core/marker-index.h index 14f4cc74..062ca476 100644 --- a/src/core/marker-index.h +++ b/src/core/marker-index.h @@ -19,7 +19,7 @@ class MarkerIndex { flat_set surround; }; - MarkerIndex(unsigned seed); + MarkerIndex(unsigned seed = 0u); ~MarkerIndex(); int generate_random_number(); void insert(MarkerId id, Point start, Point end); diff --git a/src/core/patch.cc b/src/core/patch.cc index 562c5c73..9293f824 100644 --- a/src/core/patch.cc +++ b/src/core/patch.cc @@ -1218,37 +1218,33 @@ static const uint32_t SERIALIZATION_VERSION = 1; enum Transition : uint32_t { None, Left, Right, Up }; -template T network_to_host(T input); +template +void append_to_buffer(vector *output, T value) { + for (auto t = 0u; t < sizeof(T); ++t) { + output->push_back(value & 0xFF); + value >>= 8; + } +} -template T host_to_network(T input); +template +T get_from_buffer(const uint8_t **data, const uint8_t *end) { -template <> uint16_t network_to_host(uint16_t input) { return ntohs(input); } + // Note: We can't optimize this function by casting the data argument into a T*, + // because it would only work on architectures that support reading from unaligned + // memory. It would work on X86, but not on asm.js and possibly other architectures. -template <> uint16_t host_to_network(uint16_t input) { return htons(input); } + T value = 0; -template <> uint32_t network_to_host(uint32_t input) { return ntohl(input); } + if (end - *data >= sizeof(T)) + for (auto t = 0u; t < sizeof(T); ++t) + value |= static_cast(*((*data)++)) << static_cast(8 * t); -template <> uint32_t host_to_network(uint32_t input) { return htonl(input); } + return value; -template void append_to_buffer(vector *output, T value) { - value = host_to_network(value); - const uint8_t *bytes = reinterpret_cast(&value); - output->insert(output->end(), bytes, bytes + sizeof(T)); -} - -template -T get_from_buffer(const uint8_t **data, const uint8_t *end) { - const T *pointer = reinterpret_cast(*data); - *data = *data + sizeof(T); - if (*data <= end) { - return network_to_host(*pointer); - } else { - return 0; - } } void get_point_from_buffer(const uint8_t **data, const uint8_t *end, - Point *point) { + Point *point) { point->row = get_from_buffer(data, end); point->column = get_from_buffer(data, end); } diff --git a/src/core/patch.h b/src/core/patch.h index 78bd4c85..30466768 100644 --- a/src/core/patch.h +++ b/src/core/patch.h @@ -35,14 +35,14 @@ class Patch { Patch(Node *root, uint32_t hunk_count, bool merges_adjacent_hunks); Patch(Patch &&); ~Patch(); - bool splice(Point start, Point deletion_extent, Point insertion_extent, - std::unique_ptr old_text, std::unique_ptr new_text); + bool splice(Point start, Point deletion_extent, Point insertion_extent) { return this->splice(start, deletion_extent, insertion_extent, {}, {}); } + bool splice(Point start, Point deletion_extent, Point insertion_extent, std::unique_ptr old_text, std::unique_ptr new_text); bool splice_old(Point start, Point deletion_extent, Point insertion_extent); Patch copy(); Patch invert(); std::vector get_hunks() const; - std::vector get_hunks_in_new_range(Point start, Point end, - bool inclusive = false); + std::vector get_hunks_in_new_range(Point start, Point end) { return this->get_hunks_in_new_range(start, end, false); } + std::vector get_hunks_in_new_range(Point start, Point end, bool inclusive); std::vector get_hunks_in_old_range(Point start, Point end); optional hunk_for_old_position(Point position); optional hunk_for_new_position(Point position); diff --git a/src/core/text.h b/src/core/text.h index b9045ad3..8090b3ca 100644 --- a/src/core/text.h +++ b/src/core/text.h @@ -6,7 +6,12 @@ #include #include "point.h" -using Text = std::vector; +struct Text : public std::vector { + using std::vector::vector; + Text(void) : vector() {} + Text(std::vector const & vec) : vector(vec) {} + Text(std::vector && vec) : vector(std::move(vec)) {} +}; struct TextSlice { Text *text; diff --git a/test/js/marker-index.test.js b/test/js/marker-index.test.js index 2ac6374f..0450993c 100644 --- a/test/js/marker-index.test.js +++ b/test/js/marker-index.test.js @@ -10,7 +10,7 @@ describe('MarkerIndex', () => { let seed, seedMessage, random, markerIndex, markers, idCounter for (let i = 0; i < 1000; i++) { - seed = Date.now() + seed = 42;//Date.now() seedMessage = `Random Seed: ${seed}` random = new Random(seed) markerIndex = new MarkerIndex(seed) @@ -54,8 +54,8 @@ describe('MarkerIndex', () => { function verifyRanges () { for (let marker of markers) { let range = markerIndex.getRange(marker.id) - assert.deepEqual(range[0], marker.start, `Marker ${marker.id} start. ` + seedMessage) - assert.deepEqual(range[1], marker.end, `Marker ${marker.id} end. ` + seedMessage) + assert.deepEqual(range.start, marker.start, `Marker ${marker.id} start. ` + seedMessage) + assert.deepEqual(range.end, marker.end, `Marker ${marker.id} end. ` + seedMessage) } } diff --git a/test/js/patch.test.js b/test/js/patch.test.js index d32404d1..d36ad078 100644 --- a/test/js/patch.test.js +++ b/test/js/patch.test.js @@ -11,7 +11,7 @@ const {Patch} = require('../..') describe('Patch', function () { it('honors the mergeAdjacentHunks option set to false', function () { - const patch = new Patch({mergeAdjacentHunks: false}) + const patch = new Patch({ mergeAdjacentHunks: false }) patch.splice({row: 0, column: 10}, {row: 0, column: 0}, {row: 1, column: 5}) patch.splice({row: 1, column: 5}, {row: 0, column: 2}, {row: 0, column: 8}) @@ -30,10 +30,12 @@ describe('Patch', function () { newEnd: {row: 1, column: 13} } ]) + + patch.delete(); }) it('honors the mergeAdjacentHunks option set to true', function () { - const patch = new Patch({mergeAdjacentHunks: true}) + const patch = new Patch({ mergeAdjacentHunks: true }) patch.splice({row: 0, column: 5}, {row: 0, column: 1}, {row: 0, column: 2}) patch.splice({row: 0, column: 10}, {row: 0, column: 3}, {row: 0, column: 4}) @@ -55,6 +57,8 @@ describe('Patch', function () { newStart: {row: 0, column: 5}, newEnd: {row: 0, column: 11} } ]) + + patch.delete(); }) it('can compose multiple patches together', function () { @@ -91,6 +95,11 @@ describe('Patch', function () { assert.throws(() => Patch.compose([{}, {}])) assert.throws(() => Patch.compose([1, 'a'])) + + for (let patch of patches) + patch.delete(); + + composedPatch.delete(); }) it('can invert patches', function () { @@ -127,6 +136,10 @@ describe('Patch', function () { newStart: {row: 0, column: 9}, newEnd: {row: 0, column: 14} } ]) + + patch.delete(); + invertedPatch.delete(); + patch2.delete(); }) it('can copy patches', function () { @@ -139,13 +152,16 @@ describe('Patch', function () { patch2.splice({row: 0, column: 3}, {row: 0, column: 4}, {row: 0, column: 5}) patch2.splice({row: 0, column: 10}, {row: 0, column: 5}, {row: 0, column: 5}) assert.deepEqual(patch2.copy().getHunks(), patch2.getHunks()) + + patch.delete(); + patch2.delete(); }) it('can serialize/deserialize patches', () => { const patch1 = new Patch() patch1.splice({row: 0, column: 3}, {row: 0, column: 5}, {row: 0, column: 5}, 'hello', 'world') - const patch2 = Patch.deserialize(Buffer.from(patch1.serialize().toString('base64'), 'base64')) + const patch2 = Patch.deserialize(patch1.serialize()) assert.deepEqual(JSON.parse(JSON.stringify(patch2.getHunks())), [{ oldStart: {row: 0, column: 3}, newStart: {row: 0, column: 3}, @@ -154,6 +170,9 @@ describe('Patch', function () { oldText: 'hello', newText: 'world' }]) + + patch1.delete(); + patch2.delete(); }) it('correctly records random splices', function () { @@ -167,7 +186,7 @@ describe('Patch', function () { const originalDocument = new TestDocument(seed) const mutatedDocument = originalDocument.clone() const mergeAdjacentHunks = random(2) - const patch = new Patch({mergeAdjacentHunks: mergeAdjacentHunks}) + const patch = new Patch({ mergeAdjacentHunks }) for (let j = 0; j < 20; j++) { if (random(10) < 1) { @@ -268,7 +287,7 @@ describe('Patch', function () { let oldPoint = originalDocument.buildRandomPoint() - let blob = Buffer.from(patch.serialize().toString('base64'), 'base64') + let blob = patch.serialize() const patchCopy1 = Patch.deserialize(blob) assert.deepEqual(patchCopy1.getHunks(), patch.getHunks()) assert.deepEqual(patchCopy1.hunkForOldPosition(oldPoint), patch.hunkForOldPosition(oldPoint)) @@ -277,6 +296,8 @@ describe('Patch', function () { assert.deepEqual(patchCopy2.getHunks(), patch.getHunks()) assert.deepEqual(patchCopy2.hunkForOldPosition(oldPoint), patch.hunkForOldPosition(oldPoint)) } + + patch.delete(); } }) }) From 006255c1adf398fa3787a41f30eec867e22101cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Mon, 16 Jan 2017 11:29:24 +0100 Subject: [PATCH 02/26] Implements Patch.compose --- src/bindings/em/as.h | 15 +++++++++++++++ src/bindings/em/auto-wrap.h | 1 + src/bindings/em/patch.cc | 8 ++++++++ src/core/patch.h | 2 ++ 4 files changed, 26 insertions(+) create mode 100644 src/bindings/em/as.h diff --git a/src/bindings/em/as.h b/src/bindings/em/as.h new file mode 100644 index 00000000..6970f7d4 --- /dev/null +++ b/src/bindings/em/as.h @@ -0,0 +1,15 @@ +#pragma once + +#include + +#include "patch.h" + +template<> inline Patch const * emscripten::val::as(void) const { + using namespace emscripten; + using namespace internal; + + EM_DESTRUCTORS destructors; + EM_GENERIC_WIRE_TYPE result = _emval_as(handle, TypeID>::get(), &destructors); + DestructorsRunner dr(destructors); + return fromGenericWireType(result); +} diff --git a/src/bindings/em/auto-wrap.h b/src/bindings/em/auto-wrap.h index 5c6f75e9..a7b4a985 100644 --- a/src/bindings/em/auto-wrap.h +++ b/src/bindings/em/auto-wrap.h @@ -7,6 +7,7 @@ #include +#include "as.h" #include "flat_set.h" #include "marker-index.h" #include "optional.h" diff --git a/src/bindings/em/patch.cc b/src/bindings/em/patch.cc index 2e28363a..2f660615 100644 --- a/src/bindings/em/patch.cc +++ b/src/bindings/em/patch.cc @@ -1,6 +1,7 @@ #include #include +#include "as.h" #include "auto-wrap.h" #include "patch.h" @@ -25,6 +26,11 @@ std::vector serialize(Patch const & patch) return vec; } +Patch * compose(std::vector const & vec) +{ + return new Patch(vec); +} + Patch * deserialize(std::vector const & vec) { return new Patch(vec); @@ -58,6 +64,8 @@ EMSCRIPTEN_BINDINGS(Patch) { .function("serialize", WRAP(&serialize)) + .class_function("compose", WRAP_STATIC(&compose), emscripten::allow_raw_pointers()) + .class_function("deserialize", WRAP_STATIC(&deserialize), emscripten::allow_raw_pointers()) ; diff --git a/src/core/patch.h b/src/core/patch.h index 30466768..d887d166 100644 --- a/src/core/patch.h +++ b/src/core/patch.h @@ -1,3 +1,5 @@ +#pragma once + #include "optional.h" #include "point.h" #include "text.h" From 87bda034ca8c5df1ee276b6979bfb7c48678dd49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Mon, 16 Jan 2017 12:00:45 +0100 Subject: [PATCH 03/26] Reverts snakecase bindings --- src/bindings/buffer-offset-index-wrapper.cc | 4 +- src/bindings/em/buffer-offset-index.cc | 4 +- test/js/buffer-index.test.js | 4 +- test/js/reference-buffer-offset-index.js | 4 +- test/js/reference-buffer-offset-index.test.js | 76 +++++++++---------- 5 files changed, 46 insertions(+), 46 deletions(-) diff --git a/src/bindings/buffer-offset-index-wrapper.cc b/src/bindings/buffer-offset-index-wrapper.cc index d98348f1..112df62c 100644 --- a/src/bindings/buffer-offset-index-wrapper.cc +++ b/src/bindings/buffer-offset-index-wrapper.cc @@ -11,8 +11,8 @@ void BufferOffsetIndexWrapper::init(Local exports) { const auto &prototype_template = constructor_template->PrototypeTemplate(); prototype_template->Set(Nan::New("delete").ToLocalChecked(), Nan::New(noop)); prototype_template->Set(Nan::New("splice").ToLocalChecked(), Nan::New(splice)); - prototype_template->Set(Nan::New("position_for_character_index").ToLocalChecked(), Nan::New(position_for_character_index)); - prototype_template->Set(Nan::New("character_index_for_position").ToLocalChecked(), Nan::New(character_index_for_position)); + prototype_template->Set(Nan::New("positionForCharacterIndex").ToLocalChecked(), Nan::New(position_for_character_index)); + prototype_template->Set(Nan::New("characterIndexForPosition").ToLocalChecked(), Nan::New(character_index_for_position)); exports->Set(Nan::New("BufferOffsetIndex").ToLocalChecked(), constructor_template->GetFunction()); } diff --git a/src/bindings/em/buffer-offset-index.cc b/src/bindings/em/buffer-offset-index.cc index 4a23cfee..a56fc42c 100644 --- a/src/bindings/em/buffer-offset-index.cc +++ b/src/bindings/em/buffer-offset-index.cc @@ -11,8 +11,8 @@ EMSCRIPTEN_BINDINGS(BufferOffsetIndex) { .function("splice", WRAP(&BufferOffsetIndex::splice)) - .function("character_index_for_position", WRAP(&BufferOffsetIndex::character_index_for_position)) - .function("position_for_character_index", WRAP(&BufferOffsetIndex::position_for_character_index)) + .function("characterIndexForPosition", WRAP(&BufferOffsetIndex::character_index_for_position)) + .function("positionForCharacterIndex", WRAP(&BufferOffsetIndex::position_for_character_index)) ; diff --git a/test/js/buffer-index.test.js b/test/js/buffer-index.test.js index d367ac52..9d3d8790 100644 --- a/test/js/buffer-index.test.js +++ b/test/js/buffer-index.test.js @@ -31,8 +31,8 @@ describe('BufferOffsetIndex', () => { const row = random(10) <= 1 ? Infinity : random.intBetween(0, referenceIndex.getLineCount() + 10) const column = random(10) <= 1 ? Infinity : random.intBetween(0, referenceIndex.getLongestColumn() + 10) const position = {row, column} - assert.equal(bufferIndex.character_index_for_position(position), referenceIndex.character_index_for_position(position)) - assert.deepEqual(bufferIndex.position_for_character_index(index), referenceIndex.position_for_character_index(index)) + assert.equal(bufferIndex.characterIndexForPosition(position), referenceIndex.characterIndexForPosition(position)) + assert.deepEqual(bufferIndex.positionForCharacterIndex(index), referenceIndex.positionForCharacterIndex(index)) } } } diff --git a/test/js/reference-buffer-offset-index.js b/test/js/reference-buffer-offset-index.js index 7130bc39..cc2077e9 100644 --- a/test/js/reference-buffer-offset-index.js +++ b/test/js/reference-buffer-offset-index.js @@ -23,7 +23,7 @@ module.exports = class ReferenceBufferOffsetIndex { this.longestColumn = this.lineLengths.reduce((a, b) => Math.max(a, b), 0) } - position_for_character_index (index) { + positionForCharacterIndex (index) { let charIndex = 0 let row = 0 for (const lineLength of this.lineLengths) { @@ -38,7 +38,7 @@ module.exports = class ReferenceBufferOffsetIndex { return {row, column: Math.min(index - charIndex, lineLength)} } - character_index_for_position (position) { + characterIndexForPosition (position) { const charIndex = this.lineLengths.slice(0, position.row).reduce((a, b) => a + b, 0) const lineLength = this.lineLengths[position.row] if (lineLength == null) { diff --git a/test/js/reference-buffer-offset-index.test.js b/test/js/reference-buffer-offset-index.test.js index 3646bbe0..515df73c 100644 --- a/test/js/reference-buffer-offset-index.test.js +++ b/test/js/reference-buffer-offset-index.test.js @@ -5,45 +5,45 @@ describe('ReferenceBufferOffsetIndex', () => { it('maps character indices to 2d points and viceversa', () => { const bufferIndex = new ReferenceBufferOffsetIndex() bufferIndex.splice(0, 0, [1, 3, 5]) // a|bcd|efghi - assert.deepEqual(bufferIndex.position_for_character_index(0), {row: 0, column: 0}) - assert.equal(bufferIndex.character_index_for_position({row: 0, column: 0}), 0) - assert.deepEqual(bufferIndex.position_for_character_index(1), {row: 1, column: 0}) - assert.equal(bufferIndex.character_index_for_position({row: 1, column: 0}), 1) - assert.deepEqual(bufferIndex.position_for_character_index(2), {row: 1, column: 1}) - assert.equal(bufferIndex.character_index_for_position({row: 1, column: 1}), 2) - assert.deepEqual(bufferIndex.position_for_character_index(4), {row: 2, column: 0}) - assert.equal(bufferIndex.character_index_for_position({row: 2, column: 0}), 4) - assert.deepEqual(bufferIndex.position_for_character_index(7), {row: 2, column: 3}) - assert.equal(bufferIndex.character_index_for_position({row: 2, column: 3}), 7) - assert.deepEqual(bufferIndex.position_for_character_index(8), {row: 2, column: 4}) - assert.equal(bufferIndex.character_index_for_position({row: 2, column: 4}), 8) - assert.deepEqual(bufferIndex.position_for_character_index(Infinity), {row: 2, column: 5}) - assert.equal(bufferIndex.character_index_for_position({row: 2, column: 5}), 9) - assert.equal(bufferIndex.character_index_for_position({row: 2, column: 6}), 9) - assert.equal(bufferIndex.character_index_for_position({row: 2, column: Infinity}), 9) - assert.equal(bufferIndex.character_index_for_position({row: Infinity, column: Infinity}), 9) + assert.deepEqual(bufferIndex.positionForCharacterIndex(0), {row: 0, column: 0}) + assert.equal(bufferIndex.characterIndexForPosition({row: 0, column: 0}), 0) + assert.deepEqual(bufferIndex.positionForCharacterIndex(1), {row: 1, column: 0}) + assert.equal(bufferIndex.characterIndexForPosition({row: 1, column: 0}), 1) + assert.deepEqual(bufferIndex.positionForCharacterIndex(2), {row: 1, column: 1}) + assert.equal(bufferIndex.characterIndexForPosition({row: 1, column: 1}), 2) + assert.deepEqual(bufferIndex.positionForCharacterIndex(4), {row: 2, column: 0}) + assert.equal(bufferIndex.characterIndexForPosition({row: 2, column: 0}), 4) + assert.deepEqual(bufferIndex.positionForCharacterIndex(7), {row: 2, column: 3}) + assert.equal(bufferIndex.characterIndexForPosition({row: 2, column: 3}), 7) + assert.deepEqual(bufferIndex.positionForCharacterIndex(8), {row: 2, column: 4}) + assert.equal(bufferIndex.characterIndexForPosition({row: 2, column: 4}), 8) + assert.deepEqual(bufferIndex.positionForCharacterIndex(Infinity), {row: 2, column: 5}) + assert.equal(bufferIndex.characterIndexForPosition({row: 2, column: 5}), 9) + assert.equal(bufferIndex.characterIndexForPosition({row: 2, column: 6}), 9) + assert.equal(bufferIndex.characterIndexForPosition({row: 2, column: Infinity}), 9) + assert.equal(bufferIndex.characterIndexForPosition({row: Infinity, column: Infinity}), 9) bufferIndex.splice(0, 2, [5, 1, 4]) // abcde|f|ghij|klmno - assert.deepEqual(bufferIndex.position_for_character_index(0), {row: 0, column: 0}) - assert.equal(bufferIndex.character_index_for_position({row: 0, column: 0}), 0) - assert.deepEqual(bufferIndex.position_for_character_index(1), {row: 0, column: 1}) - assert.equal(bufferIndex.character_index_for_position({row: 0, column: 1}), 1) - assert.deepEqual(bufferIndex.position_for_character_index(5), {row: 1, column: 0}) - assert.equal(bufferIndex.character_index_for_position({row: 1, column: 0}), 5) - assert.deepEqual(bufferIndex.position_for_character_index(6), {row: 2, column: 0}) - assert.equal(bufferIndex.character_index_for_position({row: 2, column: 0}), 6) - assert.deepEqual(bufferIndex.position_for_character_index(7), {row: 2, column: 1}) - assert.equal(bufferIndex.character_index_for_position({row: 2, column: 1}), 7) - assert.deepEqual(bufferIndex.position_for_character_index(10), {row: 3, column: 0}) - assert.equal(bufferIndex.character_index_for_position({row: 3, column: 0}), 10) - assert.deepEqual(bufferIndex.position_for_character_index(13), {row: 3, column: 3}) - assert.equal(bufferIndex.character_index_for_position({row: 3, column: 3}), 13) - assert.deepEqual(bufferIndex.position_for_character_index(14), {row: 3, column: 4}) - assert.equal(bufferIndex.character_index_for_position({row: 3, column: 4}), 14) - assert.deepEqual(bufferIndex.position_for_character_index(Infinity), {row: 3, column: 5}) - assert.equal(bufferIndex.character_index_for_position({row: 3, column: 5}), 15) - assert.equal(bufferIndex.character_index_for_position({row: 3, column: 6}), 15) - assert.equal(bufferIndex.character_index_for_position({row: 3, column: Infinity}), 15) - assert.equal(bufferIndex.character_index_for_position({row: Infinity, column: Infinity}), 15) + assert.deepEqual(bufferIndex.positionForCharacterIndex(0), {row: 0, column: 0}) + assert.equal(bufferIndex.characterIndexForPosition({row: 0, column: 0}), 0) + assert.deepEqual(bufferIndex.positionForCharacterIndex(1), {row: 0, column: 1}) + assert.equal(bufferIndex.characterIndexForPosition({row: 0, column: 1}), 1) + assert.deepEqual(bufferIndex.positionForCharacterIndex(5), {row: 1, column: 0}) + assert.equal(bufferIndex.characterIndexForPosition({row: 1, column: 0}), 5) + assert.deepEqual(bufferIndex.positionForCharacterIndex(6), {row: 2, column: 0}) + assert.equal(bufferIndex.characterIndexForPosition({row: 2, column: 0}), 6) + assert.deepEqual(bufferIndex.positionForCharacterIndex(7), {row: 2, column: 1}) + assert.equal(bufferIndex.characterIndexForPosition({row: 2, column: 1}), 7) + assert.deepEqual(bufferIndex.positionForCharacterIndex(10), {row: 3, column: 0}) + assert.equal(bufferIndex.characterIndexForPosition({row: 3, column: 0}), 10) + assert.deepEqual(bufferIndex.positionForCharacterIndex(13), {row: 3, column: 3}) + assert.equal(bufferIndex.characterIndexForPosition({row: 3, column: 3}), 13) + assert.deepEqual(bufferIndex.positionForCharacterIndex(14), {row: 3, column: 4}) + assert.equal(bufferIndex.characterIndexForPosition({row: 3, column: 4}), 14) + assert.deepEqual(bufferIndex.positionForCharacterIndex(Infinity), {row: 3, column: 5}) + assert.equal(bufferIndex.characterIndexForPosition({row: 3, column: 5}), 15) + assert.equal(bufferIndex.characterIndexForPosition({row: 3, column: 6}), 15) + assert.equal(bufferIndex.characterIndexForPosition({row: 3, column: Infinity}), 15) + assert.equal(bufferIndex.characterIndexForPosition({row: Infinity, column: Infinity}), 15) }) }) From 82d34a7483f0e716d833db801e72244d00fc743a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Wed, 18 Jan 2017 21:20:44 +0100 Subject: [PATCH 04/26] Fixes the compilation warning by enforcing unsigned (end will never be lower than *data) --- src/core/patch.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/patch.cc b/src/core/patch.cc index 9293f824..c946a4f5 100644 --- a/src/core/patch.cc +++ b/src/core/patch.cc @@ -1235,7 +1235,7 @@ T get_from_buffer(const uint8_t **data, const uint8_t *end) { T value = 0; - if (end - *data >= sizeof(T)) + if (static_cast(end - *data) >= sizeof(T)) for (auto t = 0u; t < sizeof(T); ++t) value |= static_cast(*((*data)++)) << static_cast(8 * t); From 68c5d2c8ca39d7e16fcf5cd64e7be930d94fd54d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Wed, 18 Jan 2017 21:21:17 +0100 Subject: [PATCH 05/26] Tries to compile browser.js if possible; useful for using the git repo as dependency --- package.json | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/package.json b/package.json index 289d2005..a36e0555 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,11 @@ "main": "./index", "browser": "./browser", "scripts": { + "build:node": "node-gyp configure build", "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", + "build:browser:maybe": "test -f browser.js || test -n \"$CI\" || ! command -v em++ 2>&1 > /dev/null || npm run build:browser", + "build:all": "npm run build:node && npm run build:browser", + "install": "npm run build:node && npm run build:browser:maybe", "test-native": "script/test-native.js", "test": "mocha test/js/*.js", "benchmark": "node benchmark/marker-index.benchmark.js", From dc262d524ee80ac6da245d593b92423837c5cc4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Thu, 19 Jan 2017 11:41:15 +0100 Subject: [PATCH 06/26] Wraps the generated code inside UMD markers --- package.json | 2 +- src/bindings/em/epilogue.js | 4 ++++ src/bindings/em/prologue.js | 11 +++++++++++ 3 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 src/bindings/em/epilogue.js create mode 100644 src/bindings/em/prologue.js diff --git a/package.json b/package.json index a36e0555..3f4dcb22 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "browser": "./browser", "scripts": { "build:node": "node-gyp configure build", - "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", + "build:browser": "em++ --bind -o browser.js -O3 -std=c++14 -I src/bindings/em -I src/core --pre-js src/bindings/em/prologue.js --post-js src/bindings/em/epilogue.js src/core/*.cc src/bindings/em/*.cc -s TOTAL_MEMORY=134217728 --memory-init-file 0", "build:browser:maybe": "test -f browser.js || test -n \"$CI\" || ! command -v em++ 2>&1 > /dev/null || npm run build:browser", "build:all": "npm run build:node && npm run build:browser", "install": "npm run build:node && npm run build:browser:maybe", diff --git a/src/bindings/em/epilogue.js b/src/bindings/em/epilogue.js new file mode 100644 index 00000000..3e4a559b --- /dev/null +++ b/src/bindings/em/epilogue.js @@ -0,0 +1,4 @@ + + return Module; + +})); diff --git a/src/bindings/em/prologue.js b/src/bindings/em/prologue.js new file mode 100644 index 00000000..0e4ec50a --- /dev/null +++ b/src/bindings/em/prologue.js @@ -0,0 +1,11 @@ +(function (root, factory) { + + if (typeof define === 'function' && define.amd) { + define([], factory); + } else if (typeof exports === 'object') { + module.exports = factory(); + } else { + window.Superstring = factory(); + } + +}(this, function () { From 87d1c2531d5d57751dae95ea41dcbc7f292da5b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Thu, 19 Jan 2017 15:51:56 +0100 Subject: [PATCH 07/26] Exposes legacy properties --- package.json | 5 ++++- src/bindings/em/patch.cc | 22 ++++++++++++++++++++++ test/js/patch.test.js | 12 ++++++++++++ 3 files changed, 38 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 3f4dcb22..c75e7565 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,10 @@ "build:all": "npm run build:node && npm run build:browser", "install": "npm run build:node && npm run build:browser:maybe", "test-native": "script/test-native.js", - "test": "mocha test/js/*.js", + "test:node": "mocha test/js/*.js", + "test:browser": "FORCE_BROWSER_FALLBACK=1 mocha test/js/*.js", + "test:all": "npm run test:node && npm run test:browser", + "test": "npm run test:all", "benchmark": "node benchmark/marker-index.benchmark.js", "prepublish": "npm run standard", "standard": "standard --recursive src test", diff --git a/src/bindings/em/patch.cc b/src/bindings/em/patch.cc index 2f660615..ff10d027 100644 --- a/src/bindings/em/patch.cc +++ b/src/bindings/em/patch.cc @@ -36,6 +36,21 @@ Patch * deserialize(std::vector const & vec) return new Patch(vec); } +Point get_old_extent(Patch::Hunk const & hunk) +{ + return hunk.old_end.traversal(hunk.old_start); +} + +Point get_new_extent(Patch::Hunk const & hunk) +{ + return hunk.new_end.traversal(hunk.new_start); +} + +template +void hunk_set_noop(Patch::Hunk & hunk, T const &) +{ +} + EMSCRIPTEN_BINDINGS(Patch) { emscripten::class_("Patch") @@ -81,6 +96,13 @@ EMSCRIPTEN_BINDINGS(Patch) { .field("oldText", WRAP_FIELD(Patch::Hunk, old_text)) .field("newText", WRAP_FIELD(Patch::Hunk, new_text)) + // The following fields are legacy only (most notably, TextBuffer doesn't work without them) + + .field("start", WRAP_FIELD(Patch::Hunk, new_start)) + + .field("oldExtent", WRAP(&get_old_extent), WRAP(&hunk_set_noop)) + .field("newExtent", WRAP(&get_new_extent), WRAP(&hunk_set_noop)) + ; } diff --git a/test/js/patch.test.js b/test/js/patch.test.js index d36ad078..c8c66867 100644 --- a/test/js/patch.test.js +++ b/test/js/patch.test.js @@ -34,6 +34,18 @@ describe('Patch', function () { patch.delete(); }) + it('expose legacy fields', function () { + const patch = new Patch({ mergeAdjacentHunks: false }) + + patch.splice({row: 0, column: 10}, {row: 0, column: 0}, {row: 1, column: 5}) + patch.splice({row: 1, column: 5}, {row: 0, column: 2}, {row: 0, column: 8}) + + const hunk = patch.getHunks()[0]; + + assert.ok(hunk.oldExtent); + assert.ok(hunk.newExtent); + }) + it('honors the mergeAdjacentHunks option set to true', function () { const patch = new Patch({ mergeAdjacentHunks: true }) From accbd20cb6c9778365794e50a5f843ca7e662e89 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Fri, 24 Feb 2017 14:12:54 -0800 Subject: [PATCH 08/26] Bridge MarkerIndex.has in emscripten binding --- src/bindings/em/marker-index.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/src/bindings/em/marker-index.cc b/src/bindings/em/marker-index.cc index 17eda429..78af0829 100644 --- a/src/bindings/em/marker-index.cc +++ b/src/bindings/em/marker-index.cc @@ -17,6 +17,7 @@ EMSCRIPTEN_BINDINGS(MarkerIndex) { .function("delete", WRAP(&MarkerIndex::delete_marker)) .function("splice", WRAP(&MarkerIndex::splice)) + .function("has", WRAP(&MarkerIndex::has)) .function("getStart", WRAP(&MarkerIndex::get_start)) .function("getEnd", WRAP(&MarkerIndex::get_end)) .function("getRange", WRAP(&MarkerIndex::get_range)) From 3b02be299d3ace644de18850bd35a089b96bc449 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Fri, 24 Feb 2017 14:14:52 -0800 Subject: [PATCH 09/26] Rename Marker::delete to remove to avoid conflict w/ emscripten method Emscripten adds a .delete method to every bridged class which calls the c++ destructor. --- src/bindings/em/marker-index.cc | 2 +- src/bindings/marker-index-wrapper.cc | 6 +++--- src/bindings/marker-index-wrapper.h | 2 +- src/core/marker-index.cc | 2 +- src/core/marker-index.h | 2 +- test/js/marker-index.test.js | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/bindings/em/marker-index.cc b/src/bindings/em/marker-index.cc index 78af0829..b17801bf 100644 --- a/src/bindings/em/marker-index.cc +++ b/src/bindings/em/marker-index.cc @@ -14,7 +14,7 @@ EMSCRIPTEN_BINDINGS(MarkerIndex) { .function("insert", WRAP(&MarkerIndex::insert)) .function("setExclusive", WRAP(&MarkerIndex::set_exclusive)) - .function("delete", WRAP(&MarkerIndex::delete_marker)) + .function("remove", WRAP(&MarkerIndex::remove)) .function("splice", WRAP(&MarkerIndex::splice)) .function("has", WRAP(&MarkerIndex::has)) diff --git a/src/bindings/marker-index-wrapper.cc b/src/bindings/marker-index-wrapper.cc index 0a9e4e14..b8e78e48 100644 --- a/src/bindings/marker-index-wrapper.cc +++ b/src/bindings/marker-index-wrapper.cc @@ -29,7 +29,7 @@ void MarkerIndexWrapper::init(Local exports) { Nan::New(generate_random_number)); prototype_template->Set(Nan::New("insert").ToLocalChecked(), Nan::New(insert)); prototype_template->Set(Nan::New("setExclusive").ToLocalChecked(), Nan::New(set_exclusive)); - prototype_template->Set(Nan::New("delete").ToLocalChecked(), Nan::New(delete_marker)); + prototype_template->Set(Nan::New("remove").ToLocalChecked(), Nan::New(remove)); prototype_template->Set(Nan::New("has").ToLocalChecked(), Nan::New(has)); prototype_template->Set(Nan::New("splice").ToLocalChecked(), Nan::New(splice)); prototype_template->Set(Nan::New("getStart").ToLocalChecked(), Nan::New(get_start)); @@ -148,12 +148,12 @@ void MarkerIndexWrapper::set_exclusive(const Nan::FunctionCallbackInfo &i } } -void MarkerIndexWrapper::delete_marker(const Nan::FunctionCallbackInfo &info) { +void MarkerIndexWrapper::remove(const Nan::FunctionCallbackInfo &info) { MarkerIndexWrapper *wrapper = Nan::ObjectWrap::Unwrap(info.This()); optional id = marker_id_from_js(info[0]); if (id) { - wrapper->marker_index.delete_marker(*id); + wrapper->marker_index.remove(*id); } } diff --git a/src/bindings/marker-index-wrapper.h b/src/bindings/marker-index-wrapper.h index e851fad0..df799912 100644 --- a/src/bindings/marker-index-wrapper.h +++ b/src/bindings/marker-index-wrapper.h @@ -18,7 +18,7 @@ class MarkerIndexWrapper : public Nan::ObjectWrap { static optional bool_from_js(v8::Local value); static void insert(const Nan::FunctionCallbackInfo &info); static void set_exclusive(const Nan::FunctionCallbackInfo &info); - static void delete_marker(const Nan::FunctionCallbackInfo &info); + static void remove(const Nan::FunctionCallbackInfo &info); static void has(const Nan::FunctionCallbackInfo &info); static void splice(const Nan::FunctionCallbackInfo &info); static void get_start(const Nan::FunctionCallbackInfo &info); diff --git a/src/core/marker-index.cc b/src/core/marker-index.cc index 66ce3b7b..444166ba 100644 --- a/src/core/marker-index.cc +++ b/src/core/marker-index.cc @@ -404,7 +404,7 @@ void MarkerIndex::set_exclusive(MarkerId id, bool exclusive) { } } -void MarkerIndex::delete_marker(MarkerId id) { +void MarkerIndex::remove(MarkerId id) { Node *start_node = start_nodes_by_id.find(id)->second; Node *end_node = end_nodes_by_id.find(id)->second; diff --git a/src/core/marker-index.h b/src/core/marker-index.h index 945b8b6c..7b51fbce 100644 --- a/src/core/marker-index.h +++ b/src/core/marker-index.h @@ -24,7 +24,7 @@ class MarkerIndex { int generate_random_number(); void insert(MarkerId id, Point start, Point end); void set_exclusive(MarkerId id, bool exclusive); - void delete_marker(MarkerId id); + void remove(MarkerId id); bool has(MarkerId id); SpliceResult splice(Point start, Point old_extent, Point new_extent); Point get_start(MarkerId id) const; diff --git a/test/js/marker-index.test.js b/test/js/marker-index.test.js index 06a592ac..547182bb 100644 --- a/test/js/marker-index.test.js +++ b/test/js/marker-index.test.js @@ -304,7 +304,7 @@ describe('MarkerIndex', () => { let [{id}] = markers.splice(random(markers.length), 1) write(() => `delete ${id}`) assert(markerIndex.has(id), `Expected marker index to have ${id}. ` + seedMessage) - markerIndex.delete(id) + markerIndex.remove(id) assert(!markerIndex.has(id), `Expected marker index to not have ${id}. ` + seedMessage) } From afd22997a52b7db371955b65516131f7ded33243 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Fri, 24 Feb 2017 14:15:20 -0800 Subject: [PATCH 10/26] Remove legacy fields from Hunk We'll remove usages of these in TextBuffer --- src/bindings/em/patch.cc | 7 ------- src/bindings/patch-wrapper.cc | 18 ------------------ test/js/patch.test.js | 12 ------------ 3 files changed, 37 deletions(-) diff --git a/src/bindings/em/patch.cc b/src/bindings/em/patch.cc index ff10d027..5a94f9f2 100644 --- a/src/bindings/em/patch.cc +++ b/src/bindings/em/patch.cc @@ -96,13 +96,6 @@ EMSCRIPTEN_BINDINGS(Patch) { .field("oldText", WRAP_FIELD(Patch::Hunk, old_text)) .field("newText", WRAP_FIELD(Patch::Hunk, new_text)) - // The following fields are legacy only (most notably, TextBuffer doesn't work without them) - - .field("start", WRAP_FIELD(Patch::Hunk, new_start)) - - .field("oldExtent", WRAP(&get_old_extent), WRAP(&hunk_set_noop)) - .field("newExtent", WRAP(&get_new_extent), WRAP(&hunk_set_noop)) - ; } diff --git a/src/bindings/patch-wrapper.cc b/src/bindings/patch-wrapper.cc index 189c0edb..50bc112c 100644 --- a/src/bindings/patch-wrapper.cc +++ b/src/bindings/patch-wrapper.cc @@ -47,14 +47,6 @@ class HunkWrapper : public Nan::ObjectWrap { Nan::SetAccessor(instance_template, Nan::New("oldEnd").ToLocalChecked(), get_old_end); Nan::SetAccessor(instance_template, Nan::New("newEnd").ToLocalChecked(), get_new_end); - // Non-enumerable legacy properties for backward compatibility - Nan::SetAccessor(instance_template, Nan::New("start").ToLocalChecked(), get_new_start, nullptr, Handle(), - AccessControl::DEFAULT, PropertyAttribute::DontEnum); - Nan::SetAccessor(instance_template, Nan::New("oldExtent").ToLocalChecked(), get_old_extent, nullptr, Handle(), - AccessControl::DEFAULT, PropertyAttribute::DontEnum); - Nan::SetAccessor(instance_template, Nan::New("newExtent").ToLocalChecked(), get_new_extent, nullptr, Handle(), - AccessControl::DEFAULT, PropertyAttribute::DontEnum); - const auto &prototype_template = constructor_template->PrototypeTemplate(); prototype_template->Set(Nan::New("toString").ToLocalChecked(), Nan::New(to_string)); hunk_wrapper_constructor.Reset(constructor_template->GetFunction()); @@ -101,16 +93,6 @@ class HunkWrapper : public Nan::ObjectWrap { info.GetReturnValue().Set(PointWrapper::from_point(hunk.new_end)); } - static void get_old_extent(v8::Local property, const Nan::PropertyCallbackInfo &info) { - Patch::Hunk &hunk = Nan::ObjectWrap::Unwrap(info.This())->hunk; - info.GetReturnValue().Set(PointWrapper::from_point(hunk.old_end.traversal(hunk.old_start))); - } - - static void get_new_extent(v8::Local property, const Nan::PropertyCallbackInfo &info) { - Patch::Hunk &hunk = Nan::ObjectWrap::Unwrap(info.This())->hunk; - info.GetReturnValue().Set(PointWrapper::from_point(hunk.new_end.traversal(hunk.new_start))); - } - static void to_string(const Nan::FunctionCallbackInfo &info) { Patch::Hunk &hunk = Nan::ObjectWrap::Unwrap(info.This())->hunk; std::stringstream result; diff --git a/test/js/patch.test.js b/test/js/patch.test.js index 218d146a..ceecd9ef 100644 --- a/test/js/patch.test.js +++ b/test/js/patch.test.js @@ -34,18 +34,6 @@ describe('Patch', function () { patch.delete(); }) - it('expose legacy fields', function () { - const patch = new Patch({ mergeAdjacentHunks: false }) - - patch.splice({row: 0, column: 10}, {row: 0, column: 0}, {row: 1, column: 5}) - patch.splice({row: 1, column: 5}, {row: 0, column: 2}, {row: 0, column: 8}) - - const hunk = patch.getHunks()[0]; - - assert.ok(hunk.oldExtent); - assert.ok(hunk.newExtent); - }) - it('honors the mergeAdjacentHunks option set to true', function () { const patch = new Patch({ mergeAdjacentHunks: true }) From 6c075bda3d2ef42640fdfe6a988c19acb2bee9a6 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Fri, 3 Mar 2017 11:15:33 -0800 Subject: [PATCH 11/26] Add script for installing emscripten --- .gitignore | 1 + .npmignore | 1 + .travis.yml | 4 ++++ package.json | 16 +++++++--------- script/build-browser-version.sh | 18 ++++++++++++++++++ script/install-emscripten.sh | 15 +++++++++++++++ 6 files changed, 46 insertions(+), 9 deletions(-) create mode 100755 script/build-browser-version.sh create mode 100755 script/install-emscripten.sh diff --git a/.gitignore b/.gitignore index 2e1b21f5..cd82260b 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ build .clang_complete /browser.js +emsdk_portable \ No newline at end of file diff --git a/.npmignore b/.npmignore index 78a84fd8..9ecf6428 100644 --- a/.npmignore +++ b/.npmignore @@ -1,3 +1,4 @@ test build .gitignore +emsdk_portable diff --git a/.travis.yml b/.travis.yml index 4b8399c3..8bc3c6d6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -22,3 +22,7 @@ sudo: false env: - CXX=clang++ + +cache: + directories: + - emsdk_portable \ No newline at end of file diff --git a/package.json b/package.json index e33ebf0f..9d273a8d 100644 --- a/package.json +++ b/package.json @@ -6,19 +6,16 @@ "browser": "./browser", "scripts": { "build:node": "node-gyp configure build", - "build:browser": "em++ --bind -o browser.js -O3 -std=c++14 -I src/bindings/em -I src/core --pre-js src/bindings/em/prologue.js --post-js src/bindings/em/epilogue.js src/core/*.cc src/bindings/em/*.cc -s TOTAL_MEMORY=134217728 --memory-init-file 0", - "build:browser:maybe": "test -f browser.js || test -n \"$CI\" || ! command -v em++ 2>&1 > /dev/null || npm run build:browser", - "build:all": "npm run build:node && npm run build:browser", - "install": "npm run build:node && npm run build:browser:maybe", - "test-native": "script/test-native.js", + "build:browser": "script/build-browser-version.sh", + "build": "npm run build:node && npm run build:browser", + "test:native": "script/test-native.js", "test:node": "mocha test/js/*.js", "test:browser": "FORCE_BROWSER_FALLBACK=1 mocha test/js/*.js", - "test:all": "npm run test:node && npm run test:browser", - "test": "npm run test:all", + "test": "npm run test:node && npm run test:browser", "benchmark": "node benchmark/marker-index.benchmark.js", - "prepublish": "npm run standard", + "prepublish": "not-in-install && npm run build:browser || in-install", "standard": "standard --recursive src test", - "ci": "npm run standard && node-gyp rebuild --debug --tests && npm run test" + "ci": "script/install-emscripten.sh && script/build-browser-version.sh && npm run standard && node-gyp rebuild --debug --tests && npm run test" }, "repository": { "type": "git", @@ -39,6 +36,7 @@ }, "devDependencies": { "chai": "^2.0.0", + "in-publish": "^2.0.0", "mocha": "^2.3.4", "random-seed": "^0.2.0", "segfault-handler": "^1.0.0", diff --git a/script/build-browser-version.sh b/script/build-browser-version.sh new file mode 100755 index 00000000..635bffeb --- /dev/null +++ b/script/build-browser-version.sh @@ -0,0 +1,18 @@ +#!/usr/bin/env bash + +EM_COMPILER_PATH=$(find emsdk_portable -name em++ | head -n1) + +echo "Running ${EM_COMPILER_PATH}" +${EM_COMPILER_PATH} \ + --bind \ + -o browser.js \ + -O3 \ + -std=c++14 \ + -I src/bindings/em \ + -I src/core \ + --pre-js src/bindings/em/prologue.js \ + --post-js src/bindings/em/epilogue.js \ + src/core/*.cc \ + src/bindings/em/*.cc \ + -s TOTAL_MEMORY=134217728 \ + --memory-init-file 0 \ diff --git a/script/install-emscripten.sh b/script/install-emscripten.sh new file mode 100755 index 00000000..ea0e1d87 --- /dev/null +++ b/script/install-emscripten.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash + +EMSCRIPTEN_DOWNLOAD_URL='https://s3.amazonaws.com/mozilla-games/emscripten/releases/emsdk-portable.tar.gz' +EMSDK_PATH="./emsdk_portable/emsdk" + +if [ ! -f $EMSDK_PATH ]; then + echo 'Downloading emscripten SDK installer...' + curl $EMSCRIPTEN_DOWNLOAD_URL | tar xz +fi + +echo 'Installing emscripten SDK...' + +$EMSDK_PATH update +$EMSDK_PATH install latest +$EMSDK_PATH activate latest From 81289964567a5077142335a316df2698301dfc43 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Fri, 3 Mar 2017 11:48:30 -0800 Subject: [PATCH 12/26] Install cmake on travis --- .travis.yml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 8bc3c6d6..43b4ca74 100644 --- a/.travis.yml +++ b/.travis.yml @@ -25,4 +25,9 @@ env: cache: directories: - - emsdk_portable \ No newline at end of file + - emsdk_portable + +addons: + apt: + packages: + - cmake From 18bd75dcdd6e31f6ae0ec2374946d83b731fd56a Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Fri, 3 Mar 2017 12:06:18 -0800 Subject: [PATCH 13/26] Install newer cmake on travis --- .travis.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 43b4ca74..019016b8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -29,5 +29,8 @@ cache: addons: apt: + sources: + - george-edison55-precise-backports # cmake 3.2.3 packages: - - cmake + - cmake + - cmake-data From fc9e947717916b0be2eb0d2e8ed465fe70d45869 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Fri, 3 Mar 2017 12:20:34 -0800 Subject: [PATCH 14/26] Try to get Travis to build the right commit From afbeff3e7e1837ab2dd3cd42d194da1d107ecc6a Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Fri, 3 Mar 2017 12:25:18 -0800 Subject: [PATCH 15/26] Try using trusty on Travis --- .travis.yml | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/.travis.yml b/.travis.yml index 019016b8..f4a3ca94 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,6 @@ language: node_js +dist: trusty +sudo: false notifications: email: @@ -18,19 +20,9 @@ branches: only: - master -sudo: false - env: - CXX=clang++ cache: directories: - emsdk_portable - -addons: - apt: - sources: - - george-edison55-precise-backports # cmake 3.2.3 - packages: - - cmake - - cmake-data From 48230bfe12e71e8b29513ff7f2bd7c83db0915d9 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Fri, 3 Mar 2017 15:35:53 -0800 Subject: [PATCH 16/26] Download cmake binary manually on travis --- .travis.yml | 5 ++++- script/install-emscripten.sh | 2 ++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index f4a3ca94..a92bdf29 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,4 @@ language: node_js -dist: trusty sudo: false notifications: @@ -10,6 +9,10 @@ notifications: node_js: - "node" +before_install: + - curl https://cmake.org/files/v3.6/cmake-3.6.3-Linux-x86_64.tar.gz | tar xz + - export PATH=${PWD}/cmake-3.6.3-Linux-x86_64/bin:$PATH + script: - "npm run ci" diff --git a/script/install-emscripten.sh b/script/install-emscripten.sh index ea0e1d87..e5734b69 100755 --- a/script/install-emscripten.sh +++ b/script/install-emscripten.sh @@ -1,5 +1,7 @@ #!/usr/bin/env bash +set -e + EMSCRIPTEN_DOWNLOAD_URL='https://s3.amazonaws.com/mozilla-games/emscripten/releases/emsdk-portable.tar.gz' EMSDK_PATH="./emsdk_portable/emsdk" From 9acb148e8d27e135efc9ba92796bd5c0c632e707 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Fri, 3 Mar 2017 15:42:43 -0800 Subject: [PATCH 17/26] Install a newer libstdc++ version on travis --- .travis.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.travis.yml b/.travis.yml index a92bdf29..fdd6ed90 100644 --- a/.travis.yml +++ b/.travis.yml @@ -29,3 +29,8 @@ env: cache: directories: - emsdk_portable + +addons: + apt: + packages: + - libstdc++-4.8-dev From 814d50540e3f261b823d6b265316b3ab41ed6bf5 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Fri, 3 Mar 2017 15:52:29 -0800 Subject: [PATCH 18/26] Try another name for the libstdc++ package on travis --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index fdd6ed90..c0dc4ff9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -33,4 +33,4 @@ cache: addons: apt: packages: - - libstdc++-4.8-dev + - libstdc++6-4.8-dev From 5ab2b74b2d5303a86eaec14e10f1ddc62d33635a Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Fri, 3 Mar 2017 15:55:17 -0800 Subject: [PATCH 19/26] Install libc++ via gcc package on travis --- .travis.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index c0dc4ff9..6ab6b374 100644 --- a/.travis.yml +++ b/.travis.yml @@ -32,5 +32,8 @@ cache: addons: apt: + sources: + - ubuntu-toolchain-r-test packages: - - libstdc++6-4.8-dev + - gcc-4.8 + - g++-4.8 From 76e9b13a5166996ee3a147d7cef690e96f73f67c Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Fri, 3 Mar 2017 16:03:46 -0800 Subject: [PATCH 20/26] Try using gcc rather than clang on travis --- .gitignore | 2 +- .travis.yml | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index cd82260b..843bd5fa 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,4 @@ build .clang_complete /browser.js -emsdk_portable \ No newline at end of file +emsdk_portable diff --git a/.travis.yml b/.travis.yml index 6ab6b374..5b3aa4b6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,6 +10,7 @@ node_js: - "node" before_install: + - export CXX="g++-4.8" CC="gcc-4.8" - curl https://cmake.org/files/v3.6/cmake-3.6.3-Linux-x86_64.tar.gz | tar xz - export PATH=${PWD}/cmake-3.6.3-Linux-x86_64/bin:$PATH @@ -23,9 +24,6 @@ branches: only: - master -env: - - CXX=clang++ - cache: directories: - emsdk_portable From 4b2c5151ccd139c78d8e0b21585e2b75496d68d8 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Mon, 6 Mar 2017 12:33:30 -0800 Subject: [PATCH 21/26] Just use 2 cores when building emscripten --- script/install-emscripten.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/script/install-emscripten.sh b/script/install-emscripten.sh index e5734b69..84e84489 100755 --- a/script/install-emscripten.sh +++ b/script/install-emscripten.sh @@ -13,5 +13,5 @@ fi echo 'Installing emscripten SDK...' $EMSDK_PATH update -$EMSDK_PATH install latest +$EMSDK_PATH install -j2 latest $EMSDK_PATH activate latest From 97f6d9f98ca7bcf261d482f1b896fa38aa1829d2 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Mon, 6 Mar 2017 14:27:59 -0800 Subject: [PATCH 22/26] Install emscripten earlier in travis build and use 4 cores --- .travis.yml | 3 ++- package.json | 2 +- script/install-emscripten.sh | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 5b3aa4b6..0a2a66cc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,9 +13,10 @@ before_install: - export CXX="g++-4.8" CC="gcc-4.8" - curl https://cmake.org/files/v3.6/cmake-3.6.3-Linux-x86_64.tar.gz | tar xz - export PATH=${PWD}/cmake-3.6.3-Linux-x86_64/bin:$PATH + - script/install-emscripten.sh script: - - "npm run ci" + - npm run ci git: depth: 10 diff --git a/package.json b/package.json index 9d273a8d..29f625a1 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,7 @@ "benchmark": "node benchmark/marker-index.benchmark.js", "prepublish": "not-in-install && npm run build:browser || in-install", "standard": "standard --recursive src test", - "ci": "script/install-emscripten.sh && script/build-browser-version.sh && npm run standard && node-gyp rebuild --debug --tests && npm run test" + "ci": "script/build-browser-version.sh && npm run standard && node-gyp rebuild --debug --tests && npm run test" }, "repository": { "type": "git", diff --git a/script/install-emscripten.sh b/script/install-emscripten.sh index 84e84489..25695ca2 100755 --- a/script/install-emscripten.sh +++ b/script/install-emscripten.sh @@ -13,5 +13,5 @@ fi echo 'Installing emscripten SDK...' $EMSDK_PATH update -$EMSDK_PATH install -j2 latest +$EMSDK_PATH install -j4 latest $EMSDK_PATH activate latest From 64afc4b666bf5b11e29293b78da83839278c2f57 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Mon, 6 Mar 2017 15:04:50 -0800 Subject: [PATCH 23/26] Cache emscripten's cache directory on travis --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 0a2a66cc..4734d3b8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -28,6 +28,7 @@ branches: cache: directories: - emsdk_portable + - $HOME/.emscripten_cache addons: apt: From 1aa3cee563144387890589daf3c401daf74345f2 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Mon, 6 Mar 2017 15:16:00 -0800 Subject: [PATCH 24/26] Change environment variable used to force browser version --- .travis.yml | 6 +++++- index.js | 14 +++++++------- package.json | 7 +++---- 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/.travis.yml b/.travis.yml index 4734d3b8..0d332187 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,7 +16,11 @@ before_install: - script/install-emscripten.sh script: - - npm run ci + - npm run standard + - npm run build:browser + - npm run test:browser + - npm run build:node + - npm run test:node git: depth: 10 diff --git a/index.js b/index.js index c9933d4c..418d695d 100644 --- a/index.js +++ b/index.js @@ -1,9 +1,9 @@ -if (process.env.FORCE_BROWSER_FALLBACK) { - module.exports = require('./browser'); +if (process.env.SUPERSTRING_USE_BROWSER_VERSION) { + module.exports = require('./browser'); } else { - try { - module.exports = require('./build/Release/superstring.node') - } catch (e) { - module.exports = require('./build/Debug/superstring.node') - } + try { + module.exports = require('./build/Release/superstring.node') + } catch (e) { + module.exports = require('./build/Debug/superstring.node') + } } diff --git a/package.json b/package.json index 29f625a1..ed4a5927 100644 --- a/package.json +++ b/package.json @@ -5,17 +5,16 @@ "main": "./index", "browser": "./browser", "scripts": { - "build:node": "node-gyp configure build", + "build:node": "node-gyp rebuild", "build:browser": "script/build-browser-version.sh", "build": "npm run build:node && npm run build:browser", "test:native": "script/test-native.js", "test:node": "mocha test/js/*.js", - "test:browser": "FORCE_BROWSER_FALLBACK=1 mocha test/js/*.js", + "test:browser": "SUPERSTRING_USE_BROWSER_VERSION=1 mocha test/js/*.js", "test": "npm run test:node && npm run test:browser", "benchmark": "node benchmark/marker-index.benchmark.js", "prepublish": "not-in-install && npm run build:browser || in-install", - "standard": "standard --recursive src test", - "ci": "script/build-browser-version.sh && npm run standard && node-gyp rebuild --debug --tests && npm run test" + "standard": "standard --recursive src test" }, "repository": { "type": "git", From ea0c0145fbb8c0fbacbf5acf671bddaa02a75adc Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Mon, 6 Mar 2017 15:30:03 -0800 Subject: [PATCH 25/26] Use two spaces in browser.js sources --- src/bindings/em/epilogue.js | 4 +--- src/bindings/em/prologue.js | 16 +++++++--------- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/src/bindings/em/epilogue.js b/src/bindings/em/epilogue.js index 3e4a559b..b6be84de 100644 --- a/src/bindings/em/epilogue.js +++ b/src/bindings/em/epilogue.js @@ -1,4 +1,2 @@ - - return Module; - + return Module; })); diff --git a/src/bindings/em/prologue.js b/src/bindings/em/prologue.js index 0e4ec50a..e3f7da8b 100644 --- a/src/bindings/em/prologue.js +++ b/src/bindings/em/prologue.js @@ -1,11 +1,9 @@ (function (root, factory) { - - if (typeof define === 'function' && define.amd) { - define([], factory); - } else if (typeof exports === 'object') { - module.exports = factory(); - } else { - window.Superstring = factory(); - } - + if (typeof define === 'function' && define.amd) { + define([], factory); + } else if (typeof exports === 'object') { + module.exports = factory(); + } else { + window.Superstring = factory(); + } }(this, function () { From c49a89df4bb56479d864229e28a5c81979af552e Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Mon, 6 Mar 2017 15:37:24 -0800 Subject: [PATCH 26/26] Remove unnecessary rebuild on Travis --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 0d332187..bdce12cf 100644 --- a/.travis.yml +++ b/.travis.yml @@ -19,7 +19,6 @@ script: - npm run standard - npm run build:browser - npm run test:browser - - npm run build:node - npm run test:node git: