├── vec.png ├── bg@2x.png ├── README.md ├── index.html ├── vec.js └── includes └── immutable.js /vec.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tonsky/vec/HEAD/vec.png -------------------------------------------------------------------------------- /bg@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tonsky/vec/HEAD/bg@2x.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # React.js + Immutable.js vector editor example 2 | 3 | App written during http://dou.ua/calendar/7213/ 4 | 5 | - Immutable model 6 | - Fast reference-comparison `shouldComponentUpdate` on everything 7 | - Speculative rendering 8 | - Undo/redo 9 | - `localStorage` persistence 10 | - vanilla.js 11 | 12 | Check out [vec.js](https://github.com/tonsky/vec/blob/gh-pages/vec.js), it’s decently commented. 13 | 14 | Read more [about approach](http://tonsky.me/talks/2015-codefest/) (in Russian). 15 | 16 | Video (in Russian): [code walkthrough](http://www.youtube.com/watch?v=lDkrXTDwbJQ), [Q&A session](http://www.youtube.com/watch?v=tUtLe1VlkYc) 17 | 18 | [Live version](http://tonsky.me/vec/) 19 | 20 | [](http://tonsky.me/vec/) 21 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Vector editor 6 | 7 | 8 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /vec.js: -------------------------------------------------------------------------------- 1 | // UTILS 2 | 3 | 4 | // Multimethods are flexible polymorphic construct, decoulped from class, open for extension 5 | 6 | function defmulti(name, dispatch_fn) { 7 | var dispatch_table_name = "_" + name + "_mm"; 8 | window[dispatch_table_name] = {}; 9 | window[name] = function() { 10 | var fun = window[dispatch_table_name][dispatch_fn.apply(null, arguments)]; 11 | if (fun !== undefined) 12 | return fun.apply(null, arguments); 13 | } 14 | } 15 | 16 | function defmethod(name, dispatch_value, fn) { 17 | window["_" + name + "_mm"][dispatch_value] = fn; 18 | } 19 | 20 | 21 | // Atom is a mutable reference with listeners (watchers) 22 | 23 | function atom(value) { 24 | return {value: value, 25 | listeners: []}; 26 | } 27 | 28 | function add_watch(atom, cb) { 29 | atom.listeners.push(cb); 30 | } 31 | 32 | function reset(atom, value) { 33 | var old = atom.value; 34 | atom.value = value; 35 | for (var i = 0; i < atom.listeners.length; ++i) { 36 | atom.listeners[i](atom, old, value); 37 | } 38 | } 39 | 40 | 41 | // Some shortcuts to ease immutable structs construction 42 | 43 | var list = function() { return Immutable.List.of.apply(Immutable.List, arguments); }, 44 | map = function() { return Immutable.Map.apply(Immutable, arguments); }, 45 | set = function() { return Immutable.Set.of.apply(Immutable.Set, arguments); }, 46 | eq = function(a, b) { return Immutable.is(a,b); }; 47 | 48 | 49 | // Tracking window size 50 | 51 | function current_viewport() { 52 | return map({w: document.body.clientWidth, h: document.body.clientHeight}); 53 | } 54 | 55 | window.addEventListener("resize", function(e) { 56 | reset(world_ref, world_ref.value.set("viewport", current_viewport())); 57 | } ); 58 | 59 | 60 | // Compares set of immutable props via Immutable.is() — fast pointer comparison 61 | function should_update(name, from, to, props) { 62 | for (var i = 0; i < props.length; ++i) { 63 | var prop = props[i]; 64 | if (!eq(from[prop], to[prop])) { 65 | // console.log(name + "." + prop + " changed"); 66 | return true; 67 | } 68 | }; 69 | // console.log(name + " // skip"); 70 | return false; 71 | } 72 | 73 | 74 | // HISTORY 75 | 76 | // Everything we render is kept in a single atom, including auxiliary stuff like click positions 77 | // and window size 78 | var world_ref = atom(new_world()); 79 | 80 | function new_world() { 81 | var empty_model = map({ tool: "select", 82 | figures: list(), 83 | selection: set() }); 84 | return map({ history: list(empty_model), // collection of models 85 | at: 0, // position in history 86 | viewport: current_viewport() }); 87 | } 88 | 89 | 90 | // Model we’re looking at right now 91 | function current_model(w) { 92 | var world = w || world_ref.value; 93 | return world.get("history").get(world.get("at")); 94 | } 95 | 96 | 97 | // Edit “mutates” current model, either pushing new model to the history or replacing it inplace 98 | // All changes to model go through this place only 99 | function edit_model(model) { 100 | // create new history record only if figures have changed 101 | if (!eq(model.get("figures"), current_model().get("figures"))) { 102 | var history = world_ref.value.get("history"), 103 | at = world_ref.value.get("at"), 104 | new_history = history.setSize(at+1).push(model), 105 | new_at = at+1; 106 | 107 | // limiting history size 108 | var skip = new_history.size - 50; 109 | if (skip > 0) { 110 | new_at -= skip; 111 | new_history = new_history.skip(skip); 112 | } 113 | 114 | reset(world_ref, world_ref.value.set("history", new_history).set("at", new_at)); 115 | } else { 116 | var world = world_ref.value; 117 | reset(world_ref, world.setIn(["history", world.get("at")], model)); 118 | } 119 | } 120 | 121 | 122 | // Note how plain dead trivial undo/redo are 123 | function undo() { 124 | var at = world_ref.value.get("at"); 125 | if (at > 0) 126 | reset(world_ref, world_ref.value.set("at", at-1)); 127 | } 128 | 129 | function redo() { 130 | var history = world_ref.value.get("history"), 131 | at = world_ref.value.get("at"); 132 | if (at < history.size-1) 133 | reset(world_ref, world_ref.value.set("at", at+1)); 134 | } 135 | 136 | 137 | 138 | // FIGURES 139 | // mostly trivial code, some math and stuff 140 | 141 | defmulti("render_figure", function(fig, selected, key) { return fig.get("type"); }); 142 | defmulti("inside_figure", function(fig, point) { return fig.get("type"); }); 143 | defmulti("inside_stroke", function(fig, point) { return fig.get("type"); }); 144 | defmulti("move_figure", function(fig, delta) { return fig.get("type"); }); 145 | defmulti("figure_from_bb", function(type, p1, p2) { return type; }); 146 | 147 | function find_selected(figures, point) { 148 | var by_stroke = figures.find(function(fig) { return inside_stroke(fig, point); }); 149 | // if (by_stroke !== undefined) 150 | return by_stroke; 151 | // return figures.find(function(fig) { return inside_figure(fig, point); }); 152 | } 153 | 154 | var selection_treshold = 8; 155 | 156 | // RECT 157 | 158 | defmethod("render_figure", "rect", function(fig, selected, key) { 159 | return React.createElement( 160 | "rect", 161 | { key: key, 162 | className: selected ? "figure selected" : "figure", 163 | width: fig.get("w"), 164 | height: fig.get("h"), 165 | x: fig.get("x"), 166 | y: fig.get("y") }); 167 | }); 168 | 169 | defmethod("inside_figure", "rect", function(fig, point) { 170 | return fig.get("x") <= point.get("x") && 171 | fig.get("x") + fig.get("w") >= point.get("x") && 172 | fig.get("y") <= point.get("y") && 173 | fig.get("y") + fig.get("h") >= point.get("y"); 174 | }); 175 | 176 | defmethod("inside_stroke", "rect", function(fig, point) { 177 | var x1 = fig.get("x"), 178 | y1 = fig.get("y"), 179 | x2 = fig.get("x") + fig.get("w"), 180 | y2 = fig.get("y") + fig.get("h"), 181 | x = point.get("x"), 182 | y = point.get("y"), 183 | t = selection_treshold; 184 | 185 | return ( y1 - t <= y && y <= y2 + t && 186 | ((x1 - t <= x && x <= x1 + t) || 187 | (x2 - t <= x && x <= x2 + t))) || 188 | ( x1 - t <= x && x <= x2 + t && 189 | ((y1 - t <= y && y <= y1 + t) || 190 | (y2 - t <= y && y <= y2 + t))); 191 | }); 192 | 193 | defmethod("figure_from_bb", "rect", function(type, p1, p2) { 194 | return map({ 195 | type: "rect", 196 | x: Math.min(p1.get("x"), p2.get("x")), 197 | y: Math.min(p1.get("y"), p2.get("y")), 198 | w: Math.abs(p1.get("x") - p2.get("x")), 199 | h: Math.abs(p1.get("y") - p2.get("y")) 200 | }); 201 | }); 202 | 203 | defmethod("move_figure", "rect", function(fig, delta) { 204 | return map({ 205 | type: "rect", 206 | x: fig.get("x") + delta.get("x"), 207 | y: fig.get("y") + delta.get("y"), 208 | w: fig.get("w"), 209 | h: fig.get("h") 210 | }); 211 | }); 212 | 213 | 214 | // OVAL 215 | 216 | defmethod("render_figure", "oval", function(fig, selected, key) { 217 | return React.createElement( 218 | "ellipse", 219 | { key: key, 220 | className: selected ? "figure selected" : "figure", 221 | cx: fig.get("cx"), 222 | cy: fig.get("cy"), 223 | rx: fig.get("rx"), 224 | ry: fig.get("ry") }); 225 | }); 226 | 227 | 228 | function inside_ellipse(x, y, cx, cy, rx, ry) { 229 | return (x-cx)*(x-cx)/(rx*rx) + (y-cy)*(y-cy)/(ry*ry) <= 1; 230 | } 231 | 232 | defmethod("inside_figure", "oval", function(fig, point) { 233 | return inside_ellipse(point.get("x"), point.get("y"), fig.get("cx"), fig.get("cy"), fig.get("rx"), fig.get("ry")); 234 | }); 235 | 236 | 237 | defmethod("inside_stroke", "oval", function(fig, point) { 238 | var x = point.get("x"), 239 | y = point.get("y"), 240 | cx = fig.get("cx"), 241 | cy = fig.get("cy"), 242 | rx = fig.get("rx"), 243 | ry = fig.get("ry"), 244 | t = selection_treshold; 245 | return inside_ellipse(x, y, cx, cy, rx+t, ry+t) && (rx <= t || ry <= t || !inside_ellipse(x, y, cx, cy, rx-t, ry-t)); 246 | }); 247 | 248 | 249 | 250 | defmethod("figure_from_bb", "oval", function(type, p1, p2) { 251 | return map({ 252 | type: "oval", 253 | cx: (p1.get("x") + p2.get("x"))/2, 254 | cy: (p1.get("y") + p2.get("y"))/2, 255 | rx: Math.abs(p1.get("x") - p2.get("x"))/2, 256 | ry: Math.abs(p1.get("y") - p2.get("y"))/2 257 | }); 258 | }); 259 | 260 | defmethod("move_figure", "oval", function(fig, delta) { 261 | return map({ 262 | type: "oval", 263 | cx: fig.get("cx") + delta.get("x"), 264 | cy: fig.get("cy") + delta.get("y"), 265 | rx: fig.get("rx"), 266 | ry: fig.get("ry") 267 | }); 268 | }); 269 | 270 | 271 | // LINE 272 | 273 | defmethod("render_figure", "line", function(fig, selected, key) { 274 | return React.createElement("line", 275 | { key: key, 276 | className: selected ? "figure selected" : "figure", 277 | x1: fig.get("x1"), 278 | y1: fig.get("y1"), 279 | x2: fig.get("x2"), 280 | y2: fig.get("y2") }); 281 | }); 282 | 283 | defmethod("inside_stroke", "line", function(fig, point) { 284 | var x1 = fig.get("x1"), 285 | y1 = fig.get("y1"), 286 | x2 = fig.get("x2"), 287 | y2 = fig.get("y2"), 288 | x = point.get("x"), 289 | y = point.get("y"); 290 | 291 | if (Math.min(x1, x2) <= x && 292 | Math.max(x1, x2) >= x && 293 | Math.min(y1, y2) <= y && 294 | Math.max(y1, y2) >= y) 295 | return Math.abs((y2 - y1) * x - (x2 - x1) * y + x2 * y1 - y2 * x1) / 296 | Math.sqrt((y2-y1) * (y2-y1) + (x2 - x1) * (x2 - x1)) <= selection_treshold; 297 | }); 298 | 299 | defmethod("figure_from_bb", "line", function(type, p1, p2) { 300 | return map({ type: "line", x1: p1.get("x"), y1: p1.get("y"), x2: p2.get("x"), y2: p2.get("y") }); 301 | }); 302 | 303 | defmethod("move_figure", "line", function(fig, delta) { 304 | return map({ 305 | type: "line", 306 | x1: fig.get("x1") + delta.get("x"), 307 | y1: fig.get("y1") + delta.get("y"), 308 | x2: fig.get("x2") + delta.get("x"), 309 | y2: fig.get("y2") + delta.get("y") 310 | }); 311 | }); 312 | 313 | 314 | // TOOLS 315 | 316 | // round mouse position for “snap to grid” behaviour 317 | function mouse_pos(e) { 318 | return map({x: 10 * Math.round(e.clientX / 10), 319 | y: 10 * Math.round(e.clientY / 10)}); 320 | } 321 | 322 | // These multimethods take current model and return new model 323 | // They are pure and don’t mutate anything 324 | // This allows us to use them for speculative rendering 325 | defmulti("tool_on_click", function(tool, model, point, e) { return tool; }); 326 | defmulti("tool_on_drag", function(tool, model, p1, p2, e) { return tool; }); 327 | 328 | // Select changes “selection” set of a model 329 | defmethod("tool_on_click", "select", 330 | function(tool, model, point, e) { 331 | var fig = find_selected(model.get("figures"), point), 332 | multi = e.shiftKey, 333 | selection = model.get("selection"); 334 | if (fig !== undefined && multi && selection.contains(fig)) 335 | return model.set("selection", selection.delete(fig)); 336 | else if (fig !== undefined && multi && !selection.contains(fig)) 337 | return model.set("selection", selection.add(fig)); 338 | else if (fig !== undefined && !multi) 339 | return model.set("selection", set(fig)); 340 | else if (fig === undefined && !multi) 341 | return model.set("selection", set()); 342 | }); 343 | 344 | // or moves figures 345 | defmethod("tool_on_drag", "select", 346 | function(tool, model, p1, p2, e) { 347 | var delta = map({x: p2.get("x") - p1.get("x"), y: p2.get("y") - p1.get("y")}), 348 | selection = model.get("selection"), 349 | scene = model.get("figures"); 350 | 351 | if (find_selected(selection, p1) === undefined) { 352 | var fig = find_selected(scene, p1); 353 | if (fig !== undefined) { 354 | selection = set(fig); 355 | model = model.set("selection", selection); 356 | } 357 | } 358 | 359 | if (find_selected(selection, p1) !== undefined) { 360 | return model 361 | .set("figures", scene.map(function(fig) { 362 | return selection.contains(fig) ? move_figure(fig, delta) : fig; 363 | })) 364 | .set("selection", selection.map(function(fig) { return move_figure(fig, delta); })); 365 | } 366 | }); 367 | 368 | // figures just add new figure on drag 369 | function fig_drag_fn(tool, model, p1, p2, e) { 370 | if (!eq(p1, p2)) { 371 | var scene = model.get("figures"); 372 | var instance = figure_from_bb(tool, p1, p2); 373 | return model.set("figures", scene.push(instance)) 374 | .set("selection", set(instance)); 375 | } 376 | } 377 | 378 | defmethod("tool_on_drag", "rect", fig_drag_fn); 379 | defmethod("tool_on_drag", "oval", fig_drag_fn); 380 | defmethod("tool_on_drag", "line", fig_drag_fn); 381 | 382 | 383 | // REACT COMPONENTS 384 | 385 | var tool_keys = list( 386 | ["select", "V"], 387 | ["rect", "R"], 388 | ["oval", "O"], 389 | ["line", "L"] 390 | ); 391 | 392 | 393 | var Tool = React.createClass({ 394 | // Component will only be updated whenever props it depends on change 395 | shouldComponentUpdate: function(next_props) { 396 | return should_update(" Tool_" + this.props.code, this.props, next_props, ["code", "shortcut", "offset", "selected"]); 397 | }, 398 | render: function() { 399 | var code = this.props.code, 400 | shortcut = this.props.shortcut, 401 | offset = 40 * this.props.offset; 402 | 403 | return React.createElement("g", 404 | { className: "tool_" + code + (this.props.selected ? " selected" : ""), 405 | transform: "translate(" + offset + ",0)", 406 | onClick: function(e) { 407 | edit_model(current_model().set("tool", code)); 408 | e.stopPropagation(); 409 | } }, 410 | React.createElement("rect", {x: 0, y: 0, width: 40, height: 40}), 411 | React.createElement("text", {textAnchor: "middle", x: 20, y: 27}, shortcut)); 412 | } 413 | }); 414 | 415 | 416 | var Toolbar = React.createClass({ 417 | shouldComponentUpdate: function(next_props) { 418 | return should_update(" Toolbar", this.props, next_props, ["tool"]); 419 | }, 420 | render: function() { 421 | var tool = this.props.tool; 422 | return React.createElement("g", 423 | { id: "toolbar", transform: "translate(10,10)" }, 424 | tool_keys.map(function(t, i) { 425 | return React.createElement(Tool, {key: t[0], code: t[0], shortcut: t[1], selected: tool === t[0], offset: i}) 426 | })); 427 | } 428 | }); 429 | 430 | 431 | var Scene = React.createClass({ 432 | shouldComponentUpdate: function(next_props) { 433 | return should_update(" Scene", this.props, next_props, ["figures", "selection"]); 434 | }, 435 | render: function() { 436 | var figures = this.props.figures, 437 | selection = this.props.selection, 438 | render = function(fig, i) { return render_figure(fig, selection.contains(fig), i); }; 439 | return React.createElement("g", {}, figures.map(render)); 440 | } 441 | }); 442 | 443 | 444 | var History = React.createClass({ 445 | shouldComponentUpdate: function(next_props) { 446 | return should_update(" History", this.props, next_props, ["history", "at", "viewport"]); 447 | }, 448 | render: function() { 449 | var history = this.props.history, 450 | at = this.props.at, 451 | viewport = this.props.viewport, 452 | render = function(m, i) { 453 | return React.createElement("rect", { 454 | key: i, 455 | className: i === at ? "selected" : "", 456 | x: i*14 + 10, 457 | y: viewport.get("h") - 20, 458 | width: 12, 459 | height: 12, 460 | onClick: function(e) { 461 | reset(world_ref, world_ref.value.set("at", i)); 462 | }, 463 | onMouseOver: function(e) { render_ui(world_ref.value.set("at", i)); }, 464 | onMouseOut: function(e) { render_ui(world_ref.value); }, 465 | }); 466 | }; 467 | return React.createElement("g", { id: "history" }, this.props.history.map(render)); 468 | } 469 | }); 470 | 471 | 472 | // Rendering is top-down. Components implement shouldComponentUpdate to decide whether 473 | // they should be updated on this particular change or not 474 | var UI = React.createClass({ 475 | shouldComponentUpdate: function(next_props) { 476 | return should_update("UI", this.props, next_props, ["world"]); 477 | }, 478 | render: function() { 479 | var world = this.props.world, 480 | model = current_model(world); 481 | return React.createElement("svg", 482 | { id: "canvas" }, 483 | React.createElement(Toolbar, { tool: model.get("tool") }), 484 | React.createElement(History, { history: world.get("history"), 485 | at: world.get("at"), 486 | viewport: world.get("viewport") }), 487 | React.createElement(Scene, 488 | { figures: model.get("figures"), 489 | selection: model.get("selection") })); 490 | } 491 | }); 492 | 493 | function render_ui(world) { 494 | React.render(React.createElement(UI, { world: world }), document.body); 495 | } 496 | 497 | // We do not call render_ui explicitly. Every change gets applied to world_ref 498 | // and re-render fires from its watcher 499 | add_watch(world_ref, function(world, old, _new) { 500 | render_ui(_new); 501 | }); 502 | 503 | 504 | // MOUSE HANDLING 505 | 506 | function canvas_mouse_down(e) { 507 | if (world_ref.value.get("click_pos") === undefined) 508 | reset(world_ref, world_ref.value.set("click_pos", mouse_pos(e))); 509 | } 510 | 511 | function canvas_mouse_move(e) { 512 | var click_pos = world_ref.value.get("click_pos"), 513 | drag_pos = world_ref.value.get("drag_pos"), 514 | pos = mouse_pos(e); 515 | if (click_pos !== undefined && 516 | (drag_pos !== undefined || !eq(click_pos, pos))) { 517 | reset(world_ref, world_ref.value.set("drag_pos", pos)); 518 | 519 | // if we’re in the process of the dragging, we render not a model stored in history, 520 | // but the one tool_on_drag() call return. This model is auxiliary and ephemeral, it is 521 | // not stored anywhere. It’s used to show intermediate states of figures move or creation. 522 | // No other code knows anything about that. Everybody expects a model, and they get a model 523 | 524 | var model = current_model(), 525 | new_model = tool_on_drag(model.get("tool"), model, click_pos, pos, e); 526 | if (new_model !== undefined) 527 | render_ui(world_ref.value.setIn(["history", world_ref.value.get("at")], new_model)); 528 | } 529 | } 530 | 531 | function canvas_mouse_up(e) { 532 | var model = current_model(), 533 | tool = model.get("tool"), 534 | click_pos = world_ref.value.get("click_pos"), 535 | drag_pos = world_ref.value.get("drag_pos"), 536 | pos = mouse_pos(e); 537 | 538 | // On mouse up we’re reusing tool_on_drag() and tool_on_click() 539 | // to commit new model to the history 540 | if (click_pos !== undefined) { 541 | if (drag_pos !== undefined) { 542 | var new_model = tool_on_drag(tool, model, click_pos, drag_pos, e); 543 | if (new_model !== undefined) 544 | edit_model(new_model); 545 | } else { 546 | var new_model = tool_on_click(tool, model, click_pos, e); 547 | if (new_model !== undefined) 548 | edit_model(new_model); 549 | } 550 | } 551 | reset(world_ref, world_ref.value.delete("click_pos").delete("drag_pos")); 552 | } 553 | 554 | document.addEventListener("mousedown", canvas_mouse_down); 555 | document.addEventListener("mousemove", canvas_mouse_move); 556 | document.addEventListener("mouseup", canvas_mouse_up); 557 | 558 | 559 | // KEYBOARD HANDLING 560 | 561 | document.addEventListener("keydown", function(e) { 562 | if (!e.ctrlKey && !e.shiftKey && !e.metaKey) { 563 | var tool = tool_keys.find(function(t) { return t[1].charCodeAt(0) === e.keyCode }); 564 | if (tool !== undefined) 565 | edit_model(current_model().set("tool", tool[0])); 566 | } 567 | switch (e.keyCode) { 568 | case 27: // escape 569 | reset(world_ref, world_ref.value.delete("click_pos").delete("drag_pos")); 570 | break; 571 | case 8: // backspace 572 | case 46: // delete 573 | var model = current_model(), 574 | scene = model.get("figures"), 575 | selection = model.get("selection"), 576 | selected = function(fig) { return selection.contains(fig); }; 577 | edit_model(model.set("figures", scene.filterNot(selected))); 578 | e.preventDefault(); 579 | break; 580 | case 90: // Z 581 | if (e.metaKey || e.ctrlKey) { 582 | if (e.shiftKey) redo(); else undo(); 583 | } 584 | e.preventDefault(); 585 | break; 586 | } 587 | }); 588 | 589 | 590 | 591 | // LocalStorage-powered persistence 592 | // We’re using “smart” serialization: each figure is stored only once (cache), 593 | // and models are referencing figures by ids instead of serializing their body 594 | function world_to_js(world) { 595 | var cache = list(), 596 | obj_id = function (o) { 597 | var idx = cache.indexOf(o); 598 | if (idx === -1) { 599 | cache = cache.push(o); 600 | return cache.size - 1; 601 | } else 602 | return idx; 603 | }, 604 | history = []; 605 | world.get("history").forEach(function(model, i) { 606 | history.push({ tool: model.get("tool"), 607 | selection: model.get("selection").map(obj_id).toArray(), 608 | figures: model.get("figures").map(obj_id).toArray() }); 609 | }); 610 | return { history: history, 611 | at: world.get("at"), 612 | figures: cache.map(function(o) { return o.toJS(); }).toArray() }; 613 | } 614 | 615 | function world_from_js(json) { 616 | var figures = Immutable.List(json.figures).map(Immutable.Map), 617 | get_fig = function(i) { return figures.get(i); }, 618 | history = Immutable.List(json.history).map(function(m) { 619 | return map({ 620 | tool: m.tool, 621 | selection: Immutable.List(m.selection).map(get_fig), 622 | figures: Immutable.List(m.figures).map(get_fig) 623 | })}); 624 | return new_world().set("history", history).set("at", json.at); 625 | } 626 | 627 | // Whenever interesting parts of the world change, we store it 628 | add_watch(world_ref, function(world, old, _new) { 629 | if (!eq(old.get("history"), _new.get("history")) || !eq(old.get("at"), _new.get("at"))) 630 | localStorage.setItem("vec/world", JSON.stringify(world_to_js(_new))); 631 | }); 632 | 633 | // load stored world or build initial built-in scene 634 | if (localStorage.getItem("vec/world") !== null) { 635 | reset(world_ref, world_from_js(JSON.parse(localStorage.getItem("vec/world")))); 636 | } else { 637 | list( 638 | figure_from_bb("oval", map({x: 110, y: 115}), map({x: 120, y: 125})), 639 | figure_from_bb("oval", map({x: 130, y: 115}), map({x: 140, y: 125})), 640 | figure_from_bb("oval", map({x: 150, y: 115}), map({x: 160, y: 125})), 641 | figure_from_bb("line", map({x: 100, y: 140}), map({x: 170, y: 140})), 642 | figure_from_bb("line", map({x: 170, y: 140}), map({x: 180, y: 110})), 643 | figure_from_bb("line", map({x: 180, y: 110}), map({x: 280, y: 110})), 644 | figure_from_bb("line", map({x: 280, y: 110}), map({x: 290, y: 140})), 645 | figure_from_bb("line", map({x: 290, y: 140}), map({x: 600, y: 140})), 646 | figure_from_bb("line", map({x: 100, y: 180}), map({x: 600, y: 180})), 647 | figure_from_bb("rect", map({x: 100, y: 100}), map({x: 600, y: 400})) 648 | ).forEach(function(fig) { 649 | edit_model(current_model().set("figures", current_model().get("figures").push(fig))); 650 | }); 651 | } 652 | 653 | 654 | 655 | 656 | 657 | -------------------------------------------------------------------------------- /includes/immutable.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2014-2015, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | */ 9 | (function (global, factory) { 10 | typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : 11 | typeof define === 'function' && define.amd ? define(factory) : 12 | global.Immutable = factory() 13 | }(this, function () { 'use strict';var SLICE$0 = Array.prototype.slice; 14 | 15 | function createClass(ctor, superClass) { 16 | if (superClass) { 17 | ctor.prototype = Object.create(superClass.prototype); 18 | } 19 | ctor.prototype.constructor = ctor; 20 | } 21 | 22 | // Used for setting prototype methods that IE8 chokes on. 23 | var DELETE = 'delete'; 24 | 25 | // Constants describing the size of trie nodes. 26 | var SHIFT = 5; // Resulted in best performance after ______? 27 | var SIZE = 1 << SHIFT; 28 | var MASK = SIZE - 1; 29 | 30 | // A consistent shared value representing "not set" which equals nothing other 31 | // than itself, and nothing that could be provided externally. 32 | var NOT_SET = {}; 33 | 34 | // Boolean references, Rough equivalent of `bool &`. 35 | var CHANGE_LENGTH = { value: false }; 36 | var DID_ALTER = { value: false }; 37 | 38 | function MakeRef(ref) { 39 | ref.value = false; 40 | return ref; 41 | } 42 | 43 | function SetRef(ref) { 44 | ref && (ref.value = true); 45 | } 46 | 47 | // A function which returns a value representing an "owner" for transient writes 48 | // to tries. The return value will only ever equal itself, and will not equal 49 | // the return of any subsequent call of this function. 50 | function OwnerID() {} 51 | 52 | // http://jsperf.com/copy-array-inline 53 | function arrCopy(arr, offset) { 54 | offset = offset || 0; 55 | var len = Math.max(0, arr.length - offset); 56 | var newArr = new Array(len); 57 | for (var ii = 0; ii < len; ii++) { 58 | newArr[ii] = arr[ii + offset]; 59 | } 60 | return newArr; 61 | } 62 | 63 | function ensureSize(iter) { 64 | if (iter.size === undefined) { 65 | iter.size = iter.__iterate(returnTrue); 66 | } 67 | return iter.size; 68 | } 69 | 70 | function wrapIndex(iter, index) { 71 | return index >= 0 ? (+index) : ensureSize(iter) + (+index); 72 | } 73 | 74 | function returnTrue() { 75 | return true; 76 | } 77 | 78 | function wholeSlice(begin, end, size) { 79 | return (begin === 0 || (size !== undefined && begin <= -size)) && 80 | (end === undefined || (size !== undefined && end >= size)); 81 | } 82 | 83 | function resolveBegin(begin, size) { 84 | return resolveIndex(begin, size, 0); 85 | } 86 | 87 | function resolveEnd(end, size) { 88 | return resolveIndex(end, size, size); 89 | } 90 | 91 | function resolveIndex(index, size, defaultIndex) { 92 | return index === undefined ? 93 | defaultIndex : 94 | index < 0 ? 95 | Math.max(0, size + index) : 96 | size === undefined ? 97 | index : 98 | Math.min(size, index); 99 | } 100 | 101 | function Iterable(value) { 102 | return isIterable(value) ? value : Seq(value); 103 | } 104 | 105 | 106 | createClass(KeyedIterable, Iterable); 107 | function KeyedIterable(value) { 108 | return isKeyed(value) ? value : KeyedSeq(value); 109 | } 110 | 111 | 112 | createClass(IndexedIterable, Iterable); 113 | function IndexedIterable(value) { 114 | return isIndexed(value) ? value : IndexedSeq(value); 115 | } 116 | 117 | 118 | createClass(SetIterable, Iterable); 119 | function SetIterable(value) { 120 | return isIterable(value) && !isAssociative(value) ? value : SetSeq(value); 121 | } 122 | 123 | 124 | 125 | function isIterable(maybeIterable) { 126 | return !!(maybeIterable && maybeIterable[IS_ITERABLE_SENTINEL]); 127 | } 128 | 129 | function isKeyed(maybeKeyed) { 130 | return !!(maybeKeyed && maybeKeyed[IS_KEYED_SENTINEL]); 131 | } 132 | 133 | function isIndexed(maybeIndexed) { 134 | return !!(maybeIndexed && maybeIndexed[IS_INDEXED_SENTINEL]); 135 | } 136 | 137 | function isAssociative(maybeAssociative) { 138 | return isKeyed(maybeAssociative) || isIndexed(maybeAssociative); 139 | } 140 | 141 | function isOrdered(maybeOrdered) { 142 | return !!(maybeOrdered && maybeOrdered[IS_ORDERED_SENTINEL]); 143 | } 144 | 145 | Iterable.isIterable = isIterable; 146 | Iterable.isKeyed = isKeyed; 147 | Iterable.isIndexed = isIndexed; 148 | Iterable.isAssociative = isAssociative; 149 | Iterable.isOrdered = isOrdered; 150 | 151 | Iterable.Keyed = KeyedIterable; 152 | Iterable.Indexed = IndexedIterable; 153 | Iterable.Set = SetIterable; 154 | 155 | 156 | var IS_ITERABLE_SENTINEL = '@@__IMMUTABLE_ITERABLE__@@'; 157 | var IS_KEYED_SENTINEL = '@@__IMMUTABLE_KEYED__@@'; 158 | var IS_INDEXED_SENTINEL = '@@__IMMUTABLE_INDEXED__@@'; 159 | var IS_ORDERED_SENTINEL = '@@__IMMUTABLE_ORDERED__@@'; 160 | 161 | /* global Symbol */ 162 | 163 | var ITERATE_KEYS = 0; 164 | var ITERATE_VALUES = 1; 165 | var ITERATE_ENTRIES = 2; 166 | 167 | var REAL_ITERATOR_SYMBOL = typeof Symbol === 'function' && Symbol.iterator; 168 | var FAUX_ITERATOR_SYMBOL = '@@iterator'; 169 | 170 | var ITERATOR_SYMBOL = REAL_ITERATOR_SYMBOL || FAUX_ITERATOR_SYMBOL; 171 | 172 | 173 | function src_Iterator__Iterator(next) { 174 | this.next = next; 175 | } 176 | 177 | src_Iterator__Iterator.prototype.toString = function() { 178 | return '[Iterator]'; 179 | }; 180 | 181 | 182 | src_Iterator__Iterator.KEYS = ITERATE_KEYS; 183 | src_Iterator__Iterator.VALUES = ITERATE_VALUES; 184 | src_Iterator__Iterator.ENTRIES = ITERATE_ENTRIES; 185 | 186 | src_Iterator__Iterator.prototype.inspect = 187 | src_Iterator__Iterator.prototype.toSource = function () { return this.toString(); } 188 | src_Iterator__Iterator.prototype[ITERATOR_SYMBOL] = function () { 189 | return this; 190 | }; 191 | 192 | 193 | function iteratorValue(type, k, v, iteratorResult) { 194 | var value = type === 0 ? k : type === 1 ? v : [k, v]; 195 | iteratorResult ? (iteratorResult.value = value) : (iteratorResult = { 196 | value: value, done: false 197 | }); 198 | return iteratorResult; 199 | } 200 | 201 | function iteratorDone() { 202 | return { value: undefined, done: true }; 203 | } 204 | 205 | function hasIterator(maybeIterable) { 206 | return !!getIteratorFn(maybeIterable); 207 | } 208 | 209 | function isIterator(maybeIterator) { 210 | return maybeIterator && typeof maybeIterator.next === 'function'; 211 | } 212 | 213 | function getIterator(iterable) { 214 | var iteratorFn = getIteratorFn(iterable); 215 | return iteratorFn && iteratorFn.call(iterable); 216 | } 217 | 218 | function getIteratorFn(iterable) { 219 | var iteratorFn = iterable && ( 220 | (REAL_ITERATOR_SYMBOL && iterable[REAL_ITERATOR_SYMBOL]) || 221 | iterable[FAUX_ITERATOR_SYMBOL] 222 | ); 223 | if (typeof iteratorFn === 'function') { 224 | return iteratorFn; 225 | } 226 | } 227 | 228 | function isArrayLike(value) { 229 | return value && typeof value.length === 'number'; 230 | } 231 | 232 | createClass(Seq, Iterable); 233 | function Seq(value) { 234 | return value === null || value === undefined ? emptySequence() : 235 | isIterable(value) ? value.toSeq() : seqFromValue(value); 236 | } 237 | 238 | Seq.of = function(/*...values*/) { 239 | return Seq(arguments); 240 | }; 241 | 242 | Seq.prototype.toSeq = function() { 243 | return this; 244 | }; 245 | 246 | Seq.prototype.toString = function() { 247 | return this.__toString('Seq {', '}'); 248 | }; 249 | 250 | Seq.prototype.cacheResult = function() { 251 | if (!this._cache && this.__iterateUncached) { 252 | this._cache = this.entrySeq().toArray(); 253 | this.size = this._cache.length; 254 | } 255 | return this; 256 | }; 257 | 258 | // abstract __iterateUncached(fn, reverse) 259 | 260 | Seq.prototype.__iterate = function(fn, reverse) { 261 | return seqIterate(this, fn, reverse, true); 262 | }; 263 | 264 | // abstract __iteratorUncached(type, reverse) 265 | 266 | Seq.prototype.__iterator = function(type, reverse) { 267 | return seqIterator(this, type, reverse, true); 268 | }; 269 | 270 | 271 | 272 | createClass(KeyedSeq, Seq); 273 | function KeyedSeq(value) { 274 | return value === null || value === undefined ? 275 | emptySequence().toKeyedSeq() : 276 | isIterable(value) ? 277 | (isKeyed(value) ? value.toSeq() : value.fromEntrySeq()) : 278 | keyedSeqFromValue(value); 279 | } 280 | 281 | KeyedSeq.prototype.toKeyedSeq = function() { 282 | return this; 283 | }; 284 | 285 | 286 | 287 | createClass(IndexedSeq, Seq); 288 | function IndexedSeq(value) { 289 | return value === null || value === undefined ? emptySequence() : 290 | !isIterable(value) ? indexedSeqFromValue(value) : 291 | isKeyed(value) ? value.entrySeq() : value.toIndexedSeq(); 292 | } 293 | 294 | IndexedSeq.of = function(/*...values*/) { 295 | return IndexedSeq(arguments); 296 | }; 297 | 298 | IndexedSeq.prototype.toIndexedSeq = function() { 299 | return this; 300 | }; 301 | 302 | IndexedSeq.prototype.toString = function() { 303 | return this.__toString('Seq [', ']'); 304 | }; 305 | 306 | IndexedSeq.prototype.__iterate = function(fn, reverse) { 307 | return seqIterate(this, fn, reverse, false); 308 | }; 309 | 310 | IndexedSeq.prototype.__iterator = function(type, reverse) { 311 | return seqIterator(this, type, reverse, false); 312 | }; 313 | 314 | 315 | 316 | createClass(SetSeq, Seq); 317 | function SetSeq(value) { 318 | return ( 319 | value === null || value === undefined ? emptySequence() : 320 | !isIterable(value) ? indexedSeqFromValue(value) : 321 | isKeyed(value) ? value.entrySeq() : value 322 | ).toSetSeq(); 323 | } 324 | 325 | SetSeq.of = function(/*...values*/) { 326 | return SetSeq(arguments); 327 | }; 328 | 329 | SetSeq.prototype.toSetSeq = function() { 330 | return this; 331 | }; 332 | 333 | 334 | 335 | Seq.isSeq = isSeq; 336 | Seq.Keyed = KeyedSeq; 337 | Seq.Set = SetSeq; 338 | Seq.Indexed = IndexedSeq; 339 | 340 | var IS_SEQ_SENTINEL = '@@__IMMUTABLE_SEQ__@@'; 341 | 342 | Seq.prototype[IS_SEQ_SENTINEL] = true; 343 | 344 | 345 | 346 | // #pragma Root Sequences 347 | 348 | createClass(ArraySeq, IndexedSeq); 349 | function ArraySeq(array) { 350 | this._array = array; 351 | this.size = array.length; 352 | } 353 | 354 | ArraySeq.prototype.get = function(index, notSetValue) { 355 | return this.has(index) ? this._array[wrapIndex(this, index)] : notSetValue; 356 | }; 357 | 358 | ArraySeq.prototype.__iterate = function(fn, reverse) { 359 | var array = this._array; 360 | var maxIndex = array.length - 1; 361 | for (var ii = 0; ii <= maxIndex; ii++) { 362 | if (fn(array[reverse ? maxIndex - ii : ii], ii, this) === false) { 363 | return ii + 1; 364 | } 365 | } 366 | return ii; 367 | }; 368 | 369 | ArraySeq.prototype.__iterator = function(type, reverse) { 370 | var array = this._array; 371 | var maxIndex = array.length - 1; 372 | var ii = 0; 373 | return new src_Iterator__Iterator(function() 374 | {return ii > maxIndex ? 375 | iteratorDone() : 376 | iteratorValue(type, ii, array[reverse ? maxIndex - ii++ : ii++])} 377 | ); 378 | }; 379 | 380 | 381 | 382 | createClass(ObjectSeq, KeyedSeq); 383 | function ObjectSeq(object) { 384 | var keys = Object.keys(object); 385 | this._object = object; 386 | this._keys = keys; 387 | this.size = keys.length; 388 | } 389 | 390 | ObjectSeq.prototype.get = function(key, notSetValue) { 391 | if (notSetValue !== undefined && !this.has(key)) { 392 | return notSetValue; 393 | } 394 | return this._object[key]; 395 | }; 396 | 397 | ObjectSeq.prototype.has = function(key) { 398 | return this._object.hasOwnProperty(key); 399 | }; 400 | 401 | ObjectSeq.prototype.__iterate = function(fn, reverse) { 402 | var object = this._object; 403 | var keys = this._keys; 404 | var maxIndex = keys.length - 1; 405 | for (var ii = 0; ii <= maxIndex; ii++) { 406 | var key = keys[reverse ? maxIndex - ii : ii]; 407 | if (fn(object[key], key, this) === false) { 408 | return ii + 1; 409 | } 410 | } 411 | return ii; 412 | }; 413 | 414 | ObjectSeq.prototype.__iterator = function(type, reverse) { 415 | var object = this._object; 416 | var keys = this._keys; 417 | var maxIndex = keys.length - 1; 418 | var ii = 0; 419 | return new src_Iterator__Iterator(function() { 420 | var key = keys[reverse ? maxIndex - ii : ii]; 421 | return ii++ > maxIndex ? 422 | iteratorDone() : 423 | iteratorValue(type, key, object[key]); 424 | }); 425 | }; 426 | 427 | ObjectSeq.prototype[IS_ORDERED_SENTINEL] = true; 428 | 429 | 430 | createClass(IterableSeq, IndexedSeq); 431 | function IterableSeq(iterable) { 432 | this._iterable = iterable; 433 | this.size = iterable.length || iterable.size; 434 | } 435 | 436 | IterableSeq.prototype.__iterateUncached = function(fn, reverse) { 437 | if (reverse) { 438 | return this.cacheResult().__iterate(fn, reverse); 439 | } 440 | var iterable = this._iterable; 441 | var iterator = getIterator(iterable); 442 | var iterations = 0; 443 | if (isIterator(iterator)) { 444 | var step; 445 | while (!(step = iterator.next()).done) { 446 | if (fn(step.value, iterations++, this) === false) { 447 | break; 448 | } 449 | } 450 | } 451 | return iterations; 452 | }; 453 | 454 | IterableSeq.prototype.__iteratorUncached = function(type, reverse) { 455 | if (reverse) { 456 | return this.cacheResult().__iterator(type, reverse); 457 | } 458 | var iterable = this._iterable; 459 | var iterator = getIterator(iterable); 460 | if (!isIterator(iterator)) { 461 | return new src_Iterator__Iterator(iteratorDone); 462 | } 463 | var iterations = 0; 464 | return new src_Iterator__Iterator(function() { 465 | var step = iterator.next(); 466 | return step.done ? step : iteratorValue(type, iterations++, step.value); 467 | }); 468 | }; 469 | 470 | 471 | 472 | createClass(IteratorSeq, IndexedSeq); 473 | function IteratorSeq(iterator) { 474 | this._iterator = iterator; 475 | this._iteratorCache = []; 476 | } 477 | 478 | IteratorSeq.prototype.__iterateUncached = function(fn, reverse) { 479 | if (reverse) { 480 | return this.cacheResult().__iterate(fn, reverse); 481 | } 482 | var iterator = this._iterator; 483 | var cache = this._iteratorCache; 484 | var iterations = 0; 485 | while (iterations < cache.length) { 486 | if (fn(cache[iterations], iterations++, this) === false) { 487 | return iterations; 488 | } 489 | } 490 | var step; 491 | while (!(step = iterator.next()).done) { 492 | var val = step.value; 493 | cache[iterations] = val; 494 | if (fn(val, iterations++, this) === false) { 495 | break; 496 | } 497 | } 498 | return iterations; 499 | }; 500 | 501 | IteratorSeq.prototype.__iteratorUncached = function(type, reverse) { 502 | if (reverse) { 503 | return this.cacheResult().__iterator(type, reverse); 504 | } 505 | var iterator = this._iterator; 506 | var cache = this._iteratorCache; 507 | var iterations = 0; 508 | return new src_Iterator__Iterator(function() { 509 | if (iterations >= cache.length) { 510 | var step = iterator.next(); 511 | if (step.done) { 512 | return step; 513 | } 514 | cache[iterations] = step.value; 515 | } 516 | return iteratorValue(type, iterations, cache[iterations++]); 517 | }); 518 | }; 519 | 520 | 521 | 522 | 523 | // # pragma Helper functions 524 | 525 | function isSeq(maybeSeq) { 526 | return !!(maybeSeq && maybeSeq[IS_SEQ_SENTINEL]); 527 | } 528 | 529 | var EMPTY_SEQ; 530 | 531 | function emptySequence() { 532 | return EMPTY_SEQ || (EMPTY_SEQ = new ArraySeq([])); 533 | } 534 | 535 | function keyedSeqFromValue(value) { 536 | var seq = 537 | Array.isArray(value) ? new ArraySeq(value).fromEntrySeq() : 538 | isIterator(value) ? new IteratorSeq(value).fromEntrySeq() : 539 | hasIterator(value) ? new IterableSeq(value).fromEntrySeq() : 540 | typeof value === 'object' ? new ObjectSeq(value) : 541 | undefined; 542 | if (!seq) { 543 | throw new TypeError( 544 | 'Expected Array or iterable object of [k, v] entries, '+ 545 | 'or keyed object: ' + value 546 | ); 547 | } 548 | return seq; 549 | } 550 | 551 | function indexedSeqFromValue(value) { 552 | var seq = maybeIndexedSeqFromValue(value); 553 | if (!seq) { 554 | throw new TypeError( 555 | 'Expected Array or iterable object of values: ' + value 556 | ); 557 | } 558 | return seq; 559 | } 560 | 561 | function seqFromValue(value) { 562 | var seq = maybeIndexedSeqFromValue(value) || 563 | (typeof value === 'object' && new ObjectSeq(value)); 564 | if (!seq) { 565 | throw new TypeError( 566 | 'Expected Array or iterable object of values, or keyed object: ' + value 567 | ); 568 | } 569 | return seq; 570 | } 571 | 572 | function maybeIndexedSeqFromValue(value) { 573 | return ( 574 | isArrayLike(value) ? new ArraySeq(value) : 575 | isIterator(value) ? new IteratorSeq(value) : 576 | hasIterator(value) ? new IterableSeq(value) : 577 | undefined 578 | ); 579 | } 580 | 581 | function seqIterate(seq, fn, reverse, useKeys) { 582 | var cache = seq._cache; 583 | if (cache) { 584 | var maxIndex = cache.length - 1; 585 | for (var ii = 0; ii <= maxIndex; ii++) { 586 | var entry = cache[reverse ? maxIndex - ii : ii]; 587 | if (fn(entry[1], useKeys ? entry[0] : ii, seq) === false) { 588 | return ii + 1; 589 | } 590 | } 591 | return ii; 592 | } 593 | return seq.__iterateUncached(fn, reverse); 594 | } 595 | 596 | function seqIterator(seq, type, reverse, useKeys) { 597 | var cache = seq._cache; 598 | if (cache) { 599 | var maxIndex = cache.length - 1; 600 | var ii = 0; 601 | return new src_Iterator__Iterator(function() { 602 | var entry = cache[reverse ? maxIndex - ii : ii]; 603 | return ii++ > maxIndex ? 604 | iteratorDone() : 605 | iteratorValue(type, useKeys ? entry[0] : ii - 1, entry[1]); 606 | }); 607 | } 608 | return seq.__iteratorUncached(type, reverse); 609 | } 610 | 611 | createClass(Collection, Iterable); 612 | function Collection() { 613 | throw TypeError('Abstract'); 614 | } 615 | 616 | 617 | createClass(KeyedCollection, Collection);function KeyedCollection() {} 618 | 619 | createClass(IndexedCollection, Collection);function IndexedCollection() {} 620 | 621 | createClass(SetCollection, Collection);function SetCollection() {} 622 | 623 | 624 | Collection.Keyed = KeyedCollection; 625 | Collection.Indexed = IndexedCollection; 626 | Collection.Set = SetCollection; 627 | 628 | /** 629 | * An extension of the "same-value" algorithm as [described for use by ES6 Map 630 | * and Set](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map#Key_equality) 631 | * 632 | * NaN is considered the same as NaN, however -0 and 0 are considered the same 633 | * value, which is different from the algorithm described by 634 | * [`Object.is`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is). 635 | * 636 | * This is extended further to allow Objects to describe the values they 637 | * represent, by way of `valueOf` or `equals` (and `hashCode`). 638 | * 639 | * Note: because of this extension, the key equality of Immutable.Map and the 640 | * value equality of Immutable.Set will differ from ES6 Map and Set. 641 | * 642 | * ### Defining custom values 643 | * 644 | * The easiest way to describe the value an object represents is by implementing 645 | * `valueOf`. For example, `Date` represents a value by returning a unix 646 | * timestamp for `valueOf`: 647 | * 648 | * var date1 = new Date(1234567890000); // Fri Feb 13 2009 ... 649 | * var date2 = new Date(1234567890000); 650 | * date1.valueOf(); // 1234567890000 651 | * assert( date1 !== date2 ); 652 | * assert( Immutable.is( date1, date2 ) ); 653 | * 654 | * Note: overriding `valueOf` may have other implications if you use this object 655 | * where JavaScript expects a primitive, such as implicit string coercion. 656 | * 657 | * For more complex types, especially collections, implementing `valueOf` may 658 | * not be performant. An alternative is to implement `equals` and `hashCode`. 659 | * 660 | * `equals` takes another object, presumably of similar type, and returns true 661 | * if the it is equal. Equality is symmetrical, so the same result should be 662 | * returned if this and the argument are flipped. 663 | * 664 | * assert( a.equals(b) === b.equals(a) ); 665 | * 666 | * `hashCode` returns a 32bit integer number representing the object which will 667 | * be used to determine how to store the value object in a Map or Set. You must 668 | * provide both or neither methods, one must not exist without the other. 669 | * 670 | * Also, an important relationship between these methods must be upheld: if two 671 | * values are equal, they *must* return the same hashCode. If the values are not 672 | * equal, they might have the same hashCode; this is called a hash collision, 673 | * and while undesirable for performance reasons, it is acceptable. 674 | * 675 | * if (a.equals(b)) { 676 | * assert( a.hashCode() === b.hashCode() ); 677 | * } 678 | * 679 | * All Immutable collections implement `equals` and `hashCode`. 680 | * 681 | */ 682 | function is(valueA, valueB) { 683 | if (valueA === valueB || (valueA !== valueA && valueB !== valueB)) { 684 | return true; 685 | } 686 | if (!valueA || !valueB) { 687 | return false; 688 | } 689 | if (typeof valueA.valueOf === 'function' && 690 | typeof valueB.valueOf === 'function') { 691 | valueA = valueA.valueOf(); 692 | valueB = valueB.valueOf(); 693 | if (valueA === valueB || (valueA !== valueA && valueB !== valueB)) { 694 | return true; 695 | } 696 | if (!valueA || !valueB) { 697 | return false; 698 | } 699 | } 700 | if (typeof valueA.equals === 'function' && 701 | typeof valueB.equals === 'function' && 702 | valueA.equals(valueB)) { 703 | return true; 704 | } 705 | return false; 706 | } 707 | 708 | function fromJS(json, converter) { 709 | return converter ? 710 | fromJSWith(converter, json, '', {'': json}) : 711 | fromJSDefault(json); 712 | } 713 | 714 | function fromJSWith(converter, json, key, parentJSON) { 715 | if (Array.isArray(json)) { 716 | return converter.call(parentJSON, key, IndexedSeq(json).map(function(v, k) {return fromJSWith(converter, v, k, json)})); 717 | } 718 | if (isPlainObj(json)) { 719 | return converter.call(parentJSON, key, KeyedSeq(json).map(function(v, k) {return fromJSWith(converter, v, k, json)})); 720 | } 721 | return json; 722 | } 723 | 724 | function fromJSDefault(json) { 725 | if (Array.isArray(json)) { 726 | return IndexedSeq(json).map(fromJSDefault).toList(); 727 | } 728 | if (isPlainObj(json)) { 729 | return KeyedSeq(json).map(fromJSDefault).toMap(); 730 | } 731 | return json; 732 | } 733 | 734 | function isPlainObj(value) { 735 | return value && (value.constructor === Object || value.constructor === undefined); 736 | } 737 | 738 | var src_Math__imul = 739 | typeof Math.imul === 'function' && Math.imul(0xffffffff, 2) === -2 ? 740 | Math.imul : 741 | function imul(a, b) { 742 | a = a | 0; // int 743 | b = b | 0; // int 744 | var c = a & 0xffff; 745 | var d = b & 0xffff; 746 | // Shift by 0 fixes the sign on the high part. 747 | return (c * d) + ((((a >>> 16) * d + c * (b >>> 16)) << 16) >>> 0) | 0; // int 748 | }; 749 | 750 | // v8 has an optimization for storing 31-bit signed numbers. 751 | // Values which have either 00 or 11 as the high order bits qualify. 752 | // This function drops the highest order bit in a signed number, maintaining 753 | // the sign bit. 754 | function smi(i32) { 755 | return ((i32 >>> 1) & 0x40000000) | (i32 & 0xBFFFFFFF); 756 | } 757 | 758 | function hash(o) { 759 | if (o === false || o === null || o === undefined) { 760 | return 0; 761 | } 762 | if (typeof o.valueOf === 'function') { 763 | o = o.valueOf(); 764 | if (o === false || o === null || o === undefined) { 765 | return 0; 766 | } 767 | } 768 | if (o === true) { 769 | return 1; 770 | } 771 | var type = typeof o; 772 | if (type === 'number') { 773 | var h = o | 0; 774 | if (h !== o) { 775 | h ^= o * 0xFFFFFFFF; 776 | } 777 | while (o > 0xFFFFFFFF) { 778 | o /= 0xFFFFFFFF; 779 | h ^= o; 780 | } 781 | return smi(h); 782 | } 783 | if (type === 'string') { 784 | return o.length > STRING_HASH_CACHE_MIN_STRLEN ? cachedHashString(o) : hashString(o); 785 | } 786 | if (typeof o.hashCode === 'function') { 787 | return o.hashCode(); 788 | } 789 | return hashJSObj(o); 790 | } 791 | 792 | function cachedHashString(string) { 793 | var hash = stringHashCache[string]; 794 | if (hash === undefined) { 795 | hash = hashString(string); 796 | if (STRING_HASH_CACHE_SIZE === STRING_HASH_CACHE_MAX_SIZE) { 797 | STRING_HASH_CACHE_SIZE = 0; 798 | stringHashCache = {}; 799 | } 800 | STRING_HASH_CACHE_SIZE++; 801 | stringHashCache[string] = hash; 802 | } 803 | return hash; 804 | } 805 | 806 | // http://jsperf.com/hashing-strings 807 | function hashString(string) { 808 | // This is the hash from JVM 809 | // The hash code for a string is computed as 810 | // s[0] * 31 ^ (n - 1) + s[1] * 31 ^ (n - 2) + ... + s[n - 1], 811 | // where s[i] is the ith character of the string and n is the length of 812 | // the string. We "mod" the result to make it between 0 (inclusive) and 2^31 813 | // (exclusive) by dropping high bits. 814 | var hash = 0; 815 | for (var ii = 0; ii < string.length; ii++) { 816 | hash = 31 * hash + string.charCodeAt(ii) | 0; 817 | } 818 | return smi(hash); 819 | } 820 | 821 | function hashJSObj(obj) { 822 | var hash; 823 | if (usingWeakMap) { 824 | hash = weakMap.get(obj); 825 | if (hash !== undefined) { 826 | return hash; 827 | } 828 | } 829 | 830 | hash = obj[UID_HASH_KEY]; 831 | if (hash !== undefined) { 832 | return hash; 833 | } 834 | 835 | if (!canDefineProperty) { 836 | hash = obj.propertyIsEnumerable && obj.propertyIsEnumerable[UID_HASH_KEY]; 837 | if (hash !== undefined) { 838 | return hash; 839 | } 840 | 841 | hash = getIENodeHash(obj); 842 | if (hash !== undefined) { 843 | return hash; 844 | } 845 | } 846 | 847 | hash = ++objHashUID; 848 | if (objHashUID & 0x40000000) { 849 | objHashUID = 0; 850 | } 851 | 852 | if (usingWeakMap) { 853 | weakMap.set(obj, hash); 854 | } else if (isExtensible !== undefined && isExtensible(obj) === false) { 855 | throw new Error('Non-extensible objects are not allowed as keys.'); 856 | } else if (canDefineProperty) { 857 | Object.defineProperty(obj, UID_HASH_KEY, { 858 | 'enumerable': false, 859 | 'configurable': false, 860 | 'writable': false, 861 | 'value': hash 862 | }); 863 | } else if (obj.propertyIsEnumerable !== undefined && 864 | obj.propertyIsEnumerable === obj.constructor.prototype.propertyIsEnumerable) { 865 | // Since we can't define a non-enumerable property on the object 866 | // we'll hijack one of the less-used non-enumerable properties to 867 | // save our hash on it. Since this is a function it will not show up in 868 | // `JSON.stringify` which is what we want. 869 | obj.propertyIsEnumerable = function() { 870 | return this.constructor.prototype.propertyIsEnumerable.apply(this, arguments); 871 | }; 872 | obj.propertyIsEnumerable[UID_HASH_KEY] = hash; 873 | } else if (obj.nodeType !== undefined) { 874 | // At this point we couldn't get the IE `uniqueID` to use as a hash 875 | // and we couldn't use a non-enumerable property to exploit the 876 | // dontEnum bug so we simply add the `UID_HASH_KEY` on the node 877 | // itself. 878 | obj[UID_HASH_KEY] = hash; 879 | } else { 880 | throw new Error('Unable to set a non-enumerable property on object.'); 881 | } 882 | 883 | return hash; 884 | } 885 | 886 | // Get references to ES5 object methods. 887 | var isExtensible = Object.isExtensible; 888 | 889 | // True if Object.defineProperty works as expected. IE8 fails this test. 890 | var canDefineProperty = (function() { 891 | try { 892 | Object.defineProperty({}, '@', {}); 893 | return true; 894 | } catch (e) { 895 | return false; 896 | } 897 | }()); 898 | 899 | // IE has a `uniqueID` property on DOM nodes. We can construct the hash from it 900 | // and avoid memory leaks from the IE cloneNode bug. 901 | function getIENodeHash(node) { 902 | if (node && node.nodeType > 0) { 903 | switch (node.nodeType) { 904 | case 1: // Element 905 | return node.uniqueID; 906 | case 9: // Document 907 | return node.documentElement && node.documentElement.uniqueID; 908 | } 909 | } 910 | } 911 | 912 | // If possible, use a WeakMap. 913 | var usingWeakMap = typeof WeakMap === 'function'; 914 | var weakMap; 915 | if (usingWeakMap) { 916 | weakMap = new WeakMap(); 917 | } 918 | 919 | var objHashUID = 0; 920 | 921 | var UID_HASH_KEY = '__immutablehash__'; 922 | if (typeof Symbol === 'function') { 923 | UID_HASH_KEY = Symbol(UID_HASH_KEY); 924 | } 925 | 926 | var STRING_HASH_CACHE_MIN_STRLEN = 16; 927 | var STRING_HASH_CACHE_MAX_SIZE = 255; 928 | var STRING_HASH_CACHE_SIZE = 0; 929 | var stringHashCache = {}; 930 | 931 | function invariant(condition, error) { 932 | if (!condition) throw new Error(error); 933 | } 934 | 935 | function assertNotInfinite(size) { 936 | invariant( 937 | size !== Infinity, 938 | 'Cannot perform this action with an infinite size.' 939 | ); 940 | } 941 | 942 | createClass(ToKeyedSequence, KeyedSeq); 943 | function ToKeyedSequence(indexed, useKeys) { 944 | this._iter = indexed; 945 | this._useKeys = useKeys; 946 | this.size = indexed.size; 947 | } 948 | 949 | ToKeyedSequence.prototype.get = function(key, notSetValue) { 950 | return this._iter.get(key, notSetValue); 951 | }; 952 | 953 | ToKeyedSequence.prototype.has = function(key) { 954 | return this._iter.has(key); 955 | }; 956 | 957 | ToKeyedSequence.prototype.valueSeq = function() { 958 | return this._iter.valueSeq(); 959 | }; 960 | 961 | ToKeyedSequence.prototype.reverse = function() {var this$0 = this; 962 | var reversedSequence = reverseFactory(this, true); 963 | if (!this._useKeys) { 964 | reversedSequence.valueSeq = function() {return this$0._iter.toSeq().reverse()}; 965 | } 966 | return reversedSequence; 967 | }; 968 | 969 | ToKeyedSequence.prototype.map = function(mapper, context) {var this$0 = this; 970 | var mappedSequence = mapFactory(this, mapper, context); 971 | if (!this._useKeys) { 972 | mappedSequence.valueSeq = function() {return this$0._iter.toSeq().map(mapper, context)}; 973 | } 974 | return mappedSequence; 975 | }; 976 | 977 | ToKeyedSequence.prototype.__iterate = function(fn, reverse) {var this$0 = this; 978 | var ii; 979 | return this._iter.__iterate( 980 | this._useKeys ? 981 | function(v, k) {return fn(v, k, this$0)} : 982 | ((ii = reverse ? resolveSize(this) : 0), 983 | function(v ) {return fn(v, reverse ? --ii : ii++, this$0)}), 984 | reverse 985 | ); 986 | }; 987 | 988 | ToKeyedSequence.prototype.__iterator = function(type, reverse) { 989 | if (this._useKeys) { 990 | return this._iter.__iterator(type, reverse); 991 | } 992 | var iterator = this._iter.__iterator(ITERATE_VALUES, reverse); 993 | var ii = reverse ? resolveSize(this) : 0; 994 | return new src_Iterator__Iterator(function() { 995 | var step = iterator.next(); 996 | return step.done ? step : 997 | iteratorValue(type, reverse ? --ii : ii++, step.value, step); 998 | }); 999 | }; 1000 | 1001 | ToKeyedSequence.prototype[IS_ORDERED_SENTINEL] = true; 1002 | 1003 | 1004 | createClass(ToIndexedSequence, IndexedSeq); 1005 | function ToIndexedSequence(iter) { 1006 | this._iter = iter; 1007 | this.size = iter.size; 1008 | } 1009 | 1010 | ToIndexedSequence.prototype.includes = function(value) { 1011 | return this._iter.includes(value); 1012 | }; 1013 | 1014 | ToIndexedSequence.prototype.__iterate = function(fn, reverse) {var this$0 = this; 1015 | var iterations = 0; 1016 | return this._iter.__iterate(function(v ) {return fn(v, iterations++, this$0)}, reverse); 1017 | }; 1018 | 1019 | ToIndexedSequence.prototype.__iterator = function(type, reverse) { 1020 | var iterator = this._iter.__iterator(ITERATE_VALUES, reverse); 1021 | var iterations = 0; 1022 | return new src_Iterator__Iterator(function() { 1023 | var step = iterator.next(); 1024 | return step.done ? step : 1025 | iteratorValue(type, iterations++, step.value, step) 1026 | }); 1027 | }; 1028 | 1029 | 1030 | 1031 | createClass(ToSetSequence, SetSeq); 1032 | function ToSetSequence(iter) { 1033 | this._iter = iter; 1034 | this.size = iter.size; 1035 | } 1036 | 1037 | ToSetSequence.prototype.has = function(key) { 1038 | return this._iter.includes(key); 1039 | }; 1040 | 1041 | ToSetSequence.prototype.__iterate = function(fn, reverse) {var this$0 = this; 1042 | return this._iter.__iterate(function(v ) {return fn(v, v, this$0)}, reverse); 1043 | }; 1044 | 1045 | ToSetSequence.prototype.__iterator = function(type, reverse) { 1046 | var iterator = this._iter.__iterator(ITERATE_VALUES, reverse); 1047 | return new src_Iterator__Iterator(function() { 1048 | var step = iterator.next(); 1049 | return step.done ? step : 1050 | iteratorValue(type, step.value, step.value, step); 1051 | }); 1052 | }; 1053 | 1054 | 1055 | 1056 | createClass(FromEntriesSequence, KeyedSeq); 1057 | function FromEntriesSequence(entries) { 1058 | this._iter = entries; 1059 | this.size = entries.size; 1060 | } 1061 | 1062 | FromEntriesSequence.prototype.entrySeq = function() { 1063 | return this._iter.toSeq(); 1064 | }; 1065 | 1066 | FromEntriesSequence.prototype.__iterate = function(fn, reverse) {var this$0 = this; 1067 | return this._iter.__iterate(function(entry ) { 1068 | // Check if entry exists first so array access doesn't throw for holes 1069 | // in the parent iteration. 1070 | if (entry) { 1071 | validateEntry(entry); 1072 | var indexedIterable = isIterable(entry); 1073 | return fn( 1074 | indexedIterable ? entry.get(1) : entry[1], 1075 | indexedIterable ? entry.get(0) : entry[0], 1076 | this$0 1077 | ); 1078 | } 1079 | }, reverse); 1080 | }; 1081 | 1082 | FromEntriesSequence.prototype.__iterator = function(type, reverse) { 1083 | var iterator = this._iter.__iterator(ITERATE_VALUES, reverse); 1084 | return new src_Iterator__Iterator(function() { 1085 | while (true) { 1086 | var step = iterator.next(); 1087 | if (step.done) { 1088 | return step; 1089 | } 1090 | var entry = step.value; 1091 | // Check if entry exists first so array access doesn't throw for holes 1092 | // in the parent iteration. 1093 | if (entry) { 1094 | validateEntry(entry); 1095 | var indexedIterable = isIterable(entry); 1096 | return iteratorValue( 1097 | type, 1098 | indexedIterable ? entry.get(0) : entry[0], 1099 | indexedIterable ? entry.get(1) : entry[1], 1100 | step 1101 | ); 1102 | } 1103 | } 1104 | }); 1105 | }; 1106 | 1107 | 1108 | ToIndexedSequence.prototype.cacheResult = 1109 | ToKeyedSequence.prototype.cacheResult = 1110 | ToSetSequence.prototype.cacheResult = 1111 | FromEntriesSequence.prototype.cacheResult = 1112 | cacheResultThrough; 1113 | 1114 | 1115 | function flipFactory(iterable) { 1116 | var flipSequence = makeSequence(iterable); 1117 | flipSequence._iter = iterable; 1118 | flipSequence.size = iterable.size; 1119 | flipSequence.flip = function() {return iterable}; 1120 | flipSequence.reverse = function () { 1121 | var reversedSequence = iterable.reverse.apply(this); // super.reverse() 1122 | reversedSequence.flip = function() {return iterable.reverse()}; 1123 | return reversedSequence; 1124 | }; 1125 | flipSequence.has = function(key ) {return iterable.includes(key)}; 1126 | flipSequence.includes = function(key ) {return iterable.has(key)}; 1127 | flipSequence.cacheResult = cacheResultThrough; 1128 | flipSequence.__iterateUncached = function (fn, reverse) {var this$0 = this; 1129 | return iterable.__iterate(function(v, k) {return fn(k, v, this$0) !== false}, reverse); 1130 | } 1131 | flipSequence.__iteratorUncached = function(type, reverse) { 1132 | if (type === ITERATE_ENTRIES) { 1133 | var iterator = iterable.__iterator(type, reverse); 1134 | return new src_Iterator__Iterator(function() { 1135 | var step = iterator.next(); 1136 | if (!step.done) { 1137 | var k = step.value[0]; 1138 | step.value[0] = step.value[1]; 1139 | step.value[1] = k; 1140 | } 1141 | return step; 1142 | }); 1143 | } 1144 | return iterable.__iterator( 1145 | type === ITERATE_VALUES ? ITERATE_KEYS : ITERATE_VALUES, 1146 | reverse 1147 | ); 1148 | } 1149 | return flipSequence; 1150 | } 1151 | 1152 | 1153 | function mapFactory(iterable, mapper, context) { 1154 | var mappedSequence = makeSequence(iterable); 1155 | mappedSequence.size = iterable.size; 1156 | mappedSequence.has = function(key ) {return iterable.has(key)}; 1157 | mappedSequence.get = function(key, notSetValue) { 1158 | var v = iterable.get(key, NOT_SET); 1159 | return v === NOT_SET ? 1160 | notSetValue : 1161 | mapper.call(context, v, key, iterable); 1162 | }; 1163 | mappedSequence.__iterateUncached = function (fn, reverse) {var this$0 = this; 1164 | return iterable.__iterate( 1165 | function(v, k, c) {return fn(mapper.call(context, v, k, c), k, this$0) !== false}, 1166 | reverse 1167 | ); 1168 | } 1169 | mappedSequence.__iteratorUncached = function (type, reverse) { 1170 | var iterator = iterable.__iterator(ITERATE_ENTRIES, reverse); 1171 | return new src_Iterator__Iterator(function() { 1172 | var step = iterator.next(); 1173 | if (step.done) { 1174 | return step; 1175 | } 1176 | var entry = step.value; 1177 | var key = entry[0]; 1178 | return iteratorValue( 1179 | type, 1180 | key, 1181 | mapper.call(context, entry[1], key, iterable), 1182 | step 1183 | ); 1184 | }); 1185 | } 1186 | return mappedSequence; 1187 | } 1188 | 1189 | 1190 | function reverseFactory(iterable, useKeys) { 1191 | var reversedSequence = makeSequence(iterable); 1192 | reversedSequence._iter = iterable; 1193 | reversedSequence.size = iterable.size; 1194 | reversedSequence.reverse = function() {return iterable}; 1195 | if (iterable.flip) { 1196 | reversedSequence.flip = function () { 1197 | var flipSequence = flipFactory(iterable); 1198 | flipSequence.reverse = function() {return iterable.flip()}; 1199 | return flipSequence; 1200 | }; 1201 | } 1202 | reversedSequence.get = function(key, notSetValue) 1203 | {return iterable.get(useKeys ? key : -1 - key, notSetValue)}; 1204 | reversedSequence.has = function(key ) 1205 | {return iterable.has(useKeys ? key : -1 - key)}; 1206 | reversedSequence.includes = function(value ) {return iterable.includes(value)}; 1207 | reversedSequence.cacheResult = cacheResultThrough; 1208 | reversedSequence.__iterate = function (fn, reverse) {var this$0 = this; 1209 | return iterable.__iterate(function(v, k) {return fn(v, k, this$0)}, !reverse); 1210 | }; 1211 | reversedSequence.__iterator = 1212 | function(type, reverse) {return iterable.__iterator(type, !reverse)}; 1213 | return reversedSequence; 1214 | } 1215 | 1216 | 1217 | function filterFactory(iterable, predicate, context, useKeys) { 1218 | var filterSequence = makeSequence(iterable); 1219 | if (useKeys) { 1220 | filterSequence.has = function(key ) { 1221 | var v = iterable.get(key, NOT_SET); 1222 | return v !== NOT_SET && !!predicate.call(context, v, key, iterable); 1223 | }; 1224 | filterSequence.get = function(key, notSetValue) { 1225 | var v = iterable.get(key, NOT_SET); 1226 | return v !== NOT_SET && predicate.call(context, v, key, iterable) ? 1227 | v : notSetValue; 1228 | }; 1229 | } 1230 | filterSequence.__iterateUncached = function (fn, reverse) {var this$0 = this; 1231 | var iterations = 0; 1232 | iterable.__iterate(function(v, k, c) { 1233 | if (predicate.call(context, v, k, c)) { 1234 | iterations++; 1235 | return fn(v, useKeys ? k : iterations - 1, this$0); 1236 | } 1237 | }, reverse); 1238 | return iterations; 1239 | }; 1240 | filterSequence.__iteratorUncached = function (type, reverse) { 1241 | var iterator = iterable.__iterator(ITERATE_ENTRIES, reverse); 1242 | var iterations = 0; 1243 | return new src_Iterator__Iterator(function() { 1244 | while (true) { 1245 | var step = iterator.next(); 1246 | if (step.done) { 1247 | return step; 1248 | } 1249 | var entry = step.value; 1250 | var key = entry[0]; 1251 | var value = entry[1]; 1252 | if (predicate.call(context, value, key, iterable)) { 1253 | return iteratorValue(type, useKeys ? key : iterations++, value, step); 1254 | } 1255 | } 1256 | }); 1257 | } 1258 | return filterSequence; 1259 | } 1260 | 1261 | 1262 | function countByFactory(iterable, grouper, context) { 1263 | var groups = src_Map__Map().asMutable(); 1264 | iterable.__iterate(function(v, k) { 1265 | groups.update( 1266 | grouper.call(context, v, k, iterable), 1267 | 0, 1268 | function(a ) {return a + 1} 1269 | ); 1270 | }); 1271 | return groups.asImmutable(); 1272 | } 1273 | 1274 | 1275 | function groupByFactory(iterable, grouper, context) { 1276 | var isKeyedIter = isKeyed(iterable); 1277 | var groups = (isOrdered(iterable) ? OrderedMap() : src_Map__Map()).asMutable(); 1278 | iterable.__iterate(function(v, k) { 1279 | groups.update( 1280 | grouper.call(context, v, k, iterable), 1281 | function(a ) {return (a = a || [], a.push(isKeyedIter ? [k, v] : v), a)} 1282 | ); 1283 | }); 1284 | var coerce = iterableClass(iterable); 1285 | return groups.map(function(arr ) {return reify(iterable, coerce(arr))}); 1286 | } 1287 | 1288 | 1289 | function sliceFactory(iterable, begin, end, useKeys) { 1290 | var originalSize = iterable.size; 1291 | 1292 | if (wholeSlice(begin, end, originalSize)) { 1293 | return iterable; 1294 | } 1295 | 1296 | var resolvedBegin = resolveBegin(begin, originalSize); 1297 | var resolvedEnd = resolveEnd(end, originalSize); 1298 | 1299 | // begin or end will be NaN if they were provided as negative numbers and 1300 | // this iterable's size is unknown. In that case, cache first so there is 1301 | // a known size and these do not resolve to NaN. 1302 | if (resolvedBegin !== resolvedBegin || resolvedEnd !== resolvedEnd) { 1303 | return sliceFactory(iterable.toSeq().cacheResult(), begin, end, useKeys); 1304 | } 1305 | 1306 | // Note: resolvedEnd is undefined when the original sequence's length is 1307 | // unknown and this slice did not supply an end and should contain all 1308 | // elements after resolvedBegin. 1309 | // In that case, resolvedSize will be NaN and sliceSize will remain undefined. 1310 | var resolvedSize = resolvedEnd - resolvedBegin; 1311 | var sliceSize; 1312 | if (resolvedSize === resolvedSize) { 1313 | sliceSize = resolvedSize < 0 ? 0 : resolvedSize; 1314 | } 1315 | 1316 | var sliceSeq = makeSequence(iterable); 1317 | 1318 | sliceSeq.size = sliceSize; 1319 | 1320 | if (!useKeys && isSeq(iterable) && sliceSize >= 0) { 1321 | sliceSeq.get = function (index, notSetValue) { 1322 | index = wrapIndex(this, index); 1323 | return index >= 0 && index < sliceSize ? 1324 | iterable.get(index + resolvedBegin, notSetValue) : 1325 | notSetValue; 1326 | } 1327 | } 1328 | 1329 | sliceSeq.__iterateUncached = function(fn, reverse) {var this$0 = this; 1330 | if (sliceSize === 0) { 1331 | return 0; 1332 | } 1333 | if (reverse) { 1334 | return this.cacheResult().__iterate(fn, reverse); 1335 | } 1336 | var skipped = 0; 1337 | var isSkipping = true; 1338 | var iterations = 0; 1339 | iterable.__iterate(function(v, k) { 1340 | if (!(isSkipping && (isSkipping = skipped++ < resolvedBegin))) { 1341 | iterations++; 1342 | return fn(v, useKeys ? k : iterations - 1, this$0) !== false && 1343 | iterations !== sliceSize; 1344 | } 1345 | }); 1346 | return iterations; 1347 | }; 1348 | 1349 | sliceSeq.__iteratorUncached = function(type, reverse) { 1350 | if (sliceSize !== 0 && reverse) { 1351 | return this.cacheResult().__iterator(type, reverse); 1352 | } 1353 | // Don't bother instantiating parent iterator if taking 0. 1354 | var iterator = sliceSize !== 0 && iterable.__iterator(type, reverse); 1355 | var skipped = 0; 1356 | var iterations = 0; 1357 | return new src_Iterator__Iterator(function() { 1358 | while (skipped++ < resolvedBegin) { 1359 | iterator.next(); 1360 | } 1361 | if (++iterations > sliceSize) { 1362 | return iteratorDone(); 1363 | } 1364 | var step = iterator.next(); 1365 | if (useKeys || type === ITERATE_VALUES) { 1366 | return step; 1367 | } else if (type === ITERATE_KEYS) { 1368 | return iteratorValue(type, iterations - 1, undefined, step); 1369 | } else { 1370 | return iteratorValue(type, iterations - 1, step.value[1], step); 1371 | } 1372 | }); 1373 | } 1374 | 1375 | return sliceSeq; 1376 | } 1377 | 1378 | 1379 | function takeWhileFactory(iterable, predicate, context) { 1380 | var takeSequence = makeSequence(iterable); 1381 | takeSequence.__iterateUncached = function(fn, reverse) {var this$0 = this; 1382 | if (reverse) { 1383 | return this.cacheResult().__iterate(fn, reverse); 1384 | } 1385 | var iterations = 0; 1386 | iterable.__iterate(function(v, k, c) 1387 | {return predicate.call(context, v, k, c) && ++iterations && fn(v, k, this$0)} 1388 | ); 1389 | return iterations; 1390 | }; 1391 | takeSequence.__iteratorUncached = function(type, reverse) {var this$0 = this; 1392 | if (reverse) { 1393 | return this.cacheResult().__iterator(type, reverse); 1394 | } 1395 | var iterator = iterable.__iterator(ITERATE_ENTRIES, reverse); 1396 | var iterating = true; 1397 | return new src_Iterator__Iterator(function() { 1398 | if (!iterating) { 1399 | return iteratorDone(); 1400 | } 1401 | var step = iterator.next(); 1402 | if (step.done) { 1403 | return step; 1404 | } 1405 | var entry = step.value; 1406 | var k = entry[0]; 1407 | var v = entry[1]; 1408 | if (!predicate.call(context, v, k, this$0)) { 1409 | iterating = false; 1410 | return iteratorDone(); 1411 | } 1412 | return type === ITERATE_ENTRIES ? step : 1413 | iteratorValue(type, k, v, step); 1414 | }); 1415 | }; 1416 | return takeSequence; 1417 | } 1418 | 1419 | 1420 | function skipWhileFactory(iterable, predicate, context, useKeys) { 1421 | var skipSequence = makeSequence(iterable); 1422 | skipSequence.__iterateUncached = function (fn, reverse) {var this$0 = this; 1423 | if (reverse) { 1424 | return this.cacheResult().__iterate(fn, reverse); 1425 | } 1426 | var isSkipping = true; 1427 | var iterations = 0; 1428 | iterable.__iterate(function(v, k, c) { 1429 | if (!(isSkipping && (isSkipping = predicate.call(context, v, k, c)))) { 1430 | iterations++; 1431 | return fn(v, useKeys ? k : iterations - 1, this$0); 1432 | } 1433 | }); 1434 | return iterations; 1435 | }; 1436 | skipSequence.__iteratorUncached = function(type, reverse) {var this$0 = this; 1437 | if (reverse) { 1438 | return this.cacheResult().__iterator(type, reverse); 1439 | } 1440 | var iterator = iterable.__iterator(ITERATE_ENTRIES, reverse); 1441 | var skipping = true; 1442 | var iterations = 0; 1443 | return new src_Iterator__Iterator(function() { 1444 | var step, k, v; 1445 | do { 1446 | step = iterator.next(); 1447 | if (step.done) { 1448 | if (useKeys || type === ITERATE_VALUES) { 1449 | return step; 1450 | } else if (type === ITERATE_KEYS) { 1451 | return iteratorValue(type, iterations++, undefined, step); 1452 | } else { 1453 | return iteratorValue(type, iterations++, step.value[1], step); 1454 | } 1455 | } 1456 | var entry = step.value; 1457 | k = entry[0]; 1458 | v = entry[1]; 1459 | skipping && (skipping = predicate.call(context, v, k, this$0)); 1460 | } while (skipping); 1461 | return type === ITERATE_ENTRIES ? step : 1462 | iteratorValue(type, k, v, step); 1463 | }); 1464 | }; 1465 | return skipSequence; 1466 | } 1467 | 1468 | 1469 | function concatFactory(iterable, values) { 1470 | var isKeyedIterable = isKeyed(iterable); 1471 | var iters = [iterable].concat(values).map(function(v ) { 1472 | if (!isIterable(v)) { 1473 | v = isKeyedIterable ? 1474 | keyedSeqFromValue(v) : 1475 | indexedSeqFromValue(Array.isArray(v) ? v : [v]); 1476 | } else if (isKeyedIterable) { 1477 | v = KeyedIterable(v); 1478 | } 1479 | return v; 1480 | }).filter(function(v ) {return v.size !== 0}); 1481 | 1482 | if (iters.length === 0) { 1483 | return iterable; 1484 | } 1485 | 1486 | if (iters.length === 1) { 1487 | var singleton = iters[0]; 1488 | if (singleton === iterable || 1489 | isKeyedIterable && isKeyed(singleton) || 1490 | isIndexed(iterable) && isIndexed(singleton)) { 1491 | return singleton; 1492 | } 1493 | } 1494 | 1495 | var concatSeq = new ArraySeq(iters); 1496 | if (isKeyedIterable) { 1497 | concatSeq = concatSeq.toKeyedSeq(); 1498 | } else if (!isIndexed(iterable)) { 1499 | concatSeq = concatSeq.toSetSeq(); 1500 | } 1501 | concatSeq = concatSeq.flatten(true); 1502 | concatSeq.size = iters.reduce( 1503 | function(sum, seq) { 1504 | if (sum !== undefined) { 1505 | var size = seq.size; 1506 | if (size !== undefined) { 1507 | return sum + size; 1508 | } 1509 | } 1510 | }, 1511 | 0 1512 | ); 1513 | return concatSeq; 1514 | } 1515 | 1516 | 1517 | function flattenFactory(iterable, depth, useKeys) { 1518 | var flatSequence = makeSequence(iterable); 1519 | flatSequence.__iterateUncached = function(fn, reverse) { 1520 | var iterations = 0; 1521 | var stopped = false; 1522 | function flatDeep(iter, currentDepth) {var this$0 = this; 1523 | iter.__iterate(function(v, k) { 1524 | if ((!depth || currentDepth < depth) && isIterable(v)) { 1525 | flatDeep(v, currentDepth + 1); 1526 | } else if (fn(v, useKeys ? k : iterations++, this$0) === false) { 1527 | stopped = true; 1528 | } 1529 | return !stopped; 1530 | }, reverse); 1531 | } 1532 | flatDeep(iterable, 0); 1533 | return iterations; 1534 | } 1535 | flatSequence.__iteratorUncached = function(type, reverse) { 1536 | var iterator = iterable.__iterator(type, reverse); 1537 | var stack = []; 1538 | var iterations = 0; 1539 | return new src_Iterator__Iterator(function() { 1540 | while (iterator) { 1541 | var step = iterator.next(); 1542 | if (step.done !== false) { 1543 | iterator = stack.pop(); 1544 | continue; 1545 | } 1546 | var v = step.value; 1547 | if (type === ITERATE_ENTRIES) { 1548 | v = v[1]; 1549 | } 1550 | if ((!depth || stack.length < depth) && isIterable(v)) { 1551 | stack.push(iterator); 1552 | iterator = v.__iterator(type, reverse); 1553 | } else { 1554 | return useKeys ? step : iteratorValue(type, iterations++, v, step); 1555 | } 1556 | } 1557 | return iteratorDone(); 1558 | }); 1559 | } 1560 | return flatSequence; 1561 | } 1562 | 1563 | 1564 | function flatMapFactory(iterable, mapper, context) { 1565 | var coerce = iterableClass(iterable); 1566 | return iterable.toSeq().map( 1567 | function(v, k) {return coerce(mapper.call(context, v, k, iterable))} 1568 | ).flatten(true); 1569 | } 1570 | 1571 | 1572 | function interposeFactory(iterable, separator) { 1573 | var interposedSequence = makeSequence(iterable); 1574 | interposedSequence.size = iterable.size && iterable.size * 2 -1; 1575 | interposedSequence.__iterateUncached = function(fn, reverse) {var this$0 = this; 1576 | var iterations = 0; 1577 | iterable.__iterate(function(v, k) 1578 | {return (!iterations || fn(separator, iterations++, this$0) !== false) && 1579 | fn(v, iterations++, this$0) !== false}, 1580 | reverse 1581 | ); 1582 | return iterations; 1583 | }; 1584 | interposedSequence.__iteratorUncached = function(type, reverse) { 1585 | var iterator = iterable.__iterator(ITERATE_VALUES, reverse); 1586 | var iterations = 0; 1587 | var step; 1588 | return new src_Iterator__Iterator(function() { 1589 | if (!step || iterations % 2) { 1590 | step = iterator.next(); 1591 | if (step.done) { 1592 | return step; 1593 | } 1594 | } 1595 | return iterations % 2 ? 1596 | iteratorValue(type, iterations++, separator) : 1597 | iteratorValue(type, iterations++, step.value, step); 1598 | }); 1599 | }; 1600 | return interposedSequence; 1601 | } 1602 | 1603 | 1604 | function sortFactory(iterable, comparator, mapper) { 1605 | if (!comparator) { 1606 | comparator = defaultComparator; 1607 | } 1608 | var isKeyedIterable = isKeyed(iterable); 1609 | var index = 0; 1610 | var entries = iterable.toSeq().map( 1611 | function(v, k) {return [k, v, index++, mapper ? mapper(v, k, iterable) : v]} 1612 | ).toArray(); 1613 | entries.sort(function(a, b) {return comparator(a[3], b[3]) || a[2] - b[2]}).forEach( 1614 | isKeyedIterable ? 1615 | function(v, i) { entries[i].length = 2; } : 1616 | function(v, i) { entries[i] = v[1]; } 1617 | ); 1618 | return isKeyedIterable ? KeyedSeq(entries) : 1619 | isIndexed(iterable) ? IndexedSeq(entries) : 1620 | SetSeq(entries); 1621 | } 1622 | 1623 | 1624 | function maxFactory(iterable, comparator, mapper) { 1625 | if (!comparator) { 1626 | comparator = defaultComparator; 1627 | } 1628 | if (mapper) { 1629 | var entry = iterable.toSeq() 1630 | .map(function(v, k) {return [v, mapper(v, k, iterable)]}) 1631 | .reduce(function(a, b) {return maxCompare(comparator, a[1], b[1]) ? b : a}); 1632 | return entry && entry[0]; 1633 | } else { 1634 | return iterable.reduce(function(a, b) {return maxCompare(comparator, a, b) ? b : a}); 1635 | } 1636 | } 1637 | 1638 | function maxCompare(comparator, a, b) { 1639 | var comp = comparator(b, a); 1640 | // b is considered the new max if the comparator declares them equal, but 1641 | // they are not equal and b is in fact a nullish value. 1642 | return (comp === 0 && b !== a && (b === undefined || b === null || b !== b)) || comp > 0; 1643 | } 1644 | 1645 | 1646 | function zipWithFactory(keyIter, zipper, iters) { 1647 | var zipSequence = makeSequence(keyIter); 1648 | zipSequence.size = new ArraySeq(iters).map(function(i ) {return i.size}).min(); 1649 | // Note: this a generic base implementation of __iterate in terms of 1650 | // __iterator which may be more generically useful in the future. 1651 | zipSequence.__iterate = function(fn, reverse) { 1652 | /* generic: 1653 | var iterator = this.__iterator(ITERATE_ENTRIES, reverse); 1654 | var step; 1655 | var iterations = 0; 1656 | while (!(step = iterator.next()).done) { 1657 | iterations++; 1658 | if (fn(step.value[1], step.value[0], this) === false) { 1659 | break; 1660 | } 1661 | } 1662 | return iterations; 1663 | */ 1664 | // indexed: 1665 | var iterator = this.__iterator(ITERATE_VALUES, reverse); 1666 | var step; 1667 | var iterations = 0; 1668 | while (!(step = iterator.next()).done) { 1669 | if (fn(step.value, iterations++, this) === false) { 1670 | break; 1671 | } 1672 | } 1673 | return iterations; 1674 | }; 1675 | zipSequence.__iteratorUncached = function(type, reverse) { 1676 | var iterators = iters.map(function(i ) 1677 | {return (i = Iterable(i), getIterator(reverse ? i.reverse() : i))} 1678 | ); 1679 | var iterations = 0; 1680 | var isDone = false; 1681 | return new src_Iterator__Iterator(function() { 1682 | var steps; 1683 | if (!isDone) { 1684 | steps = iterators.map(function(i ) {return i.next()}); 1685 | isDone = steps.some(function(s ) {return s.done}); 1686 | } 1687 | if (isDone) { 1688 | return iteratorDone(); 1689 | } 1690 | return iteratorValue( 1691 | type, 1692 | iterations++, 1693 | zipper.apply(null, steps.map(function(s ) {return s.value})) 1694 | ); 1695 | }); 1696 | }; 1697 | return zipSequence 1698 | } 1699 | 1700 | 1701 | // #pragma Helper Functions 1702 | 1703 | function reify(iter, seq) { 1704 | return isSeq(iter) ? seq : iter.constructor(seq); 1705 | } 1706 | 1707 | function validateEntry(entry) { 1708 | if (entry !== Object(entry)) { 1709 | throw new TypeError('Expected [K, V] tuple: ' + entry); 1710 | } 1711 | } 1712 | 1713 | function resolveSize(iter) { 1714 | assertNotInfinite(iter.size); 1715 | return ensureSize(iter); 1716 | } 1717 | 1718 | function iterableClass(iterable) { 1719 | return isKeyed(iterable) ? KeyedIterable : 1720 | isIndexed(iterable) ? IndexedIterable : 1721 | SetIterable; 1722 | } 1723 | 1724 | function makeSequence(iterable) { 1725 | return Object.create( 1726 | ( 1727 | isKeyed(iterable) ? KeyedSeq : 1728 | isIndexed(iterable) ? IndexedSeq : 1729 | SetSeq 1730 | ).prototype 1731 | ); 1732 | } 1733 | 1734 | function cacheResultThrough() { 1735 | if (this._iter.cacheResult) { 1736 | this._iter.cacheResult(); 1737 | this.size = this._iter.size; 1738 | return this; 1739 | } else { 1740 | return Seq.prototype.cacheResult.call(this); 1741 | } 1742 | } 1743 | 1744 | function defaultComparator(a, b) { 1745 | return a > b ? 1 : a < b ? -1 : 0; 1746 | } 1747 | 1748 | function forceIterator(keyPath) { 1749 | var iter = getIterator(keyPath); 1750 | if (!iter) { 1751 | // Array might not be iterable in this environment, so we need a fallback 1752 | // to our wrapped type. 1753 | if (!isArrayLike(keyPath)) { 1754 | throw new TypeError('Expected iterable or array-like: ' + keyPath); 1755 | } 1756 | iter = getIterator(Iterable(keyPath)); 1757 | } 1758 | return iter; 1759 | } 1760 | 1761 | createClass(src_Map__Map, KeyedCollection); 1762 | 1763 | // @pragma Construction 1764 | 1765 | function src_Map__Map(value) { 1766 | return value === null || value === undefined ? emptyMap() : 1767 | isMap(value) ? value : 1768 | emptyMap().withMutations(function(map ) { 1769 | var iter = KeyedIterable(value); 1770 | assertNotInfinite(iter.size); 1771 | iter.forEach(function(v, k) {return map.set(k, v)}); 1772 | }); 1773 | } 1774 | 1775 | src_Map__Map.prototype.toString = function() { 1776 | return this.__toString('Map {', '}'); 1777 | }; 1778 | 1779 | // @pragma Access 1780 | 1781 | src_Map__Map.prototype.get = function(k, notSetValue) { 1782 | return this._root ? 1783 | this._root.get(0, undefined, k, notSetValue) : 1784 | notSetValue; 1785 | }; 1786 | 1787 | // @pragma Modification 1788 | 1789 | src_Map__Map.prototype.set = function(k, v) { 1790 | return updateMap(this, k, v); 1791 | }; 1792 | 1793 | src_Map__Map.prototype.setIn = function(keyPath, v) { 1794 | return this.updateIn(keyPath, NOT_SET, function() {return v}); 1795 | }; 1796 | 1797 | src_Map__Map.prototype.remove = function(k) { 1798 | return updateMap(this, k, NOT_SET); 1799 | }; 1800 | 1801 | src_Map__Map.prototype.deleteIn = function(keyPath) { 1802 | return this.updateIn(keyPath, function() {return NOT_SET}); 1803 | }; 1804 | 1805 | src_Map__Map.prototype.update = function(k, notSetValue, updater) { 1806 | return arguments.length === 1 ? 1807 | k(this) : 1808 | this.updateIn([k], notSetValue, updater); 1809 | }; 1810 | 1811 | src_Map__Map.prototype.updateIn = function(keyPath, notSetValue, updater) { 1812 | if (!updater) { 1813 | updater = notSetValue; 1814 | notSetValue = undefined; 1815 | } 1816 | var updatedValue = updateInDeepMap( 1817 | this, 1818 | forceIterator(keyPath), 1819 | notSetValue, 1820 | updater 1821 | ); 1822 | return updatedValue === NOT_SET ? undefined : updatedValue; 1823 | }; 1824 | 1825 | src_Map__Map.prototype.clear = function() { 1826 | if (this.size === 0) { 1827 | return this; 1828 | } 1829 | if (this.__ownerID) { 1830 | this.size = 0; 1831 | this._root = null; 1832 | this.__hash = undefined; 1833 | this.__altered = true; 1834 | return this; 1835 | } 1836 | return emptyMap(); 1837 | }; 1838 | 1839 | // @pragma Composition 1840 | 1841 | src_Map__Map.prototype.merge = function(/*...iters*/) { 1842 | return mergeIntoMapWith(this, undefined, arguments); 1843 | }; 1844 | 1845 | src_Map__Map.prototype.mergeWith = function(merger) {var iters = SLICE$0.call(arguments, 1); 1846 | return mergeIntoMapWith(this, merger, iters); 1847 | }; 1848 | 1849 | src_Map__Map.prototype.mergeIn = function(keyPath) {var iters = SLICE$0.call(arguments, 1); 1850 | return this.updateIn(keyPath, emptyMap(), function(m ) {return m.merge.apply(m, iters)}); 1851 | }; 1852 | 1853 | src_Map__Map.prototype.mergeDeep = function(/*...iters*/) { 1854 | return mergeIntoMapWith(this, deepMerger(undefined), arguments); 1855 | }; 1856 | 1857 | src_Map__Map.prototype.mergeDeepWith = function(merger) {var iters = SLICE$0.call(arguments, 1); 1858 | return mergeIntoMapWith(this, deepMerger(merger), iters); 1859 | }; 1860 | 1861 | src_Map__Map.prototype.mergeDeepIn = function(keyPath) {var iters = SLICE$0.call(arguments, 1); 1862 | return this.updateIn(keyPath, emptyMap(), function(m ) {return m.mergeDeep.apply(m, iters)}); 1863 | }; 1864 | 1865 | src_Map__Map.prototype.sort = function(comparator) { 1866 | // Late binding 1867 | return OrderedMap(sortFactory(this, comparator)); 1868 | }; 1869 | 1870 | src_Map__Map.prototype.sortBy = function(mapper, comparator) { 1871 | // Late binding 1872 | return OrderedMap(sortFactory(this, comparator, mapper)); 1873 | }; 1874 | 1875 | // @pragma Mutability 1876 | 1877 | src_Map__Map.prototype.withMutations = function(fn) { 1878 | var mutable = this.asMutable(); 1879 | fn(mutable); 1880 | return mutable.wasAltered() ? mutable.__ensureOwner(this.__ownerID) : this; 1881 | }; 1882 | 1883 | src_Map__Map.prototype.asMutable = function() { 1884 | return this.__ownerID ? this : this.__ensureOwner(new OwnerID()); 1885 | }; 1886 | 1887 | src_Map__Map.prototype.asImmutable = function() { 1888 | return this.__ensureOwner(); 1889 | }; 1890 | 1891 | src_Map__Map.prototype.wasAltered = function() { 1892 | return this.__altered; 1893 | }; 1894 | 1895 | src_Map__Map.prototype.__iterator = function(type, reverse) { 1896 | return new MapIterator(this, type, reverse); 1897 | }; 1898 | 1899 | src_Map__Map.prototype.__iterate = function(fn, reverse) {var this$0 = this; 1900 | var iterations = 0; 1901 | this._root && this._root.iterate(function(entry ) { 1902 | iterations++; 1903 | return fn(entry[1], entry[0], this$0); 1904 | }, reverse); 1905 | return iterations; 1906 | }; 1907 | 1908 | src_Map__Map.prototype.__ensureOwner = function(ownerID) { 1909 | if (ownerID === this.__ownerID) { 1910 | return this; 1911 | } 1912 | if (!ownerID) { 1913 | this.__ownerID = ownerID; 1914 | this.__altered = false; 1915 | return this; 1916 | } 1917 | return makeMap(this.size, this._root, ownerID, this.__hash); 1918 | }; 1919 | 1920 | 1921 | function isMap(maybeMap) { 1922 | return !!(maybeMap && maybeMap[IS_MAP_SENTINEL]); 1923 | } 1924 | 1925 | src_Map__Map.isMap = isMap; 1926 | 1927 | var IS_MAP_SENTINEL = '@@__IMMUTABLE_MAP__@@'; 1928 | 1929 | var MapPrototype = src_Map__Map.prototype; 1930 | MapPrototype[IS_MAP_SENTINEL] = true; 1931 | MapPrototype[DELETE] = MapPrototype.remove; 1932 | MapPrototype.removeIn = MapPrototype.deleteIn; 1933 | 1934 | 1935 | // #pragma Trie Nodes 1936 | 1937 | 1938 | 1939 | function ArrayMapNode(ownerID, entries) { 1940 | this.ownerID = ownerID; 1941 | this.entries = entries; 1942 | } 1943 | 1944 | ArrayMapNode.prototype.get = function(shift, keyHash, key, notSetValue) { 1945 | var entries = this.entries; 1946 | for (var ii = 0, len = entries.length; ii < len; ii++) { 1947 | if (is(key, entries[ii][0])) { 1948 | return entries[ii][1]; 1949 | } 1950 | } 1951 | return notSetValue; 1952 | }; 1953 | 1954 | ArrayMapNode.prototype.update = function(ownerID, shift, keyHash, key, value, didChangeSize, didAlter) { 1955 | var removed = value === NOT_SET; 1956 | 1957 | var entries = this.entries; 1958 | var idx = 0; 1959 | for (var len = entries.length; idx < len; idx++) { 1960 | if (is(key, entries[idx][0])) { 1961 | break; 1962 | } 1963 | } 1964 | var exists = idx < len; 1965 | 1966 | if (exists ? entries[idx][1] === value : removed) { 1967 | return this; 1968 | } 1969 | 1970 | SetRef(didAlter); 1971 | (removed || !exists) && SetRef(didChangeSize); 1972 | 1973 | if (removed && entries.length === 1) { 1974 | return; // undefined 1975 | } 1976 | 1977 | if (!exists && !removed && entries.length >= MAX_ARRAY_MAP_SIZE) { 1978 | return createNodes(ownerID, entries, key, value); 1979 | } 1980 | 1981 | var isEditable = ownerID && ownerID === this.ownerID; 1982 | var newEntries = isEditable ? entries : arrCopy(entries); 1983 | 1984 | if (exists) { 1985 | if (removed) { 1986 | idx === len - 1 ? newEntries.pop() : (newEntries[idx] = newEntries.pop()); 1987 | } else { 1988 | newEntries[idx] = [key, value]; 1989 | } 1990 | } else { 1991 | newEntries.push([key, value]); 1992 | } 1993 | 1994 | if (isEditable) { 1995 | this.entries = newEntries; 1996 | return this; 1997 | } 1998 | 1999 | return new ArrayMapNode(ownerID, newEntries); 2000 | }; 2001 | 2002 | 2003 | 2004 | 2005 | function BitmapIndexedNode(ownerID, bitmap, nodes) { 2006 | this.ownerID = ownerID; 2007 | this.bitmap = bitmap; 2008 | this.nodes = nodes; 2009 | } 2010 | 2011 | BitmapIndexedNode.prototype.get = function(shift, keyHash, key, notSetValue) { 2012 | if (keyHash === undefined) { 2013 | keyHash = hash(key); 2014 | } 2015 | var bit = (1 << ((shift === 0 ? keyHash : keyHash >>> shift) & MASK)); 2016 | var bitmap = this.bitmap; 2017 | return (bitmap & bit) === 0 ? notSetValue : 2018 | this.nodes[popCount(bitmap & (bit - 1))].get(shift + SHIFT, keyHash, key, notSetValue); 2019 | }; 2020 | 2021 | BitmapIndexedNode.prototype.update = function(ownerID, shift, keyHash, key, value, didChangeSize, didAlter) { 2022 | if (keyHash === undefined) { 2023 | keyHash = hash(key); 2024 | } 2025 | var keyHashFrag = (shift === 0 ? keyHash : keyHash >>> shift) & MASK; 2026 | var bit = 1 << keyHashFrag; 2027 | var bitmap = this.bitmap; 2028 | var exists = (bitmap & bit) !== 0; 2029 | 2030 | if (!exists && value === NOT_SET) { 2031 | return this; 2032 | } 2033 | 2034 | var idx = popCount(bitmap & (bit - 1)); 2035 | var nodes = this.nodes; 2036 | var node = exists ? nodes[idx] : undefined; 2037 | var newNode = updateNode(node, ownerID, shift + SHIFT, keyHash, key, value, didChangeSize, didAlter); 2038 | 2039 | if (newNode === node) { 2040 | return this; 2041 | } 2042 | 2043 | if (!exists && newNode && nodes.length >= MAX_BITMAP_INDEXED_SIZE) { 2044 | return expandNodes(ownerID, nodes, bitmap, keyHashFrag, newNode); 2045 | } 2046 | 2047 | if (exists && !newNode && nodes.length === 2 && isLeafNode(nodes[idx ^ 1])) { 2048 | return nodes[idx ^ 1]; 2049 | } 2050 | 2051 | if (exists && newNode && nodes.length === 1 && isLeafNode(newNode)) { 2052 | return newNode; 2053 | } 2054 | 2055 | var isEditable = ownerID && ownerID === this.ownerID; 2056 | var newBitmap = exists ? newNode ? bitmap : bitmap ^ bit : bitmap | bit; 2057 | var newNodes = exists ? newNode ? 2058 | setIn(nodes, idx, newNode, isEditable) : 2059 | spliceOut(nodes, idx, isEditable) : 2060 | spliceIn(nodes, idx, newNode, isEditable); 2061 | 2062 | if (isEditable) { 2063 | this.bitmap = newBitmap; 2064 | this.nodes = newNodes; 2065 | return this; 2066 | } 2067 | 2068 | return new BitmapIndexedNode(ownerID, newBitmap, newNodes); 2069 | }; 2070 | 2071 | 2072 | 2073 | 2074 | function HashArrayMapNode(ownerID, count, nodes) { 2075 | this.ownerID = ownerID; 2076 | this.count = count; 2077 | this.nodes = nodes; 2078 | } 2079 | 2080 | HashArrayMapNode.prototype.get = function(shift, keyHash, key, notSetValue) { 2081 | if (keyHash === undefined) { 2082 | keyHash = hash(key); 2083 | } 2084 | var idx = (shift === 0 ? keyHash : keyHash >>> shift) & MASK; 2085 | var node = this.nodes[idx]; 2086 | return node ? node.get(shift + SHIFT, keyHash, key, notSetValue) : notSetValue; 2087 | }; 2088 | 2089 | HashArrayMapNode.prototype.update = function(ownerID, shift, keyHash, key, value, didChangeSize, didAlter) { 2090 | if (keyHash === undefined) { 2091 | keyHash = hash(key); 2092 | } 2093 | var idx = (shift === 0 ? keyHash : keyHash >>> shift) & MASK; 2094 | var removed = value === NOT_SET; 2095 | var nodes = this.nodes; 2096 | var node = nodes[idx]; 2097 | 2098 | if (removed && !node) { 2099 | return this; 2100 | } 2101 | 2102 | var newNode = updateNode(node, ownerID, shift + SHIFT, keyHash, key, value, didChangeSize, didAlter); 2103 | if (newNode === node) { 2104 | return this; 2105 | } 2106 | 2107 | var newCount = this.count; 2108 | if (!node) { 2109 | newCount++; 2110 | } else if (!newNode) { 2111 | newCount--; 2112 | if (newCount < MIN_HASH_ARRAY_MAP_SIZE) { 2113 | return packNodes(ownerID, nodes, newCount, idx); 2114 | } 2115 | } 2116 | 2117 | var isEditable = ownerID && ownerID === this.ownerID; 2118 | var newNodes = setIn(nodes, idx, newNode, isEditable); 2119 | 2120 | if (isEditable) { 2121 | this.count = newCount; 2122 | this.nodes = newNodes; 2123 | return this; 2124 | } 2125 | 2126 | return new HashArrayMapNode(ownerID, newCount, newNodes); 2127 | }; 2128 | 2129 | 2130 | 2131 | 2132 | function HashCollisionNode(ownerID, keyHash, entries) { 2133 | this.ownerID = ownerID; 2134 | this.keyHash = keyHash; 2135 | this.entries = entries; 2136 | } 2137 | 2138 | HashCollisionNode.prototype.get = function(shift, keyHash, key, notSetValue) { 2139 | var entries = this.entries; 2140 | for (var ii = 0, len = entries.length; ii < len; ii++) { 2141 | if (is(key, entries[ii][0])) { 2142 | return entries[ii][1]; 2143 | } 2144 | } 2145 | return notSetValue; 2146 | }; 2147 | 2148 | HashCollisionNode.prototype.update = function(ownerID, shift, keyHash, key, value, didChangeSize, didAlter) { 2149 | if (keyHash === undefined) { 2150 | keyHash = hash(key); 2151 | } 2152 | 2153 | var removed = value === NOT_SET; 2154 | 2155 | if (keyHash !== this.keyHash) { 2156 | if (removed) { 2157 | return this; 2158 | } 2159 | SetRef(didAlter); 2160 | SetRef(didChangeSize); 2161 | return mergeIntoNode(this, ownerID, shift, keyHash, [key, value]); 2162 | } 2163 | 2164 | var entries = this.entries; 2165 | var idx = 0; 2166 | for (var len = entries.length; idx < len; idx++) { 2167 | if (is(key, entries[idx][0])) { 2168 | break; 2169 | } 2170 | } 2171 | var exists = idx < len; 2172 | 2173 | if (exists ? entries[idx][1] === value : removed) { 2174 | return this; 2175 | } 2176 | 2177 | SetRef(didAlter); 2178 | (removed || !exists) && SetRef(didChangeSize); 2179 | 2180 | if (removed && len === 2) { 2181 | return new ValueNode(ownerID, this.keyHash, entries[idx ^ 1]); 2182 | } 2183 | 2184 | var isEditable = ownerID && ownerID === this.ownerID; 2185 | var newEntries = isEditable ? entries : arrCopy(entries); 2186 | 2187 | if (exists) { 2188 | if (removed) { 2189 | idx === len - 1 ? newEntries.pop() : (newEntries[idx] = newEntries.pop()); 2190 | } else { 2191 | newEntries[idx] = [key, value]; 2192 | } 2193 | } else { 2194 | newEntries.push([key, value]); 2195 | } 2196 | 2197 | if (isEditable) { 2198 | this.entries = newEntries; 2199 | return this; 2200 | } 2201 | 2202 | return new HashCollisionNode(ownerID, this.keyHash, newEntries); 2203 | }; 2204 | 2205 | 2206 | 2207 | 2208 | function ValueNode(ownerID, keyHash, entry) { 2209 | this.ownerID = ownerID; 2210 | this.keyHash = keyHash; 2211 | this.entry = entry; 2212 | } 2213 | 2214 | ValueNode.prototype.get = function(shift, keyHash, key, notSetValue) { 2215 | return is(key, this.entry[0]) ? this.entry[1] : notSetValue; 2216 | }; 2217 | 2218 | ValueNode.prototype.update = function(ownerID, shift, keyHash, key, value, didChangeSize, didAlter) { 2219 | var removed = value === NOT_SET; 2220 | var keyMatch = is(key, this.entry[0]); 2221 | if (keyMatch ? value === this.entry[1] : removed) { 2222 | return this; 2223 | } 2224 | 2225 | SetRef(didAlter); 2226 | 2227 | if (removed) { 2228 | SetRef(didChangeSize); 2229 | return; // undefined 2230 | } 2231 | 2232 | if (keyMatch) { 2233 | if (ownerID && ownerID === this.ownerID) { 2234 | this.entry[1] = value; 2235 | return this; 2236 | } 2237 | return new ValueNode(ownerID, this.keyHash, [key, value]); 2238 | } 2239 | 2240 | SetRef(didChangeSize); 2241 | return mergeIntoNode(this, ownerID, shift, hash(key), [key, value]); 2242 | }; 2243 | 2244 | 2245 | 2246 | // #pragma Iterators 2247 | 2248 | ArrayMapNode.prototype.iterate = 2249 | HashCollisionNode.prototype.iterate = function (fn, reverse) { 2250 | var entries = this.entries; 2251 | for (var ii = 0, maxIndex = entries.length - 1; ii <= maxIndex; ii++) { 2252 | if (fn(entries[reverse ? maxIndex - ii : ii]) === false) { 2253 | return false; 2254 | } 2255 | } 2256 | } 2257 | 2258 | BitmapIndexedNode.prototype.iterate = 2259 | HashArrayMapNode.prototype.iterate = function (fn, reverse) { 2260 | var nodes = this.nodes; 2261 | for (var ii = 0, maxIndex = nodes.length - 1; ii <= maxIndex; ii++) { 2262 | var node = nodes[reverse ? maxIndex - ii : ii]; 2263 | if (node && node.iterate(fn, reverse) === false) { 2264 | return false; 2265 | } 2266 | } 2267 | } 2268 | 2269 | ValueNode.prototype.iterate = function (fn, reverse) { 2270 | return fn(this.entry); 2271 | } 2272 | 2273 | createClass(MapIterator, src_Iterator__Iterator); 2274 | 2275 | function MapIterator(map, type, reverse) { 2276 | this._type = type; 2277 | this._reverse = reverse; 2278 | this._stack = map._root && mapIteratorFrame(map._root); 2279 | } 2280 | 2281 | MapIterator.prototype.next = function() { 2282 | var type = this._type; 2283 | var stack = this._stack; 2284 | while (stack) { 2285 | var node = stack.node; 2286 | var index = stack.index++; 2287 | var maxIndex; 2288 | if (node.entry) { 2289 | if (index === 0) { 2290 | return mapIteratorValue(type, node.entry); 2291 | } 2292 | } else if (node.entries) { 2293 | maxIndex = node.entries.length - 1; 2294 | if (index <= maxIndex) { 2295 | return mapIteratorValue(type, node.entries[this._reverse ? maxIndex - index : index]); 2296 | } 2297 | } else { 2298 | maxIndex = node.nodes.length - 1; 2299 | if (index <= maxIndex) { 2300 | var subNode = node.nodes[this._reverse ? maxIndex - index : index]; 2301 | if (subNode) { 2302 | if (subNode.entry) { 2303 | return mapIteratorValue(type, subNode.entry); 2304 | } 2305 | stack = this._stack = mapIteratorFrame(subNode, stack); 2306 | } 2307 | continue; 2308 | } 2309 | } 2310 | stack = this._stack = this._stack.__prev; 2311 | } 2312 | return iteratorDone(); 2313 | }; 2314 | 2315 | 2316 | function mapIteratorValue(type, entry) { 2317 | return iteratorValue(type, entry[0], entry[1]); 2318 | } 2319 | 2320 | function mapIteratorFrame(node, prev) { 2321 | return { 2322 | node: node, 2323 | index: 0, 2324 | __prev: prev 2325 | }; 2326 | } 2327 | 2328 | function makeMap(size, root, ownerID, hash) { 2329 | var map = Object.create(MapPrototype); 2330 | map.size = size; 2331 | map._root = root; 2332 | map.__ownerID = ownerID; 2333 | map.__hash = hash; 2334 | map.__altered = false; 2335 | return map; 2336 | } 2337 | 2338 | var EMPTY_MAP; 2339 | function emptyMap() { 2340 | return EMPTY_MAP || (EMPTY_MAP = makeMap(0)); 2341 | } 2342 | 2343 | function updateMap(map, k, v) { 2344 | var newRoot; 2345 | var newSize; 2346 | if (!map._root) { 2347 | if (v === NOT_SET) { 2348 | return map; 2349 | } 2350 | newSize = 1; 2351 | newRoot = new ArrayMapNode(map.__ownerID, [[k, v]]); 2352 | } else { 2353 | var didChangeSize = MakeRef(CHANGE_LENGTH); 2354 | var didAlter = MakeRef(DID_ALTER); 2355 | newRoot = updateNode(map._root, map.__ownerID, 0, undefined, k, v, didChangeSize, didAlter); 2356 | if (!didAlter.value) { 2357 | return map; 2358 | } 2359 | newSize = map.size + (didChangeSize.value ? v === NOT_SET ? -1 : 1 : 0); 2360 | } 2361 | if (map.__ownerID) { 2362 | map.size = newSize; 2363 | map._root = newRoot; 2364 | map.__hash = undefined; 2365 | map.__altered = true; 2366 | return map; 2367 | } 2368 | return newRoot ? makeMap(newSize, newRoot) : emptyMap(); 2369 | } 2370 | 2371 | function updateNode(node, ownerID, shift, keyHash, key, value, didChangeSize, didAlter) { 2372 | if (!node) { 2373 | if (value === NOT_SET) { 2374 | return node; 2375 | } 2376 | SetRef(didAlter); 2377 | SetRef(didChangeSize); 2378 | return new ValueNode(ownerID, keyHash, [key, value]); 2379 | } 2380 | return node.update(ownerID, shift, keyHash, key, value, didChangeSize, didAlter); 2381 | } 2382 | 2383 | function isLeafNode(node) { 2384 | return node.constructor === ValueNode || node.constructor === HashCollisionNode; 2385 | } 2386 | 2387 | function mergeIntoNode(node, ownerID, shift, keyHash, entry) { 2388 | if (node.keyHash === keyHash) { 2389 | return new HashCollisionNode(ownerID, keyHash, [node.entry, entry]); 2390 | } 2391 | 2392 | var idx1 = (shift === 0 ? node.keyHash : node.keyHash >>> shift) & MASK; 2393 | var idx2 = (shift === 0 ? keyHash : keyHash >>> shift) & MASK; 2394 | 2395 | var newNode; 2396 | var nodes = idx1 === idx2 ? 2397 | [mergeIntoNode(node, ownerID, shift + SHIFT, keyHash, entry)] : 2398 | ((newNode = new ValueNode(ownerID, keyHash, entry)), idx1 < idx2 ? [node, newNode] : [newNode, node]); 2399 | 2400 | return new BitmapIndexedNode(ownerID, (1 << idx1) | (1 << idx2), nodes); 2401 | } 2402 | 2403 | function createNodes(ownerID, entries, key, value) { 2404 | if (!ownerID) { 2405 | ownerID = new OwnerID(); 2406 | } 2407 | var node = new ValueNode(ownerID, hash(key), [key, value]); 2408 | for (var ii = 0; ii < entries.length; ii++) { 2409 | var entry = entries[ii]; 2410 | node = node.update(ownerID, 0, undefined, entry[0], entry[1]); 2411 | } 2412 | return node; 2413 | } 2414 | 2415 | function packNodes(ownerID, nodes, count, excluding) { 2416 | var bitmap = 0; 2417 | var packedII = 0; 2418 | var packedNodes = new Array(count); 2419 | for (var ii = 0, bit = 1, len = nodes.length; ii < len; ii++, bit <<= 1) { 2420 | var node = nodes[ii]; 2421 | if (node !== undefined && ii !== excluding) { 2422 | bitmap |= bit; 2423 | packedNodes[packedII++] = node; 2424 | } 2425 | } 2426 | return new BitmapIndexedNode(ownerID, bitmap, packedNodes); 2427 | } 2428 | 2429 | function expandNodes(ownerID, nodes, bitmap, including, node) { 2430 | var count = 0; 2431 | var expandedNodes = new Array(SIZE); 2432 | for (var ii = 0; bitmap !== 0; ii++, bitmap >>>= 1) { 2433 | expandedNodes[ii] = bitmap & 1 ? nodes[count++] : undefined; 2434 | } 2435 | expandedNodes[including] = node; 2436 | return new HashArrayMapNode(ownerID, count + 1, expandedNodes); 2437 | } 2438 | 2439 | function mergeIntoMapWith(map, merger, iterables) { 2440 | var iters = []; 2441 | for (var ii = 0; ii < iterables.length; ii++) { 2442 | var value = iterables[ii]; 2443 | var iter = KeyedIterable(value); 2444 | if (!isIterable(value)) { 2445 | iter = iter.map(function(v ) {return fromJS(v)}); 2446 | } 2447 | iters.push(iter); 2448 | } 2449 | return mergeIntoCollectionWith(map, merger, iters); 2450 | } 2451 | 2452 | function deepMerger(merger) { 2453 | return function(existing, value, key) 2454 | {return existing && existing.mergeDeepWith && isIterable(value) ? 2455 | existing.mergeDeepWith(merger, value) : 2456 | merger ? merger(existing, value, key) : value}; 2457 | } 2458 | 2459 | function mergeIntoCollectionWith(collection, merger, iters) { 2460 | iters = iters.filter(function(x ) {return x.size !== 0}); 2461 | if (iters.length === 0) { 2462 | return collection; 2463 | } 2464 | if (collection.size === 0 && !collection.__ownerID && iters.length === 1) { 2465 | return collection.constructor(iters[0]); 2466 | } 2467 | return collection.withMutations(function(collection ) { 2468 | var mergeIntoMap = merger ? 2469 | function(value, key) { 2470 | collection.update(key, NOT_SET, function(existing ) 2471 | {return existing === NOT_SET ? value : merger(existing, value, key)} 2472 | ); 2473 | } : 2474 | function(value, key) { 2475 | collection.set(key, value); 2476 | } 2477 | for (var ii = 0; ii < iters.length; ii++) { 2478 | iters[ii].forEach(mergeIntoMap); 2479 | } 2480 | }); 2481 | } 2482 | 2483 | function updateInDeepMap(existing, keyPathIter, notSetValue, updater) { 2484 | var isNotSet = existing === NOT_SET; 2485 | var step = keyPathIter.next(); 2486 | if (step.done) { 2487 | var existingValue = isNotSet ? notSetValue : existing; 2488 | var newValue = updater(existingValue); 2489 | return newValue === existingValue ? existing : newValue; 2490 | } 2491 | invariant( 2492 | isNotSet || (existing && existing.set), 2493 | 'invalid keyPath' 2494 | ); 2495 | var key = step.value; 2496 | var nextExisting = isNotSet ? NOT_SET : existing.get(key, NOT_SET); 2497 | var nextUpdated = updateInDeepMap( 2498 | nextExisting, 2499 | keyPathIter, 2500 | notSetValue, 2501 | updater 2502 | ); 2503 | return nextUpdated === nextExisting ? existing : 2504 | nextUpdated === NOT_SET ? existing.remove(key) : 2505 | (isNotSet ? emptyMap() : existing).set(key, nextUpdated); 2506 | } 2507 | 2508 | function popCount(x) { 2509 | x = x - ((x >> 1) & 0x55555555); 2510 | x = (x & 0x33333333) + ((x >> 2) & 0x33333333); 2511 | x = (x + (x >> 4)) & 0x0f0f0f0f; 2512 | x = x + (x >> 8); 2513 | x = x + (x >> 16); 2514 | return x & 0x7f; 2515 | } 2516 | 2517 | function setIn(array, idx, val, canEdit) { 2518 | var newArray = canEdit ? array : arrCopy(array); 2519 | newArray[idx] = val; 2520 | return newArray; 2521 | } 2522 | 2523 | function spliceIn(array, idx, val, canEdit) { 2524 | var newLen = array.length + 1; 2525 | if (canEdit && idx + 1 === newLen) { 2526 | array[idx] = val; 2527 | return array; 2528 | } 2529 | var newArray = new Array(newLen); 2530 | var after = 0; 2531 | for (var ii = 0; ii < newLen; ii++) { 2532 | if (ii === idx) { 2533 | newArray[ii] = val; 2534 | after = -1; 2535 | } else { 2536 | newArray[ii] = array[ii + after]; 2537 | } 2538 | } 2539 | return newArray; 2540 | } 2541 | 2542 | function spliceOut(array, idx, canEdit) { 2543 | var newLen = array.length - 1; 2544 | if (canEdit && idx === newLen) { 2545 | array.pop(); 2546 | return array; 2547 | } 2548 | var newArray = new Array(newLen); 2549 | var after = 0; 2550 | for (var ii = 0; ii < newLen; ii++) { 2551 | if (ii === idx) { 2552 | after = 1; 2553 | } 2554 | newArray[ii] = array[ii + after]; 2555 | } 2556 | return newArray; 2557 | } 2558 | 2559 | var MAX_ARRAY_MAP_SIZE = SIZE / 4; 2560 | var MAX_BITMAP_INDEXED_SIZE = SIZE / 2; 2561 | var MIN_HASH_ARRAY_MAP_SIZE = SIZE / 4; 2562 | 2563 | createClass(List, IndexedCollection); 2564 | 2565 | // @pragma Construction 2566 | 2567 | function List(value) { 2568 | var empty = emptyList(); 2569 | if (value === null || value === undefined) { 2570 | return empty; 2571 | } 2572 | if (isList(value)) { 2573 | return value; 2574 | } 2575 | var iter = IndexedIterable(value); 2576 | var size = iter.size; 2577 | if (size === 0) { 2578 | return empty; 2579 | } 2580 | assertNotInfinite(size); 2581 | if (size > 0 && size < SIZE) { 2582 | return makeList(0, size, SHIFT, null, new VNode(iter.toArray())); 2583 | } 2584 | return empty.withMutations(function(list ) { 2585 | list.setSize(size); 2586 | iter.forEach(function(v, i) {return list.set(i, v)}); 2587 | }); 2588 | } 2589 | 2590 | List.of = function(/*...values*/) { 2591 | return this(arguments); 2592 | }; 2593 | 2594 | List.prototype.toString = function() { 2595 | return this.__toString('List [', ']'); 2596 | }; 2597 | 2598 | // @pragma Access 2599 | 2600 | List.prototype.get = function(index, notSetValue) { 2601 | index = wrapIndex(this, index); 2602 | if (index < 0 || index >= this.size) { 2603 | return notSetValue; 2604 | } 2605 | index += this._origin; 2606 | var node = listNodeFor(this, index); 2607 | return node && node.array[index & MASK]; 2608 | }; 2609 | 2610 | // @pragma Modification 2611 | 2612 | List.prototype.set = function(index, value) { 2613 | return updateList(this, index, value); 2614 | }; 2615 | 2616 | List.prototype.remove = function(index) { 2617 | return !this.has(index) ? this : 2618 | index === 0 ? this.shift() : 2619 | index === this.size - 1 ? this.pop() : 2620 | this.splice(index, 1); 2621 | }; 2622 | 2623 | List.prototype.clear = function() { 2624 | if (this.size === 0) { 2625 | return this; 2626 | } 2627 | if (this.__ownerID) { 2628 | this.size = this._origin = this._capacity = 0; 2629 | this._level = SHIFT; 2630 | this._root = this._tail = null; 2631 | this.__hash = undefined; 2632 | this.__altered = true; 2633 | return this; 2634 | } 2635 | return emptyList(); 2636 | }; 2637 | 2638 | List.prototype.push = function(/*...values*/) { 2639 | var values = arguments; 2640 | var oldSize = this.size; 2641 | return this.withMutations(function(list ) { 2642 | setListBounds(list, 0, oldSize + values.length); 2643 | for (var ii = 0; ii < values.length; ii++) { 2644 | list.set(oldSize + ii, values[ii]); 2645 | } 2646 | }); 2647 | }; 2648 | 2649 | List.prototype.pop = function() { 2650 | return setListBounds(this, 0, -1); 2651 | }; 2652 | 2653 | List.prototype.unshift = function(/*...values*/) { 2654 | var values = arguments; 2655 | return this.withMutations(function(list ) { 2656 | setListBounds(list, -values.length); 2657 | for (var ii = 0; ii < values.length; ii++) { 2658 | list.set(ii, values[ii]); 2659 | } 2660 | }); 2661 | }; 2662 | 2663 | List.prototype.shift = function() { 2664 | return setListBounds(this, 1); 2665 | }; 2666 | 2667 | // @pragma Composition 2668 | 2669 | List.prototype.merge = function(/*...iters*/) { 2670 | return mergeIntoListWith(this, undefined, arguments); 2671 | }; 2672 | 2673 | List.prototype.mergeWith = function(merger) {var iters = SLICE$0.call(arguments, 1); 2674 | return mergeIntoListWith(this, merger, iters); 2675 | }; 2676 | 2677 | List.prototype.mergeDeep = function(/*...iters*/) { 2678 | return mergeIntoListWith(this, deepMerger(undefined), arguments); 2679 | }; 2680 | 2681 | List.prototype.mergeDeepWith = function(merger) {var iters = SLICE$0.call(arguments, 1); 2682 | return mergeIntoListWith(this, deepMerger(merger), iters); 2683 | }; 2684 | 2685 | List.prototype.setSize = function(size) { 2686 | return setListBounds(this, 0, size); 2687 | }; 2688 | 2689 | // @pragma Iteration 2690 | 2691 | List.prototype.slice = function(begin, end) { 2692 | var size = this.size; 2693 | if (wholeSlice(begin, end, size)) { 2694 | return this; 2695 | } 2696 | return setListBounds( 2697 | this, 2698 | resolveBegin(begin, size), 2699 | resolveEnd(end, size) 2700 | ); 2701 | }; 2702 | 2703 | List.prototype.__iterator = function(type, reverse) { 2704 | var index = 0; 2705 | var values = iterateList(this, reverse); 2706 | return new src_Iterator__Iterator(function() { 2707 | var value = values(); 2708 | return value === DONE ? 2709 | iteratorDone() : 2710 | iteratorValue(type, index++, value); 2711 | }); 2712 | }; 2713 | 2714 | List.prototype.__iterate = function(fn, reverse) { 2715 | var index = 0; 2716 | var values = iterateList(this, reverse); 2717 | var value; 2718 | while ((value = values()) !== DONE) { 2719 | if (fn(value, index++, this) === false) { 2720 | break; 2721 | } 2722 | } 2723 | return index; 2724 | }; 2725 | 2726 | List.prototype.__ensureOwner = function(ownerID) { 2727 | if (ownerID === this.__ownerID) { 2728 | return this; 2729 | } 2730 | if (!ownerID) { 2731 | this.__ownerID = ownerID; 2732 | return this; 2733 | } 2734 | return makeList(this._origin, this._capacity, this._level, this._root, this._tail, ownerID, this.__hash); 2735 | }; 2736 | 2737 | 2738 | function isList(maybeList) { 2739 | return !!(maybeList && maybeList[IS_LIST_SENTINEL]); 2740 | } 2741 | 2742 | List.isList = isList; 2743 | 2744 | var IS_LIST_SENTINEL = '@@__IMMUTABLE_LIST__@@'; 2745 | 2746 | var ListPrototype = List.prototype; 2747 | ListPrototype[IS_LIST_SENTINEL] = true; 2748 | ListPrototype[DELETE] = ListPrototype.remove; 2749 | ListPrototype.setIn = MapPrototype.setIn; 2750 | ListPrototype.deleteIn = 2751 | ListPrototype.removeIn = MapPrototype.removeIn; 2752 | ListPrototype.update = MapPrototype.update; 2753 | ListPrototype.updateIn = MapPrototype.updateIn; 2754 | ListPrototype.mergeIn = MapPrototype.mergeIn; 2755 | ListPrototype.mergeDeepIn = MapPrototype.mergeDeepIn; 2756 | ListPrototype.withMutations = MapPrototype.withMutations; 2757 | ListPrototype.asMutable = MapPrototype.asMutable; 2758 | ListPrototype.asImmutable = MapPrototype.asImmutable; 2759 | ListPrototype.wasAltered = MapPrototype.wasAltered; 2760 | 2761 | 2762 | 2763 | function VNode(array, ownerID) { 2764 | this.array = array; 2765 | this.ownerID = ownerID; 2766 | } 2767 | 2768 | // TODO: seems like these methods are very similar 2769 | 2770 | VNode.prototype.removeBefore = function(ownerID, level, index) { 2771 | if (index === level ? 1 << level : 0 || this.array.length === 0) { 2772 | return this; 2773 | } 2774 | var originIndex = (index >>> level) & MASK; 2775 | if (originIndex >= this.array.length) { 2776 | return new VNode([], ownerID); 2777 | } 2778 | var removingFirst = originIndex === 0; 2779 | var newChild; 2780 | if (level > 0) { 2781 | var oldChild = this.array[originIndex]; 2782 | newChild = oldChild && oldChild.removeBefore(ownerID, level - SHIFT, index); 2783 | if (newChild === oldChild && removingFirst) { 2784 | return this; 2785 | } 2786 | } 2787 | if (removingFirst && !newChild) { 2788 | return this; 2789 | } 2790 | var editable = editableVNode(this, ownerID); 2791 | if (!removingFirst) { 2792 | for (var ii = 0; ii < originIndex; ii++) { 2793 | editable.array[ii] = undefined; 2794 | } 2795 | } 2796 | if (newChild) { 2797 | editable.array[originIndex] = newChild; 2798 | } 2799 | return editable; 2800 | }; 2801 | 2802 | VNode.prototype.removeAfter = function(ownerID, level, index) { 2803 | if (index === level ? 1 << level : 0 || this.array.length === 0) { 2804 | return this; 2805 | } 2806 | var sizeIndex = ((index - 1) >>> level) & MASK; 2807 | if (sizeIndex >= this.array.length) { 2808 | return this; 2809 | } 2810 | var removingLast = sizeIndex === this.array.length - 1; 2811 | var newChild; 2812 | if (level > 0) { 2813 | var oldChild = this.array[sizeIndex]; 2814 | newChild = oldChild && oldChild.removeAfter(ownerID, level - SHIFT, index); 2815 | if (newChild === oldChild && removingLast) { 2816 | return this; 2817 | } 2818 | } 2819 | if (removingLast && !newChild) { 2820 | return this; 2821 | } 2822 | var editable = editableVNode(this, ownerID); 2823 | if (!removingLast) { 2824 | editable.array.pop(); 2825 | } 2826 | if (newChild) { 2827 | editable.array[sizeIndex] = newChild; 2828 | } 2829 | return editable; 2830 | }; 2831 | 2832 | 2833 | 2834 | var DONE = {}; 2835 | 2836 | function iterateList(list, reverse) { 2837 | var left = list._origin; 2838 | var right = list._capacity; 2839 | var tailPos = getTailOffset(right); 2840 | var tail = list._tail; 2841 | 2842 | return iterateNodeOrLeaf(list._root, list._level, 0); 2843 | 2844 | function iterateNodeOrLeaf(node, level, offset) { 2845 | return level === 0 ? 2846 | iterateLeaf(node, offset) : 2847 | iterateNode(node, level, offset); 2848 | } 2849 | 2850 | function iterateLeaf(node, offset) { 2851 | var array = offset === tailPos ? tail && tail.array : node && node.array; 2852 | var from = offset > left ? 0 : left - offset; 2853 | var to = right - offset; 2854 | if (to > SIZE) { 2855 | to = SIZE; 2856 | } 2857 | return function() { 2858 | if (from === to) { 2859 | return DONE; 2860 | } 2861 | var idx = reverse ? --to : from++; 2862 | return array && array[idx]; 2863 | }; 2864 | } 2865 | 2866 | function iterateNode(node, level, offset) { 2867 | var values; 2868 | var array = node && node.array; 2869 | var from = offset > left ? 0 : (left - offset) >> level; 2870 | var to = ((right - offset) >> level) + 1; 2871 | if (to > SIZE) { 2872 | to = SIZE; 2873 | } 2874 | return function() { 2875 | do { 2876 | if (values) { 2877 | var value = values(); 2878 | if (value !== DONE) { 2879 | return value; 2880 | } 2881 | values = null; 2882 | } 2883 | if (from === to) { 2884 | return DONE; 2885 | } 2886 | var idx = reverse ? --to : from++; 2887 | values = iterateNodeOrLeaf( 2888 | array && array[idx], level - SHIFT, offset + (idx << level) 2889 | ); 2890 | } while (true); 2891 | }; 2892 | } 2893 | } 2894 | 2895 | function makeList(origin, capacity, level, root, tail, ownerID, hash) { 2896 | var list = Object.create(ListPrototype); 2897 | list.size = capacity - origin; 2898 | list._origin = origin; 2899 | list._capacity = capacity; 2900 | list._level = level; 2901 | list._root = root; 2902 | list._tail = tail; 2903 | list.__ownerID = ownerID; 2904 | list.__hash = hash; 2905 | list.__altered = false; 2906 | return list; 2907 | } 2908 | 2909 | var EMPTY_LIST; 2910 | function emptyList() { 2911 | return EMPTY_LIST || (EMPTY_LIST = makeList(0, 0, SHIFT)); 2912 | } 2913 | 2914 | function updateList(list, index, value) { 2915 | index = wrapIndex(list, index); 2916 | 2917 | if (index >= list.size || index < 0) { 2918 | return list.withMutations(function(list ) { 2919 | index < 0 ? 2920 | setListBounds(list, index).set(0, value) : 2921 | setListBounds(list, 0, index + 1).set(index, value) 2922 | }); 2923 | } 2924 | 2925 | index += list._origin; 2926 | 2927 | var newTail = list._tail; 2928 | var newRoot = list._root; 2929 | var didAlter = MakeRef(DID_ALTER); 2930 | if (index >= getTailOffset(list._capacity)) { 2931 | newTail = updateVNode(newTail, list.__ownerID, 0, index, value, didAlter); 2932 | } else { 2933 | newRoot = updateVNode(newRoot, list.__ownerID, list._level, index, value, didAlter); 2934 | } 2935 | 2936 | if (!didAlter.value) { 2937 | return list; 2938 | } 2939 | 2940 | if (list.__ownerID) { 2941 | list._root = newRoot; 2942 | list._tail = newTail; 2943 | list.__hash = undefined; 2944 | list.__altered = true; 2945 | return list; 2946 | } 2947 | return makeList(list._origin, list._capacity, list._level, newRoot, newTail); 2948 | } 2949 | 2950 | function updateVNode(node, ownerID, level, index, value, didAlter) { 2951 | var idx = (index >>> level) & MASK; 2952 | var nodeHas = node && idx < node.array.length; 2953 | if (!nodeHas && value === undefined) { 2954 | return node; 2955 | } 2956 | 2957 | var newNode; 2958 | 2959 | if (level > 0) { 2960 | var lowerNode = node && node.array[idx]; 2961 | var newLowerNode = updateVNode(lowerNode, ownerID, level - SHIFT, index, value, didAlter); 2962 | if (newLowerNode === lowerNode) { 2963 | return node; 2964 | } 2965 | newNode = editableVNode(node, ownerID); 2966 | newNode.array[idx] = newLowerNode; 2967 | return newNode; 2968 | } 2969 | 2970 | if (nodeHas && node.array[idx] === value) { 2971 | return node; 2972 | } 2973 | 2974 | SetRef(didAlter); 2975 | 2976 | newNode = editableVNode(node, ownerID); 2977 | if (value === undefined && idx === newNode.array.length - 1) { 2978 | newNode.array.pop(); 2979 | } else { 2980 | newNode.array[idx] = value; 2981 | } 2982 | return newNode; 2983 | } 2984 | 2985 | function editableVNode(node, ownerID) { 2986 | if (ownerID && node && ownerID === node.ownerID) { 2987 | return node; 2988 | } 2989 | return new VNode(node ? node.array.slice() : [], ownerID); 2990 | } 2991 | 2992 | function listNodeFor(list, rawIndex) { 2993 | if (rawIndex >= getTailOffset(list._capacity)) { 2994 | return list._tail; 2995 | } 2996 | if (rawIndex < 1 << (list._level + SHIFT)) { 2997 | var node = list._root; 2998 | var level = list._level; 2999 | while (node && level > 0) { 3000 | node = node.array[(rawIndex >>> level) & MASK]; 3001 | level -= SHIFT; 3002 | } 3003 | return node; 3004 | } 3005 | } 3006 | 3007 | function setListBounds(list, begin, end) { 3008 | var owner = list.__ownerID || new OwnerID(); 3009 | var oldOrigin = list._origin; 3010 | var oldCapacity = list._capacity; 3011 | var newOrigin = oldOrigin + begin; 3012 | var newCapacity = end === undefined ? oldCapacity : end < 0 ? oldCapacity + end : oldOrigin + end; 3013 | if (newOrigin === oldOrigin && newCapacity === oldCapacity) { 3014 | return list; 3015 | } 3016 | 3017 | // If it's going to end after it starts, it's empty. 3018 | if (newOrigin >= newCapacity) { 3019 | return list.clear(); 3020 | } 3021 | 3022 | var newLevel = list._level; 3023 | var newRoot = list._root; 3024 | 3025 | // New origin might require creating a higher root. 3026 | var offsetShift = 0; 3027 | while (newOrigin + offsetShift < 0) { 3028 | newRoot = new VNode(newRoot && newRoot.array.length ? [undefined, newRoot] : [], owner); 3029 | newLevel += SHIFT; 3030 | offsetShift += 1 << newLevel; 3031 | } 3032 | if (offsetShift) { 3033 | newOrigin += offsetShift; 3034 | oldOrigin += offsetShift; 3035 | newCapacity += offsetShift; 3036 | oldCapacity += offsetShift; 3037 | } 3038 | 3039 | var oldTailOffset = getTailOffset(oldCapacity); 3040 | var newTailOffset = getTailOffset(newCapacity); 3041 | 3042 | // New size might require creating a higher root. 3043 | while (newTailOffset >= 1 << (newLevel + SHIFT)) { 3044 | newRoot = new VNode(newRoot && newRoot.array.length ? [newRoot] : [], owner); 3045 | newLevel += SHIFT; 3046 | } 3047 | 3048 | // Locate or create the new tail. 3049 | var oldTail = list._tail; 3050 | var newTail = newTailOffset < oldTailOffset ? 3051 | listNodeFor(list, newCapacity - 1) : 3052 | newTailOffset > oldTailOffset ? new VNode([], owner) : oldTail; 3053 | 3054 | // Merge Tail into tree. 3055 | if (oldTail && newTailOffset > oldTailOffset && newOrigin < oldCapacity && oldTail.array.length) { 3056 | newRoot = editableVNode(newRoot, owner); 3057 | var node = newRoot; 3058 | for (var level = newLevel; level > SHIFT; level -= SHIFT) { 3059 | var idx = (oldTailOffset >>> level) & MASK; 3060 | node = node.array[idx] = editableVNode(node.array[idx], owner); 3061 | } 3062 | node.array[(oldTailOffset >>> SHIFT) & MASK] = oldTail; 3063 | } 3064 | 3065 | // If the size has been reduced, there's a chance the tail needs to be trimmed. 3066 | if (newCapacity < oldCapacity) { 3067 | newTail = newTail && newTail.removeAfter(owner, 0, newCapacity); 3068 | } 3069 | 3070 | // If the new origin is within the tail, then we do not need a root. 3071 | if (newOrigin >= newTailOffset) { 3072 | newOrigin -= newTailOffset; 3073 | newCapacity -= newTailOffset; 3074 | newLevel = SHIFT; 3075 | newRoot = null; 3076 | newTail = newTail && newTail.removeBefore(owner, 0, newOrigin); 3077 | 3078 | // Otherwise, if the root has been trimmed, garbage collect. 3079 | } else if (newOrigin > oldOrigin || newTailOffset < oldTailOffset) { 3080 | offsetShift = 0; 3081 | 3082 | // Identify the new top root node of the subtree of the old root. 3083 | while (newRoot) { 3084 | var beginIndex = (newOrigin >>> newLevel) & MASK; 3085 | if (beginIndex !== (newTailOffset >>> newLevel) & MASK) { 3086 | break; 3087 | } 3088 | if (beginIndex) { 3089 | offsetShift += (1 << newLevel) * beginIndex; 3090 | } 3091 | newLevel -= SHIFT; 3092 | newRoot = newRoot.array[beginIndex]; 3093 | } 3094 | 3095 | // Trim the new sides of the new root. 3096 | if (newRoot && newOrigin > oldOrigin) { 3097 | newRoot = newRoot.removeBefore(owner, newLevel, newOrigin - offsetShift); 3098 | } 3099 | if (newRoot && newTailOffset < oldTailOffset) { 3100 | newRoot = newRoot.removeAfter(owner, newLevel, newTailOffset - offsetShift); 3101 | } 3102 | if (offsetShift) { 3103 | newOrigin -= offsetShift; 3104 | newCapacity -= offsetShift; 3105 | } 3106 | } 3107 | 3108 | if (list.__ownerID) { 3109 | list.size = newCapacity - newOrigin; 3110 | list._origin = newOrigin; 3111 | list._capacity = newCapacity; 3112 | list._level = newLevel; 3113 | list._root = newRoot; 3114 | list._tail = newTail; 3115 | list.__hash = undefined; 3116 | list.__altered = true; 3117 | return list; 3118 | } 3119 | return makeList(newOrigin, newCapacity, newLevel, newRoot, newTail); 3120 | } 3121 | 3122 | function mergeIntoListWith(list, merger, iterables) { 3123 | var iters = []; 3124 | var maxSize = 0; 3125 | for (var ii = 0; ii < iterables.length; ii++) { 3126 | var value = iterables[ii]; 3127 | var iter = IndexedIterable(value); 3128 | if (iter.size > maxSize) { 3129 | maxSize = iter.size; 3130 | } 3131 | if (!isIterable(value)) { 3132 | iter = iter.map(function(v ) {return fromJS(v)}); 3133 | } 3134 | iters.push(iter); 3135 | } 3136 | if (maxSize > list.size) { 3137 | list = list.setSize(maxSize); 3138 | } 3139 | return mergeIntoCollectionWith(list, merger, iters); 3140 | } 3141 | 3142 | function getTailOffset(size) { 3143 | return size < SIZE ? 0 : (((size - 1) >>> SHIFT) << SHIFT); 3144 | } 3145 | 3146 | createClass(OrderedMap, src_Map__Map); 3147 | 3148 | // @pragma Construction 3149 | 3150 | function OrderedMap(value) { 3151 | return value === null || value === undefined ? emptyOrderedMap() : 3152 | isOrderedMap(value) ? value : 3153 | emptyOrderedMap().withMutations(function(map ) { 3154 | var iter = KeyedIterable(value); 3155 | assertNotInfinite(iter.size); 3156 | iter.forEach(function(v, k) {return map.set(k, v)}); 3157 | }); 3158 | } 3159 | 3160 | OrderedMap.of = function(/*...values*/) { 3161 | return this(arguments); 3162 | }; 3163 | 3164 | OrderedMap.prototype.toString = function() { 3165 | return this.__toString('OrderedMap {', '}'); 3166 | }; 3167 | 3168 | // @pragma Access 3169 | 3170 | OrderedMap.prototype.get = function(k, notSetValue) { 3171 | var index = this._map.get(k); 3172 | return index !== undefined ? this._list.get(index)[1] : notSetValue; 3173 | }; 3174 | 3175 | // @pragma Modification 3176 | 3177 | OrderedMap.prototype.clear = function() { 3178 | if (this.size === 0) { 3179 | return this; 3180 | } 3181 | if (this.__ownerID) { 3182 | this.size = 0; 3183 | this._map.clear(); 3184 | this._list.clear(); 3185 | return this; 3186 | } 3187 | return emptyOrderedMap(); 3188 | }; 3189 | 3190 | OrderedMap.prototype.set = function(k, v) { 3191 | return updateOrderedMap(this, k, v); 3192 | }; 3193 | 3194 | OrderedMap.prototype.remove = function(k) { 3195 | return updateOrderedMap(this, k, NOT_SET); 3196 | }; 3197 | 3198 | OrderedMap.prototype.wasAltered = function() { 3199 | return this._map.wasAltered() || this._list.wasAltered(); 3200 | }; 3201 | 3202 | OrderedMap.prototype.__iterate = function(fn, reverse) {var this$0 = this; 3203 | return this._list.__iterate( 3204 | function(entry ) {return entry && fn(entry[1], entry[0], this$0)}, 3205 | reverse 3206 | ); 3207 | }; 3208 | 3209 | OrderedMap.prototype.__iterator = function(type, reverse) { 3210 | return this._list.fromEntrySeq().__iterator(type, reverse); 3211 | }; 3212 | 3213 | OrderedMap.prototype.__ensureOwner = function(ownerID) { 3214 | if (ownerID === this.__ownerID) { 3215 | return this; 3216 | } 3217 | var newMap = this._map.__ensureOwner(ownerID); 3218 | var newList = this._list.__ensureOwner(ownerID); 3219 | if (!ownerID) { 3220 | this.__ownerID = ownerID; 3221 | this._map = newMap; 3222 | this._list = newList; 3223 | return this; 3224 | } 3225 | return makeOrderedMap(newMap, newList, ownerID, this.__hash); 3226 | }; 3227 | 3228 | 3229 | function isOrderedMap(maybeOrderedMap) { 3230 | return isMap(maybeOrderedMap) && isOrdered(maybeOrderedMap); 3231 | } 3232 | 3233 | OrderedMap.isOrderedMap = isOrderedMap; 3234 | 3235 | OrderedMap.prototype[IS_ORDERED_SENTINEL] = true; 3236 | OrderedMap.prototype[DELETE] = OrderedMap.prototype.remove; 3237 | 3238 | 3239 | 3240 | function makeOrderedMap(map, list, ownerID, hash) { 3241 | var omap = Object.create(OrderedMap.prototype); 3242 | omap.size = map ? map.size : 0; 3243 | omap._map = map; 3244 | omap._list = list; 3245 | omap.__ownerID = ownerID; 3246 | omap.__hash = hash; 3247 | return omap; 3248 | } 3249 | 3250 | var EMPTY_ORDERED_MAP; 3251 | function emptyOrderedMap() { 3252 | return EMPTY_ORDERED_MAP || (EMPTY_ORDERED_MAP = makeOrderedMap(emptyMap(), emptyList())); 3253 | } 3254 | 3255 | function updateOrderedMap(omap, k, v) { 3256 | var map = omap._map; 3257 | var list = omap._list; 3258 | var i = map.get(k); 3259 | var has = i !== undefined; 3260 | var newMap; 3261 | var newList; 3262 | if (v === NOT_SET) { // removed 3263 | if (!has) { 3264 | return omap; 3265 | } 3266 | if (list.size >= SIZE && list.size >= map.size * 2) { 3267 | newList = list.filter(function(entry, idx) {return entry !== undefined && i !== idx}); 3268 | newMap = newList.toKeyedSeq().map(function(entry ) {return entry[0]}).flip().toMap(); 3269 | if (omap.__ownerID) { 3270 | newMap.__ownerID = newList.__ownerID = omap.__ownerID; 3271 | } 3272 | } else { 3273 | newMap = map.remove(k); 3274 | newList = i === list.size - 1 ? list.pop() : list.set(i, undefined); 3275 | } 3276 | } else { 3277 | if (has) { 3278 | if (v === list.get(i)[1]) { 3279 | return omap; 3280 | } 3281 | newMap = map; 3282 | newList = list.set(i, [k, v]); 3283 | } else { 3284 | newMap = map.set(k, list.size); 3285 | newList = list.set(list.size, [k, v]); 3286 | } 3287 | } 3288 | if (omap.__ownerID) { 3289 | omap.size = newMap.size; 3290 | omap._map = newMap; 3291 | omap._list = newList; 3292 | omap.__hash = undefined; 3293 | return omap; 3294 | } 3295 | return makeOrderedMap(newMap, newList); 3296 | } 3297 | 3298 | createClass(Stack, IndexedCollection); 3299 | 3300 | // @pragma Construction 3301 | 3302 | function Stack(value) { 3303 | return value === null || value === undefined ? emptyStack() : 3304 | isStack(value) ? value : 3305 | emptyStack().unshiftAll(value); 3306 | } 3307 | 3308 | Stack.of = function(/*...values*/) { 3309 | return this(arguments); 3310 | }; 3311 | 3312 | Stack.prototype.toString = function() { 3313 | return this.__toString('Stack [', ']'); 3314 | }; 3315 | 3316 | // @pragma Access 3317 | 3318 | Stack.prototype.get = function(index, notSetValue) { 3319 | var head = this._head; 3320 | index = wrapIndex(this, index); 3321 | while (head && index--) { 3322 | head = head.next; 3323 | } 3324 | return head ? head.value : notSetValue; 3325 | }; 3326 | 3327 | Stack.prototype.peek = function() { 3328 | return this._head && this._head.value; 3329 | }; 3330 | 3331 | // @pragma Modification 3332 | 3333 | Stack.prototype.push = function(/*...values*/) { 3334 | if (arguments.length === 0) { 3335 | return this; 3336 | } 3337 | var newSize = this.size + arguments.length; 3338 | var head = this._head; 3339 | for (var ii = arguments.length - 1; ii >= 0; ii--) { 3340 | head = { 3341 | value: arguments[ii], 3342 | next: head 3343 | }; 3344 | } 3345 | if (this.__ownerID) { 3346 | this.size = newSize; 3347 | this._head = head; 3348 | this.__hash = undefined; 3349 | this.__altered = true; 3350 | return this; 3351 | } 3352 | return makeStack(newSize, head); 3353 | }; 3354 | 3355 | Stack.prototype.pushAll = function(iter) { 3356 | iter = IndexedIterable(iter); 3357 | if (iter.size === 0) { 3358 | return this; 3359 | } 3360 | assertNotInfinite(iter.size); 3361 | var newSize = this.size; 3362 | var head = this._head; 3363 | iter.reverse().forEach(function(value ) { 3364 | newSize++; 3365 | head = { 3366 | value: value, 3367 | next: head 3368 | }; 3369 | }); 3370 | if (this.__ownerID) { 3371 | this.size = newSize; 3372 | this._head = head; 3373 | this.__hash = undefined; 3374 | this.__altered = true; 3375 | return this; 3376 | } 3377 | return makeStack(newSize, head); 3378 | }; 3379 | 3380 | Stack.prototype.pop = function() { 3381 | return this.slice(1); 3382 | }; 3383 | 3384 | Stack.prototype.unshift = function(/*...values*/) { 3385 | return this.push.apply(this, arguments); 3386 | }; 3387 | 3388 | Stack.prototype.unshiftAll = function(iter) { 3389 | return this.pushAll(iter); 3390 | }; 3391 | 3392 | Stack.prototype.shift = function() { 3393 | return this.pop.apply(this, arguments); 3394 | }; 3395 | 3396 | Stack.prototype.clear = function() { 3397 | if (this.size === 0) { 3398 | return this; 3399 | } 3400 | if (this.__ownerID) { 3401 | this.size = 0; 3402 | this._head = undefined; 3403 | this.__hash = undefined; 3404 | this.__altered = true; 3405 | return this; 3406 | } 3407 | return emptyStack(); 3408 | }; 3409 | 3410 | Stack.prototype.slice = function(begin, end) { 3411 | if (wholeSlice(begin, end, this.size)) { 3412 | return this; 3413 | } 3414 | var resolvedBegin = resolveBegin(begin, this.size); 3415 | var resolvedEnd = resolveEnd(end, this.size); 3416 | if (resolvedEnd !== this.size) { 3417 | // super.slice(begin, end); 3418 | return IndexedCollection.prototype.slice.call(this, begin, end); 3419 | } 3420 | var newSize = this.size - resolvedBegin; 3421 | var head = this._head; 3422 | while (resolvedBegin--) { 3423 | head = head.next; 3424 | } 3425 | if (this.__ownerID) { 3426 | this.size = newSize; 3427 | this._head = head; 3428 | this.__hash = undefined; 3429 | this.__altered = true; 3430 | return this; 3431 | } 3432 | return makeStack(newSize, head); 3433 | }; 3434 | 3435 | // @pragma Mutability 3436 | 3437 | Stack.prototype.__ensureOwner = function(ownerID) { 3438 | if (ownerID === this.__ownerID) { 3439 | return this; 3440 | } 3441 | if (!ownerID) { 3442 | this.__ownerID = ownerID; 3443 | this.__altered = false; 3444 | return this; 3445 | } 3446 | return makeStack(this.size, this._head, ownerID, this.__hash); 3447 | }; 3448 | 3449 | // @pragma Iteration 3450 | 3451 | Stack.prototype.__iterate = function(fn, reverse) { 3452 | if (reverse) { 3453 | return this.reverse().__iterate(fn); 3454 | } 3455 | var iterations = 0; 3456 | var node = this._head; 3457 | while (node) { 3458 | if (fn(node.value, iterations++, this) === false) { 3459 | break; 3460 | } 3461 | node = node.next; 3462 | } 3463 | return iterations; 3464 | }; 3465 | 3466 | Stack.prototype.__iterator = function(type, reverse) { 3467 | if (reverse) { 3468 | return this.reverse().__iterator(type); 3469 | } 3470 | var iterations = 0; 3471 | var node = this._head; 3472 | return new src_Iterator__Iterator(function() { 3473 | if (node) { 3474 | var value = node.value; 3475 | node = node.next; 3476 | return iteratorValue(type, iterations++, value); 3477 | } 3478 | return iteratorDone(); 3479 | }); 3480 | }; 3481 | 3482 | 3483 | function isStack(maybeStack) { 3484 | return !!(maybeStack && maybeStack[IS_STACK_SENTINEL]); 3485 | } 3486 | 3487 | Stack.isStack = isStack; 3488 | 3489 | var IS_STACK_SENTINEL = '@@__IMMUTABLE_STACK__@@'; 3490 | 3491 | var StackPrototype = Stack.prototype; 3492 | StackPrototype[IS_STACK_SENTINEL] = true; 3493 | StackPrototype.withMutations = MapPrototype.withMutations; 3494 | StackPrototype.asMutable = MapPrototype.asMutable; 3495 | StackPrototype.asImmutable = MapPrototype.asImmutable; 3496 | StackPrototype.wasAltered = MapPrototype.wasAltered; 3497 | 3498 | 3499 | function makeStack(size, head, ownerID, hash) { 3500 | var map = Object.create(StackPrototype); 3501 | map.size = size; 3502 | map._head = head; 3503 | map.__ownerID = ownerID; 3504 | map.__hash = hash; 3505 | map.__altered = false; 3506 | return map; 3507 | } 3508 | 3509 | var EMPTY_STACK; 3510 | function emptyStack() { 3511 | return EMPTY_STACK || (EMPTY_STACK = makeStack(0)); 3512 | } 3513 | 3514 | createClass(src_Set__Set, SetCollection); 3515 | 3516 | // @pragma Construction 3517 | 3518 | function src_Set__Set(value) { 3519 | return value === null || value === undefined ? emptySet() : 3520 | isSet(value) ? value : 3521 | emptySet().withMutations(function(set ) { 3522 | var iter = SetIterable(value); 3523 | assertNotInfinite(iter.size); 3524 | iter.forEach(function(v ) {return set.add(v)}); 3525 | }); 3526 | } 3527 | 3528 | src_Set__Set.of = function(/*...values*/) { 3529 | return this(arguments); 3530 | }; 3531 | 3532 | src_Set__Set.fromKeys = function(value) { 3533 | return this(KeyedIterable(value).keySeq()); 3534 | }; 3535 | 3536 | src_Set__Set.prototype.toString = function() { 3537 | return this.__toString('Set {', '}'); 3538 | }; 3539 | 3540 | // @pragma Access 3541 | 3542 | src_Set__Set.prototype.has = function(value) { 3543 | return this._map.has(value); 3544 | }; 3545 | 3546 | // @pragma Modification 3547 | 3548 | src_Set__Set.prototype.add = function(value) { 3549 | return updateSet(this, this._map.set(value, true)); 3550 | }; 3551 | 3552 | src_Set__Set.prototype.remove = function(value) { 3553 | return updateSet(this, this._map.remove(value)); 3554 | }; 3555 | 3556 | src_Set__Set.prototype.clear = function() { 3557 | return updateSet(this, this._map.clear()); 3558 | }; 3559 | 3560 | // @pragma Composition 3561 | 3562 | src_Set__Set.prototype.union = function() {var iters = SLICE$0.call(arguments, 0); 3563 | iters = iters.filter(function(x ) {return x.size !== 0}); 3564 | if (iters.length === 0) { 3565 | return this; 3566 | } 3567 | if (this.size === 0 && !this.__ownerID && iters.length === 1) { 3568 | return this.constructor(iters[0]); 3569 | } 3570 | return this.withMutations(function(set ) { 3571 | for (var ii = 0; ii < iters.length; ii++) { 3572 | SetIterable(iters[ii]).forEach(function(value ) {return set.add(value)}); 3573 | } 3574 | }); 3575 | }; 3576 | 3577 | src_Set__Set.prototype.intersect = function() {var iters = SLICE$0.call(arguments, 0); 3578 | if (iters.length === 0) { 3579 | return this; 3580 | } 3581 | iters = iters.map(function(iter ) {return SetIterable(iter)}); 3582 | var originalSet = this; 3583 | return this.withMutations(function(set ) { 3584 | originalSet.forEach(function(value ) { 3585 | if (!iters.every(function(iter ) {return iter.includes(value)})) { 3586 | set.remove(value); 3587 | } 3588 | }); 3589 | }); 3590 | }; 3591 | 3592 | src_Set__Set.prototype.subtract = function() {var iters = SLICE$0.call(arguments, 0); 3593 | if (iters.length === 0) { 3594 | return this; 3595 | } 3596 | iters = iters.map(function(iter ) {return SetIterable(iter)}); 3597 | var originalSet = this; 3598 | return this.withMutations(function(set ) { 3599 | originalSet.forEach(function(value ) { 3600 | if (iters.some(function(iter ) {return iter.includes(value)})) { 3601 | set.remove(value); 3602 | } 3603 | }); 3604 | }); 3605 | }; 3606 | 3607 | src_Set__Set.prototype.merge = function() { 3608 | return this.union.apply(this, arguments); 3609 | }; 3610 | 3611 | src_Set__Set.prototype.mergeWith = function(merger) {var iters = SLICE$0.call(arguments, 1); 3612 | return this.union.apply(this, iters); 3613 | }; 3614 | 3615 | src_Set__Set.prototype.sort = function(comparator) { 3616 | // Late binding 3617 | return OrderedSet(sortFactory(this, comparator)); 3618 | }; 3619 | 3620 | src_Set__Set.prototype.sortBy = function(mapper, comparator) { 3621 | // Late binding 3622 | return OrderedSet(sortFactory(this, comparator, mapper)); 3623 | }; 3624 | 3625 | src_Set__Set.prototype.wasAltered = function() { 3626 | return this._map.wasAltered(); 3627 | }; 3628 | 3629 | src_Set__Set.prototype.__iterate = function(fn, reverse) {var this$0 = this; 3630 | return this._map.__iterate(function(_, k) {return fn(k, k, this$0)}, reverse); 3631 | }; 3632 | 3633 | src_Set__Set.prototype.__iterator = function(type, reverse) { 3634 | return this._map.map(function(_, k) {return k}).__iterator(type, reverse); 3635 | }; 3636 | 3637 | src_Set__Set.prototype.__ensureOwner = function(ownerID) { 3638 | if (ownerID === this.__ownerID) { 3639 | return this; 3640 | } 3641 | var newMap = this._map.__ensureOwner(ownerID); 3642 | if (!ownerID) { 3643 | this.__ownerID = ownerID; 3644 | this._map = newMap; 3645 | return this; 3646 | } 3647 | return this.__make(newMap, ownerID); 3648 | }; 3649 | 3650 | 3651 | function isSet(maybeSet) { 3652 | return !!(maybeSet && maybeSet[IS_SET_SENTINEL]); 3653 | } 3654 | 3655 | src_Set__Set.isSet = isSet; 3656 | 3657 | var IS_SET_SENTINEL = '@@__IMMUTABLE_SET__@@'; 3658 | 3659 | var SetPrototype = src_Set__Set.prototype; 3660 | SetPrototype[IS_SET_SENTINEL] = true; 3661 | SetPrototype[DELETE] = SetPrototype.remove; 3662 | SetPrototype.mergeDeep = SetPrototype.merge; 3663 | SetPrototype.mergeDeepWith = SetPrototype.mergeWith; 3664 | SetPrototype.withMutations = MapPrototype.withMutations; 3665 | SetPrototype.asMutable = MapPrototype.asMutable; 3666 | SetPrototype.asImmutable = MapPrototype.asImmutable; 3667 | 3668 | SetPrototype.__empty = emptySet; 3669 | SetPrototype.__make = makeSet; 3670 | 3671 | function updateSet(set, newMap) { 3672 | if (set.__ownerID) { 3673 | set.size = newMap.size; 3674 | set._map = newMap; 3675 | return set; 3676 | } 3677 | return newMap === set._map ? set : 3678 | newMap.size === 0 ? set.__empty() : 3679 | set.__make(newMap); 3680 | } 3681 | 3682 | function makeSet(map, ownerID) { 3683 | var set = Object.create(SetPrototype); 3684 | set.size = map ? map.size : 0; 3685 | set._map = map; 3686 | set.__ownerID = ownerID; 3687 | return set; 3688 | } 3689 | 3690 | var EMPTY_SET; 3691 | function emptySet() { 3692 | return EMPTY_SET || (EMPTY_SET = makeSet(emptyMap())); 3693 | } 3694 | 3695 | createClass(OrderedSet, src_Set__Set); 3696 | 3697 | // @pragma Construction 3698 | 3699 | function OrderedSet(value) { 3700 | return value === null || value === undefined ? emptyOrderedSet() : 3701 | isOrderedSet(value) ? value : 3702 | emptyOrderedSet().withMutations(function(set ) { 3703 | var iter = SetIterable(value); 3704 | assertNotInfinite(iter.size); 3705 | iter.forEach(function(v ) {return set.add(v)}); 3706 | }); 3707 | } 3708 | 3709 | OrderedSet.of = function(/*...values*/) { 3710 | return this(arguments); 3711 | }; 3712 | 3713 | OrderedSet.fromKeys = function(value) { 3714 | return this(KeyedIterable(value).keySeq()); 3715 | }; 3716 | 3717 | OrderedSet.prototype.toString = function() { 3718 | return this.__toString('OrderedSet {', '}'); 3719 | }; 3720 | 3721 | 3722 | function isOrderedSet(maybeOrderedSet) { 3723 | return isSet(maybeOrderedSet) && isOrdered(maybeOrderedSet); 3724 | } 3725 | 3726 | OrderedSet.isOrderedSet = isOrderedSet; 3727 | 3728 | var OrderedSetPrototype = OrderedSet.prototype; 3729 | OrderedSetPrototype[IS_ORDERED_SENTINEL] = true; 3730 | 3731 | OrderedSetPrototype.__empty = emptyOrderedSet; 3732 | OrderedSetPrototype.__make = makeOrderedSet; 3733 | 3734 | function makeOrderedSet(map, ownerID) { 3735 | var set = Object.create(OrderedSetPrototype); 3736 | set.size = map ? map.size : 0; 3737 | set._map = map; 3738 | set.__ownerID = ownerID; 3739 | return set; 3740 | } 3741 | 3742 | var EMPTY_ORDERED_SET; 3743 | function emptyOrderedSet() { 3744 | return EMPTY_ORDERED_SET || (EMPTY_ORDERED_SET = makeOrderedSet(emptyOrderedMap())); 3745 | } 3746 | 3747 | createClass(Record, KeyedCollection); 3748 | 3749 | function Record(defaultValues, name) { 3750 | var hasInitialized; 3751 | 3752 | var RecordType = function Record(values) { 3753 | if (values instanceof RecordType) { 3754 | return values; 3755 | } 3756 | if (!(this instanceof RecordType)) { 3757 | return new RecordType(values); 3758 | } 3759 | if (!hasInitialized) { 3760 | hasInitialized = true; 3761 | var keys = Object.keys(defaultValues); 3762 | setProps(RecordTypePrototype, keys); 3763 | RecordTypePrototype.size = keys.length; 3764 | RecordTypePrototype._name = name; 3765 | RecordTypePrototype._keys = keys; 3766 | RecordTypePrototype._defaultValues = defaultValues; 3767 | } 3768 | this._map = src_Map__Map(values); 3769 | }; 3770 | 3771 | var RecordTypePrototype = RecordType.prototype = Object.create(RecordPrototype); 3772 | RecordTypePrototype.constructor = RecordType; 3773 | 3774 | return RecordType; 3775 | } 3776 | 3777 | Record.prototype.toString = function() { 3778 | return this.__toString(recordName(this) + ' {', '}'); 3779 | }; 3780 | 3781 | // @pragma Access 3782 | 3783 | Record.prototype.has = function(k) { 3784 | return this._defaultValues.hasOwnProperty(k); 3785 | }; 3786 | 3787 | Record.prototype.get = function(k, notSetValue) { 3788 | if (!this.has(k)) { 3789 | return notSetValue; 3790 | } 3791 | var defaultVal = this._defaultValues[k]; 3792 | return this._map ? this._map.get(k, defaultVal) : defaultVal; 3793 | }; 3794 | 3795 | // @pragma Modification 3796 | 3797 | Record.prototype.clear = function() { 3798 | if (this.__ownerID) { 3799 | this._map && this._map.clear(); 3800 | return this; 3801 | } 3802 | var RecordType = this.constructor; 3803 | return RecordType._empty || (RecordType._empty = makeRecord(this, emptyMap())); 3804 | }; 3805 | 3806 | Record.prototype.set = function(k, v) { 3807 | if (!this.has(k)) { 3808 | throw new Error('Cannot set unknown key "' + k + '" on ' + recordName(this)); 3809 | } 3810 | var newMap = this._map && this._map.set(k, v); 3811 | if (this.__ownerID || newMap === this._map) { 3812 | return this; 3813 | } 3814 | return makeRecord(this, newMap); 3815 | }; 3816 | 3817 | Record.prototype.remove = function(k) { 3818 | if (!this.has(k)) { 3819 | return this; 3820 | } 3821 | var newMap = this._map && this._map.remove(k); 3822 | if (this.__ownerID || newMap === this._map) { 3823 | return this; 3824 | } 3825 | return makeRecord(this, newMap); 3826 | }; 3827 | 3828 | Record.prototype.wasAltered = function() { 3829 | return this._map.wasAltered(); 3830 | }; 3831 | 3832 | Record.prototype.__iterator = function(type, reverse) {var this$0 = this; 3833 | return KeyedIterable(this._defaultValues).map(function(_, k) {return this$0.get(k)}).__iterator(type, reverse); 3834 | }; 3835 | 3836 | Record.prototype.__iterate = function(fn, reverse) {var this$0 = this; 3837 | return KeyedIterable(this._defaultValues).map(function(_, k) {return this$0.get(k)}).__iterate(fn, reverse); 3838 | }; 3839 | 3840 | Record.prototype.__ensureOwner = function(ownerID) { 3841 | if (ownerID === this.__ownerID) { 3842 | return this; 3843 | } 3844 | var newMap = this._map && this._map.__ensureOwner(ownerID); 3845 | if (!ownerID) { 3846 | this.__ownerID = ownerID; 3847 | this._map = newMap; 3848 | return this; 3849 | } 3850 | return makeRecord(this, newMap, ownerID); 3851 | }; 3852 | 3853 | 3854 | var RecordPrototype = Record.prototype; 3855 | RecordPrototype[DELETE] = RecordPrototype.remove; 3856 | RecordPrototype.deleteIn = 3857 | RecordPrototype.removeIn = MapPrototype.removeIn; 3858 | RecordPrototype.merge = MapPrototype.merge; 3859 | RecordPrototype.mergeWith = MapPrototype.mergeWith; 3860 | RecordPrototype.mergeIn = MapPrototype.mergeIn; 3861 | RecordPrototype.mergeDeep = MapPrototype.mergeDeep; 3862 | RecordPrototype.mergeDeepWith = MapPrototype.mergeDeepWith; 3863 | RecordPrototype.mergeDeepIn = MapPrototype.mergeDeepIn; 3864 | RecordPrototype.setIn = MapPrototype.setIn; 3865 | RecordPrototype.update = MapPrototype.update; 3866 | RecordPrototype.updateIn = MapPrototype.updateIn; 3867 | RecordPrototype.withMutations = MapPrototype.withMutations; 3868 | RecordPrototype.asMutable = MapPrototype.asMutable; 3869 | RecordPrototype.asImmutable = MapPrototype.asImmutable; 3870 | 3871 | 3872 | function makeRecord(likeRecord, map, ownerID) { 3873 | var record = Object.create(Object.getPrototypeOf(likeRecord)); 3874 | record._map = map; 3875 | record.__ownerID = ownerID; 3876 | return record; 3877 | } 3878 | 3879 | function recordName(record) { 3880 | return record._name || record.constructor.name || 'Record'; 3881 | } 3882 | 3883 | function setProps(prototype, names) { 3884 | try { 3885 | names.forEach(setProp.bind(undefined, prototype)); 3886 | } catch (error) { 3887 | // Object.defineProperty failed. Probably IE8. 3888 | } 3889 | } 3890 | 3891 | function setProp(prototype, name) { 3892 | Object.defineProperty(prototype, name, { 3893 | get: function() { 3894 | return this.get(name); 3895 | }, 3896 | set: function(value) { 3897 | invariant(this.__ownerID, 'Cannot set on an immutable record.'); 3898 | this.set(name, value); 3899 | } 3900 | }); 3901 | } 3902 | 3903 | function deepEqual(a, b) { 3904 | if (a === b) { 3905 | return true; 3906 | } 3907 | 3908 | if ( 3909 | !isIterable(b) || 3910 | a.size !== undefined && b.size !== undefined && a.size !== b.size || 3911 | a.__hash !== undefined && b.__hash !== undefined && a.__hash !== b.__hash || 3912 | isKeyed(a) !== isKeyed(b) || 3913 | isIndexed(a) !== isIndexed(b) || 3914 | isOrdered(a) !== isOrdered(b) 3915 | ) { 3916 | return false; 3917 | } 3918 | 3919 | if (a.size === 0 && b.size === 0) { 3920 | return true; 3921 | } 3922 | 3923 | var notAssociative = !isAssociative(a); 3924 | 3925 | if (isOrdered(a)) { 3926 | var entries = a.entries(); 3927 | return b.every(function(v, k) { 3928 | var entry = entries.next().value; 3929 | return entry && is(entry[1], v) && (notAssociative || is(entry[0], k)); 3930 | }) && entries.next().done; 3931 | } 3932 | 3933 | var flipped = false; 3934 | 3935 | if (a.size === undefined) { 3936 | if (b.size === undefined) { 3937 | if (typeof a.cacheResult === 'function') { 3938 | a.cacheResult(); 3939 | } 3940 | } else { 3941 | flipped = true; 3942 | var _ = a; 3943 | a = b; 3944 | b = _; 3945 | } 3946 | } 3947 | 3948 | var allEqual = true; 3949 | var bSize = b.__iterate(function(v, k) { 3950 | if (notAssociative ? !a.has(v) : 3951 | flipped ? !is(v, a.get(k, NOT_SET)) : !is(a.get(k, NOT_SET), v)) { 3952 | allEqual = false; 3953 | return false; 3954 | } 3955 | }); 3956 | 3957 | return allEqual && a.size === bSize; 3958 | } 3959 | 3960 | createClass(Range, IndexedSeq); 3961 | 3962 | function Range(start, end, step) { 3963 | if (!(this instanceof Range)) { 3964 | return new Range(start, end, step); 3965 | } 3966 | invariant(step !== 0, 'Cannot step a Range by 0'); 3967 | start = start || 0; 3968 | if (end === undefined) { 3969 | end = Infinity; 3970 | } 3971 | step = step === undefined ? 1 : Math.abs(step); 3972 | if (end < start) { 3973 | step = -step; 3974 | } 3975 | this._start = start; 3976 | this._end = end; 3977 | this._step = step; 3978 | this.size = Math.max(0, Math.ceil((end - start) / step - 1) + 1); 3979 | if (this.size === 0) { 3980 | if (EMPTY_RANGE) { 3981 | return EMPTY_RANGE; 3982 | } 3983 | EMPTY_RANGE = this; 3984 | } 3985 | } 3986 | 3987 | Range.prototype.toString = function() { 3988 | if (this.size === 0) { 3989 | return 'Range []'; 3990 | } 3991 | return 'Range [ ' + 3992 | this._start + '...' + this._end + 3993 | (this._step > 1 ? ' by ' + this._step : '') + 3994 | ' ]'; 3995 | }; 3996 | 3997 | Range.prototype.get = function(index, notSetValue) { 3998 | return this.has(index) ? 3999 | this._start + wrapIndex(this, index) * this._step : 4000 | notSetValue; 4001 | }; 4002 | 4003 | Range.prototype.includes = function(searchValue) { 4004 | var possibleIndex = (searchValue - this._start) / this._step; 4005 | return possibleIndex >= 0 && 4006 | possibleIndex < this.size && 4007 | possibleIndex === Math.floor(possibleIndex); 4008 | }; 4009 | 4010 | Range.prototype.slice = function(begin, end) { 4011 | if (wholeSlice(begin, end, this.size)) { 4012 | return this; 4013 | } 4014 | begin = resolveBegin(begin, this.size); 4015 | end = resolveEnd(end, this.size); 4016 | if (end <= begin) { 4017 | return new Range(0, 0); 4018 | } 4019 | return new Range(this.get(begin, this._end), this.get(end, this._end), this._step); 4020 | }; 4021 | 4022 | Range.prototype.indexOf = function(searchValue) { 4023 | var offsetValue = searchValue - this._start; 4024 | if (offsetValue % this._step === 0) { 4025 | var index = offsetValue / this._step; 4026 | if (index >= 0 && index < this.size) { 4027 | return index 4028 | } 4029 | } 4030 | return -1; 4031 | }; 4032 | 4033 | Range.prototype.lastIndexOf = function(searchValue) { 4034 | return this.indexOf(searchValue); 4035 | }; 4036 | 4037 | Range.prototype.__iterate = function(fn, reverse) { 4038 | var maxIndex = this.size - 1; 4039 | var step = this._step; 4040 | var value = reverse ? this._start + maxIndex * step : this._start; 4041 | for (var ii = 0; ii <= maxIndex; ii++) { 4042 | if (fn(value, ii, this) === false) { 4043 | return ii + 1; 4044 | } 4045 | value += reverse ? -step : step; 4046 | } 4047 | return ii; 4048 | }; 4049 | 4050 | Range.prototype.__iterator = function(type, reverse) { 4051 | var maxIndex = this.size - 1; 4052 | var step = this._step; 4053 | var value = reverse ? this._start + maxIndex * step : this._start; 4054 | var ii = 0; 4055 | return new src_Iterator__Iterator(function() { 4056 | var v = value; 4057 | value += reverse ? -step : step; 4058 | return ii > maxIndex ? iteratorDone() : iteratorValue(type, ii++, v); 4059 | }); 4060 | }; 4061 | 4062 | Range.prototype.equals = function(other) { 4063 | return other instanceof Range ? 4064 | this._start === other._start && 4065 | this._end === other._end && 4066 | this._step === other._step : 4067 | deepEqual(this, other); 4068 | }; 4069 | 4070 | 4071 | var EMPTY_RANGE; 4072 | 4073 | createClass(Repeat, IndexedSeq); 4074 | 4075 | function Repeat(value, times) { 4076 | if (!(this instanceof Repeat)) { 4077 | return new Repeat(value, times); 4078 | } 4079 | this._value = value; 4080 | this.size = times === undefined ? Infinity : Math.max(0, times); 4081 | if (this.size === 0) { 4082 | if (EMPTY_REPEAT) { 4083 | return EMPTY_REPEAT; 4084 | } 4085 | EMPTY_REPEAT = this; 4086 | } 4087 | } 4088 | 4089 | Repeat.prototype.toString = function() { 4090 | if (this.size === 0) { 4091 | return 'Repeat []'; 4092 | } 4093 | return 'Repeat [ ' + this._value + ' ' + this.size + ' times ]'; 4094 | }; 4095 | 4096 | Repeat.prototype.get = function(index, notSetValue) { 4097 | return this.has(index) ? this._value : notSetValue; 4098 | }; 4099 | 4100 | Repeat.prototype.includes = function(searchValue) { 4101 | return is(this._value, searchValue); 4102 | }; 4103 | 4104 | Repeat.prototype.slice = function(begin, end) { 4105 | var size = this.size; 4106 | return wholeSlice(begin, end, size) ? this : 4107 | new Repeat(this._value, resolveEnd(end, size) - resolveBegin(begin, size)); 4108 | }; 4109 | 4110 | Repeat.prototype.reverse = function() { 4111 | return this; 4112 | }; 4113 | 4114 | Repeat.prototype.indexOf = function(searchValue) { 4115 | if (is(this._value, searchValue)) { 4116 | return 0; 4117 | } 4118 | return -1; 4119 | }; 4120 | 4121 | Repeat.prototype.lastIndexOf = function(searchValue) { 4122 | if (is(this._value, searchValue)) { 4123 | return this.size; 4124 | } 4125 | return -1; 4126 | }; 4127 | 4128 | Repeat.prototype.__iterate = function(fn, reverse) { 4129 | for (var ii = 0; ii < this.size; ii++) { 4130 | if (fn(this._value, ii, this) === false) { 4131 | return ii + 1; 4132 | } 4133 | } 4134 | return ii; 4135 | }; 4136 | 4137 | Repeat.prototype.__iterator = function(type, reverse) {var this$0 = this; 4138 | var ii = 0; 4139 | return new src_Iterator__Iterator(function() 4140 | {return ii < this$0.size ? iteratorValue(type, ii++, this$0._value) : iteratorDone()} 4141 | ); 4142 | }; 4143 | 4144 | Repeat.prototype.equals = function(other) { 4145 | return other instanceof Repeat ? 4146 | is(this._value, other._value) : 4147 | deepEqual(other); 4148 | }; 4149 | 4150 | 4151 | var EMPTY_REPEAT; 4152 | 4153 | /** 4154 | * Contributes additional methods to a constructor 4155 | */ 4156 | function mixin(ctor, methods) { 4157 | var keyCopier = function(key ) { ctor.prototype[key] = methods[key]; }; 4158 | Object.keys(methods).forEach(keyCopier); 4159 | Object.getOwnPropertySymbols && 4160 | Object.getOwnPropertySymbols(methods).forEach(keyCopier); 4161 | return ctor; 4162 | } 4163 | 4164 | Iterable.Iterator = src_Iterator__Iterator; 4165 | 4166 | mixin(Iterable, { 4167 | 4168 | // ### Conversion to other types 4169 | 4170 | toArray: function() { 4171 | assertNotInfinite(this.size); 4172 | var array = new Array(this.size || 0); 4173 | this.valueSeq().__iterate(function(v, i) { array[i] = v; }); 4174 | return array; 4175 | }, 4176 | 4177 | toIndexedSeq: function() { 4178 | return new ToIndexedSequence(this); 4179 | }, 4180 | 4181 | toJS: function() { 4182 | return this.toSeq().map( 4183 | function(value ) {return value && typeof value.toJS === 'function' ? value.toJS() : value} 4184 | ).__toJS(); 4185 | }, 4186 | 4187 | toJSON: function() { 4188 | return this.toSeq().map( 4189 | function(value ) {return value && typeof value.toJSON === 'function' ? value.toJSON() : value} 4190 | ).__toJS(); 4191 | }, 4192 | 4193 | toKeyedSeq: function() { 4194 | return new ToKeyedSequence(this, true); 4195 | }, 4196 | 4197 | toMap: function() { 4198 | // Use Late Binding here to solve the circular dependency. 4199 | return src_Map__Map(this.toKeyedSeq()); 4200 | }, 4201 | 4202 | toObject: function() { 4203 | assertNotInfinite(this.size); 4204 | var object = {}; 4205 | this.__iterate(function(v, k) { object[k] = v; }); 4206 | return object; 4207 | }, 4208 | 4209 | toOrderedMap: function() { 4210 | // Use Late Binding here to solve the circular dependency. 4211 | return OrderedMap(this.toKeyedSeq()); 4212 | }, 4213 | 4214 | toOrderedSet: function() { 4215 | // Use Late Binding here to solve the circular dependency. 4216 | return OrderedSet(isKeyed(this) ? this.valueSeq() : this); 4217 | }, 4218 | 4219 | toSet: function() { 4220 | // Use Late Binding here to solve the circular dependency. 4221 | return src_Set__Set(isKeyed(this) ? this.valueSeq() : this); 4222 | }, 4223 | 4224 | toSetSeq: function() { 4225 | return new ToSetSequence(this); 4226 | }, 4227 | 4228 | toSeq: function() { 4229 | return isIndexed(this) ? this.toIndexedSeq() : 4230 | isKeyed(this) ? this.toKeyedSeq() : 4231 | this.toSetSeq(); 4232 | }, 4233 | 4234 | toStack: function() { 4235 | // Use Late Binding here to solve the circular dependency. 4236 | return Stack(isKeyed(this) ? this.valueSeq() : this); 4237 | }, 4238 | 4239 | toList: function() { 4240 | // Use Late Binding here to solve the circular dependency. 4241 | return List(isKeyed(this) ? this.valueSeq() : this); 4242 | }, 4243 | 4244 | 4245 | // ### Common JavaScript methods and properties 4246 | 4247 | toString: function() { 4248 | return '[Iterable]'; 4249 | }, 4250 | 4251 | __toString: function(head, tail) { 4252 | if (this.size === 0) { 4253 | return head + tail; 4254 | } 4255 | return head + ' ' + this.toSeq().map(this.__toStringMapper).join(', ') + ' ' + tail; 4256 | }, 4257 | 4258 | 4259 | // ### ES6 Collection methods (ES6 Array and Map) 4260 | 4261 | concat: function() {var values = SLICE$0.call(arguments, 0); 4262 | return reify(this, concatFactory(this, values)); 4263 | }, 4264 | 4265 | contains: function(searchValue) { 4266 | return this.includes(searchValue); 4267 | }, 4268 | 4269 | includes: function(searchValue) { 4270 | return this.some(function(value ) {return is(value, searchValue)}); 4271 | }, 4272 | 4273 | entries: function() { 4274 | return this.__iterator(ITERATE_ENTRIES); 4275 | }, 4276 | 4277 | every: function(predicate, context) { 4278 | assertNotInfinite(this.size); 4279 | var returnValue = true; 4280 | this.__iterate(function(v, k, c) { 4281 | if (!predicate.call(context, v, k, c)) { 4282 | returnValue = false; 4283 | return false; 4284 | } 4285 | }); 4286 | return returnValue; 4287 | }, 4288 | 4289 | filter: function(predicate, context) { 4290 | return reify(this, filterFactory(this, predicate, context, true)); 4291 | }, 4292 | 4293 | find: function(predicate, context, notSetValue) { 4294 | var entry = this.findEntry(predicate, context); 4295 | return entry ? entry[1] : notSetValue; 4296 | }, 4297 | 4298 | findEntry: function(predicate, context) { 4299 | var found; 4300 | this.__iterate(function(v, k, c) { 4301 | if (predicate.call(context, v, k, c)) { 4302 | found = [k, v]; 4303 | return false; 4304 | } 4305 | }); 4306 | return found; 4307 | }, 4308 | 4309 | findLastEntry: function(predicate, context) { 4310 | return this.toSeq().reverse().findEntry(predicate, context); 4311 | }, 4312 | 4313 | forEach: function(sideEffect, context) { 4314 | assertNotInfinite(this.size); 4315 | return this.__iterate(context ? sideEffect.bind(context) : sideEffect); 4316 | }, 4317 | 4318 | join: function(separator) { 4319 | assertNotInfinite(this.size); 4320 | separator = separator !== undefined ? '' + separator : ','; 4321 | var joined = ''; 4322 | var isFirst = true; 4323 | this.__iterate(function(v ) { 4324 | isFirst ? (isFirst = false) : (joined += separator); 4325 | joined += v !== null && v !== undefined ? v.toString() : ''; 4326 | }); 4327 | return joined; 4328 | }, 4329 | 4330 | keys: function() { 4331 | return this.__iterator(ITERATE_KEYS); 4332 | }, 4333 | 4334 | map: function(mapper, context) { 4335 | return reify(this, mapFactory(this, mapper, context)); 4336 | }, 4337 | 4338 | reduce: function(reducer, initialReduction, context) { 4339 | assertNotInfinite(this.size); 4340 | var reduction; 4341 | var useFirst; 4342 | if (arguments.length < 2) { 4343 | useFirst = true; 4344 | } else { 4345 | reduction = initialReduction; 4346 | } 4347 | this.__iterate(function(v, k, c) { 4348 | if (useFirst) { 4349 | useFirst = false; 4350 | reduction = v; 4351 | } else { 4352 | reduction = reducer.call(context, reduction, v, k, c); 4353 | } 4354 | }); 4355 | return reduction; 4356 | }, 4357 | 4358 | reduceRight: function(reducer, initialReduction, context) { 4359 | var reversed = this.toKeyedSeq().reverse(); 4360 | return reversed.reduce.apply(reversed, arguments); 4361 | }, 4362 | 4363 | reverse: function() { 4364 | return reify(this, reverseFactory(this, true)); 4365 | }, 4366 | 4367 | slice: function(begin, end) { 4368 | return reify(this, sliceFactory(this, begin, end, true)); 4369 | }, 4370 | 4371 | some: function(predicate, context) { 4372 | return !this.every(not(predicate), context); 4373 | }, 4374 | 4375 | sort: function(comparator) { 4376 | return reify(this, sortFactory(this, comparator)); 4377 | }, 4378 | 4379 | values: function() { 4380 | return this.__iterator(ITERATE_VALUES); 4381 | }, 4382 | 4383 | 4384 | // ### More sequential methods 4385 | 4386 | butLast: function() { 4387 | return this.slice(0, -1); 4388 | }, 4389 | 4390 | isEmpty: function() { 4391 | return this.size !== undefined ? this.size === 0 : !this.some(function() {return true}); 4392 | }, 4393 | 4394 | count: function(predicate, context) { 4395 | return ensureSize( 4396 | predicate ? this.toSeq().filter(predicate, context) : this 4397 | ); 4398 | }, 4399 | 4400 | countBy: function(grouper, context) { 4401 | return countByFactory(this, grouper, context); 4402 | }, 4403 | 4404 | equals: function(other) { 4405 | return deepEqual(this, other); 4406 | }, 4407 | 4408 | entrySeq: function() { 4409 | var iterable = this; 4410 | if (iterable._cache) { 4411 | // We cache as an entries array, so we can just return the cache! 4412 | return new ArraySeq(iterable._cache); 4413 | } 4414 | var entriesSequence = iterable.toSeq().map(entryMapper).toIndexedSeq(); 4415 | entriesSequence.fromEntrySeq = function() {return iterable.toSeq()}; 4416 | return entriesSequence; 4417 | }, 4418 | 4419 | filterNot: function(predicate, context) { 4420 | return this.filter(not(predicate), context); 4421 | }, 4422 | 4423 | findLast: function(predicate, context, notSetValue) { 4424 | return this.toKeyedSeq().reverse().find(predicate, context, notSetValue); 4425 | }, 4426 | 4427 | first: function() { 4428 | return this.find(returnTrue); 4429 | }, 4430 | 4431 | flatMap: function(mapper, context) { 4432 | return reify(this, flatMapFactory(this, mapper, context)); 4433 | }, 4434 | 4435 | flatten: function(depth) { 4436 | return reify(this, flattenFactory(this, depth, true)); 4437 | }, 4438 | 4439 | fromEntrySeq: function() { 4440 | return new FromEntriesSequence(this); 4441 | }, 4442 | 4443 | get: function(searchKey, notSetValue) { 4444 | return this.find(function(_, key) {return is(key, searchKey)}, undefined, notSetValue); 4445 | }, 4446 | 4447 | getIn: function(searchKeyPath, notSetValue) { 4448 | var nested = this; 4449 | // Note: in an ES6 environment, we would prefer: 4450 | // for (var key of searchKeyPath) { 4451 | var iter = forceIterator(searchKeyPath); 4452 | var step; 4453 | while (!(step = iter.next()).done) { 4454 | var key = step.value; 4455 | nested = nested && nested.get ? nested.get(key, NOT_SET) : NOT_SET; 4456 | if (nested === NOT_SET) { 4457 | return notSetValue; 4458 | } 4459 | } 4460 | return nested; 4461 | }, 4462 | 4463 | groupBy: function(grouper, context) { 4464 | return groupByFactory(this, grouper, context); 4465 | }, 4466 | 4467 | has: function(searchKey) { 4468 | return this.get(searchKey, NOT_SET) !== NOT_SET; 4469 | }, 4470 | 4471 | hasIn: function(searchKeyPath) { 4472 | return this.getIn(searchKeyPath, NOT_SET) !== NOT_SET; 4473 | }, 4474 | 4475 | isSubset: function(iter) { 4476 | iter = typeof iter.includes === 'function' ? iter : Iterable(iter); 4477 | return this.every(function(value ) {return iter.includes(value)}); 4478 | }, 4479 | 4480 | isSuperset: function(iter) { 4481 | return iter.isSubset(this); 4482 | }, 4483 | 4484 | keySeq: function() { 4485 | return this.toSeq().map(keyMapper).toIndexedSeq(); 4486 | }, 4487 | 4488 | last: function() { 4489 | return this.toSeq().reverse().first(); 4490 | }, 4491 | 4492 | max: function(comparator) { 4493 | return maxFactory(this, comparator); 4494 | }, 4495 | 4496 | maxBy: function(mapper, comparator) { 4497 | return maxFactory(this, comparator, mapper); 4498 | }, 4499 | 4500 | min: function(comparator) { 4501 | return maxFactory(this, comparator ? neg(comparator) : defaultNegComparator); 4502 | }, 4503 | 4504 | minBy: function(mapper, comparator) { 4505 | return maxFactory(this, comparator ? neg(comparator) : defaultNegComparator, mapper); 4506 | }, 4507 | 4508 | rest: function() { 4509 | return this.slice(1); 4510 | }, 4511 | 4512 | skip: function(amount) { 4513 | return this.slice(Math.max(0, amount)); 4514 | }, 4515 | 4516 | skipLast: function(amount) { 4517 | return reify(this, this.toSeq().reverse().skip(amount).reverse()); 4518 | }, 4519 | 4520 | skipWhile: function(predicate, context) { 4521 | return reify(this, skipWhileFactory(this, predicate, context, true)); 4522 | }, 4523 | 4524 | skipUntil: function(predicate, context) { 4525 | return this.skipWhile(not(predicate), context); 4526 | }, 4527 | 4528 | sortBy: function(mapper, comparator) { 4529 | return reify(this, sortFactory(this, comparator, mapper)); 4530 | }, 4531 | 4532 | take: function(amount) { 4533 | return this.slice(0, Math.max(0, amount)); 4534 | }, 4535 | 4536 | takeLast: function(amount) { 4537 | return reify(this, this.toSeq().reverse().take(amount).reverse()); 4538 | }, 4539 | 4540 | takeWhile: function(predicate, context) { 4541 | return reify(this, takeWhileFactory(this, predicate, context)); 4542 | }, 4543 | 4544 | takeUntil: function(predicate, context) { 4545 | return this.takeWhile(not(predicate), context); 4546 | }, 4547 | 4548 | valueSeq: function() { 4549 | return this.toIndexedSeq(); 4550 | }, 4551 | 4552 | 4553 | // ### Hashable Object 4554 | 4555 | hashCode: function() { 4556 | return this.__hash || (this.__hash = hashIterable(this)); 4557 | }, 4558 | 4559 | 4560 | // ### Internal 4561 | 4562 | // abstract __iterate(fn, reverse) 4563 | 4564 | // abstract __iterator(type, reverse) 4565 | }); 4566 | 4567 | // var IS_ITERABLE_SENTINEL = '@@__IMMUTABLE_ITERABLE__@@'; 4568 | // var IS_KEYED_SENTINEL = '@@__IMMUTABLE_KEYED__@@'; 4569 | // var IS_INDEXED_SENTINEL = '@@__IMMUTABLE_INDEXED__@@'; 4570 | // var IS_ORDERED_SENTINEL = '@@__IMMUTABLE_ORDERED__@@'; 4571 | 4572 | var IterablePrototype = Iterable.prototype; 4573 | IterablePrototype[IS_ITERABLE_SENTINEL] = true; 4574 | IterablePrototype[ITERATOR_SYMBOL] = IterablePrototype.values; 4575 | IterablePrototype.__toJS = IterablePrototype.toArray; 4576 | IterablePrototype.__toStringMapper = quoteString; 4577 | IterablePrototype.inspect = 4578 | IterablePrototype.toSource = function() { return this.toString(); }; 4579 | IterablePrototype.chain = IterablePrototype.flatMap; 4580 | 4581 | // Temporary warning about using length 4582 | (function () { 4583 | try { 4584 | Object.defineProperty(IterablePrototype, 'length', { 4585 | get: function () { 4586 | if (!Iterable.noLengthWarning) { 4587 | var stack; 4588 | try { 4589 | throw new Error(); 4590 | } catch (error) { 4591 | stack = error.stack; 4592 | } 4593 | if (stack.indexOf('_wrapObject') === -1) { 4594 | console && console.warn && console.warn( 4595 | 'iterable.length has been deprecated, '+ 4596 | 'use iterable.size or iterable.count(). '+ 4597 | 'This warning will become a silent error in a future version. ' + 4598 | stack 4599 | ); 4600 | return this.size; 4601 | } 4602 | } 4603 | } 4604 | }); 4605 | } catch (e) {} 4606 | })(); 4607 | 4608 | 4609 | 4610 | mixin(KeyedIterable, { 4611 | 4612 | // ### More sequential methods 4613 | 4614 | flip: function() { 4615 | return reify(this, flipFactory(this)); 4616 | }, 4617 | 4618 | findKey: function(predicate, context) { 4619 | var entry = this.findEntry(predicate, context); 4620 | return entry && entry[0]; 4621 | }, 4622 | 4623 | findLastKey: function(predicate, context) { 4624 | return this.toSeq().reverse().findKey(predicate, context); 4625 | }, 4626 | 4627 | keyOf: function(searchValue) { 4628 | return this.findKey(function(value ) {return is(value, searchValue)}); 4629 | }, 4630 | 4631 | lastKeyOf: function(searchValue) { 4632 | return this.findLastKey(function(value ) {return is(value, searchValue)}); 4633 | }, 4634 | 4635 | mapEntries: function(mapper, context) {var this$0 = this; 4636 | var iterations = 0; 4637 | return reify(this, 4638 | this.toSeq().map( 4639 | function(v, k) {return mapper.call(context, [k, v], iterations++, this$0)} 4640 | ).fromEntrySeq() 4641 | ); 4642 | }, 4643 | 4644 | mapKeys: function(mapper, context) {var this$0 = this; 4645 | return reify(this, 4646 | this.toSeq().flip().map( 4647 | function(k, v) {return mapper.call(context, k, v, this$0)} 4648 | ).flip() 4649 | ); 4650 | }, 4651 | 4652 | }); 4653 | 4654 | var KeyedIterablePrototype = KeyedIterable.prototype; 4655 | KeyedIterablePrototype[IS_KEYED_SENTINEL] = true; 4656 | KeyedIterablePrototype[ITERATOR_SYMBOL] = IterablePrototype.entries; 4657 | KeyedIterablePrototype.__toJS = IterablePrototype.toObject; 4658 | KeyedIterablePrototype.__toStringMapper = function(v, k) {return JSON.stringify(k) + ': ' + quoteString(v)}; 4659 | 4660 | 4661 | 4662 | mixin(IndexedIterable, { 4663 | 4664 | // ### Conversion to other types 4665 | 4666 | toKeyedSeq: function() { 4667 | return new ToKeyedSequence(this, false); 4668 | }, 4669 | 4670 | 4671 | // ### ES6 Collection methods (ES6 Array and Map) 4672 | 4673 | filter: function(predicate, context) { 4674 | return reify(this, filterFactory(this, predicate, context, false)); 4675 | }, 4676 | 4677 | findIndex: function(predicate, context) { 4678 | var entry = this.findEntry(predicate, context); 4679 | return entry ? entry[0] : -1; 4680 | }, 4681 | 4682 | indexOf: function(searchValue) { 4683 | var key = this.toKeyedSeq().keyOf(searchValue); 4684 | return key === undefined ? -1 : key; 4685 | }, 4686 | 4687 | lastIndexOf: function(searchValue) { 4688 | return this.toSeq().reverse().indexOf(searchValue); 4689 | }, 4690 | 4691 | reverse: function() { 4692 | return reify(this, reverseFactory(this, false)); 4693 | }, 4694 | 4695 | slice: function(begin, end) { 4696 | return reify(this, sliceFactory(this, begin, end, false)); 4697 | }, 4698 | 4699 | splice: function(index, removeNum /*, ...values*/) { 4700 | var numArgs = arguments.length; 4701 | removeNum = Math.max(removeNum | 0, 0); 4702 | if (numArgs === 0 || (numArgs === 2 && !removeNum)) { 4703 | return this; 4704 | } 4705 | index = resolveBegin(index, this.size); 4706 | var spliced = this.slice(0, index); 4707 | return reify( 4708 | this, 4709 | numArgs === 1 ? 4710 | spliced : 4711 | spliced.concat(arrCopy(arguments, 2), this.slice(index + removeNum)) 4712 | ); 4713 | }, 4714 | 4715 | 4716 | // ### More collection methods 4717 | 4718 | findLastIndex: function(predicate, context) { 4719 | var key = this.toKeyedSeq().findLastKey(predicate, context); 4720 | return key === undefined ? -1 : key; 4721 | }, 4722 | 4723 | first: function() { 4724 | return this.get(0); 4725 | }, 4726 | 4727 | flatten: function(depth) { 4728 | return reify(this, flattenFactory(this, depth, false)); 4729 | }, 4730 | 4731 | get: function(index, notSetValue) { 4732 | index = wrapIndex(this, index); 4733 | return (index < 0 || (this.size === Infinity || 4734 | (this.size !== undefined && index > this.size))) ? 4735 | notSetValue : 4736 | this.find(function(_, key) {return key === index}, undefined, notSetValue); 4737 | }, 4738 | 4739 | has: function(index) { 4740 | index = wrapIndex(this, index); 4741 | return index >= 0 && (this.size !== undefined ? 4742 | this.size === Infinity || index < this.size : 4743 | this.indexOf(index) !== -1 4744 | ); 4745 | }, 4746 | 4747 | interpose: function(separator) { 4748 | return reify(this, interposeFactory(this, separator)); 4749 | }, 4750 | 4751 | interleave: function(/*...iterables*/) { 4752 | var iterables = [this].concat(arrCopy(arguments)); 4753 | var zipped = zipWithFactory(this.toSeq(), IndexedSeq.of, iterables); 4754 | var interleaved = zipped.flatten(true); 4755 | if (zipped.size) { 4756 | interleaved.size = zipped.size * iterables.length; 4757 | } 4758 | return reify(this, interleaved); 4759 | }, 4760 | 4761 | last: function() { 4762 | return this.get(-1); 4763 | }, 4764 | 4765 | skipWhile: function(predicate, context) { 4766 | return reify(this, skipWhileFactory(this, predicate, context, false)); 4767 | }, 4768 | 4769 | zip: function(/*, ...iterables */) { 4770 | var iterables = [this].concat(arrCopy(arguments)); 4771 | return reify(this, zipWithFactory(this, defaultZipper, iterables)); 4772 | }, 4773 | 4774 | zipWith: function(zipper/*, ...iterables */) { 4775 | var iterables = arrCopy(arguments); 4776 | iterables[0] = this; 4777 | return reify(this, zipWithFactory(this, zipper, iterables)); 4778 | }, 4779 | 4780 | }); 4781 | 4782 | IndexedIterable.prototype[IS_INDEXED_SENTINEL] = true; 4783 | IndexedIterable.prototype[IS_ORDERED_SENTINEL] = true; 4784 | 4785 | 4786 | 4787 | mixin(SetIterable, { 4788 | 4789 | // ### ES6 Collection methods (ES6 Array and Map) 4790 | 4791 | get: function(value, notSetValue) { 4792 | return this.has(value) ? value : notSetValue; 4793 | }, 4794 | 4795 | includes: function(value) { 4796 | return this.has(value); 4797 | }, 4798 | 4799 | 4800 | // ### More sequential methods 4801 | 4802 | keySeq: function() { 4803 | return this.valueSeq(); 4804 | }, 4805 | 4806 | }); 4807 | 4808 | SetIterable.prototype.has = IterablePrototype.includes; 4809 | 4810 | 4811 | // Mixin subclasses 4812 | 4813 | mixin(KeyedSeq, KeyedIterable.prototype); 4814 | mixin(IndexedSeq, IndexedIterable.prototype); 4815 | mixin(SetSeq, SetIterable.prototype); 4816 | 4817 | mixin(KeyedCollection, KeyedIterable.prototype); 4818 | mixin(IndexedCollection, IndexedIterable.prototype); 4819 | mixin(SetCollection, SetIterable.prototype); 4820 | 4821 | 4822 | // #pragma Helper functions 4823 | 4824 | function keyMapper(v, k) { 4825 | return k; 4826 | } 4827 | 4828 | function entryMapper(v, k) { 4829 | return [k, v]; 4830 | } 4831 | 4832 | function not(predicate) { 4833 | return function() { 4834 | return !predicate.apply(this, arguments); 4835 | } 4836 | } 4837 | 4838 | function neg(predicate) { 4839 | return function() { 4840 | return -predicate.apply(this, arguments); 4841 | } 4842 | } 4843 | 4844 | function quoteString(value) { 4845 | return typeof value === 'string' ? JSON.stringify(value) : value; 4846 | } 4847 | 4848 | function defaultZipper() { 4849 | return arrCopy(arguments); 4850 | } 4851 | 4852 | function defaultNegComparator(a, b) { 4853 | return a < b ? 1 : a > b ? -1 : 0; 4854 | } 4855 | 4856 | function hashIterable(iterable) { 4857 | if (iterable.size === Infinity) { 4858 | return 0; 4859 | } 4860 | var ordered = isOrdered(iterable); 4861 | var keyed = isKeyed(iterable); 4862 | var h = ordered ? 1 : 0; 4863 | var size = iterable.__iterate( 4864 | keyed ? 4865 | ordered ? 4866 | function(v, k) { h = 31 * h + hashMerge(hash(v), hash(k)) | 0; } : 4867 | function(v, k) { h = h + hashMerge(hash(v), hash(k)) | 0; } : 4868 | ordered ? 4869 | function(v ) { h = 31 * h + hash(v) | 0; } : 4870 | function(v ) { h = h + hash(v) | 0; } 4871 | ); 4872 | return murmurHashOfSize(size, h); 4873 | } 4874 | 4875 | function murmurHashOfSize(size, h) { 4876 | h = src_Math__imul(h, 0xCC9E2D51); 4877 | h = src_Math__imul(h << 15 | h >>> -15, 0x1B873593); 4878 | h = src_Math__imul(h << 13 | h >>> -13, 5); 4879 | h = (h + 0xE6546B64 | 0) ^ size; 4880 | h = src_Math__imul(h ^ h >>> 16, 0x85EBCA6B); 4881 | h = src_Math__imul(h ^ h >>> 13, 0xC2B2AE35); 4882 | h = smi(h ^ h >>> 16); 4883 | return h; 4884 | } 4885 | 4886 | function hashMerge(a, b) { 4887 | return a ^ b + 0x9E3779B9 + (a << 6) + (a >> 2) | 0; // int 4888 | } 4889 | 4890 | var Immutable = { 4891 | 4892 | Iterable: Iterable, 4893 | 4894 | Seq: Seq, 4895 | Collection: Collection, 4896 | Map: src_Map__Map, 4897 | OrderedMap: OrderedMap, 4898 | List: List, 4899 | Stack: Stack, 4900 | Set: src_Set__Set, 4901 | OrderedSet: OrderedSet, 4902 | 4903 | Record: Record, 4904 | Range: Range, 4905 | Repeat: Repeat, 4906 | 4907 | is: is, 4908 | fromJS: fromJS, 4909 | 4910 | }; 4911 | 4912 | return Immutable; 4913 | 4914 | })); --------------------------------------------------------------------------------