@@ -37,10 +37,44 @@ import type {
3737} from "./detachedFieldIndexTypes.js" ;
3838import { makeDetachedFieldIndexCodec } from "./detachedFieldIndexCodecs.js" ;
3939
40+ /**
41+ * Readonly interface for {@link DetachedFieldIndex}.
42+ */
43+ export interface ReadOnlyDetachedFieldIndex {
44+ /**
45+ * Creates a deep clone of this `DetachedFieldIndex`.
46+ */
47+ clone ( ) : DetachedFieldIndex ;
48+
49+ /**
50+ * Returns a field key for the given ID.
51+ * This does not save the field key on the index. To do so, call {@link createEntry}.
52+ */
53+ toFieldKey ( id : ForestRootId ) : FieldKey ;
54+
55+ /**
56+ * Returns the `ForestRootId` associated with the given id.
57+ * Returns undefined if no such id is known to the index.
58+ */
59+ tryGetEntry ( id : Delta . DetachedNodeId ) : ForestRootId | undefined ;
60+
61+ /**
62+ * Returns the `ForestRootId` associated with the given id.
63+ * Fails if no such id is known to the index.
64+ */
65+ getEntry ( id : Delta . DetachedNodeId ) : ForestRootId ;
66+ }
67+
68+ /**
69+ * Restores the originating DetachedFieldIndex to the state it was in when the checkpoint was created.
70+ * Can be invoked multiple times.
71+ */
72+ export type DetachedFieldIndexCheckpoint = ( ) => void ;
73+
4074/**
4175 * The tree index records detached field IDs and associates them with a change atom ID.
4276 */
43- export class DetachedFieldIndex {
77+ export class DetachedFieldIndex implements ReadOnlyDetachedFieldIndex {
4478 /**
4579 * A mapping from detached node ids to detached fields.
4680 */
@@ -106,6 +140,25 @@ export class DetachedFieldIndex {
106140 return clone ;
107141 }
108142
143+ /**
144+ * Creates a restorable checkpoint of the current state of the DetachedFieldIndex.
145+ */
146+ public createCheckpoint ( ) : DetachedFieldIndexCheckpoint {
147+ const clone = this . clone ( ) ;
148+ return ( ) => {
149+ this . purge ( ) ;
150+ populateNestedMap ( clone . detachedNodeToField , this . detachedNodeToField , true ) ;
151+ populateNestedMap (
152+ clone . latestRelevantRevisionToFields ,
153+ this . latestRelevantRevisionToFields ,
154+ true ,
155+ ) ;
156+ this . rootIdAllocator = idAllocatorFromMaxId (
157+ clone . rootIdAllocator . getMaxId ( ) ,
158+ ) as IdAllocator < ForestRootId > ;
159+ } ;
160+ }
161+
109162 public * entries ( ) : Generator < {
110163 root : ForestRootId ;
111164 latestRelevantRevision ?: RevisionTag ;
@@ -201,26 +254,14 @@ export class DetachedFieldIndex {
201254 }
202255 }
203256
204- /**
205- * Returns a field key for the given ID.
206- * This does not save the field key on the index. To do so, call {@link createEntry}.
207- */
208257 public toFieldKey ( id : ForestRootId ) : FieldKey {
209258 return brand ( `${ this . name } -${ id } ` ) ;
210259 }
211260
212- /**
213- * Returns the FieldKey associated with the given id.
214- * Returns undefined if no such id is known to the index.
215- */
216261 public tryGetEntry ( id : Delta . DetachedNodeId ) : ForestRootId | undefined {
217262 return tryGetFromNestedMap ( this . detachedNodeToField , id . major , id . minor ) ?. root ;
218263 }
219264
220- /**
221- * Returns the FieldKey associated with the given id.
222- * Fails if no such id is known to the index.
223- */
224265 public getEntry ( id : Delta . DetachedNodeId ) : ForestRootId {
225266 const key = this . tryGetEntry ( id ) ;
226267 assert ( key !== undefined , 0x7aa /* Unknown removed node ID */ ) ;
0 commit comments