import Foundation public final class ItemCacheEntryId: Equatable, Hashable { public let collectionId: ItemCacheCollectionId public let key: ValueBoxKey public init(collectionId: ItemCacheCollectionId, key: ValueBoxKey) { self.collectionId = collectionId self.key = key } public func hash(into hasher: inout Hasher) { hasher.combine(self.collectionId) hasher.combine(self.key) } public static func ==(lhs: ItemCacheEntryId, rhs: ItemCacheEntryId) -> Bool { return lhs.collectionId == rhs.collectionId && lhs.key == rhs.key } } private enum ItemCacheSection: Int8 { case items = 0 case accessIndexToItemId = 1 case itemIdToAccessIndex = 2 } final class ItemCacheTable: Table { static func tableSpec(_ id: Int32) -> ValueBoxTable { return ValueBoxTable(id: id, keyType: .binary, compactValuesOnCreation: false) } private func itemKey(id: ItemCacheEntryId) -> ValueBoxKey { let key = ValueBoxKey(length: 1 + 1 + id.key.length) key.setInt8(0, value: ItemCacheSection.items.rawValue) key.setInt8(1, value: id.collectionId) memcpy(key.memory.advanced(by: 2), id.key.memory, id.key.length) return key } private func lowerBound(collectionId: ItemCacheCollectionId) -> ValueBoxKey { let key = ValueBoxKey(length: 1 + 1) key.setInt8(0, value: ItemCacheSection.items.rawValue) key.setInt8(1, value: collectionId) return key } private func upperBound(collectionId: ItemCacheCollectionId) -> ValueBoxKey { return self.lowerBound(collectionId: collectionId).successor } private func itemIdToAccessIndexKey(id: ItemCacheEntryId) -> ValueBoxKey { let key = ValueBoxKey(length: 1 + 1 + id.key.length) key.setInt8(0, value: ItemCacheSection.accessIndexToItemId.rawValue) key.setInt8(1, value: id.collectionId) memcpy(key.memory.advanced(by: 2), id.key.memory, id.key.length) return key } private func accessIndexToItemId(collectionId: ItemCacheCollectionId, index: Int32) -> ValueBoxKey { let key = ValueBoxKey(length: 1 + 1 + 4) key.setInt8(0, value: ItemCacheSection.accessIndexToItemId.rawValue) key.setInt8(1, value: collectionId) key.setInt32(2, value: index) return key } func put(id: ItemCacheEntryId, entry: CodableEntry, metaTable: ItemCacheMetaTable) { self.valueBox.set(self.table, key: self.itemKey(id: id), value: ReadBuffer(data: entry.data)) } func retrieve(id: ItemCacheEntryId, metaTable: ItemCacheMetaTable) -> CodableEntry? { if let value = self.valueBox.get(self.table, key: self.itemKey(id: id)) { return CodableEntry(data: value.makeData()) } return nil } func remove(id: ItemCacheEntryId, metaTable: ItemCacheMetaTable) { self.valueBox.remove(self.table, key: self.itemKey(id: id), secure: false) } func removeAll(collectionId: ItemCacheCollectionId) { self.valueBox.removeRange(self.table, start: self.lowerBound(collectionId: collectionId), end: self.upperBound(collectionId: collectionId)) } override func clearMemoryCache() { } override func beforeCommit() { } }