@@ -6,31 +6,16 @@ import Utils
66private let logger = Logger ( label: " InMemoryBackend " )
77
88public actor InMemoryBackend : StateBackendProtocol {
9- public struct KVPair : Comparable , Sendable {
10- var key : Data
11- var value : Data
12-
13- public static func < ( lhs: KVPair , rhs: KVPair ) -> Bool {
14- lhs. key. lexicographicallyPrecedes ( rhs. key)
15- }
16- }
17-
18- // we really should be using Heap or some other Tree based structure here
19- // but let's keep it simple for now
20- public private( set) var store : SortedArray < KVPair > = . init( [ ] )
9+ // Use Dictionary for O(1) lookups
10+ private var store : [ Data : Data ] = [ : ]
2111 private var rawValues : [ Data32 : Data ] = [ : ]
2212 public private( set) var refCounts : [ Data : Int ] = [ : ]
2313 private var rawValueRefCounts : [ Data32 : Int ] = [ : ]
2414
2515 public init ( ) { }
2616
2717 public func read( key: Data ) async throws -> Data ? {
28- let idx = store. insertIndex ( KVPair ( key: key, value: Data ( ) ) )
29- let item = store. array [ safe: idx]
30- if item? . key == key {
31- return item? . value
32- }
33- return nil
18+ store [ key]
3419 }
3520
3621 public func readAll( prefix: Data , startKey: Data ? , limit: UInt32 ? ) async throws -> [ ( key: Data , value: Data ) ] {
@@ -41,33 +26,25 @@ public actor InMemoryBackend: StateBackendProtocol {
4126 }
4227
4328 let startKey = startKey ?? prefix
44- let startIndex = store. insertIndex ( KVPair ( key: startKey, value: Data ( ) ) )
45- for i in startIndex ..< store. array. count {
46- let item = store. array [ i]
47- if item. key. starts ( with: prefix) {
48- resp. append ( ( item. key, item. value) )
49- } else {
50- break
51- }
52- if let limit, resp. count == limit {
53- break
54- }
29+
30+ // Filter and sort entries
31+ let filtered = store
32+ . filter { $0. key. starts ( with: prefix) && !$0. key. lexicographicallyPrecedes ( startKey) }
33+ . sorted { $0. key. lexicographicallyPrecedes ( $1. key) }
34+
35+ // Apply limit if specified
36+ if let limit {
37+ return Array ( filtered. prefix ( Int ( limit) ) )
5538 }
56- return resp
39+
40+ return filtered
5741 }
5842
5943 public func batchUpdate( _ updates: [ StateBackendOperation ] ) async throws {
6044 for update in updates {
6145 switch update {
6246 case let . write( key, value) :
63- let idx = store. insertIndex ( KVPair ( key: key, value: value) )
64- let item = store. array [ safe: idx]
65- if let item, item. key == key { // found
66- // value is not used for ordering so this is safe
67- store. unsafeArrayAccess [ idx] . value = value
68- } else { // not found
69- store. insert ( KVPair ( key: key, value: value) )
70- }
47+ store [ key] = value
7148 case let . writeRawValue( key, value) :
7249 rawValues [ key] = value
7350 rawValueRefCounts [ key, default: 0 ] += 1
@@ -86,11 +63,9 @@ public actor InMemoryBackend: StateBackendProtocol {
8663 public func gc( callback: @Sendable ( Data ) -> Data32 ? ) async throws {
8764 // check ref counts and remove keys with 0 ref count
8865 for (key, count) in refCounts where count == 0 {
89- let idx = store. insertIndex ( KVPair ( key: key, value: Data ( ) ) )
90- let item = store. array [ safe: idx]
91- if let item, item. key == key {
92- store. remove ( at: idx)
93- if let rawValueKey = callback ( item. value) {
66+ if let value = store [ key] {
67+ store. removeValue ( forKey: key)
68+ if let rawValueKey = callback ( value) {
9469 rawValueRefCounts [ rawValueKey, default: 0 ] -= 1
9570 if rawValueRefCounts [ rawValueKey] == 0 {
9671 rawValues. removeValue ( forKey: rawValueKey)
@@ -102,31 +77,30 @@ public actor InMemoryBackend: StateBackendProtocol {
10277 }
10378
10479 public func debugPrint( ) {
105- for item in store. array {
106- let refCount = refCounts [ item . key, default: 0 ]
107- logger. info ( " key: \( item . key. toHexString ( ) ) " )
108- logger. info ( " value: \( item . value. toHexString ( ) ) " )
80+ for (key , value ) in store {
81+ let refCount = refCounts [ key, default: 0 ]
82+ logger. info ( " key: \( key. toHexString ( ) ) " )
83+ logger. info ( " value: \( value. toHexString ( ) ) " )
10984 logger. info ( " ref count: \( refCount) " )
11085 }
11186 }
11287
11388 public func createIterator( prefix: Data , startKey: Data ? ) async throws -> StateBackendIterator {
114- InMemoryStateIterator ( store: store, prefix: prefix, startKey: startKey)
89+ // Create sorted array of matching items
90+ let searchKey = startKey ?? prefix
91+ let matchingItems = store
92+ . filter { $0. key. starts ( with: prefix) && !$0. key. lexicographicallyPrecedes ( searchKey) }
93+ . sorted { $0. key. lexicographicallyPrecedes ( $1. key) }
94+
95+ return InMemoryStateIterator ( items: matchingItems)
11596 }
11697}
11798
11899public final class InMemoryStateIterator : StateBackendIterator , @unchecked Sendable {
119100 private var iterator : Array < ( key: Data , value: Data ) > . Iterator
120101
121- init ( store: SortedArray < InMemoryBackend . KVPair > , prefix: Data , startKey: Data ? ) {
122- let searchKey = startKey ?? prefix
123- let startIndex = store. insertIndex ( InMemoryBackend . KVPair ( key: searchKey, value: Data ( ) ) )
124-
125- let matchingItems = Array ( store. array [ startIndex... ] . prefix { item in
126- item. key. starts ( with: prefix)
127- } . map { ( key: $0. key, value: $0. value) } )
128-
129- iterator = matchingItems. makeIterator ( )
102+ init ( items: [ ( key: Data , value: Data ) ] ) {
103+ iterator = items. makeIterator ( )
130104 }
131105
132106 public func next( ) async throws -> ( key: Data , value: Data ) ? {
0 commit comments