Skip to content

Commit 3bfa17b

Browse files
authored
chore(jsii-reflect): use Maps instead of Records (#3671)
Instead of using objects as maps, use actual `Map` as this has better performance characteristics (results in fewer shadow classes being generated, and is friendlier with the optimizer).
1 parent 4b15226 commit 3bfa17b

File tree

7 files changed

+105
-119
lines changed

7 files changed

+105
-119
lines changed

packages/jsii-reflect/lib/assembly.ts

+31-36
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@ import { Type } from './type';
1010
import { TypeSystem } from './type-system';
1111

1212
export class Assembly extends ModuleLike {
13-
private _typeCache?: { [fqn: string]: Type };
14-
private _submoduleCache?: { [fqn: string]: Submodule };
15-
private _dependencyCache?: { [name: string]: Dependency };
13+
private _typeCache?: Map<string, Type>;
14+
private _submoduleCache?: Map<string, Submodule>;
15+
private _dependencyCache?: Map<string, Dependency>;
1616

1717
public constructor(system: TypeSystem, public readonly spec: jsii.Assembly) {
1818
super(system);
@@ -124,13 +124,11 @@ export class Assembly extends ModuleLike {
124124
* Dependencies on other assemblies (with semver), the key is the JSII assembly name.
125125
*/
126126
public get dependencies(): readonly Dependency[] {
127-
return Object.keys(this._dependencies).map(
128-
(name) => this._dependencies[name],
129-
);
127+
return Array.from(this._dependencies.values());
130128
}
131129

132130
public findDependency(name: string) {
133-
const dep = this._dependencies[name];
131+
const dep = this._dependencies.get(name);
134132
if (!dep) {
135133
throw new Error(`Dependency ${name} not found for assembly ${this.name}`);
136134
}
@@ -156,7 +154,7 @@ export class Assembly extends ModuleLike {
156154
*/
157155
public get submodules(): readonly Submodule[] {
158156
const { submodules } = this._analyzeTypes();
159-
return Object.entries(submodules)
157+
return Array.from(submodules.entries())
160158
.filter(([name, _]) => name.split('.').length === 2)
161159
.map(([_, submodule]) => submodule);
162160
}
@@ -166,14 +164,14 @@ export class Assembly extends ModuleLike {
166164
*/
167165
public get allSubmodules(): readonly Submodule[] {
168166
const { submodules } = this._analyzeTypes();
169-
return Object.values(submodules);
167+
return Array.from(submodules.values());
170168
}
171169

172170
/**
173171
* All types, even those in submodules and nested submodules.
174172
*/
175173
public get types(): readonly Type[] {
176-
return Object.values(this.typeMap);
174+
return Array.from(this.typeMap.values());
177175
}
178176

179177
/**
@@ -201,26 +199,25 @@ export class Assembly extends ModuleLike {
201199
jsii.validateAssembly(this.spec);
202200
}
203201

204-
protected get submoduleMap(): Readonly<Record<string, Submodule>> {
202+
protected get submoduleMap(): ReadonlyMap<string, Submodule> {
205203
return this._analyzeTypes().submodules;
206204
}
207205

208206
/**
209207
* All types in the root of the assembly
210208
*/
211-
protected get typeMap(): Readonly<Record<string, Type>> {
209+
protected get typeMap(): ReadonlyMap<string, Type> {
212210
return this._analyzeTypes().types;
213211
}
214212

215213
private get _dependencies() {
216214
if (!this._dependencyCache) {
217-
this._dependencyCache = {};
215+
this._dependencyCache = new Map();
218216
if (this.spec.dependencies) {
219217
for (const name of Object.keys(this.spec.dependencies)) {
220-
this._dependencyCache[name] = new Dependency(
221-
this.system,
218+
this._dependencyCache.set(
222219
name,
223-
this.spec.dependencies[name],
220+
new Dependency(this.system, name, this.spec.dependencies[name]),
224221
);
225222
}
226223
}
@@ -231,7 +228,7 @@ export class Assembly extends ModuleLike {
231228

232229
private _analyzeTypes() {
233230
if (!this._typeCache || !this._submoduleCache) {
234-
this._typeCache = {};
231+
this._typeCache = new Map();
235232

236233
const submoduleBuilders = this.discoverSubmodules();
237234

@@ -264,9 +261,9 @@ export class Assembly extends ModuleLike {
264261

265262
if (submodule != null) {
266263
const moduleName = `${this.spec.name}.${submodule}`;
267-
submoduleBuilders[moduleName].addType(type);
264+
submoduleBuilders.get(moduleName)!.addType(type);
268265
} else {
269-
this._typeCache[fqn] = type;
266+
this._typeCache.set(fqn, type);
270267
}
271268
}
272269

@@ -279,18 +276,16 @@ export class Assembly extends ModuleLike {
279276
* Return a builder for all submodules in this assembly (so that we can
280277
* add types into the objects).
281278
*/
282-
private discoverSubmodules(): Record<string, SubmoduleBuilder> {
279+
private discoverSubmodules(): Map<string, SubmoduleBuilder> {
283280
const system = this.system;
284281

285-
const ret: Record<string, SubmoduleBuilder> = {};
282+
const ret = new Map<string, SubmoduleBuilder>();
286283
for (const [submoduleName, submoduleSpec] of Object.entries(
287284
this.spec.submodules ?? {},
288285
)) {
289-
ret[submoduleName] = new SubmoduleBuilder(
290-
system,
291-
submoduleSpec,
286+
ret.set(
292287
submoduleName,
293-
ret,
288+
new SubmoduleBuilder(system, submoduleSpec, submoduleName, ret),
294289
);
295290
}
296291
return ret;
@@ -306,15 +301,15 @@ export class Assembly extends ModuleLike {
306301
* to translate
307302
*/
308303
class SubmoduleBuilder {
309-
private readonly types: Record<string, Type> = {};
304+
private readonly types = new Map<string, Type>();
310305

311306
private _built?: Submodule;
312307

313308
public constructor(
314309
private readonly system: TypeSystem,
315310
private readonly spec: jsii.Submodule,
316311
private readonly fullName: string,
317-
private readonly allModuleBuilders: Record<string, SubmoduleBuilder>,
312+
private readonly allModuleBuilders: Map<string, SubmoduleBuilder>,
318313
) {}
319314

320315
/**
@@ -344,27 +339,27 @@ class SubmoduleBuilder {
344339
* Return all the builders from the map that are nested underneath ourselves.
345340
*/
346341
private findSubmoduleBuilders() {
347-
const ret: Record<string, SubmoduleBuilder> = {};
348-
for (const [k, child] of Object.entries(this.allModuleBuilders)) {
342+
const ret = new Map<string, SubmoduleBuilder>();
343+
for (const [k, child] of this.allModuleBuilders) {
349344
if (child.isChildOf(this)) {
350-
ret[k] = child;
345+
ret.set(k, child);
351346
}
352347
}
353348
return ret;
354349
}
355350

356351
public addType(type: Type) {
357-
this.types[type.fqn] = type;
352+
this.types.set(type.fqn, type);
358353
}
359354
}
360355

361356
function mapValues<A, B>(
362-
xs: Record<string, A>,
357+
xs: ReadonlyMap<string, A>,
363358
fn: (x: A) => B,
364-
): Record<string, B> {
365-
const ret: Record<string, B> = {};
366-
for (const [k, v] of Object.entries(xs)) {
367-
ret[k] = fn(v);
359+
): Map<string, B> {
360+
const ret = new Map<string, B>();
361+
for (const [k, v] of xs) {
362+
ret.set(k, fn(v));
368363
}
369364
return ret;
370365
}

packages/jsii-reflect/lib/class.ts

+22-27
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import { Method } from './method';
77
import { Property } from './property';
88
import { ReferenceType } from './reference-type';
99
import { TypeSystem } from './type-system';
10-
import { indexBy } from './util';
1110

1211
export class ClassType extends ReferenceType {
1312
public constructor(
@@ -76,15 +75,15 @@ export class ClassType extends ReferenceType {
7675
* @param inherited include all properties inherited from base classes (default: false)
7776
*/
7877
public getProperties(inherited = false): { [name: string]: Property } {
79-
return this._getProperties(inherited, this);
78+
return Object.fromEntries(this._getProperties(inherited, this));
8079
}
8180

8281
/**
8382
* List all methods in this class.
8483
* @param inherited include all methods inherited from base classes (default: false)
8584
*/
8685
public getMethods(inherited = false): { [name: string]: Method } {
87-
return this._getMethods(inherited, this);
86+
return Object.fromEntries(this._getMethods(inherited, this));
8887
}
8988

9089
/**
@@ -118,39 +117,35 @@ export class ClassType extends ReferenceType {
118117
private _getProperties(
119118
inherited: boolean,
120119
parentType: ReferenceType,
121-
): { [name: string]: Property } {
122-
const base =
120+
): Map<string, Property> {
121+
const result =
123122
inherited && this.base
124123
? this.base._getProperties(inherited, parentType)
125-
: {};
126-
return Object.assign(
127-
base,
128-
indexBy(
129-
(this.spec.properties ?? []).map(
130-
(p) => new Property(this.system, this.assembly, parentType, this, p),
131-
),
132-
(p) => p.name,
133-
),
134-
);
124+
: new Map<string, Property>();
125+
for (const p of this.spec.properties ?? []) {
126+
result.set(
127+
p.name,
128+
new Property(this.system, this.assembly, parentType, this, p),
129+
);
130+
}
131+
return result;
135132
}
136133

137134
private _getMethods(
138135
inherited: boolean,
139136
parentType: ReferenceType,
140-
): { [name: string]: Method } {
141-
const base =
137+
): Map<string, Method> {
138+
const result =
142139
inherited && this.base
143140
? this.base._getMethods(inherited, parentType)
144-
: {};
145-
return Object.assign(
146-
base,
147-
indexBy(
148-
(this.spec.methods ?? []).map(
149-
(m) => new Method(this.system, this.assembly, parentType, this, m),
150-
),
151-
(m) => m.name,
152-
),
153-
);
141+
: new Map<string, Method>();
142+
for (const m of this.spec.methods ?? []) {
143+
result.set(
144+
m.name,
145+
new Method(this.system, this.assembly, parentType, this, m),
146+
);
147+
}
148+
return result;
154149
}
155150
}
156151

packages/jsii-reflect/lib/interface.ts

+29-27
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import { Method } from './method';
55
import { Property } from './property';
66
import { ReferenceType } from './reference-type';
77
import { TypeSystem } from './type-system';
8-
import { indexBy } from './util';
98

109
export class InterfaceType extends ReferenceType {
1110
/** Caches the result of `getInterfaces`. */
@@ -62,15 +61,15 @@ export class InterfaceType extends ReferenceType {
6261
* @param inherited include all properties inherited from base classes (default: false)
6362
*/
6463
public getProperties(inherited = false): { [name: string]: Property } {
65-
return this._getProperties(inherited, this);
64+
return Object.fromEntries(this._getProperties(inherited, this));
6665
}
6766

6867
/**
6968
* List all methods in this class.
7069
* @param inherited include all methods inherited from base classes (default: false)
7170
*/
7271
public getMethods(inherited = false): { [name: string]: Method } {
73-
return this._getMethods(inherited, this);
72+
return Object.fromEntries(this._getMethods(inherited, this));
7473
}
7574

7675
public isDataType() {
@@ -84,42 +83,45 @@ export class InterfaceType extends ReferenceType {
8483
private _getProperties(
8584
inherited: boolean,
8685
parentType: ReferenceType,
87-
): { [name: string]: Property } {
88-
const base: { [name: string]: Property } = {};
86+
): Map<string, Property> {
87+
const result = new Map<string, Property>();
8988
if (inherited) {
9089
for (const parent of this.getInterfaces()) {
91-
Object.assign(base, parent._getProperties(inherited, parentType));
90+
for (const [key, value] of parent._getProperties(
91+
inherited,
92+
parentType,
93+
)) {
94+
result.set(key, value);
95+
}
9296
}
9397
}
94-
return Object.assign(
95-
base,
96-
indexBy(
97-
(this.spec.properties ?? []).map(
98-
(p) => new Property(this.system, this.assembly, parentType, this, p),
99-
),
100-
(p) => p.name,
101-
),
102-
);
98+
for (const p of this.spec.properties ?? []) {
99+
result.set(
100+
p.name,
101+
new Property(this.system, this.assembly, parentType, this, p),
102+
);
103+
}
104+
return result;
103105
}
104106

105107
private _getMethods(
106108
inherited: boolean,
107109
parentType: ReferenceType,
108-
): { [name: string]: Method } {
109-
const base: { [name: string]: Property } = {};
110+
): Map<string, Method> {
111+
const methods = new Map<string, Method>();
110112
if (inherited) {
111113
for (const parent of this.getInterfaces()) {
112-
Object.assign(base, parent._getMethods(inherited, parentType));
114+
for (const [key, value] of parent._getMethods(inherited, parentType)) {
115+
methods.set(key, value);
116+
}
113117
}
114118
}
115-
return Object.assign(
116-
base,
117-
indexBy(
118-
(this.spec.methods ?? []).map(
119-
(m) => new Method(this.system, this.assembly, parentType, this, m),
120-
),
121-
(m) => m.name,
122-
),
123-
);
119+
for (const m of this.spec.methods ?? []) {
120+
methods.set(
121+
m.name,
122+
new Method(this.system, this.assembly, parentType, this, m),
123+
);
124+
}
125+
return methods;
124126
}
125127
}

0 commit comments

Comments
 (0)