diff --git a/skiplang/prelude/src/skstore/Context.sk b/skiplang/prelude/src/skstore/Context.sk index 1d2862584..b6685ba3d 100644 --- a/skiplang/prelude/src/skstore/Context.sk +++ b/skiplang/prelude/src/skstore/Context.sk @@ -341,20 +341,18 @@ mutable class Context private { mutable newDirs: SortedSet = SortedSet[], mutable globals: SortedMap = SortedMap[], private mutable persistents: SortedMap = SortedMap[], - private mutable dirty: SortedMap> = SortedMap[], + private mutable dirty: SortedMap = SortedMap[], private mutable dirtyReaders: /* parentName => childName => keys */ SortedMap< DirName, - SortedMap>, + SortedMap, > = SortedMap[], mutable canReuse: CanReuse = CRIfMatch(), private mutable arrowStack: List<(ArrowKey, TimeStack)> = List[], - private mutable lazyGets: SortedMap> = SortedMap[], - private mutable lazyGetsQueue: Queue< - SortedMap>, - > = Queue[], + private mutable lazyGets: SortedMap = SortedMap[], + private mutable lazyGetsQueue: Queue> = Queue[], private mutable lazyGetsRefCount: SortedMap< DirName, - SortedMap, + KeyMap, > = SortedMap[], private mutable sessions: SortedMap = SortedMap[], private mutable postponables: List = List[], @@ -593,7 +591,10 @@ mutable class Context private { ); map.set( reader.childName, - map.maybeGet(reader.childName).default(SortedSet[]).set(reader.key), + parent.addReaderKeyToKeySetOpt( + reader, + map.maybeGet(reader.childName), + ), ) }; time = if (reader.parentName == reader.childName) { @@ -649,19 +650,20 @@ mutable class Context private { this.!lazyGets = SortedMap[] } - mutable fun addLazyGet(dir: LazyDir, key: Key): void { + mutable fun addLazyGet(dir: TLazyDir, key: Key): void { dirName = dir.dirName; - this.!lazyGets[dirName] = this.lazyGets.maybeGet(dirName) - .default(SortedSet[]) - .set(key) + this.!lazyGets[dirName] = dir.addKeyToKeySetOpt( + key, + this.lazyGets.maybeGet(dirName), + ) } - mutable fun addDirty(dir: EagerDir, key: Key): void { + mutable fun addDirty(dir: TEagerDir, key: Key): void { dirName = dir.dirName; - this.!dirty[dirName] = this.dirty.maybeGet(dirName) match { - | None() -> SortedSet[key] - | Some(set) -> set.set(key) - } + this.!dirty[dirName] = dir.addKeyToKeySetOpt( + key, + this.dirty.maybeGet(dirName), + ) } mutable fun update(): void { diff --git a/skiplang/prelude/src/skstore/Dir.sk b/skiplang/prelude/src/skstore/Dir.sk index 1c1db9e62..ee971f832 100644 --- a/skiplang/prelude/src/skstore/Dir.sk +++ b/skiplang/prelude/src/skstore/Dir.sk @@ -27,6 +27,8 @@ base class Dir protected {timeStack: TimeStack, dirName: DirName} { } fun typed(): TDir; + + fun addReaderKeyToKeySetOpt(arrowKey: ArrowKey, keySetOpt: ?KeySet): KeySet; } base class TDir extends Dir { @@ -54,6 +56,30 @@ base class TDir extends Dir { * Returns the list of files in a directory. Should only be used for testing. */ fun keys(): SortedSet; + + fun castKeySet(keySet: KeySet): TKeySet { + Unsafe.cast(keySet, TKeySet) + } + + fun castOrEmptyKeySet(keySetOpt: ?KeySet): TKeySet { + keySetOpt.map(this.castKeySet).default(TKeySet::empty()) + } + + fun addKeyToKeySetOpt(key: Key, keySetOpt: ?KeySet): KeySet { + this.castOrEmptyKeySet(keySetOpt).set(key) + } + + fun addReaderKeyToKeySetOpt(arrowKey: ArrowKey, keySetOpt: ?KeySet): KeySet { + this.addKeyToKeySetOpt(arrowKey.key, keySetOpt) + } + + fun castKeyMap(keyMap: KeyMap): TKeyMap { + Unsafe.cast(keyMap, TKeyMap) + } + + fun castOrEmptyKeyMap(keyMapOpt: ?KeyMap): TKeyMap { + keyMapOpt.map(this.castKeyMap).default(TKeyMap::empty()) + } } /*****************************************************************************/ diff --git a/skiplang/prelude/src/skstore/EagerDir.sk b/skiplang/prelude/src/skstore/EagerDir.sk index 46919b4c5..61c4b3b81 100644 --- a/skiplang/prelude/src/skstore/EagerDir.sk +++ b/skiplang/prelude/src/skstore/EagerDir.sk @@ -1420,8 +1420,8 @@ base class EagerDir protected { fun update( /* this is the parent */ context: mutable Context, - parentDirtyOpt: ?SortedSet, - contextDirtyReadersOpt: ?SortedMap>, + parentDirtyOpt: ?KeySet, + contextDirtyReadersOpt: ?SortedMap, parentMaps: Array< ( MapFun, @@ -1443,7 +1443,7 @@ base class EagerDir protected { contextDirtyReaders.maybeGet(childName) match { | None() -> void | Some(dirtyKeys) -> - keys = dirtyKeys.values(); + keys = parent.typed().castKeySet(dirtyKeys).values(); !dirty = withRegionFold(None(), keys, dirty, (_, key, dirtyInRegion) ~> { for (p in parentMaps) { (_, rangeOpt, _) = p; @@ -1464,7 +1464,7 @@ base class EagerDir protected { parentDirtyOpt match { | None() -> void | Some(dirtyKeys) -> - keys = dirtyKeys.values(); + keys = parent.typed().castKeySet(dirtyKeys).values(); !dirty = withRegionFold(None(), keys, dirty, (_, key, dirtyInRegion) ~> { for (p in parentMaps) { (_, rangeOpt, _) = p; @@ -1655,7 +1655,7 @@ base class EagerDir protected { Some(cdata) }; - context.addDirty(this, k); + context.addDirty(this.typed(), k); path = Path::create(this.dirName, k); if (this.totalSize != totalSize) { diff --git a/skiplang/prelude/src/skstore/LazyDir.sk b/skiplang/prelude/src/skstore/LazyDir.sk index c9651cfaa..83dd27c0c 100644 --- a/skiplang/prelude/src/skstore/LazyDir.sk +++ b/skiplang/prelude/src/skstore/LazyDir.sk @@ -21,14 +21,14 @@ base class LazyDir protected {protected collect: Bool} extends Dir { /* Updates the lazyGets ref counts and return as well a potentially updated LazyDir in which dead keys have been removed. */ fun updateLazyGets( - refCountsOpt: ?SortedMap, - newKeysOpt: ?SortedSet, - deadKeysOpt: ?SortedSet, - ): (?SortedMap, ?this); + refCountsOpt: ?KeyMap, + newKeysOpt: ?KeySet, + deadKeysOpt: ?KeySet, + ): (?KeyMap, ?this); fun update( context: mutable Context, - dirtyReadersOpt: ?SortedMap>, + dirtyReadersOpt: ?SortedMap, ): void; fun typed(): TLazyDir; @@ -39,18 +39,18 @@ class TLazyDir{ protected lazyFun: (mutable Context, DirName, Key) ~> ?Array, } extends LazyDir, TDir { fun updateLazyGets( - refCountsOpt: ?SortedMap, - newKeysOpt: ?SortedSet, - deadKeysOpt: ?SortedSet, - ): (?SortedMap, ?this) { - refCounts = refCountsOpt.default(SortedMap[]); - newKeys = newKeysOpt.default(SortedSet[]); - deadKeys = deadKeysOpt.default(SortedSet[]); + refCountsOpt: ?KeyMap, + newKeysOpt: ?KeySet, + deadKeysOpt: ?KeySet, + ): (?KeyMap, ?this) { + refCounts = this.castOrEmptyKeyMap(refCountsOpt); + newKeys = this.castOrEmptyKeySet(newKeysOpt); + deadKeys = this.castOrEmptyKeySet(deadKeysOpt); toRemove = mutable Vector[]; !refCounts = refCounts.mergeWith2( - newKeys.inner, - deadKeys.inner, + newKeys.getInner(), + deadKeys.getInner(), (key, refCountOpt, newOpt, deadOpt) -> { (refCountOpt, newOpt, deadOpt) match { | (_, None(), None()) @@ -108,13 +108,13 @@ class TLazyDir{ fun update( context: mutable Context, - dirtyReadersOpt: ?SortedMap>, + dirtyReadersOpt: ?SortedMap, ): void { dirtyReadersOpt match { | None() -> void | Some(dirtyReaders) -> for (dirtyReaderDirName => dirtyReaderKeys in dirtyReaders) { - for (key in dirtyReaderKeys) { + for (key in this.castKeySet(dirtyReaderKeys)) { oldValue = this.data.maybeGet(key); !this.data = this.data.remove(key); context.updateDirtyReaders(Path::create(dirtyReaderDirName, key)); diff --git a/skiplang/prelude/src/skstore/Path.sk b/skiplang/prelude/src/skstore/Path.sk index 7a38603d8..512122a3c 100644 --- a/skiplang/prelude/src/skstore/Path.sk +++ b/skiplang/prelude/src/skstore/Path.sk @@ -247,6 +247,59 @@ class SID(value: String) extends Key { } } +base class KeySet uses Unsafe.Downcastable + +class TKeySet<+K: Orderable> private (inner: SortedSet) extends KeySet { + static fun empty(): this { + static(SortedSet[]) + } + + fun set[K: K2](key: K2): TKeySet { + TKeySet(this.inner.set(key)) + } + + fun values(): mutable Iterator { + this.inner.values() + } + + fun getInner(): TKeyMap { + TKeyMap::ofKeySet(this) + } +} + +base class KeyMap<+V> uses Unsafe.Downcastable + +class TKeyMap<+K: Orderable, +V: frozen> private ( + inner: SortedMap, +) extends KeyMap { + static fun empty(): this { + static(SortedMap[]) + } + + static fun ofKeySet[V: void](set: TKeySet): TKeyMap { + TKeyMap(set.inner.inner) + } + + fun isEmpty(): Bool { + this.inner.isEmpty() + } + + fun set[K: K2, V: V2]( + key: K2, + value: V2, + ): TKeyMap { + TKeyMap(this.inner.set(key, value)) + } + + fun mergeWith2[K: K2]( + other1: TKeyMap, + other2: TKeyMap, + f: (K2, ?V, ?U, ?W) -> ?R, + ): TKeyMap { + TKeyMap(this.inner.mergeWith2(other1.inner, other2.inner, f)) + } +} + base class Exception extends .Exception uses Show fun error(msg: String): T {