Skip to content

Commit e632b39

Browse files
authored
Derive MapTreeField MapTrees from parent (microsoft#22172)
## Description This removes an unnecessary cache of the `MapTrees` backing unhydrated fields. Removing this cache simplifies the code but is also necessary for upcoming work that will allow unhydrated nodes to be mutated. Also renames `adopt` to `adoptBy` for clarity.
1 parent 1296cd1 commit e632b39

File tree

1 file changed

+26
-25
lines changed

1 file changed

+26
-25
lines changed

packages/dds/tree/src/feature-libraries/flex-map-tree/mapTreeNode.ts

+26-25
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ export class EagerMapTreeNode<TSchema extends FlexTreeNodeSchema> implements Map
127127
* Set this node's parentage (see {@link FlexTreeNode.parentField}).
128128
* @remarks A node may only be adopted to a new parent one time, and only if it was not constructed with a parent.
129129
*/
130-
public adopt(parent: MapTreeField, index: number): void {
130+
public adoptBy(parent: MapTreeField, index: number): void {
131131
assert(
132132
this.location === undefined,
133133
0x98c /* Node may not be adopted if it already has a parent */,
@@ -160,19 +160,18 @@ export class EagerMapTreeNode<TSchema extends FlexTreeNodeSchema> implements Map
160160
const field = this.mapTree.fields.get(key);
161161
// Only return the field if it is not empty, in order to fulfill the contract of `tryGetField`.
162162
if (field !== undefined && field.length > 0) {
163-
return getOrCreateField(this, key, field, this.schema.getFieldSchema(key));
163+
return getOrCreateField(this, key, this.schema.getFieldSchema(key));
164164
}
165165
}
166166

167167
public getBoxed(key: string): FlexTreeField {
168168
const fieldKey: FieldKey = brand(key);
169-
const field = this.mapTree.fields.get(fieldKey) ?? [];
170-
return getOrCreateField(this, fieldKey, field, this.schema.getFieldSchema(fieldKey));
169+
return getOrCreateField(this, fieldKey, this.schema.getFieldSchema(fieldKey));
171170
}
172171

173172
public boxedIterator(): IterableIterator<FlexTreeField> {
174-
return mapIterable(this.mapTree.fields.entries(), ([key, field]) =>
175-
getOrCreateField(this, key, field, this.schema.getFieldSchema(key)),
173+
return mapIterable(this.mapTree.fields.entries(), ([key]) =>
174+
getOrCreateField(this, key, this.schema.getFieldSchema(key)),
176175
);
177176
}
178177

@@ -190,7 +189,7 @@ export class EagerMapTreeNode<TSchema extends FlexTreeNodeSchema> implements Map
190189

191190
private walkTree(): void {
192191
for (const [key, mapTrees] of this.mapTree.fields) {
193-
const field = getOrCreateField(this, key, mapTrees, this.schema.getFieldSchema(key));
192+
const field = getOrCreateField(this, key, this.schema.getFieldSchema(key));
194193
for (let index = 0; index < field.length; index++) {
195194
const child = getOrCreateChild(
196195
mapTrees[index] ?? oob(),
@@ -336,8 +335,13 @@ class EagerMapTreeLeafNode<TSchema extends LeafNodeSchema>
336335

337336
// #region Fields
338337

338+
/**
339+
* A readonly {@link FlexTreeField} which wraps an array of {@link MapTrees}.
340+
* @remarks Reading data from the MapTreeField will read the corresponding data from the {@link MapTree}s.
341+
* Create a `MapTreeField` by calling {@link getOrCreateField}.
342+
*/
339343
interface MapTreeField extends FlexTreeField {
340-
readonly mapTrees: readonly ExclusiveMapTree[];
344+
readonly mapTrees: readonly MapTree[];
341345
}
342346

343347
/**
@@ -372,27 +376,30 @@ class EagerMapTreeField<T extends FlexAllowedTypes> implements MapTreeField {
372376
public constructor(
373377
public readonly schema: FlexFieldSchema<FlexFieldKind, T>,
374378
public readonly key: FieldKey,
375-
public readonly parent: MapTreeNode,
376-
public readonly mapTrees: readonly ExclusiveMapTree[],
379+
public readonly parent: EagerMapTreeNode<FlexTreeNodeSchema>,
377380
) {
378381
const fieldKeyCache = getFieldKeyCache(parent);
379382
assert(!fieldKeyCache.has(key), 0x990 /* A field already exists for the given MapTrees */);
380383
fieldKeyCache.set(key, this);
381384

382385
// When this field is created (which only happens one time, because it is cached), all the children become parented for the first time.
383386
// "Adopt" each child by updating its parent information to point to this field.
384-
for (const [i, mapTree] of mapTrees.entries()) {
387+
for (const [i, mapTree] of this.mapTrees.entries()) {
385388
const mapTreeNodeChild = nodeCache.get(mapTree);
386389
if (mapTreeNodeChild !== undefined) {
387390
assert(
388391
mapTreeNodeChild.parentField.parent === rootMapTreeField,
389392
0x991 /* Node is already parented under a different field */,
390393
);
391-
mapTreeNodeChild.adopt(this, i);
394+
mapTreeNodeChild.adoptBy(this, i);
392395
}
393396
}
394397
}
395398

399+
public get mapTrees(): readonly ExclusiveMapTree[] {
400+
return this.parent.mapTree.fields.get(this.key) ?? [];
401+
}
402+
396403
public get length(): number {
397404
return this.mapTrees.length;
398405
}
@@ -633,9 +640,8 @@ function createNode<TSchema extends FlexTreeNodeSchema>(
633640

634641
/** Creates a field with the given attributes, or returns a cached field if there is one */
635642
function getOrCreateField(
636-
parent: MapTreeNode,
643+
parent: EagerMapTreeNode<FlexTreeNodeSchema>,
637644
key: FieldKey,
638-
mapTrees: readonly ExclusiveMapTree[],
639645
schema: FlexFieldSchema,
640646
): EagerMapTreeField<FlexFieldSchema["allowedTypes"]> {
641647
const cached = getFieldKeyCache(parent).get(key);
@@ -647,18 +653,18 @@ function getOrCreateField(
647653
schema.kind.identifier === FieldKinds.required.identifier ||
648654
schema.kind.identifier === FieldKinds.identifier.identifier
649655
) {
650-
return new EagerMapTreeRequiredField(schema, key, parent, mapTrees);
656+
return new EagerMapTreeRequiredField(schema, key, parent);
651657
}
652658

653659
if (schema.kind.identifier === FieldKinds.optional.identifier) {
654-
return new EagerMapTreeOptionalField(schema, key, parent, mapTrees);
660+
return new EagerMapTreeOptionalField(schema, key, parent);
655661
}
656662

657663
if (schema.kind.identifier === FieldKinds.sequence.identifier) {
658-
return new EagerMapTreeSequenceField(schema, key, parent, mapTrees);
664+
return new EagerMapTreeSequenceField(schema, key, parent);
659665
}
660666

661-
return new EagerMapTreeField(schema, key, parent, mapTrees);
667+
return new EagerMapTreeField(schema, key, parent);
662668
}
663669

664670
/** Unboxes non-polymorphic leaf nodes to their values, if applicable */
@@ -687,7 +693,7 @@ function unboxedField<TFieldSchema extends FlexFieldSchema>(
687693
field: EagerMapTreeField<FlexAllowedTypes>,
688694
key: FieldKey,
689695
mapTree: ExclusiveMapTree,
690-
parentNode: MapTreeNode,
696+
parentNode: EagerMapTreeNode<FlexTreeNodeSchema>,
691697
): FlexTreeUnboxField<TFieldSchema> {
692698
const fieldSchema = field.schema;
693699
const mapTrees =
@@ -710,12 +716,7 @@ function unboxedField<TFieldSchema extends FlexFieldSchema>(
710716
) as FlexTreeUnboxField<TFieldSchema>;
711717
}
712718

713-
return getOrCreateField(
714-
parentNode,
715-
key,
716-
mapTrees,
717-
fieldSchema,
718-
) as FlexTreeUnboxField<TFieldSchema>;
719+
return getOrCreateField(parentNode, key, fieldSchema) as FlexTreeUnboxField<TFieldSchema>;
719720
}
720721

721722
// #endregion Caching and unboxing utilities

0 commit comments

Comments
 (0)