StackedSetMap.js
2.79 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
"use strict";
const util = require("util");
const TOMBSTONE = {};
const UNDEFINED_MARKER = {};
class StackedSetMap {
constructor(parentStack) {
this.stack = parentStack === undefined ? [] : parentStack.slice();
this.map = new Map();
this.stack.push(this.map);
}
add(item) {
this.map.set(item, true);
}
set(item, value) {
this.map.set(item, value === undefined ? UNDEFINED_MARKER : value);
}
delete(item) {
if (this.stack.length > 1) {
this.map.set(item, TOMBSTONE);
} else {
this.map.delete(item);
}
}
has(item) {
const topValue = this.map.get(item);
if (topValue !== undefined) return topValue !== TOMBSTONE;
if (this.stack.length > 1) {
for (var i = this.stack.length - 2; i >= 0; i--) {
const value = this.stack[i].get(item);
if (value !== undefined) {
this.map.set(item, value);
return value !== TOMBSTONE;
}
}
this.map.set(item, TOMBSTONE);
}
return false;
}
get(item) {
const topValue = this.map.get(item);
if (topValue !== undefined) {
return topValue === TOMBSTONE || topValue === UNDEFINED_MARKER
? undefined
: topValue;
}
if (this.stack.length > 1) {
for (var i = this.stack.length - 2; i >= 0; i--) {
const value = this.stack[i].get(item);
if (value !== undefined) {
this.map.set(item, value);
return value === TOMBSTONE || value === UNDEFINED_MARKER
? undefined
: value;
}
}
this.map.set(item, TOMBSTONE);
}
return undefined;
}
_compress() {
if (this.stack.length === 1) return;
this.map = new Map();
for (const data of this.stack) {
for (const pair of data) {
if (pair[1] === TOMBSTONE) {
this.map.delete(pair[0]);
} else {
this.map.set(pair[0], pair[1]);
}
}
}
this.stack = [this.map];
}
asArray() {
this._compress();
return Array.from(this.map.entries(), pair => pair[0]);
}
asSet() {
return new Set(this.asArray());
}
asPairArray() {
this._compress();
return Array.from(this.map.entries(), pair =>
/** @type {[TODO, TODO]} */ (pair[1] === UNDEFINED_MARKER
? [pair[0], undefined]
: pair)
);
}
asMap() {
return new Map(this.asPairArray());
}
get size() {
this._compress();
return this.map.size;
}
createChild() {
return new StackedSetMap(this.stack);
}
get length() {
throw new Error("This is no longer an Array");
}
set length(value) {
throw new Error("This is no longer an Array");
}
}
// TODO remove in webpack 5
StackedSetMap.prototype.push = util.deprecate(
/**
* @deprecated
* @this {StackedSetMap}
* @param {any} item Item to add
* @returns {void}
*/
function(item) {
this.add(item);
},
"This is no longer an Array: Use add instead."
);
module.exports = StackedSetMap;