java-topology/defects/three.js/patch/three-0001-node-builder-array-includes-set.patch

53 lines
1.8 KiB
Diff

# UNDF: UNDF-2026-000000752
# UNDF: (leave blank)
--- a/src/nodes/core/NodeBuilder.js
+++ b/src/nodes/core/NodeBuilder.js
@@ -137,6 +137,13 @@ class NodeBuilder {
* @type {Array<Node>}
*/
this.nodes = [];
+
+ // O(1) membership guard for this.nodes and this.sequentialNodes.
+ // this.nodes.includes(node) is O(N) and is called once per node during
+ // the shader build traversal, making addNode() O(N²) for graphs with N
+ // nodes. A Set<Node> reduces each membership test to O(1), giving O(N)
+ // total build cost. CWE-407.
+ this._nodesSet = new Set();
+ this._sequentialNodesSet = new Set();
/**
* A list of all nodes the builder is processing in sequential order.
@@ -762,8 +762,8 @@ class NodeBuilder {
addNode( node ) {
- if ( this.nodes.includes( node ) === false ) {
+ if ( this._nodesSet.has( node ) === false ) {
this.nodes.push( node );
+ this._nodesSet.add( node );
this.setHashNode( node, node.getHash( this ) );
@@ -785,8 +785,8 @@ class NodeBuilder {
if ( updateBeforeType !== NodeUpdateType.NONE || updateAfterType !== NodeUpdateType.NONE ) {
- if ( this.sequentialNodes.includes( node ) === false ) {
+ if ( this._sequentialNodesSet.has( node ) === false ) {
this.sequentialNodes.push( node );
+ this._sequentialNodesSet.add( node );
}
--- a/src/nodes/core/StackNode.js
+++ b/src/nodes/core/StackNode.js
@@ -382,7 +382,9 @@ class StackNode extends Node {
this._currentNode = null;
- const newNodes = this.nodes.filter( ( node ) => nodes.indexOf( node ) === - 1 );
+ // nodes.indexOf(node) is O(N) inside filter → O(N²) overall.
+ // Use a Set for O(N) total. CWE-407.
+ const nodesSnapshot = new Set( nodes );
+ const newNodes = this.nodes.filter( ( node ) => nodesSnapshot.has( node ) === false );
for ( const node of newNodes ) {