@woosh/meep-engine 2.50.2 → 2.51.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -1
- package/editor/actions/concrete/WriteGridValueAction.js +13 -18
- package/editor/ecs/component/editors/Sampler2DEditor.js +2 -2
- package/editor/process/SymbolicDisplayProcess.js +1 -1
- package/editor/process/symbolic/buildThreeJSHelperEntity.js +1 -1
- package/editor/process/symbolic/makeCameraSymbolicDisplay.js +1 -1
- package/editor/process/symbolic/makeGridPositionSymbolDisplay.js +1 -1
- package/editor/process/symbolic/makeLightSymbolicDisplay.js +1 -1
- package/editor/process/symbolic/makePathSymbolicDisplay.js +1 -1
- package/editor/process/symbolic/makePositionedIconDisplaySymbol.js +1 -1
- package/editor/view/ecs/components/GridObstacleController.js +2 -2
- package/editor/view/ecs/components/TerrainController.js +2 -2
- package/package.json +1 -1
- package/samples/terrain/editor.js +2 -2
- package/src/core/UUID.spec.js +8 -0
- package/src/core/bvh2/bvh3/ExplicitBinaryBoundingVolumeHierarchy.d.ts +4 -0
- package/src/core/bvh2/bvh3/ExplicitBinaryBoundingVolumeHierarchy.js +57 -55
- package/src/core/bvh2/bvh3/ExplicitBinaryBoundingVolumeHierarchy.spec.js +54 -0
- package/src/core/bvh2/bvh3/ebvh_build_for_geometry_morton.js +3 -3
- package/src/core/bvh2/bvh3/ebvh_build_for_geometry_morton.spec.js +60 -0
- package/src/core/bvh2/visual/convert_bvh_to_dot_format_string.js +2 -2
- package/src/core/cache/Cache.d.ts +4 -0
- package/src/core/cache/Cache.js +32 -18
- package/src/core/cache/Cache.spec.js +33 -0
- package/src/core/cache/CacheElement.js +1 -0
- package/src/core/cache/FrequencySketch.js +26 -23
- package/src/core/cache/FrequencySketch.spec.js +5 -0
- package/src/core/cache/LoadingCache.d.ts +2 -0
- package/src/core/cache/LoadingCache.js +16 -7
- package/src/core/cache/LoadingCache.spec.js +24 -0
- package/src/core/collection/HashMap.d.ts +2 -0
- package/src/core/collection/HashMap.spec.js +51 -2
- package/src/core/collection/list/List.d.ts +13 -1
- package/src/core/collection/list/List.js +702 -684
- package/src/core/collection/list/List.spec.js +93 -0
- package/src/core/collection/map/AsyncLoadingCache.js +1 -0
- package/src/core/fsm/simple/SimpleStateMachine.js +23 -22
- package/src/core/function/extractFunctionBody.spec.js +15 -0
- package/src/core/geom/2d/convex-hull/convex_hull_monotone_2d.js +69 -33
- package/src/core/geom/2d/convex-hull/convex_hull_monotone_2d.spec.js +33 -0
- package/src/core/geom/2d/convex-hull/orientation3.js +55 -10
- package/src/core/geom/2d/quad-tree/PointQuadTree.js +10 -0
- package/src/core/geom/3d/aabb/aabb3_array_combine.js +3 -3
- package/src/core/graph/{convertGraphToDotString.js → convert_graph_to_dot_string.js} +1 -1
- package/src/core/graph/convert_graph_to_dot_string.spec.js +28 -0
- package/src/core/math/noise/sdnoise.js +5 -7
- package/src/core/math/noise/sdnoise.spec.js +87 -0
- package/src/core/process/matcher/Matchers.js +1 -1
- package/src/engine/asset/loaders/image/png/PNG.spec.js +5 -0
- package/src/engine/asset/loaders/image/png/PNGReader.spec.js +5 -0
- package/src/engine/asset/loaders/image/png/crc.spec.js +15 -0
- package/src/engine/{Platform.js → browserInfo.js} +1 -5
- package/src/engine/ecs/EntityBlueprint.js +4 -0
- package/src/engine/ecs/EntityBuilder.js +48 -49
- package/src/engine/ecs/EntityBuilderFlags.js +2 -2
- package/src/engine/ecs/fow/FogOfWar.js +48 -54
- package/src/engine/ecs/guid/GUID.js +1 -0
- package/src/engine/ecs/{systems → renderable}/RenderSystem.d.ts +1 -1
- package/src/engine/ecs/{systems → renderable}/RenderSystem.js +10 -38
- package/src/engine/ecs/renderable/Renderable.d.ts +25 -0
- package/src/engine/ecs/{components → renderable}/Renderable.js +18 -83
- package/src/engine/ecs/renderable/Renderable.spec.js +10 -0
- package/src/engine/ecs/speaker/VoiceSystem.js +15 -9
- package/src/engine/ecs/systems/MeshColliderSystem.js +1 -1
- package/src/engine/ecs/systems/RangedAttackSystem.js +1 -1
- package/src/engine/ecs/systems/ViewportMeshProjectionSystem.js +1 -1
- package/src/engine/ecs/terrain/ecs/layers/TerrainLayers.js +2 -2
- package/src/engine/ecs/terrain/ecs/splat/SplatMapOptimizerDebugger.js +3 -3
- package/src/engine/ecs/terrain/ecs/splat/SplatMapping.js +2 -2
- package/src/engine/ecs/terrain/overlay/TerrainOverlay.js +2 -2
- package/src/engine/ecs/terrain/util/paintTerrainOverlayViaLookupTable.js +2 -2
- package/src/engine/graphics/copy_transform_to_threejs_object.js +12 -0
- package/src/engine/graphics/debug/VisualSymbolLine.js +1 -1
- package/src/engine/graphics/ecs/decal/DecalSystem.js +1 -1
- package/src/engine/graphics/ecs/highlight/renderer/makeGaussianBlurShader.js +1 -4
- package/src/engine/graphics/ecs/highlight/system/RenderableHighlightSystem.d.ts +1 -1
- package/src/engine/graphics/ecs/highlight/system/RenderableHighlightSystem.js +2 -2
- package/src/engine/graphics/ecs/mesh/applyTransformToThreeObject.js +2 -5
- package/src/engine/graphics/ecs/path/ribbon/RibbonPathBuilder.js +2 -2
- package/src/engine/graphics/geometry/optimization/merge/prototypeGeometryMerge.js +1 -1
- package/src/engine/graphics/particles/particular/engine/utils/volume/prototypeParticleVolume.js +1 -1
- package/src/engine/graphics/render/forward_plus/plugin/ptototypeFPPlugin.js +1 -1
- package/src/engine/graphics/sh3/path_tracer/prototypePathTracer.js +2 -2
- package/src/engine/graphics/shaders/SoftOutlineShader.js +2 -4
- package/src/engine/graphics/texture/atlas/CachingTextureAtlas.spec.js +24 -0
- package/src/engine/graphics/texture/atlas/TextureAtlas.spec.js +46 -0
- package/src/engine/graphics/texture/sampler/SampleTraverser.js +1 -1
- package/src/engine/graphics/texture/sampler/bicubic.spec.js +13 -0
- package/src/engine/graphics/texture/sampler/differenceSampler.js +1 -1
- package/src/engine/graphics/texture/sampler/distance/computeSignedDistanceField_NaiveFlood.js +5 -1
- package/src/engine/graphics/texture/sampler/distance/computeSignedDistanceField_NaiveFlood.spec.js +183 -0
- package/src/engine/graphics/texture/sampler/filter/filter_lanczos3.js +20 -0
- package/src/engine/graphics/texture/sampler/filter/mitchell.js +0 -21
- package/src/engine/graphics/texture/sampler/filter/mitchell_v1.js +21 -0
- package/src/engine/graphics/texture/sampler/filter/sampler2d_scale_down_generic.js +17 -16
- package/src/engine/graphics/texture/sampler/prototypeSamplerFiltering.js +11 -9
- package/src/engine/graphics/texture/sampler/{scaleSampler2D.js → resize/sampler2d_scale.js} +8 -8
- package/src/engine/graphics/texture/sampler/resize/sampler2d_scale.spec.js +73 -0
- package/src/engine/graphics/texture/sampler/{sampler2_d_scale_down_lanczos.js → resize/sampler2d_scale_down_lanczos.js} +3 -24
- package/src/engine/graphics/texture/sampler/resize/sampler2d_scale_down_lanczos.spec.js +29 -0
- package/src/engine/graphics/texture/sampler/{sampler2d_scale_down_linear.js → resize/sampler2d_scale_down_linear.js} +5 -5
- package/src/engine/graphics/texture/sampler/resize/sampler2d_scale_down_linear.spec.js +44 -0
- package/src/engine/graphics/texture/sampler/resize/{sampler2d_downsample_mipmap.js → sampler2d_scale_down_mipmap.js} +2 -2
- package/src/engine/graphics/texture/sampler/resize/{sampler2d_downsample_mipmap.spec.js → sampler2d_scale_down_mipmap.spec.js} +2 -2
- package/src/engine/graphics/texture/sampler/{genericResampleSampler2D.js → resize/sampler2d_scale_generic.js} +16 -12
- package/src/engine/graphics/texture/sampler/{upsampleSampler2D.js → resize/sampler2d_scale_up_linear.js} +5 -2
- package/src/engine/graphics/texture/sampler/resize/sampler2d_scale_up_linear.spec.js +14 -0
- package/src/engine/graphics/texture/sampler/sampler2d_channel_compute_min_indices.js +4 -2
- package/src/engine/graphics/texture/sampler/sampler2d_channel_compute_min_indices.spec.js +15 -0
- package/src/engine/graphics/texture/sampler/util/drawSamplerHTML.js +2 -2
- package/src/engine/graphics/three/expand_aabb_by_transformed_three_object.js +66 -0
- package/src/engine/graphics/three/expand_aabb_by_transformed_three_object.spec.js +108 -0
- package/src/engine/graphics/trail/TemporalPath.js +83 -78
- package/src/engine/graphics/trail/TemporalPath.spec.js +5 -0
- package/src/engine/graphics/trail/x/RibbonX.spec.js +5 -0
- package/src/engine/input/devices/InputDeviceSwitch.spec.js +5 -0
- package/src/engine/input/ecs/{InputBinding.js → components/InputBinding.js} +1 -1
- package/src/engine/input/ecs/components/InputController.js +2 -2
- package/src/engine/input/ecs/ism/InputBinding.js +2 -2
- package/src/engine/input/ecs/util/TerrainCameraTargetSampler.js +1 -1
- package/src/engine/input/ecs/util/TopDownCameraControllerHelper.js +1 -1
- package/src/engine/intelligence/behavior/behavior_to_dot.spec.js +25 -0
- package/src/engine/intelligence/behavior/util/DelayBehavior.js +6 -4
- package/src/engine/intelligence/blackboard/Blackboard.d.ts +2 -0
- package/src/engine/intelligence/blackboard/Blackboard.js +36 -2
- package/src/engine/intelligence/blackboard/Blackboard.spec.js +49 -0
- package/src/engine/intelligence/blackboard/BlackboardSerializationAdapter.spec.js +2 -0
- package/src/engine/navigation/grid/{AStar.js → find_path_on_grid_astar.js} +21 -18
- package/src/engine/navigation/grid/find_path_on_grid_astar.spec.js +7 -0
- package/src/engine/sound/ecs/SoundListenerSystem.js +1 -1
- package/src/generation/markers/debug/visualizeMarkers.js +1 -1
- package/src/engine/MeepSettings.js +0 -9
- package/src/engine/User.js +0 -28
- package/src/engine/UserController.js +0 -273
- package/src/engine/ecs/components/AABB.js +0 -33
- package/src/engine/ecs/components/AABBCollider.js +0 -15
- package/src/engine/ecs/components/Renderable.d.ts +0 -14
- package/src/engine/ecs/grid/Sampler2DDecoder.js +0 -57
- package/src/engine/ecs/grid/makeTerrainGeometry.js +0 -110
- package/src/engine/ecs/systems/AABBColliderSystem.js +0 -61
- package/src/engine/ecs/systems/AABBSystem.js +0 -89
- package/src/engine/graphics/texture/sampler/sampler2d_make_array_filler_function.js +0 -65
- package/src/engine/graphics/texture/sampler/sampler2d_scale_down_linear.spec.js +0 -17
- package/src/engine/graphics/trail/x/simulator/RibbonState.js +0 -10
- package/src/engine/grid/Grid.js +0 -131
- package/src/engine/navigation/grid/GridField.js +0 -328
- /package/src/engine/ecs/{components → renderable}/RenderableFlags.js +0 -0
|
@@ -11,651 +11,625 @@ import { arrayIndexByEquality } from "../array/arrayIndexByEquality.js";
|
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
|
-
*
|
|
15
|
-
* @template T
|
|
16
|
-
* @param {T} element
|
|
17
|
-
* @param {number} [index]
|
|
18
|
-
*/
|
|
19
|
-
|
|
20
|
-
/**
|
|
14
|
+
*
|
|
21
15
|
* List structure with event signals for observing changes.
|
|
22
|
-
* @param {Array.<T>} [array]
|
|
23
16
|
* @template T
|
|
24
|
-
* @constructor
|
|
25
|
-
* @property {{added: Signal, removed: Signal}} on
|
|
26
17
|
*/
|
|
27
|
-
|
|
28
|
-
|
|
18
|
+
class List {
|
|
19
|
+
/**
|
|
20
|
+
* @readonly
|
|
21
|
+
*/
|
|
22
|
+
on = {
|
|
23
|
+
/**
|
|
24
|
+
* @type {Signal<T,number>}
|
|
25
|
+
*/
|
|
29
26
|
added: new Signal(),
|
|
27
|
+
/**
|
|
28
|
+
* @type {Signal<T,number>}
|
|
29
|
+
*/
|
|
30
30
|
removed: new Signal()
|
|
31
31
|
};
|
|
32
32
|
|
|
33
33
|
/**
|
|
34
|
-
* @
|
|
34
|
+
* @param {T[]} [array]
|
|
35
|
+
* @constructor
|
|
35
36
|
*/
|
|
36
|
-
|
|
37
|
+
constructor(array) {
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* @type {T[]}
|
|
41
|
+
*/
|
|
42
|
+
this.data = array !== undefined ? array.slice() : [];
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
*
|
|
46
|
+
* @type {number}
|
|
47
|
+
*/
|
|
48
|
+
this.length = this.data.length;
|
|
49
|
+
}
|
|
37
50
|
|
|
38
51
|
/**
|
|
39
|
-
*
|
|
40
|
-
* @
|
|
52
|
+
* Retrieve element at a given position in the list
|
|
53
|
+
* @param {number} index
|
|
54
|
+
* @returns {T}
|
|
41
55
|
*/
|
|
42
|
-
|
|
43
|
-
|
|
56
|
+
get(index) {
|
|
57
|
+
return this.data[index];
|
|
58
|
+
}
|
|
44
59
|
|
|
45
|
-
/**
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
};
|
|
60
|
+
/**
|
|
61
|
+
* Set element at a given position inside the list
|
|
62
|
+
* @param {number} index
|
|
63
|
+
* @param {T} value
|
|
64
|
+
*/
|
|
65
|
+
set(index, value) {
|
|
66
|
+
const oldValue = this.data[index];
|
|
53
67
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
*/
|
|
59
|
-
List.prototype.set = function (index, value) {
|
|
60
|
-
const oldValue = this.data[index];
|
|
68
|
+
if (oldValue !== undefined) {
|
|
69
|
+
this.on.removed.send2(oldValue, index)
|
|
70
|
+
} else {
|
|
71
|
+
if (index >= this.length) {
|
|
61
72
|
|
|
62
|
-
|
|
63
|
-
this.on.removed.send2(oldValue, index)
|
|
64
|
-
} else {
|
|
65
|
-
if (index >= this.length) {
|
|
73
|
+
this.length = index + 1;
|
|
66
74
|
|
|
67
|
-
|
|
75
|
+
if (index > this.length) {
|
|
76
|
+
console.error(`Overflow, attempted to set element at ${index} past the list length(=${this.length})`);
|
|
77
|
+
}
|
|
68
78
|
|
|
69
|
-
if (index > this.length) {
|
|
70
|
-
console.error(`Overflow, attempted to set element at ${index} past the list length(=${this.length})`);
|
|
71
79
|
}
|
|
72
|
-
|
|
73
80
|
}
|
|
81
|
+
|
|
82
|
+
this.data[index] = value;
|
|
83
|
+
|
|
84
|
+
this.on.added.send2(value, index);
|
|
74
85
|
}
|
|
75
86
|
|
|
76
|
-
|
|
87
|
+
/**
|
|
88
|
+
*
|
|
89
|
+
* @param {T} el
|
|
90
|
+
*/
|
|
91
|
+
add(el) {
|
|
92
|
+
this.data.push(el);
|
|
93
|
+
const oldLength = this.length;
|
|
77
94
|
|
|
78
|
-
|
|
79
|
-
};
|
|
95
|
+
this.length++;
|
|
80
96
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
*/
|
|
85
|
-
List.prototype.add = function (el) {
|
|
86
|
-
this.data.push(el);
|
|
87
|
-
const oldLength = this.length;
|
|
97
|
+
this.on.added.send2(el, oldLength);
|
|
98
|
+
return this;
|
|
99
|
+
}
|
|
88
100
|
|
|
89
|
-
|
|
101
|
+
/**
|
|
102
|
+
* Only add element if it doesn't already exist in the list
|
|
103
|
+
* Useful when you wish to ensure uniqueness of elements inside the list
|
|
104
|
+
* Note that this operation is rather slow as it triggers a linear scan
|
|
105
|
+
* If the list gets large - consider using a {@link Set} class instead
|
|
106
|
+
* @param {T} el
|
|
107
|
+
* @return {boolean}
|
|
108
|
+
*/
|
|
109
|
+
addUnique(el) {
|
|
110
|
+
if (this.contains(el)) {
|
|
111
|
+
return false;
|
|
112
|
+
}
|
|
90
113
|
|
|
91
|
-
|
|
92
|
-
return this;
|
|
93
|
-
};
|
|
114
|
+
this.add(el);
|
|
94
115
|
|
|
95
|
-
|
|
96
|
-
*
|
|
97
|
-
* @param {T} el
|
|
98
|
-
* @return {boolean}
|
|
99
|
-
*/
|
|
100
|
-
List.prototype.addUnique = function (el) {
|
|
101
|
-
if (this.contains(el)) {
|
|
102
|
-
return false;
|
|
116
|
+
return true;
|
|
103
117
|
}
|
|
104
118
|
|
|
105
|
-
|
|
119
|
+
/**
|
|
120
|
+
* Insert element at a specific position into the list
|
|
121
|
+
* This operation will result in a larger list
|
|
122
|
+
* @param {number} index
|
|
123
|
+
* @param {T} el
|
|
124
|
+
* @returns {List}
|
|
125
|
+
* @throws {Error} when trying to insert past list end
|
|
126
|
+
*/
|
|
127
|
+
insert(index, el) {
|
|
106
128
|
|
|
107
|
-
|
|
108
|
-
}
|
|
129
|
+
if (index > this.length) {
|
|
130
|
+
console.error(`Overflow, attempted to insert element at ${index} past the list length(=${this.length})`);
|
|
131
|
+
this.length = index;
|
|
132
|
+
}
|
|
109
133
|
|
|
110
|
-
|
|
111
|
-
* Insert element at a specific position into the list
|
|
112
|
-
* @param {number} index
|
|
113
|
-
* @param {T} el
|
|
114
|
-
* @returns {List}
|
|
115
|
-
* @throws {Error} when trying to insert past list end
|
|
116
|
-
*/
|
|
117
|
-
List.prototype.insert = function (index, el) {
|
|
134
|
+
this.data.splice(index, 0, el);
|
|
118
135
|
|
|
119
|
-
|
|
120
|
-
console.error(`Overflow, attempted to insert element at ${index} past the list length(=${this.length})`);
|
|
121
|
-
this.length = index + 1;
|
|
122
|
-
}
|
|
136
|
+
this.length++;
|
|
123
137
|
|
|
124
|
-
|
|
138
|
+
this.on.added.send2(el, index);
|
|
125
139
|
|
|
126
|
-
|
|
140
|
+
return this;
|
|
141
|
+
}
|
|
127
142
|
|
|
128
|
-
|
|
143
|
+
/**
|
|
144
|
+
* Reduces the list to a subsection but removing everything before startIndex and everything after endIndex
|
|
145
|
+
* @param {int} startIndex
|
|
146
|
+
* @param {int} endIndex up to this index, not including it
|
|
147
|
+
* @returns {number}
|
|
148
|
+
*/
|
|
149
|
+
crop(startIndex, endIndex) {
|
|
129
150
|
|
|
130
|
-
|
|
131
|
-
};
|
|
151
|
+
const data = this.data;
|
|
132
152
|
|
|
133
|
-
|
|
134
|
-
* Reduces the list to a sub-section but removing everything before startIndex and everything after endIndex
|
|
135
|
-
* @param {int} startIndex
|
|
136
|
-
* @param {int} endIndex up to this index, not including it
|
|
137
|
-
* @returns {number}
|
|
138
|
-
*/
|
|
139
|
-
List.prototype.crop = function (startIndex, endIndex) {
|
|
153
|
+
const tail = data.splice(endIndex, this.length - endIndex);
|
|
140
154
|
|
|
141
|
-
|
|
155
|
+
const head = data.splice(0, startIndex);
|
|
142
156
|
|
|
143
|
-
|
|
157
|
+
this.length = endIndex - startIndex;
|
|
144
158
|
|
|
145
|
-
const head = data.splice(0, startIndex);
|
|
146
159
|
|
|
147
|
-
|
|
160
|
+
const headLength = head.length;
|
|
148
161
|
|
|
162
|
+
const tailLength = tail.length;
|
|
149
163
|
|
|
150
|
-
|
|
164
|
+
const onRemoved = this.on.removed;
|
|
151
165
|
|
|
152
|
-
|
|
166
|
+
if (onRemoved.hasHandlers()) {
|
|
167
|
+
let i;
|
|
153
168
|
|
|
154
|
-
|
|
169
|
+
for (i = 0; i < headLength; i++) {
|
|
170
|
+
onRemoved.send2(head[i], i);
|
|
171
|
+
}
|
|
155
172
|
|
|
156
|
-
if (onRemoved.hasHandlers()) {
|
|
157
|
-
let i;
|
|
158
173
|
|
|
159
|
-
|
|
160
|
-
|
|
174
|
+
for (i = 0; i < tailLength; i++) {
|
|
175
|
+
onRemoved.send2(tail[i], endIndex + i);
|
|
176
|
+
}
|
|
161
177
|
}
|
|
162
178
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
onRemoved.send2(tail[i], endIndex + i);
|
|
166
|
-
}
|
|
179
|
+
//return number of dropped elements
|
|
180
|
+
return headLength + tailLength;
|
|
167
181
|
}
|
|
168
182
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
* Conversely, relevant events are dispatched that a visualisation can observe. This results in fewer changes required to the visualisation
|
|
177
|
-
* @param {T[]} newOutput
|
|
178
|
-
*/
|
|
179
|
-
List.prototype.patch = function (newOutput) {
|
|
183
|
+
/**
|
|
184
|
+
* Replace the data, replacements is performed surgically, meaning that diff is computed and add/remove operations are performed on the set
|
|
185
|
+
* This method is tailored to work well with visualisation as only elements that's missing from the new set is removed, and only elements that are new to are added
|
|
186
|
+
* Conversely, relevant events are dispatched that a visualisation can observe. This results in fewer changes required to the visualisation
|
|
187
|
+
* @param {T[]} newOutput
|
|
188
|
+
*/
|
|
189
|
+
patch(newOutput) {
|
|
180
190
|
|
|
181
|
-
|
|
191
|
+
const data = this.data;
|
|
182
192
|
|
|
183
|
-
|
|
193
|
+
const diff = arraySetDiff(data, newOutput, invokeObjectEquals);
|
|
184
194
|
|
|
185
|
-
|
|
186
|
-
|
|
195
|
+
//resolve diff
|
|
196
|
+
const removals = diff.uniqueA;
|
|
187
197
|
|
|
188
|
-
|
|
198
|
+
const removalCount = removals.length;
|
|
189
199
|
|
|
190
|
-
|
|
191
|
-
|
|
200
|
+
for (let i = 0; i < removalCount; i++) {
|
|
201
|
+
const item = removals[i];
|
|
192
202
|
|
|
193
|
-
|
|
194
|
-
|
|
203
|
+
this.removeOneOf(item);
|
|
204
|
+
}
|
|
195
205
|
|
|
196
|
-
|
|
206
|
+
const additions = diff.uniqueB;
|
|
197
207
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
208
|
+
//sort additions by their position in the input
|
|
209
|
+
additions.sort((a, b) => {
|
|
210
|
+
const ai = this.indexOf(a);
|
|
211
|
+
const bi = this.indexOf(b);
|
|
202
212
|
|
|
203
|
-
|
|
204
|
-
|
|
213
|
+
return bi - ai;
|
|
214
|
+
});
|
|
205
215
|
|
|
206
|
-
|
|
216
|
+
const additionsCount = additions.length;
|
|
207
217
|
|
|
208
|
-
|
|
209
|
-
|
|
218
|
+
for (let i = 0; i < additionsCount; i++) {
|
|
219
|
+
const item = additions[i];
|
|
210
220
|
|
|
211
|
-
|
|
212
|
-
|
|
221
|
+
//find where the item is in the input
|
|
222
|
+
const inputIndex = this.indexOf(item);
|
|
213
223
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
224
|
+
let p = 0;
|
|
225
|
+
for (let i = inputIndex - 1; i >= 0; i--) {
|
|
226
|
+
const prev = this.get(i);
|
|
217
227
|
|
|
218
|
-
|
|
219
|
-
|
|
228
|
+
//look for previous item in the output
|
|
229
|
+
const j = this.indexOf(prev);
|
|
220
230
|
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
231
|
+
if (j !== -1) {
|
|
232
|
+
p = j + 1;
|
|
233
|
+
break;
|
|
234
|
+
}
|
|
224
235
|
}
|
|
236
|
+
|
|
237
|
+
this.insert(p, item);
|
|
225
238
|
}
|
|
226
239
|
|
|
227
|
-
this.insert(p, item);
|
|
228
240
|
}
|
|
229
241
|
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
List.prototype.addAll = function (elements) {
|
|
237
|
-
const addedElementsCount = elements.length;
|
|
242
|
+
/**
|
|
243
|
+
*
|
|
244
|
+
* @param {Array.<T>} elements
|
|
245
|
+
*/
|
|
246
|
+
addAll(elements) {
|
|
247
|
+
const addedElementsCount = elements.length;
|
|
238
248
|
|
|
239
|
-
|
|
249
|
+
const added = this.on.added;
|
|
240
250
|
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
251
|
+
if (added.hasHandlers()) {
|
|
252
|
+
//only signal if there are listeners attached
|
|
253
|
+
for (let i = 0; i < addedElementsCount; i++) {
|
|
254
|
+
const element = elements[i];
|
|
255
|
+
this.data.push(element);
|
|
256
|
+
added.send2(element, this.length++);
|
|
257
|
+
}
|
|
258
|
+
} else {
|
|
259
|
+
//no observers, we can add elements faster
|
|
260
|
+
Array.prototype.push.apply(this.data, elements);
|
|
261
|
+
this.length += addedElementsCount;
|
|
247
262
|
}
|
|
248
|
-
} else {
|
|
249
|
-
//no observers, we can add elements faster
|
|
250
|
-
Array.prototype.push.apply(this.data, elements);
|
|
251
|
-
this.length += addedElementsCount;
|
|
252
263
|
}
|
|
253
|
-
};
|
|
254
264
|
|
|
255
|
-
/**
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
265
|
+
/**
|
|
266
|
+
*
|
|
267
|
+
* @param {Array.<T>} elements
|
|
268
|
+
*/
|
|
269
|
+
addAllUnique(elements) {
|
|
270
|
+
const data = this.data;
|
|
261
271
|
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
272
|
+
const unique = elements.filter(function (e, i) {
|
|
273
|
+
return data.indexOf(e) === -1 && elements.indexOf(e, i + 1) === -1;
|
|
274
|
+
});
|
|
265
275
|
|
|
266
|
-
|
|
267
|
-
}
|
|
276
|
+
this.addAll(unique);
|
|
277
|
+
}
|
|
268
278
|
|
|
269
|
-
/**
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
279
|
+
/**
|
|
280
|
+
*
|
|
281
|
+
* @param {number} index
|
|
282
|
+
* @param {number} removeCount
|
|
283
|
+
* @returns {T[]}
|
|
284
|
+
*/
|
|
285
|
+
removeMany(index, removeCount) {
|
|
286
|
+
assert.equal(typeof index, 'number', `index must a number, instead was '${typeof index}'`);
|
|
287
|
+
assert.ok(index < this.length || index < 0, `index(=${index}) out of range (${this.length})`);
|
|
278
288
|
|
|
279
|
-
|
|
289
|
+
const els = this.data.splice(index, removeCount);
|
|
280
290
|
|
|
281
|
-
|
|
291
|
+
const removedCount = els.length;
|
|
282
292
|
|
|
283
|
-
|
|
293
|
+
this.length -= removedCount;
|
|
284
294
|
|
|
285
|
-
|
|
295
|
+
assert.equal(this.length, this.data.length, `length(=${this.length}) is inconsistent with underlying data array length(=${this.data.length})`)
|
|
286
296
|
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
297
|
+
if (this.on.removed.hasHandlers()) {
|
|
298
|
+
for (let i = 0; i < removedCount; i++) {
|
|
299
|
+
const element = els[i];
|
|
290
300
|
|
|
291
|
-
|
|
301
|
+
this.on.removed.send2(element, index + i);
|
|
302
|
+
}
|
|
292
303
|
}
|
|
293
|
-
}
|
|
294
304
|
|
|
295
|
-
|
|
296
|
-
}
|
|
305
|
+
return els;
|
|
306
|
+
}
|
|
297
307
|
|
|
298
|
-
/**
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
308
|
+
/**
|
|
309
|
+
*
|
|
310
|
+
* @param {number} index
|
|
311
|
+
* @returns {T}
|
|
312
|
+
*/
|
|
313
|
+
remove(index) {
|
|
314
|
+
assert.equal(typeof index, 'number', `index must a number, instead was '${typeof index}'`);
|
|
315
|
+
assert.ok(index < this.length || index < 0, `index(=${index}) out of range (${this.length})`);
|
|
306
316
|
|
|
307
|
-
|
|
317
|
+
const els = this.data.splice(index, 1);
|
|
308
318
|
|
|
309
|
-
|
|
319
|
+
this.length--;
|
|
310
320
|
|
|
311
|
-
|
|
321
|
+
assert.equal(this.length, this.data.length, `length(=${this.length}) is inconsistent with underlying data array length(=${this.data.length})`)
|
|
312
322
|
|
|
313
|
-
|
|
323
|
+
const element = els[0];
|
|
314
324
|
|
|
315
|
-
|
|
325
|
+
this.on.removed.send2(element, index);
|
|
316
326
|
|
|
317
|
-
|
|
318
|
-
}
|
|
327
|
+
return element;
|
|
328
|
+
}
|
|
319
329
|
|
|
320
|
-
/**
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
}
|
|
330
|
+
/**
|
|
331
|
+
*
|
|
332
|
+
* @param {T[]} elements
|
|
333
|
+
* @returns {boolean} True is all specified elements were found and removed, False if some elements were not present in the list
|
|
334
|
+
*/
|
|
335
|
+
removeAll(elements) {
|
|
336
|
+
let i, il;
|
|
337
|
+
let j, jl;
|
|
329
338
|
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
* @param {Array.<T>} elements
|
|
333
|
-
* @returns {boolean} True is all specified elements were found and removed, False if some elements were not present in the list
|
|
334
|
-
*/
|
|
335
|
-
List.prototype.removeAll = function (elements) {
|
|
336
|
-
let i, il;
|
|
337
|
-
let j, jl;
|
|
339
|
+
il = elements.length;
|
|
340
|
+
jl = this.length;
|
|
338
341
|
|
|
339
|
-
|
|
340
|
-
jl = this.length;
|
|
342
|
+
let missCount = 0;
|
|
341
343
|
|
|
342
|
-
|
|
344
|
+
const data = this.data;
|
|
343
345
|
|
|
344
|
-
|
|
346
|
+
main_loop: for (i = 0; i < il; i++) {
|
|
345
347
|
|
|
346
|
-
|
|
348
|
+
const expected = elements[i];
|
|
347
349
|
|
|
348
|
-
|
|
350
|
+
for (j = jl - 1; j >= 0; j--) {
|
|
349
351
|
|
|
350
|
-
|
|
352
|
+
const actual = data[j];
|
|
351
353
|
|
|
352
|
-
|
|
354
|
+
if (objectsEqual(actual, expected)) {
|
|
353
355
|
|
|
354
|
-
|
|
356
|
+
this.remove(j);
|
|
355
357
|
|
|
356
|
-
|
|
358
|
+
jl--;
|
|
357
359
|
|
|
358
|
-
jl--;
|
|
359
360
|
|
|
361
|
+
continue main_loop;
|
|
360
362
|
|
|
361
|
-
|
|
363
|
+
}
|
|
362
364
|
|
|
363
365
|
}
|
|
364
366
|
|
|
365
|
-
}
|
|
366
367
|
|
|
368
|
+
missCount++;
|
|
369
|
+
}
|
|
367
370
|
|
|
368
|
-
|
|
371
|
+
//some elements were not deleted
|
|
372
|
+
return missCount === 0;
|
|
369
373
|
}
|
|
370
374
|
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
}
|
|
382
|
-
|
|
383
|
-
/**
|
|
384
|
-
*
|
|
385
|
-
* @param {T} value
|
|
386
|
-
* @return {boolean}
|
|
387
|
-
*/
|
|
388
|
-
List.prototype.removeOneOf = function (value) {
|
|
389
|
-
if (typeof value === "object" && typeof value.equals === "function") {
|
|
390
|
-
return this.removeOneIf(conditionEqualsViaMethod, value);
|
|
391
|
-
} else {
|
|
392
|
-
return this.removeOneIf(conditionEqualsStrict, value);
|
|
375
|
+
/**
|
|
376
|
+
*
|
|
377
|
+
* @param {T} value
|
|
378
|
+
* @return {boolean}
|
|
379
|
+
*/
|
|
380
|
+
removeOneOf(value) {
|
|
381
|
+
if (typeof value === "object" && typeof value.equals === "function") {
|
|
382
|
+
return this.removeOneIf(conditionEqualsViaMethod, value);
|
|
383
|
+
} else {
|
|
384
|
+
return this.removeOneIf(conditionEqualsStrict, value);
|
|
385
|
+
}
|
|
393
386
|
}
|
|
394
|
-
};
|
|
395
387
|
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
}
|
|
388
|
+
sort() {
|
|
389
|
+
Array.prototype.sort.apply(this.data, arguments);
|
|
390
|
+
return this;
|
|
391
|
+
}
|
|
400
392
|
|
|
401
|
-
/**
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
}
|
|
393
|
+
/**
|
|
394
|
+
* Copy of this list
|
|
395
|
+
* @returns {List.<T>}
|
|
396
|
+
*/
|
|
397
|
+
clone() {
|
|
398
|
+
return new List(this.data);
|
|
399
|
+
}
|
|
408
400
|
|
|
409
|
-
/**
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
401
|
+
/**
|
|
402
|
+
*
|
|
403
|
+
* @param {function(element:T):boolean} condition
|
|
404
|
+
* @returns {boolean}
|
|
405
|
+
*/
|
|
406
|
+
some(condition) {
|
|
407
|
+
const l = this.length;
|
|
408
|
+
const data = this.data;
|
|
409
|
+
for (let i = 0; i < l; i++) {
|
|
410
|
+
if (condition(data[i])) {
|
|
411
|
+
return true;
|
|
412
|
+
}
|
|
420
413
|
}
|
|
414
|
+
return false;
|
|
421
415
|
}
|
|
422
|
-
return false;
|
|
423
|
-
};
|
|
424
416
|
|
|
425
|
-
/**
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
417
|
+
/**
|
|
418
|
+
*
|
|
419
|
+
* @param {function(T):boolean} condition must return boolean value
|
|
420
|
+
* @param {*} [thisArg]
|
|
421
|
+
*/
|
|
422
|
+
removeIf(condition, thisArg) {
|
|
423
|
+
assert.isFunction(condition, 'condition');
|
|
424
|
+
|
|
425
|
+
let l = this.length;
|
|
426
|
+
const data = this.data;
|
|
427
|
+
for (let i = 0; i < l; i++) {
|
|
428
|
+
const element = data[i];
|
|
429
|
+
|
|
430
|
+
if (condition.call(thisArg, element)) {
|
|
431
|
+
this.remove(i);
|
|
432
|
+
i--;
|
|
433
|
+
l--;
|
|
434
|
+
}
|
|
437
435
|
}
|
|
438
436
|
}
|
|
439
|
-
};
|
|
440
437
|
|
|
441
|
-
/**
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
438
|
+
/**
|
|
439
|
+
*
|
|
440
|
+
* @param {function(T):boolean} condition
|
|
441
|
+
* @param {*} [thisArg]
|
|
442
|
+
* @return {boolean}
|
|
443
|
+
*/
|
|
444
|
+
removeOneIf(condition, thisArg) {
|
|
445
|
+
const l = this.length;
|
|
446
|
+
const data = this.data;
|
|
450
447
|
|
|
451
|
-
|
|
452
|
-
|
|
448
|
+
for (let i = 0; i < l; i++) {
|
|
449
|
+
const element = data[i];
|
|
453
450
|
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
451
|
+
if (condition.call(thisArg, element)) {
|
|
452
|
+
this.remove(i);
|
|
453
|
+
return true;
|
|
454
|
+
}
|
|
457
455
|
}
|
|
458
|
-
}
|
|
459
456
|
|
|
460
|
-
|
|
461
|
-
}
|
|
457
|
+
return false;
|
|
458
|
+
}
|
|
462
459
|
|
|
463
|
-
/**
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
460
|
+
/**
|
|
461
|
+
* INVARIANT: List length must not change during the traversal
|
|
462
|
+
* @param {function(el:T, index:number):?} f
|
|
463
|
+
* @param {*} [thisArg]
|
|
464
|
+
*/
|
|
465
|
+
forEach(f, thisArg) {
|
|
466
|
+
const l = this.length;
|
|
467
|
+
const data = this.data;
|
|
471
468
|
|
|
472
|
-
|
|
469
|
+
for (let i = 0; i < l; i++) {
|
|
473
470
|
|
|
474
|
-
|
|
471
|
+
f.call(thisArg, data[i], i);
|
|
475
472
|
|
|
473
|
+
}
|
|
476
474
|
}
|
|
477
|
-
};
|
|
478
475
|
|
|
479
|
-
/**
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
}
|
|
476
|
+
/**
|
|
477
|
+
* @param {function(*,T):*} f
|
|
478
|
+
* @param {*} initial
|
|
479
|
+
* @returns {*}
|
|
480
|
+
*/
|
|
481
|
+
reduce(f, initial) {
|
|
482
|
+
let t = initial;
|
|
483
|
+
this.forEach(function (v) {
|
|
484
|
+
t = f(t, v);
|
|
485
|
+
});
|
|
486
|
+
return t;
|
|
487
|
+
}
|
|
491
488
|
|
|
492
|
-
/**
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
}
|
|
489
|
+
/**
|
|
490
|
+
*
|
|
491
|
+
* @param {function(T):boolean} f
|
|
492
|
+
* @returns {Array.<T>}
|
|
493
|
+
*/
|
|
494
|
+
filter(f) {
|
|
495
|
+
return this.data.filter(f);
|
|
496
|
+
}
|
|
500
497
|
|
|
501
|
-
/**
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
498
|
+
/**
|
|
499
|
+
*
|
|
500
|
+
* @param {function(el:T):boolean} matcher
|
|
501
|
+
* @returns {T|undefined}
|
|
502
|
+
*/
|
|
503
|
+
find(matcher) {
|
|
504
|
+
const data = this.data;
|
|
505
|
+
let i = 0;
|
|
506
|
+
const l = this.length;
|
|
507
|
+
for (; i < l; i++) {
|
|
508
|
+
const el = data[i];
|
|
509
|
+
if (matcher(el)) {
|
|
510
|
+
return el;
|
|
511
|
+
}
|
|
514
512
|
}
|
|
515
|
-
}
|
|
516
513
|
|
|
517
|
-
|
|
518
|
-
}
|
|
514
|
+
return undefined;
|
|
515
|
+
}
|
|
519
516
|
|
|
520
|
-
/**
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
517
|
+
/**
|
|
518
|
+
*
|
|
519
|
+
* @param {function(T):boolean} matcher
|
|
520
|
+
* @returns {number} Index of the first match or -1
|
|
521
|
+
*/
|
|
522
|
+
findIndex(matcher) {
|
|
523
|
+
const data = this.data;
|
|
527
524
|
|
|
528
|
-
|
|
525
|
+
let i = 0;
|
|
529
526
|
|
|
530
|
-
|
|
527
|
+
const l = this.length;
|
|
531
528
|
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
529
|
+
for (; i < l; i++) {
|
|
530
|
+
const el = data[i];
|
|
531
|
+
if (matcher(el)) {
|
|
532
|
+
return i;
|
|
533
|
+
}
|
|
536
534
|
}
|
|
537
|
-
}
|
|
538
535
|
|
|
539
|
-
|
|
540
|
-
}
|
|
541
|
-
|
|
542
|
-
/**
|
|
543
|
-
*
|
|
544
|
-
* @param {function} matcher
|
|
545
|
-
* @param {List~ConsumerCallback<T>} callback
|
|
546
|
-
*/
|
|
547
|
-
List.prototype.visitFirstMatch = function (matcher, callback) {
|
|
548
|
-
const data = this.data;
|
|
549
|
-
let i = 0;
|
|
550
|
-
const l = this.length;
|
|
551
|
-
for (; i < l; i++) {
|
|
552
|
-
const el = data[i];
|
|
553
|
-
if (matcher(el)) {
|
|
554
|
-
callback(el, i);
|
|
555
|
-
return;
|
|
556
|
-
}
|
|
557
|
-
}
|
|
558
|
-
};
|
|
559
|
-
/**
|
|
560
|
-
*
|
|
561
|
-
* @param {T} v
|
|
562
|
-
* @returns {boolean}
|
|
563
|
-
*/
|
|
564
|
-
List.prototype.contains = function (v) {
|
|
565
|
-
return this.data.indexOf(v) !== -1;
|
|
566
|
-
};
|
|
567
|
-
|
|
568
|
-
/**
|
|
569
|
-
* Does the list contain at least one of the given options?
|
|
570
|
-
* @param {T[]} options
|
|
571
|
-
* @returns {boolean}
|
|
572
|
-
*/
|
|
573
|
-
List.prototype.containsAny = function (options) {
|
|
574
|
-
const n = options.length;
|
|
536
|
+
return -1;
|
|
537
|
+
}
|
|
575
538
|
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
539
|
+
/**
|
|
540
|
+
*
|
|
541
|
+
* @param {function(el:T):boolean} matcher
|
|
542
|
+
* @param {function(el:T, index:number):*} callback
|
|
543
|
+
*/
|
|
544
|
+
visitFirstMatch(matcher, callback) {
|
|
545
|
+
const data = this.data;
|
|
546
|
+
let i = 0;
|
|
547
|
+
const l = this.length;
|
|
548
|
+
for (; i < l; i++) {
|
|
549
|
+
const el = data[i];
|
|
550
|
+
if (matcher(el)) {
|
|
551
|
+
callback(el, i);
|
|
552
|
+
return;
|
|
553
|
+
}
|
|
580
554
|
}
|
|
581
555
|
}
|
|
582
556
|
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
return this.length <= 0;
|
|
592
|
-
};
|
|
593
|
-
|
|
594
|
-
/**
|
|
595
|
-
*
|
|
596
|
-
* @param {T} el
|
|
597
|
-
* @returns {number}
|
|
598
|
-
*/
|
|
599
|
-
List.prototype.indexOf = function (el) {
|
|
600
|
-
return this.data.indexOf(el);
|
|
601
|
-
};
|
|
602
|
-
|
|
603
|
-
/**
|
|
604
|
-
* @template R
|
|
605
|
-
* @param {function(T):R} callback
|
|
606
|
-
* @param {*} [thisArg]
|
|
607
|
-
* @returns {R[]}
|
|
608
|
-
*/
|
|
609
|
-
List.prototype.map = function (callback, thisArg) {
|
|
610
|
-
const result = [];
|
|
611
|
-
const data = this.data;
|
|
612
|
-
const l = this.length;
|
|
557
|
+
/**
|
|
558
|
+
*
|
|
559
|
+
* @param {T} v
|
|
560
|
+
* @returns {boolean}
|
|
561
|
+
*/
|
|
562
|
+
contains(v) {
|
|
563
|
+
return this.data.indexOf(v) !== -1;
|
|
564
|
+
}
|
|
613
565
|
|
|
614
|
-
|
|
566
|
+
/**
|
|
567
|
+
* Does the list contain at least one of the given options?
|
|
568
|
+
* @param {T[]} options
|
|
569
|
+
* @returns {boolean}
|
|
570
|
+
*/
|
|
571
|
+
containsAny(options) {
|
|
572
|
+
const n = options.length;
|
|
615
573
|
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
574
|
+
for (let i = 0; i < n; i++) {
|
|
575
|
+
const option = options[i];
|
|
576
|
+
if (this.contains(option)) {
|
|
577
|
+
return true;
|
|
578
|
+
}
|
|
619
579
|
}
|
|
620
|
-
}
|
|
621
580
|
|
|
622
|
-
|
|
623
|
-
}
|
|
581
|
+
return false;
|
|
582
|
+
}
|
|
624
583
|
|
|
625
|
-
/**
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
if (length > 0) {
|
|
584
|
+
/**
|
|
585
|
+
* List has no elements
|
|
586
|
+
* @returns {boolean}
|
|
587
|
+
*/
|
|
588
|
+
isEmpty() {
|
|
589
|
+
return this.length <= 0;
|
|
590
|
+
}
|
|
633
591
|
|
|
634
|
-
|
|
592
|
+
/**
|
|
593
|
+
*
|
|
594
|
+
* @param {T} el
|
|
595
|
+
* @returns {number}
|
|
596
|
+
*/
|
|
597
|
+
indexOf(el) {
|
|
598
|
+
return this.data.indexOf(el);
|
|
599
|
+
}
|
|
635
600
|
|
|
636
|
-
|
|
601
|
+
/**
|
|
602
|
+
* @template R
|
|
603
|
+
* @param {function(T):R} callback
|
|
604
|
+
* @param {*} [thisArg]
|
|
605
|
+
* @returns {R[]}
|
|
606
|
+
*/
|
|
607
|
+
map(callback, thisArg) {
|
|
608
|
+
const result = [];
|
|
609
|
+
const data = this.data;
|
|
610
|
+
const l = this.length;
|
|
637
611
|
|
|
638
|
-
|
|
639
|
-
for (let i = length - 1; i >= 0; i--) {
|
|
640
|
-
const element = oldElements[i];
|
|
641
|
-
// decrement data length gradually to allow handlers access to the rest of the elements
|
|
642
|
-
this.data.length = i;
|
|
643
|
-
this.length = i;
|
|
644
|
-
removed.send2(element, i);
|
|
612
|
+
for (let i = 0; i < l; i++) {
|
|
645
613
|
|
|
646
|
-
|
|
614
|
+
const datum = data[i];
|
|
615
|
+
if (datum !== undefined) {
|
|
616
|
+
result[i] = callback.call(thisArg, datum, i);
|
|
617
|
+
}
|
|
647
618
|
}
|
|
648
619
|
|
|
620
|
+
return result;
|
|
649
621
|
}
|
|
650
|
-
};
|
|
651
|
-
|
|
652
|
-
List.prototype.reset = function () {
|
|
653
|
-
const length = this.length;
|
|
654
|
-
if (length > 0) {
|
|
655
622
|
|
|
656
|
-
|
|
623
|
+
/**
|
|
624
|
+
*
|
|
625
|
+
* @param {function(element:T,index:number)} callback
|
|
626
|
+
* @param {*} [thisArg]
|
|
627
|
+
*/
|
|
628
|
+
resetViaCallback(callback, thisArg) {
|
|
629
|
+
const length = this.length;
|
|
630
|
+
if (length > 0) {
|
|
657
631
|
|
|
658
|
-
|
|
632
|
+
const removed = this.on.removed;
|
|
659
633
|
|
|
660
634
|
const oldElements = this.data;
|
|
661
635
|
|
|
@@ -666,281 +640,325 @@ List.prototype.reset = function () {
|
|
|
666
640
|
this.data.length = i;
|
|
667
641
|
this.length = i;
|
|
668
642
|
removed.send2(element, i);
|
|
643
|
+
|
|
644
|
+
callback.call(thisArg, element, i);
|
|
669
645
|
}
|
|
670
646
|
|
|
671
|
-
} else {
|
|
672
|
-
this.data = [];
|
|
673
|
-
this.length = 0;
|
|
674
647
|
}
|
|
675
|
-
|
|
676
648
|
}
|
|
677
|
-
};
|
|
678
649
|
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
* @param {function} [removeCallback]
|
|
683
|
-
* @param {*} [thisArg] Used on removeCallback
|
|
684
|
-
*/
|
|
685
|
-
List.prototype.deepCopy = function (other, removeCallback, thisArg) {
|
|
686
|
-
assert.notEqual(other, undefined, 'other is undefined');
|
|
687
|
-
assert.notEqual(other, null, 'other is null');
|
|
650
|
+
reset() {
|
|
651
|
+
const length = this.length;
|
|
652
|
+
if (length > 0) {
|
|
688
653
|
|
|
689
|
-
|
|
654
|
+
const removed = this.on.removed;
|
|
690
655
|
|
|
691
|
-
|
|
692
|
-
const nOtherItems = otherItems.length;
|
|
656
|
+
if (removed.hasHandlers()) {
|
|
693
657
|
|
|
694
|
-
|
|
695
|
-
let nThisItems = this.length;
|
|
658
|
+
const oldElements = this.data;
|
|
696
659
|
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
660
|
+
//only signal if there are listeners attached
|
|
661
|
+
for (let i = length - 1; i >= 0; i--) {
|
|
662
|
+
const element = oldElements[i];
|
|
663
|
+
// decrement data length gradually to allow handlers access to the rest of the elements
|
|
664
|
+
this.data.length = i;
|
|
665
|
+
this.length = i;
|
|
666
|
+
removed.send2(element, i);
|
|
667
|
+
}
|
|
700
668
|
|
|
701
|
-
|
|
669
|
+
} else {
|
|
670
|
+
this.data = [];
|
|
671
|
+
this.length = 0;
|
|
672
|
+
}
|
|
702
673
|
|
|
703
|
-
if (index !== -1) {
|
|
704
|
-
newData[index] = a;
|
|
705
|
-
} else if (typeof removeCallback === "function") {
|
|
706
|
-
removeCallback.call(thisArg, a);
|
|
707
674
|
}
|
|
708
675
|
}
|
|
709
676
|
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
677
|
+
/**
|
|
678
|
+
* Note that elements must have .clone method for this to work
|
|
679
|
+
* @param {List<T>} other
|
|
680
|
+
* @param {function} [removeCallback]
|
|
681
|
+
* @param {*} [thisArg] Used on removeCallback
|
|
682
|
+
*/
|
|
683
|
+
deepCopy(other, removeCallback, thisArg) {
|
|
684
|
+
assert.notEqual(other, undefined, 'other is undefined');
|
|
685
|
+
assert.notEqual(other, null, 'other is null');
|
|
686
|
+
|
|
687
|
+
const newData = [];
|
|
688
|
+
|
|
689
|
+
const otherItems = other.asArray();
|
|
690
|
+
const nOtherItems = otherItems.length;
|
|
691
|
+
|
|
692
|
+
const thisItems = this.data;
|
|
693
|
+
let nThisItems = this.length;
|
|
694
|
+
|
|
695
|
+
//walk existing elements and see what can be kept
|
|
696
|
+
for (let i = 0; i < nThisItems; i++) {
|
|
697
|
+
const a = thisItems[i];
|
|
698
|
+
|
|
699
|
+
const index = arrayIndexByEquality(otherItems, a, invokeObjectEquals);
|
|
700
|
+
|
|
701
|
+
if (index !== -1) {
|
|
702
|
+
newData[index] = a;
|
|
703
|
+
} else if (typeof removeCallback === "function") {
|
|
704
|
+
removeCallback.call(thisArg, a);
|
|
705
|
+
}
|
|
715
706
|
}
|
|
716
|
-
}
|
|
717
707
|
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
708
|
+
//fill in the blanks
|
|
709
|
+
for (let i = 0; i < nOtherItems; i++) {
|
|
710
|
+
if (newData[i] === undefined) {
|
|
711
|
+
const otherItem = otherItems[i];
|
|
712
|
+
newData[i] = otherItem.clone();
|
|
713
|
+
}
|
|
714
|
+
}
|
|
721
715
|
|
|
722
|
-
/**
|
|
723
|
-
*
|
|
724
|
-
* @param {List<T>|T[]} other
|
|
725
|
-
*/
|
|
726
|
-
List.prototype.copy = function (other) {
|
|
727
|
-
if (this !== other) {
|
|
728
716
|
this.reset();
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
717
|
+
this.addAll(newData);
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
/**
|
|
721
|
+
*
|
|
722
|
+
* @param {List<T>|T[]} other
|
|
723
|
+
*/
|
|
724
|
+
copy(other) {
|
|
725
|
+
if (this !== other) {
|
|
726
|
+
this.reset();
|
|
727
|
+
if (other.length > 0) {
|
|
728
|
+
if (other instanceof List) {
|
|
729
|
+
this.addAll(other.data);
|
|
730
|
+
} else {
|
|
731
|
+
this.addAll(other);
|
|
732
|
+
}
|
|
734
733
|
}
|
|
735
734
|
}
|
|
736
735
|
}
|
|
737
|
-
};
|
|
738
736
|
|
|
739
|
-
/**
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
}
|
|
737
|
+
/**
|
|
738
|
+
* NOTE: do not modify resulting array
|
|
739
|
+
* @returns {T[]}
|
|
740
|
+
*/
|
|
741
|
+
asArray() {
|
|
742
|
+
return this.data;
|
|
743
|
+
}
|
|
746
744
|
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
}
|
|
745
|
+
toJSON() {
|
|
746
|
+
return JSON.parse(JSON.stringify(this.data));
|
|
747
|
+
}
|
|
750
748
|
|
|
751
|
-
/**
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
749
|
+
/**
|
|
750
|
+
*
|
|
751
|
+
* @param {[]} json
|
|
752
|
+
* @param {function} constructor
|
|
753
|
+
*/
|
|
754
|
+
fromJSON(json, constructor) {
|
|
755
|
+
this.reset();
|
|
758
756
|
|
|
759
|
-
|
|
757
|
+
assert.isArray(json, 'json');
|
|
760
758
|
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
759
|
+
if (typeof constructor === "function") {
|
|
760
|
+
this.addAll(json.map(function (elJSON) {
|
|
761
|
+
const el = new constructor();
|
|
762
|
+
el.fromJSON(elJSON);
|
|
763
|
+
return el;
|
|
764
|
+
}));
|
|
765
|
+
} else {
|
|
766
|
+
this.addAll(json);
|
|
767
|
+
}
|
|
769
768
|
}
|
|
770
|
-
};
|
|
771
769
|
|
|
770
|
+
/**
|
|
771
|
+
*
|
|
772
|
+
* @param {BinaryBuffer} buffer
|
|
773
|
+
*/
|
|
774
|
+
toBinaryBuffer(buffer) {
|
|
775
|
+
const n = this.length;
|
|
772
776
|
|
|
773
|
-
|
|
774
|
-
*
|
|
775
|
-
* @param {BinaryBuffer} buffer
|
|
776
|
-
*/
|
|
777
|
-
List.prototype.toBinaryBuffer = function (buffer) {
|
|
778
|
-
const n = this.length;
|
|
777
|
+
buffer.writeUint32(n);
|
|
779
778
|
|
|
780
|
-
|
|
779
|
+
for (let i = 0; i < n; i++) {
|
|
780
|
+
const item = this.data[i];
|
|
781
781
|
|
|
782
|
-
|
|
783
|
-
|
|
782
|
+
if (typeof item.toBinaryBuffer !== "function") {
|
|
783
|
+
throw new Error('item.toBinaryBuffer is not a function');
|
|
784
|
+
}
|
|
784
785
|
|
|
785
|
-
|
|
786
|
-
throw new Error('item.toBinaryBuffer is not a function');
|
|
786
|
+
item.toBinaryBuffer(buffer);
|
|
787
787
|
}
|
|
788
|
-
|
|
789
|
-
item.toBinaryBuffer(buffer);
|
|
790
788
|
}
|
|
791
|
-
};
|
|
792
789
|
|
|
793
|
-
/**
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
790
|
+
/**
|
|
791
|
+
*
|
|
792
|
+
* @param {BinaryBuffer} buffer
|
|
793
|
+
* @param constructor
|
|
794
|
+
*/
|
|
795
|
+
fromBinaryBuffer(buffer, constructor) {
|
|
796
|
+
this.fromBinaryBufferViaFactory(buffer, function (buffer) {
|
|
800
797
|
|
|
801
|
-
|
|
798
|
+
const el = new constructor();
|
|
802
799
|
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
800
|
+
if (typeof el.fromBinaryBuffer !== "function") {
|
|
801
|
+
throw new Error('item.fromBinaryBuffer is not a function');
|
|
802
|
+
}
|
|
806
803
|
|
|
807
|
-
|
|
804
|
+
el.fromBinaryBuffer(buffer);
|
|
808
805
|
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
}
|
|
806
|
+
return el;
|
|
807
|
+
});
|
|
808
|
+
}
|
|
812
809
|
|
|
813
|
-
/**
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
810
|
+
/**
|
|
811
|
+
*
|
|
812
|
+
* @param {BinaryBuffer} buffer
|
|
813
|
+
* @param {function(buffer:BinaryBuffer)} factory
|
|
814
|
+
*/
|
|
815
|
+
fromBinaryBufferViaFactory(buffer, factory) {
|
|
816
|
+
this.reset();
|
|
820
817
|
|
|
821
|
-
|
|
822
|
-
}
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
818
|
+
this.addFromBinaryBufferViaFactory(buffer, factory);
|
|
819
|
+
}
|
|
820
|
+
|
|
821
|
+
/**
|
|
822
|
+
*
|
|
823
|
+
* @param {BinaryBuffer} buffer
|
|
824
|
+
* @param {function(buffer:BinaryBuffer)} factory
|
|
825
|
+
*/
|
|
826
|
+
addFromBinaryBufferViaFactory(buffer, factory) {
|
|
827
|
+
const length = buffer.readUint32();
|
|
830
828
|
|
|
831
|
-
|
|
832
|
-
|
|
829
|
+
for (let i = 0; i < length; i++) {
|
|
830
|
+
const el = factory(buffer);
|
|
833
831
|
|
|
834
|
-
|
|
832
|
+
this.add(el);
|
|
833
|
+
}
|
|
835
834
|
}
|
|
836
|
-
};
|
|
837
835
|
|
|
838
|
-
/**
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
836
|
+
/**
|
|
837
|
+
* @template J
|
|
838
|
+
* @param {J[]} data
|
|
839
|
+
* @param {function(J):T} factory
|
|
840
|
+
*/
|
|
841
|
+
addFromJSONViaFactory(data, factory) {
|
|
842
|
+
const n = data.length;
|
|
843
|
+
for (let i = 0; i < n; i++) {
|
|
844
|
+
const datum = data[i];
|
|
847
845
|
|
|
848
|
-
|
|
846
|
+
const el = factory(datum);
|
|
849
847
|
|
|
850
|
-
|
|
848
|
+
this.add(el);
|
|
849
|
+
}
|
|
851
850
|
}
|
|
852
|
-
};
|
|
853
851
|
|
|
854
|
-
/**
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
852
|
+
/**
|
|
853
|
+
* NOTE: Elements must have hash method
|
|
854
|
+
* @returns {number}
|
|
855
|
+
*/
|
|
856
|
+
hash() {
|
|
857
|
+
let hash = 0;
|
|
858
|
+
const length = this.length;
|
|
859
|
+
|
|
860
|
+
for (let i = 0; i < length; i++) {
|
|
861
|
+
const datum = this.data[i];
|
|
862
|
+
const singleValue = datum.hash();
|
|
863
|
+
hash = ((hash << 5) - hash) + singleValue;
|
|
864
|
+
hash |= 0; // Convert to 32bit integer
|
|
865
|
+
}
|
|
861
866
|
|
|
862
|
-
|
|
863
|
-
const datum = this.data[i];
|
|
864
|
-
const singleValue = datum.hash();
|
|
865
|
-
hash = ((hash << 5) - hash) + singleValue;
|
|
866
|
-
hash |= 0; // Convert to 32bit integer
|
|
867
|
+
return hash;
|
|
867
868
|
}
|
|
868
869
|
|
|
869
|
-
|
|
870
|
-
|
|
870
|
+
/**
|
|
871
|
+
*
|
|
872
|
+
* @return {T|undefined}
|
|
873
|
+
*/
|
|
874
|
+
last() {
|
|
875
|
+
return this.data[this.length - 1];
|
|
876
|
+
}
|
|
871
877
|
|
|
872
|
-
/**
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
};
|
|
878
|
+
/**
|
|
879
|
+
* Perform element-wise equality comparison with another list
|
|
880
|
+
* @param {List} other
|
|
881
|
+
*/
|
|
882
|
+
equals(other) {
|
|
883
|
+
assert.defined(other, 'other');
|
|
879
884
|
|
|
880
|
-
|
|
881
|
-
* Perform element-wise equality comparison with another list
|
|
882
|
-
* @param {List} other
|
|
883
|
-
*/
|
|
884
|
-
List.prototype.equals = function (other) {
|
|
885
|
-
assert.defined(other, 'other');
|
|
885
|
+
const length = this.length;
|
|
886
886
|
|
|
887
|
-
|
|
887
|
+
if (length !== other.length) {
|
|
888
|
+
return false;
|
|
889
|
+
}
|
|
888
890
|
|
|
889
|
-
|
|
890
|
-
return false;
|
|
891
|
-
}
|
|
891
|
+
let i;
|
|
892
892
|
|
|
893
|
-
|
|
893
|
+
for (i = 0; i < length; i++) {
|
|
894
|
+
const a = this.get(i);
|
|
894
895
|
|
|
895
|
-
|
|
896
|
-
const a = this.get(i);
|
|
896
|
+
const b = other.get(i);
|
|
897
897
|
|
|
898
|
-
|
|
898
|
+
if (a === b) {
|
|
899
|
+
continue;
|
|
900
|
+
}
|
|
899
901
|
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
902
|
+
if (typeof a === "object" && typeof b === "object" && typeof a.equals === "function" && a.equals(b)) {
|
|
903
|
+
//test via "equals" method
|
|
904
|
+
continue;
|
|
905
|
+
}
|
|
903
906
|
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
continue;
|
|
907
|
+
//elements not equal
|
|
908
|
+
return false;
|
|
907
909
|
}
|
|
908
910
|
|
|
909
|
-
|
|
910
|
-
return false;
|
|
911
|
+
return true;
|
|
911
912
|
}
|
|
912
913
|
|
|
913
|
-
|
|
914
|
-
|
|
914
|
+
/**
|
|
915
|
+
*
|
|
916
|
+
* @param {List<T>} other
|
|
917
|
+
* @returns {number}
|
|
918
|
+
*/
|
|
919
|
+
compare(other) {
|
|
920
|
+
const l = this.length;
|
|
915
921
|
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
*/
|
|
921
|
-
List.prototype.compare = function (other) {
|
|
922
|
-
const l = this.length;
|
|
922
|
+
const other_length = other.length;
|
|
923
|
+
if (l !== other_length) {
|
|
924
|
+
return l - other_length;
|
|
925
|
+
}
|
|
923
926
|
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
return l - other_length;
|
|
927
|
-
}
|
|
927
|
+
for (let i = 0; i < l; i++) {
|
|
928
|
+
const a = this.get(i);
|
|
928
929
|
|
|
929
|
-
|
|
930
|
-
const a = this.get(i);
|
|
930
|
+
const b = other.get(i);
|
|
931
931
|
|
|
932
|
-
|
|
932
|
+
const delta = a.compare(b);
|
|
933
933
|
|
|
934
|
-
|
|
934
|
+
if (delta !== 0) {
|
|
935
|
+
return delta;
|
|
936
|
+
}
|
|
935
937
|
|
|
936
|
-
if (delta !== 0) {
|
|
937
|
-
return delta;
|
|
938
938
|
}
|
|
939
939
|
|
|
940
|
+
// same
|
|
941
|
+
return 0;
|
|
940
942
|
}
|
|
943
|
+
}
|
|
944
|
+
|
|
945
|
+
/**
|
|
946
|
+
*
|
|
947
|
+
* @param {Object} a
|
|
948
|
+
* @param {Object} b
|
|
949
|
+
* @returns {boolean}
|
|
950
|
+
*/
|
|
951
|
+
function objectsEqual(a, b) {
|
|
952
|
+
return a === b || (typeof a.equals === "function" && a.equals(b));
|
|
953
|
+
}
|
|
954
|
+
|
|
955
|
+
function conditionEqualsViaMethod(v) {
|
|
956
|
+
return this === v || this.equals(v);
|
|
957
|
+
}
|
|
958
|
+
|
|
959
|
+
function conditionEqualsStrict(v) {
|
|
960
|
+
return this === v;
|
|
961
|
+
}
|
|
941
962
|
|
|
942
|
-
// same
|
|
943
|
-
return 0;
|
|
944
|
-
};
|
|
945
963
|
|
|
946
964
|
export default List;
|