Skip to content

Commit 970fdb2

Browse files
committed
feat(Map): support constructor initialization with MapInitialEntries
- Added new type alias `MapInitialEntries<K, V>` = { key: K, value: V }[] - Map constructor now accepts: • An array of { key, value } objects • Any array typed as MapInitialEntries<K,V> - This allows populating a Map in one step with strong typing. - Example: let myMap = new Map<string, i32>([ { key: "a", value: 1 }, { key: "b", value: 2 }, ]); let init: MapInitialEntries<string, i32> = [ { key: "x", value: 10 }, { key: "y", value: 20 }, ]; let anotherMap = new Map<string, i32>(init);
1 parent 6cd638e commit 970fdb2

File tree

4 files changed

+76
-3
lines changed

4 files changed

+76
-3
lines changed

NOTICE

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ under the licensing terms detailed in LICENSE:
6060
* Fabián Heredia Montiel <[email protected]>
6161
* Jonas Minnberg <[email protected]>
6262
* Kam Chehresa <[email protected]>
63+
* Pebrian <[email protected]>
6364

6465
Portions of this software are derived from third-party works licensed under
6566
the following terms:

std/assembly/index.d.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2394,7 +2394,7 @@ interface NewableFunction extends Function {
23942394
interface IArguments {}
23952395
interface RegExp {}
23962396

2397-
declare class Map<K,V> {
2397+
interface Map<K,V> {
23982398
readonly size: i32;
23992399
has(key: K): bool;
24002400
set(key: K, value: V): this;
@@ -2406,6 +2406,14 @@ declare class Map<K,V> {
24062406
toString(): string;
24072407
}
24082408

2409+
type MapInitialEntries<K,V> = {key: V, value:V}[]
2410+
2411+
interface MapConstructor {
2412+
new <K, V>(entries?: MapInitialEntries<K,V>): Map<K,V>;
2413+
}
2414+
2415+
declare const Map: MapConstructor;
2416+
24092417
declare class Set<K> {
24102418
readonly size: i32;
24112419
has(value: K): bool;

std/assembly/map.ts

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,13 @@ function ENTRY_SIZE<K,V>(): usize {
5454
return size;
5555
}
5656

57+
class KeyValue<K,V> {
58+
key: K;
59+
value: V;
60+
}
61+
62+
export type MapInitialEntries<K,V> = KeyValue<K,V>[];
63+
5764
export class Map<K,V> {
5865

5966
// buckets referencing their respective first entry, usize[bucketsMask + 1]
@@ -66,8 +73,44 @@ export class Map<K,V> {
6673
private entriesOffset: i32 = 0;
6774
private entriesCount: i32 = 0;
6875

69-
constructor() {
70-
/* nop */
76+
constructor(initialEntries: MapInitialEntries<K,V> = []) {
77+
let entriesLength = initialEntries.length;
78+
79+
if(entriesLength > 0) {
80+
if(entriesLength >= this.entriesCapacity) this.bucketsMask = entriesLength;
81+
this.rehash((this.bucketsMask << 1) | 1);
82+
83+
for(let i = 0; i < entriesLength; i++){
84+
let key = initialEntries[i].key;
85+
let value = initialEntries[i].value;
86+
let hashCode = HASH<K>(key);
87+
let entry = this.find(key, hashCode); // unmanaged!
88+
if (entry) {
89+
entry.value = value;
90+
if (isManaged<V>()) {
91+
__link(changetype<usize>(this), changetype<usize>(value), true);
92+
}
93+
} else {
94+
// append new entry
95+
let entries = this.entries;
96+
let entry = changetype<MapEntry<K,V>>(changetype<usize>(entries) + <usize>(this.entriesOffset++) * ENTRY_SIZE<K,V>());
97+
// link with the map
98+
entry.key = key;
99+
if (isManaged<K>()) {
100+
__link(changetype<usize>(this), changetype<usize>(key), true);
101+
}
102+
entry.value = value;
103+
if (isManaged<V>()) {
104+
__link(changetype<usize>(this), changetype<usize>(value), true);
105+
}
106+
++this.entriesCount;
107+
// link with previous entry in bucket
108+
let bucketPtrBase = changetype<usize>(this.buckets) + <usize>(hashCode & this.bucketsMask) * BUCKET_SIZE;
109+
entry.taggedNext = load<usize>(bucketPtrBase);
110+
store<usize>(bucketPtrBase, changetype<usize>(entry));
111+
}
112+
}
113+
}
71114
}
72115

73116
get size(): i32 {

tests/compiler/std/map.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
12
function testNumeric<K extends number,V extends number>(): void {
23
var map = new Map<K,V>();
34

@@ -58,6 +59,26 @@ function testNumeric<K extends number,V extends number>(): void {
5859
// clear
5960
map.clear();
6061
assert(map.size == 0);
62+
63+
const initialEntries: MapInitialEntries<K,V> = [];
64+
65+
for(let k: K = 0; k < 100; ++k){
66+
initialEntries.push({
67+
key: k,
68+
value: 10 + <V>k
69+
});
70+
}
71+
72+
map = new Map<K,V>(initialEntries);
73+
74+
assert(map.size == 100);
75+
for(let k: K = 0; k < 100; ++k){
76+
assert(map.has(k));
77+
assert(map.get(k) == 10 + <V>k);
78+
map.delete(k);
79+
assert(!map.has(k));
80+
}
81+
assert(map.size == 0);
6182
}
6283

6384
testNumeric<i8,i32>();

0 commit comments

Comments
 (0)