Swiftgram/submodules/Postbox/Sources/ItemCollectionInfoTable.swift
2019-11-01 17:11:12 +04:00

173 lines
7.3 KiB
Swift

import Foundation
enum ItemCollectionInfosOperation {
case replaceInfos(ItemCollectionId.Namespace)
}
final class ItemCollectionInfoTable: Table {
static func tableSpec(_ id: Int32) -> ValueBoxTable {
return ValueBoxTable(id: id, keyType: .binary, compactValuesOnCreation: false)
}
private let sharedKey = ValueBoxKey(length: 4 + 4 + 8)
private var cachedInfos: [ItemCollectionId.Namespace: [(Int, ItemCollectionId, ItemCollectionInfo)]] = [:]
private func key(collectionId: ItemCollectionId, index: Int32) -> ValueBoxKey {
self.sharedKey.setInt32(0, value: collectionId.namespace)
self.sharedKey.setInt32(4, value: index)
self.sharedKey.setInt64(4 + 4, value: collectionId.id)
return self.sharedKey
}
private func lowerBound(namespace: ItemCollectionId.Namespace) -> ValueBoxKey {
let key = ValueBoxKey(length: 4)
key.setInt32(0, value: namespace)
return key
}
private func upperBound(namespace: ItemCollectionId.Namespace) -> ValueBoxKey {
let key = ValueBoxKey(length: 4)
key.setInt32(0, value: namespace)
return key.successor
}
func getInfos(namespace: ItemCollectionId.Namespace) -> [(Int, ItemCollectionId, ItemCollectionInfo)] {
if let cachedInfo = self.cachedInfos[namespace] {
return cachedInfo
} else {
var infos: [(Int, ItemCollectionId, ItemCollectionInfo)] = []
self.valueBox.range(self.table, start: self.lowerBound(namespace: namespace), end: self.upperBound(namespace: namespace), values: { key, value in
if let info = PostboxDecoder(buffer: value).decodeRootObject() as? ItemCollectionInfo {
infos.append((Int(key.getInt32(4)), ItemCollectionId(namespace: namespace, id: key.getInt64(4 + 4)), info))
}
return true
}, limit: 0)
self.cachedInfos[namespace] = infos
return infos
}
}
func getIds(namespace: ItemCollectionId.Namespace) -> [ItemCollectionId] {
if let cachedInfo = self.cachedInfos[namespace] {
return cachedInfo.map { $0.1 }
} else {
var ids: [ItemCollectionId] = []
self.valueBox.range(self.table, start: self.lowerBound(namespace: namespace), end: self.upperBound(namespace: namespace), keys: { key in
ids.append(ItemCollectionId(namespace: namespace, id: key.getInt64(4 + 4)))
return true
}, limit: 0)
return ids
}
}
func getIndex(id: ItemCollectionId) -> Int32? {
var index: Int32?
self.valueBox.range(self.table, start: self.lowerBound(namespace: id.namespace), end: self.upperBound(namespace: id.namespace), keys: { key in
let keyId = ItemCollectionId(namespace: id.namespace, id: key.getInt64(4 + 4))
if keyId == id {
index = key.getInt32(4)
return false
}
return true
}, limit: 0)
return index
}
func getInfo(id: ItemCollectionId) -> ItemCollectionInfo? {
var infoKey: ValueBoxKey?
self.valueBox.range(self.table, start: self.lowerBound(namespace: id.namespace), end: self.upperBound(namespace: id.namespace), keys: { key in
let keyId = ItemCollectionId(namespace: id.namespace, id: key.getInt64(4 + 4))
if keyId == id {
infoKey = key
return false
}
return true
}, limit: 0)
if let infoKey = infoKey, let value = self.valueBox.get(self.table, key: infoKey), let info = PostboxDecoder(buffer: value).decodeRootObject() as? ItemCollectionInfo {
return info
} else {
return nil
}
}
func lowerCollectionId(namespaceList: [ItemCollectionId.Namespace], collectionId: ItemCollectionId, index: Int32) -> (ItemCollectionId, Int32)? {
var currentNamespace = collectionId.namespace
var currentKey = self.key(collectionId: collectionId, index: index)
while true {
var resultCollectionIdAndIndex: (ItemCollectionId, Int32)?
self.valueBox.range(self.table, start: currentKey, end: self.lowerBound(namespace: currentNamespace), keys: { key in
resultCollectionIdAndIndex = (ItemCollectionId(namespace: currentNamespace, id: key.getInt64(4 + 4)), key.getInt32(4))
return true
}, limit: 1)
if let resultCollectionIdAndIndex = resultCollectionIdAndIndex {
return resultCollectionIdAndIndex
} else {
let index = namespaceList.firstIndex(of: currentNamespace)!
if index == 0 {
return nil
} else {
currentNamespace = namespaceList[index - 1]
currentKey = self.upperBound(namespace: currentNamespace)
}
}
}
}
func higherCollectionId(namespaceList: [ItemCollectionId.Namespace], collectionId: ItemCollectionId, index: Int32) -> (ItemCollectionId, Int32)? {
var currentNamespace = collectionId.namespace
var currentKey = self.key(collectionId: collectionId, index: index)
while true {
var resultCollectionIdAndIndex: (ItemCollectionId, Int32)?
self.valueBox.range(self.table, start: currentKey, end: self.upperBound(namespace: currentNamespace), keys: { key in
resultCollectionIdAndIndex = (ItemCollectionId(namespace: currentNamespace, id: key.getInt64(4 + 4)), key.getInt32(4))
return true
}, limit: 1)
if let resultCollectionIdAndIndex = resultCollectionIdAndIndex {
return resultCollectionIdAndIndex
} else {
let index = namespaceList.firstIndex(of: currentNamespace)!
if index == namespaceList.count - 1 {
return nil
} else {
currentNamespace = namespaceList[index + 1]
currentKey = self.lowerBound(namespace: currentNamespace)
}
}
}
}
func replaceInfos(namespace: ItemCollectionId.Namespace, infos: [(ItemCollectionId, ItemCollectionInfo)]) {
self.cachedInfos.removeAll()
var currentCollectionKeys: [ValueBoxKey] = []
self.valueBox.range(self.table, start: self.lowerBound(namespace: namespace), end: self.upperBound(namespace: namespace), keys: { key in
currentCollectionKeys.append(key)
return true
}, limit: 0)
for key in currentCollectionKeys {
self.valueBox.remove(self.table, key: key, secure: false)
}
var index: Int32 = 0
let sharedEncoder = PostboxEncoder()
for (id, info) in infos {
sharedEncoder.reset()
sharedEncoder.encodeRootObject(info)
withExtendedLifetime(sharedEncoder, {
self.valueBox.set(self.table, key: self.key(collectionId: id, index: index), value: sharedEncoder.readBufferNoCopy())
})
index += 1
}
}
override func clearMemoryCache() {
self.cachedInfos.removeAll()
}
override func beforeCommit() {
}
}