UNPKG

8.02 kBJavaScriptView Raw
1'use strict';
2var create = require('../internals/object-create');
3var defineBuiltInAccessor = require('../internals/define-built-in-accessor');
4var defineBuiltIns = require('../internals/define-built-ins');
5var bind = require('../internals/function-bind-context');
6var anInstance = require('../internals/an-instance');
7var isNullOrUndefined = require('../internals/is-null-or-undefined');
8var iterate = require('../internals/iterate');
9var defineIterator = require('../internals/iterator-define');
10var createIterResultObject = require('../internals/create-iter-result-object');
11var setSpecies = require('../internals/set-species');
12var DESCRIPTORS = require('../internals/descriptors');
13var fastKey = require('../internals/internal-metadata').fastKey;
14var InternalStateModule = require('../internals/internal-state');
15
16var setInternalState = InternalStateModule.set;
17var internalStateGetterFor = InternalStateModule.getterFor;
18
19module.exports = {
20 getConstructor: function (wrapper, CONSTRUCTOR_NAME, IS_MAP, ADDER) {
21 var Constructor = wrapper(function (that, iterable) {
22 anInstance(that, Prototype);
23 setInternalState(that, {
24 type: CONSTRUCTOR_NAME,
25 index: create(null),
26 first: undefined,
27 last: undefined,
28 size: 0
29 });
30 if (!DESCRIPTORS) that.size = 0;
31 if (!isNullOrUndefined(iterable)) iterate(iterable, that[ADDER], { that: that, AS_ENTRIES: IS_MAP });
32 });
33
34 var Prototype = Constructor.prototype;
35
36 var getInternalState = internalStateGetterFor(CONSTRUCTOR_NAME);
37
38 var define = function (that, key, value) {
39 var state = getInternalState(that);
40 var entry = getEntry(that, key);
41 var previous, index;
42 // change existing entry
43 if (entry) {
44 entry.value = value;
45 // create new entry
46 } else {
47 state.last = entry = {
48 index: index = fastKey(key, true),
49 key: key,
50 value: value,
51 previous: previous = state.last,
52 next: undefined,
53 removed: false
54 };
55 if (!state.first) state.first = entry;
56 if (previous) previous.next = entry;
57 if (DESCRIPTORS) state.size++;
58 else that.size++;
59 // add to index
60 if (index !== 'F') state.index[index] = entry;
61 } return that;
62 };
63
64 var getEntry = function (that, key) {
65 var state = getInternalState(that);
66 // fast case
67 var index = fastKey(key);
68 var entry;
69 if (index !== 'F') return state.index[index];
70 // frozen object case
71 for (entry = state.first; entry; entry = entry.next) {
72 if (entry.key === key) return entry;
73 }
74 };
75
76 defineBuiltIns(Prototype, {
77 // `{ Map, Set }.prototype.clear()` methods
78 // https://tc39.es/ecma262/#sec-map.prototype.clear
79 // https://tc39.es/ecma262/#sec-set.prototype.clear
80 clear: function clear() {
81 var that = this;
82 var state = getInternalState(that);
83 var entry = state.first;
84 while (entry) {
85 entry.removed = true;
86 if (entry.previous) entry.previous = entry.previous.next = undefined;
87 entry = entry.next;
88 }
89 state.first = state.last = undefined;
90 state.index = create(null);
91 if (DESCRIPTORS) state.size = 0;
92 else that.size = 0;
93 },
94 // `{ Map, Set }.prototype.delete(key)` methods
95 // https://tc39.es/ecma262/#sec-map.prototype.delete
96 // https://tc39.es/ecma262/#sec-set.prototype.delete
97 'delete': function (key) {
98 var that = this;
99 var state = getInternalState(that);
100 var entry = getEntry(that, key);
101 if (entry) {
102 var next = entry.next;
103 var prev = entry.previous;
104 delete state.index[entry.index];
105 entry.removed = true;
106 if (prev) prev.next = next;
107 if (next) next.previous = prev;
108 if (state.first === entry) state.first = next;
109 if (state.last === entry) state.last = prev;
110 if (DESCRIPTORS) state.size--;
111 else that.size--;
112 } return !!entry;
113 },
114 // `{ Map, Set }.prototype.forEach(callbackfn, thisArg = undefined)` methods
115 // https://tc39.es/ecma262/#sec-map.prototype.foreach
116 // https://tc39.es/ecma262/#sec-set.prototype.foreach
117 forEach: function forEach(callbackfn /* , that = undefined */) {
118 var state = getInternalState(this);
119 var boundFunction = bind(callbackfn, arguments.length > 1 ? arguments[1] : undefined);
120 var entry;
121 while (entry = entry ? entry.next : state.first) {
122 boundFunction(entry.value, entry.key, this);
123 // revert to the last existing entry
124 while (entry && entry.removed) entry = entry.previous;
125 }
126 },
127 // `{ Map, Set}.prototype.has(key)` methods
128 // https://tc39.es/ecma262/#sec-map.prototype.has
129 // https://tc39.es/ecma262/#sec-set.prototype.has
130 has: function has(key) {
131 return !!getEntry(this, key);
132 }
133 });
134
135 defineBuiltIns(Prototype, IS_MAP ? {
136 // `Map.prototype.get(key)` method
137 // https://tc39.es/ecma262/#sec-map.prototype.get
138 get: function get(key) {
139 var entry = getEntry(this, key);
140 return entry && entry.value;
141 },
142 // `Map.prototype.set(key, value)` method
143 // https://tc39.es/ecma262/#sec-map.prototype.set
144 set: function set(key, value) {
145 return define(this, key === 0 ? 0 : key, value);
146 }
147 } : {
148 // `Set.prototype.add(value)` method
149 // https://tc39.es/ecma262/#sec-set.prototype.add
150 add: function add(value) {
151 return define(this, value = value === 0 ? 0 : value, value);
152 }
153 });
154 if (DESCRIPTORS) defineBuiltInAccessor(Prototype, 'size', {
155 configurable: true,
156 get: function () {
157 return getInternalState(this).size;
158 }
159 });
160 return Constructor;
161 },
162 setStrong: function (Constructor, CONSTRUCTOR_NAME, IS_MAP) {
163 var ITERATOR_NAME = CONSTRUCTOR_NAME + ' Iterator';
164 var getInternalCollectionState = internalStateGetterFor(CONSTRUCTOR_NAME);
165 var getInternalIteratorState = internalStateGetterFor(ITERATOR_NAME);
166 // `{ Map, Set }.prototype.{ keys, values, entries, @@iterator }()` methods
167 // https://tc39.es/ecma262/#sec-map.prototype.entries
168 // https://tc39.es/ecma262/#sec-map.prototype.keys
169 // https://tc39.es/ecma262/#sec-map.prototype.values
170 // https://tc39.es/ecma262/#sec-map.prototype-@@iterator
171 // https://tc39.es/ecma262/#sec-set.prototype.entries
172 // https://tc39.es/ecma262/#sec-set.prototype.keys
173 // https://tc39.es/ecma262/#sec-set.prototype.values
174 // https://tc39.es/ecma262/#sec-set.prototype-@@iterator
175 defineIterator(Constructor, CONSTRUCTOR_NAME, function (iterated, kind) {
176 setInternalState(this, {
177 type: ITERATOR_NAME,
178 target: iterated,
179 state: getInternalCollectionState(iterated),
180 kind: kind,
181 last: undefined
182 });
183 }, function () {
184 var state = getInternalIteratorState(this);
185 var kind = state.kind;
186 var entry = state.last;
187 // revert to the last existing entry
188 while (entry && entry.removed) entry = entry.previous;
189 // get next entry
190 if (!state.target || !(state.last = entry = entry ? entry.next : state.state.first)) {
191 // or finish the iteration
192 state.target = undefined;
193 return createIterResultObject(undefined, true);
194 }
195 // return step by kind
196 if (kind === 'keys') return createIterResultObject(entry.key, false);
197 if (kind === 'values') return createIterResultObject(entry.value, false);
198 return createIterResultObject([entry.key, entry.value], false);
199 }, IS_MAP ? 'entries' : 'values', !IS_MAP, true);
200
201 // `{ Map, Set }.prototype[@@species]` accessors
202 // https://tc39.es/ecma262/#sec-get-map-@@species
203 // https://tc39.es/ecma262/#sec-get-set-@@species
204 setSpecies(CONSTRUCTOR_NAME);
205 }
206};