mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-08-19 12:10:55 +00:00
no message
This commit is contained in:
parent
034531e433
commit
aa5346e28a
@ -28,6 +28,8 @@
|
||||
D01BAA561ED1D70C00295217 /* ManagedFile.swift in Sources */ = {isa = PBXBuildFile; fileRef = D01BAA541ED1D70C00295217 /* ManagedFile.swift */; };
|
||||
D01C7EDE1EF73F71008305F1 /* MessageHistoryTextIndexTable.swift in Sources */ = {isa = PBXBuildFile; fileRef = D01C7EDD1EF73F71008305F1 /* MessageHistoryTextIndexTable.swift */; };
|
||||
D01C7EDF1EF73F71008305F1 /* MessageHistoryTextIndexTable.swift in Sources */ = {isa = PBXBuildFile; fileRef = D01C7EDD1EF73F71008305F1 /* MessageHistoryTextIndexTable.swift */; };
|
||||
D01C7F071EFC1ED3008305F1 /* UnorderedItemListTable.swift in Sources */ = {isa = PBXBuildFile; fileRef = D01C7F061EFC1ED3008305F1 /* UnorderedItemListTable.swift */; };
|
||||
D01C7F081EFC1ED3008305F1 /* UnorderedItemListTable.swift in Sources */ = {isa = PBXBuildFile; fileRef = D01C7F061EFC1ED3008305F1 /* UnorderedItemListTable.swift */; };
|
||||
D01F7D9B1CBEC390008765C9 /* MessageHistoryInvalidatedReadStateTable.swift in Sources */ = {isa = PBXBuildFile; fileRef = D01F7D9A1CBEC390008765C9 /* MessageHistoryInvalidatedReadStateTable.swift */; };
|
||||
D01F7D9D1CBF8586008765C9 /* SynchronizePeerReadStatesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D01F7D9C1CBF8586008765C9 /* SynchronizePeerReadStatesView.swift */; };
|
||||
D021E0D41DB4FAE100C6B04F /* ItemCollection.swift in Sources */ = {isa = PBXBuildFile; fileRef = D021E0D31DB4FAE100C6B04F /* ItemCollection.swift */; };
|
||||
@ -304,6 +306,7 @@
|
||||
D019B1CE1E2E770700F80DB3 /* MessageGloballyUniqueIdTable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageGloballyUniqueIdTable.swift; sourceTree = "<group>"; };
|
||||
D01BAA541ED1D70C00295217 /* ManagedFile.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ManagedFile.swift; sourceTree = "<group>"; };
|
||||
D01C7EDD1EF73F71008305F1 /* MessageHistoryTextIndexTable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageHistoryTextIndexTable.swift; sourceTree = "<group>"; };
|
||||
D01C7F061EFC1ED3008305F1 /* UnorderedItemListTable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UnorderedItemListTable.swift; sourceTree = "<group>"; };
|
||||
D01F7D9A1CBEC390008765C9 /* MessageHistoryInvalidatedReadStateTable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageHistoryInvalidatedReadStateTable.swift; sourceTree = "<group>"; };
|
||||
D01F7D9C1CBF8586008765C9 /* SynchronizePeerReadStatesView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SynchronizePeerReadStatesView.swift; sourceTree = "<group>"; };
|
||||
D021E0D31DB4FAE100C6B04F /* ItemCollection.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ItemCollection.swift; sourceTree = "<group>"; };
|
||||
@ -597,6 +600,7 @@
|
||||
D08774FF1E3E3D9F00A97350 /* PreferencesTable.swift */,
|
||||
D0F82CFC1E4345D7007E499C /* OrderedItemListTable.swift */,
|
||||
D0F82D0E1E43A024007E499C /* OrderedItemListIndexTable.swift */,
|
||||
D01C7F061EFC1ED3008305F1 /* UnorderedItemListTable.swift */,
|
||||
);
|
||||
name = Tables;
|
||||
sourceTree = "<group>";
|
||||
@ -932,6 +936,7 @@
|
||||
files = (
|
||||
D050F2661E4A5B5A00988324 /* MessageGloballyUniqueIdTable.swift in Sources */,
|
||||
D03229EF1E6B33FD0000AF9C /* SqliteInterface.swift in Sources */,
|
||||
D01C7F081EFC1ED3008305F1 /* UnorderedItemListTable.swift in Sources */,
|
||||
D050F2671E4A5B5A00988324 /* TimestampBasedMessageAttributesTable.swift in Sources */,
|
||||
D050F2681E4A5B5A00988324 /* TimestampBasedMessageAttributesIndexTable.swift in Sources */,
|
||||
D050F2691E4A5B5A00988324 /* MultiplePeersView.swift in Sources */,
|
||||
@ -1062,6 +1067,7 @@
|
||||
files = (
|
||||
D08775061E3E3F2100A97350 /* PreferencesView.swift in Sources */,
|
||||
D03229EE1E6B33FD0000AF9C /* SqliteInterface.swift in Sources */,
|
||||
D01C7F071EFC1ED3008305F1 /* UnorderedItemListTable.swift in Sources */,
|
||||
D0F9E8631C579F0200037222 /* MediaCleanupTable.swift in Sources */,
|
||||
D0F3CC741DDE1EB9008148FA /* ItemCacheMetaTable.swift in Sources */,
|
||||
D08D451F1D5D2CA700A7428A /* RatingTable.swift in Sources */,
|
||||
|
@ -63,13 +63,13 @@ public func <(lhs: ChatListEntry, rhs: ChatListEntry) -> Bool {
|
||||
}
|
||||
|
||||
enum MutableChatListEntry: Equatable {
|
||||
case IntermediateMessageEntry(ChatListIndex, IntermediateMessage?, CombinedPeerReadState?, PeerNotificationSettings?, PeerChatListEmbeddedInterfaceState?)
|
||||
case IntermediateMessageEntry(ChatListIndex, IntermediateMessage?, CombinedPeerReadState?, PeerChatListEmbeddedInterfaceState?)
|
||||
case MessageEntry(ChatListIndex, Message?, CombinedPeerReadState?, PeerNotificationSettings?, PeerChatListEmbeddedInterfaceState?, RenderedPeer)
|
||||
case HoleEntry(ChatListHole)
|
||||
|
||||
var index: ChatListIndex {
|
||||
switch self {
|
||||
case let .IntermediateMessageEntry(index, _, _, _, _):
|
||||
case let .IntermediateMessageEntry(index, _, _, _):
|
||||
return index
|
||||
case let .MessageEntry(index, _, _, _, _, _):
|
||||
return index
|
||||
@ -119,6 +119,50 @@ final class MutableChatListViewReplayContext {
|
||||
}
|
||||
}
|
||||
|
||||
private func updateMessagePeers(_ message: Message, updatedPeers: [PeerId: Peer]) -> Message? {
|
||||
var updated = false
|
||||
for (peerId, currentPeer) in message.peers {
|
||||
if let updatedPeer = updatedPeers[peerId], !arePeersEqual(currentPeer, updatedPeer) {
|
||||
updated = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if updated {
|
||||
var peers = SimpleDictionary<PeerId, Peer>()
|
||||
for (peerId, currentPeer) in message.peers {
|
||||
if let updatedPeer = updatedPeers[peerId] {
|
||||
peers[peerId] = updatedPeer
|
||||
} else {
|
||||
peers[peerId] = currentPeer
|
||||
}
|
||||
}
|
||||
return Message(stableId: message.stableId, stableVersion: message.stableVersion, id: message.id, globallyUniqueId: message.globallyUniqueId, timestamp: message.timestamp, flags: message.flags, tags: message.tags, globalTags: message.globalTags, forwardInfo: message.forwardInfo, author: message.author, text: message.text, attributes: message.attributes, media: message.media, peers: peers, associatedMessages: message.associatedMessages, associatedMessageIds: message.associatedMessageIds)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
private func updatedRenderedPeer(_ renderedPeer: RenderedPeer, updatedPeers: [PeerId: Peer]) -> RenderedPeer? {
|
||||
var updated = false
|
||||
for (peerId, currentPeer) in renderedPeer.peers {
|
||||
if let updatedPeer = updatedPeers[peerId], !arePeersEqual(currentPeer, updatedPeer) {
|
||||
updated = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if updated {
|
||||
var peers = SimpleDictionary<PeerId, Peer>()
|
||||
for (peerId, currentPeer) in renderedPeer.peers {
|
||||
if let updatedPeer = updatedPeers[peerId] {
|
||||
peers[peerId] = updatedPeer
|
||||
} else {
|
||||
peers[peerId] = currentPeer
|
||||
}
|
||||
}
|
||||
return RenderedPeer(peerId: renderedPeer.peerId, peers: peers)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
final class MutableChatListView {
|
||||
fileprivate var earlier: MutableChatListEntry?
|
||||
fileprivate var later: MutableChatListEntry?
|
||||
@ -150,12 +194,12 @@ final class MutableChatListView {
|
||||
}
|
||||
}
|
||||
|
||||
func replay(_ operations: [ChatListOperation], updatedPeerNotificationSettings: [PeerId: PeerNotificationSettings], context: MutableChatListViewReplayContext) -> Bool {
|
||||
func replay(_ operations: [ChatListOperation], updatedPeerNotificationSettings: [PeerId: PeerNotificationSettings], updatedPeers: [PeerId: Peer], context: MutableChatListViewReplayContext) -> Bool {
|
||||
var hasChanges = false
|
||||
for operation in operations {
|
||||
switch operation {
|
||||
case let .InsertEntry(index, message, combinedReadState, embeddedState):
|
||||
if self.add(.IntermediateMessageEntry(index, message, combinedReadState, nil, embeddedState)) {
|
||||
if self.add(.IntermediateMessageEntry(index, message, combinedReadState, embeddedState)) {
|
||||
hasChanges = true
|
||||
}
|
||||
case let .InsertHole(index):
|
||||
@ -175,14 +219,31 @@ final class MutableChatListView {
|
||||
if !updatedPeerNotificationSettings.isEmpty {
|
||||
for i in 0 ..< self.entries.count {
|
||||
switch self.entries[i] {
|
||||
case let .IntermediateMessageEntry(index, message, readState, _, embeddedState):
|
||||
if let settings = updatedPeerNotificationSettings[index.messageIndex.id.peerId] {
|
||||
self.entries[i] = .IntermediateMessageEntry(index, message, readState, settings, embeddedState)
|
||||
case let .MessageEntry(index, message, readState, _, embeddedState, peer):
|
||||
var notificationSettingsPeerId = peer.peerId
|
||||
if let peer = peer.peers[peer.peerId], let associatedPeerId = peer.associatedPeerId {
|
||||
notificationSettingsPeerId = associatedPeerId
|
||||
}
|
||||
if let settings = updatedPeerNotificationSettings[notificationSettingsPeerId] {
|
||||
self.entries[i] = .MessageEntry(index, message, readState, settings, embeddedState, peer)
|
||||
hasChanges = true
|
||||
}
|
||||
case let .MessageEntry(index, message, readState, _, embeddedState, peer):
|
||||
if let settings = updatedPeerNotificationSettings[index.messageIndex.id.peerId] {
|
||||
self.entries[i] = .MessageEntry(index, message, readState, settings, embeddedState, peer)
|
||||
default:
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
if !updatedPeers.isEmpty {
|
||||
for i in 0 ..< self.entries.count {
|
||||
switch self.entries[i] {
|
||||
case let .MessageEntry(index, message, readState, settings, embeddedState, peer):
|
||||
var updatedMessage: Message?
|
||||
if let message = message {
|
||||
updatedMessage = updateMessagePeers(message, updatedPeers: updatedPeers)
|
||||
}
|
||||
let updatedPeer = updatedRenderedPeer(peer, updatedPeers: updatedPeers)
|
||||
if updatedMessage != nil || updatedPeer != nil {
|
||||
self.entries[i] = .MessageEntry(index, updatedMessage ?? message, readState, settings, embeddedState, updatedPeer ?? peer)
|
||||
hasChanges = true
|
||||
}
|
||||
default:
|
||||
@ -403,38 +464,10 @@ final class MutableChatListView {
|
||||
return nil
|
||||
}
|
||||
|
||||
func updatePeers(_ peers: [PeerId: Peer]) -> Bool {
|
||||
let hasChanges = false
|
||||
/*for i in 0 ..< self.entries.count {
|
||||
switch self.entries[i] {
|
||||
case let .MessageEntry(message):
|
||||
var updatedAuthor: Peer?
|
||||
if let author = message.author, let peer = peers[author.id] {
|
||||
updatedAuthor = peer
|
||||
}
|
||||
|
||||
for peer in message.peers {
|
||||
|
||||
}
|
||||
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
}*/
|
||||
return hasChanges
|
||||
}
|
||||
|
||||
func render(_ renderMessage: (IntermediateMessage) -> Message, getPeer: (PeerId) -> Peer?, getPeerNotificationSettings: (PeerId) -> PeerNotificationSettings?) {
|
||||
for i in 0 ..< self.entries.count {
|
||||
switch self.entries[i] {
|
||||
case let .IntermediateMessageEntry(index, message, combinedReadState, notificationSettings, embeddedState):
|
||||
let updatedNotificationSettings: PeerNotificationSettings?
|
||||
if let notificationSettings = notificationSettings {
|
||||
updatedNotificationSettings = notificationSettings
|
||||
} else {
|
||||
updatedNotificationSettings = getPeerNotificationSettings(index.messageIndex.id.peerId)
|
||||
}
|
||||
case let .IntermediateMessageEntry(index, message, combinedReadState, embeddedState):
|
||||
let renderedMessage: Message?
|
||||
if let message = message {
|
||||
renderedMessage = renderMessage(message)
|
||||
@ -442,15 +475,20 @@ final class MutableChatListView {
|
||||
renderedMessage = nil
|
||||
}
|
||||
var peers = SimpleDictionary<PeerId, Peer>()
|
||||
var notificationSettings: PeerNotificationSettings?
|
||||
if let peer = getPeer(index.messageIndex.id.peerId) {
|
||||
peers[peer.id] = peer
|
||||
if let associatedPeerId = peer.associatedPeerId {
|
||||
if let associatedPeer = getPeer(associatedPeerId) {
|
||||
peers[associatedPeer.id] = associatedPeer
|
||||
}
|
||||
notificationSettings = getPeerNotificationSettings(associatedPeerId)
|
||||
} else {
|
||||
notificationSettings = getPeerNotificationSettings(index.messageIndex.id.peerId)
|
||||
}
|
||||
}
|
||||
self.entries[i] = .MessageEntry(index, renderedMessage, combinedReadState, updatedNotificationSettings, embeddedState, RenderedPeer(peerId: index.messageIndex.id.peerId, peers: peers))
|
||||
|
||||
self.entries[i] = .MessageEntry(index, renderedMessage, combinedReadState, notificationSettings, embeddedState, RenderedPeer(peerId: index.messageIndex.id.peerId, peers: peers))
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
@ -108,3 +108,19 @@ public func arePeersEqual(_ lhs: Peer?, _ rhs: Peer?) -> Bool {
|
||||
return (lhs != nil) == (rhs != nil)
|
||||
}
|
||||
}
|
||||
|
||||
public func arePeerDictionariesEqual(_ lhs: SimpleDictionary<PeerId, Peer>, _ rhs: SimpleDictionary<PeerId, Peer>) -> Bool {
|
||||
if lhs.count != rhs.count {
|
||||
return false
|
||||
}
|
||||
for (id, lhsPeer) in lhs {
|
||||
if let rhsPeer = rhs[id] {
|
||||
if !lhsPeer.isEqual(rhsPeer) {
|
||||
return false
|
||||
}
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
@ -589,6 +589,24 @@ public final class Modifier {
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
public func unorderedItemListDifference(tag: UnorderedItemListEntryTag, updatedEntryInfos: [ValueBoxKey: UnorderedItemListEntryInfo]) -> (metaInfo: UnorderedItemListTagMetaInfo?, added: [ValueBoxKey], removed: [UnorderedItemListEntry], updated: [UnorderedItemListEntry]) {
|
||||
assert(!self.disposed)
|
||||
if let postbox = self.postbox {
|
||||
return postbox.unorderedItemListTable.difference(tag: tag, updatedEntryInfos: updatedEntryInfos)
|
||||
} else {
|
||||
return (nil, [], [], [])
|
||||
}
|
||||
}
|
||||
|
||||
public func unorderedItemListApplyDifference(tag: UnorderedItemListEntryTag, previousInfo: UnorderedItemListTagMetaInfo?, updatedInfo: UnorderedItemListTagMetaInfo, setItems: [UnorderedItemListEntry], removeItemIds: [ValueBoxKey]) -> Bool {
|
||||
assert(!self.disposed)
|
||||
if let postbox = self.postbox {
|
||||
return postbox.unorderedItemListTable.applyDifference(tag: tag, previousInfo: previousInfo, updatedInfo: updatedInfo, setItems: setItems, removeItemIds: removeItemIds)
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate class PipeNotifier: NSObject {
|
||||
@ -778,6 +796,7 @@ public final class Postbox {
|
||||
let orderedItemListTable: OrderedItemListTable
|
||||
let orderedItemListIndexTable: OrderedItemListIndexTable
|
||||
let textIndexTable: MessageHistoryTextIndexTable
|
||||
let unorderedItemListTable: UnorderedItemListTable
|
||||
|
||||
//temporary
|
||||
let peerRatingTable: RatingTable<PeerId>
|
||||
@ -851,6 +870,7 @@ public final class Postbox {
|
||||
self.preferencesTable = PreferencesTable(valueBox: self.valueBox, table: PreferencesTable.tableSpec(35))
|
||||
self.orderedItemListIndexTable = OrderedItemListIndexTable(valueBox: self.valueBox, table: OrderedItemListIndexTable.tableSpec(37))
|
||||
self.orderedItemListTable = OrderedItemListTable(valueBox: self.valueBox, table: OrderedItemListTable.tableSpec(38), indexTable: self.orderedItemListIndexTable)
|
||||
self.unorderedItemListTable = UnorderedItemListTable(valueBox: self.valueBox, table: UnorderedItemListTable.tableSpec(42))
|
||||
|
||||
var tables: [Table] = []
|
||||
tables.append(self.metadataTable)
|
||||
@ -893,6 +913,7 @@ public final class Postbox {
|
||||
tables.append(self.preferencesTable)
|
||||
tables.append(self.orderedItemListTable)
|
||||
tables.append(self.orderedItemListIndexTable)
|
||||
tables.append(self.unorderedItemListTable)
|
||||
|
||||
self.tables = tables
|
||||
|
||||
@ -1221,7 +1242,7 @@ public final class Postbox {
|
||||
for entry in intermediateEntries {
|
||||
switch entry {
|
||||
case let .Message(index, message, embeddedState):
|
||||
entries.append(.IntermediateMessageEntry(index, message, self.readStateTable.getCombinedState(index.messageIndex.id.peerId), self.peerNotificationSettingsTable.get(index.messageIndex.id.peerId), embeddedState))
|
||||
entries.append(.IntermediateMessageEntry(index, message, self.readStateTable.getCombinedState(index.messageIndex.id.peerId), embeddedState))
|
||||
case let .Hole(hole):
|
||||
entries.append(.HoleEntry(hole))
|
||||
}
|
||||
@ -1230,7 +1251,7 @@ public final class Postbox {
|
||||
if let intermediateLower = intermediateLower {
|
||||
switch intermediateLower {
|
||||
case let .Message(index, message, embeddedState):
|
||||
lower = .IntermediateMessageEntry(index, message, self.readStateTable.getCombinedState(index.messageIndex.id.peerId), self.peerNotificationSettingsTable.get(index.messageIndex.id.peerId), embeddedState)
|
||||
lower = .IntermediateMessageEntry(index, message, self.readStateTable.getCombinedState(index.messageIndex.id.peerId), embeddedState)
|
||||
case let .Hole(hole):
|
||||
lower = .HoleEntry(hole)
|
||||
}
|
||||
@ -1239,7 +1260,7 @@ public final class Postbox {
|
||||
if let intermediateUpper = intermediateUpper {
|
||||
switch intermediateUpper {
|
||||
case let .Message(index, message, embeddedState):
|
||||
upper = .IntermediateMessageEntry(index, message, self.readStateTable.getCombinedState(index.messageIndex.id.peerId), self.peerNotificationSettingsTable.get(index.messageIndex.id.peerId), embeddedState)
|
||||
upper = .IntermediateMessageEntry(index, message, self.readStateTable.getCombinedState(index.messageIndex.id.peerId), embeddedState)
|
||||
case let .Hole(hole):
|
||||
upper = .HoleEntry(hole)
|
||||
}
|
||||
@ -1254,7 +1275,7 @@ public final class Postbox {
|
||||
for entry in intermediateEntries {
|
||||
switch entry {
|
||||
case let .Message(index, message, embeddedState):
|
||||
entries.append(.IntermediateMessageEntry(index, message, self.readStateTable.getCombinedState(index.messageIndex.id.peerId), self.peerNotificationSettingsTable.get(index.messageIndex.id.peerId), embeddedState))
|
||||
entries.append(.IntermediateMessageEntry(index, message, self.readStateTable.getCombinedState(index.messageIndex.id.peerId), embeddedState))
|
||||
case let .Hole(hole):
|
||||
entries.append(.HoleEntry(hole))
|
||||
}
|
||||
@ -1268,7 +1289,7 @@ public final class Postbox {
|
||||
for entry in intermediateEntries {
|
||||
switch entry {
|
||||
case let .Message(index, message, embeddedState):
|
||||
entries.append(.IntermediateMessageEntry(index, message, self.readStateTable.getCombinedState(index.messageIndex.id.peerId), self.peerNotificationSettingsTable.get(index.messageIndex.id.peerId), embeddedState))
|
||||
entries.append(.IntermediateMessageEntry(index, message, self.readStateTable.getCombinedState(index.messageIndex.id.peerId), embeddedState))
|
||||
case let .Hole(index):
|
||||
entries.append(.HoleEntry(index))
|
||||
}
|
||||
|
@ -95,4 +95,3 @@ public struct SimpleDictionary<K: Hashable, V>: Sequence {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
|
219
Postbox/UnorderedItemListTable.swift
Normal file
219
Postbox/UnorderedItemListTable.swift
Normal file
@ -0,0 +1,219 @@
|
||||
import Foundation
|
||||
|
||||
public struct UnorderedItemListEntryInfo {
|
||||
public let hashValue: Int64
|
||||
|
||||
public init(hashValue: Int64) {
|
||||
self.hashValue = hashValue
|
||||
}
|
||||
}
|
||||
|
||||
public struct UnorderedItemListEntry {
|
||||
public let id: ValueBoxKey
|
||||
public let info: UnorderedItemListEntryInfo
|
||||
public let contents: Coding
|
||||
|
||||
public init(id: ValueBoxKey, info: UnorderedItemListEntryInfo, contents: Coding) {
|
||||
self.id = id
|
||||
self.info = info
|
||||
self.contents = contents
|
||||
}
|
||||
}
|
||||
|
||||
public struct UnorderedItemListEntryTag {
|
||||
public let value: ValueBoxKey
|
||||
|
||||
public init(value: ValueBoxKey) {
|
||||
self.value = value
|
||||
}
|
||||
}
|
||||
|
||||
public protocol UnorderedItemListTagMetaInfo: Coding {
|
||||
func isEqual(to: UnorderedItemListTagMetaInfo) -> Bool
|
||||
}
|
||||
|
||||
private enum UnorderedItemListTableKeyspace: UInt8 {
|
||||
case metaInfo = 0
|
||||
case entries = 1
|
||||
}
|
||||
|
||||
private func extractEntryKey(tagLength: Int, key: ValueBoxKey) -> ValueBoxKey {
|
||||
let result = ValueBoxKey(length: key.length - tagLength - 1)
|
||||
memcpy(result.memory, key.memory.advanced(by: 1 + tagLength), result.length)
|
||||
return result
|
||||
}
|
||||
|
||||
private func extractEntryInfo(_ value: ReadBuffer) -> UnorderedItemListEntryInfo {
|
||||
var hashValue: Int64 = 0
|
||||
value.read(&hashValue, offset: 0, length: 8)
|
||||
return UnorderedItemListEntryInfo(hashValue: hashValue)
|
||||
}
|
||||
|
||||
final class UnorderedItemListTable: Table {
|
||||
static func tableSpec(_ id: Int32) -> ValueBoxTable {
|
||||
return ValueBoxTable(id: id, keyType: .binary)
|
||||
}
|
||||
|
||||
private func metaInfoKey(tag: UnorderedItemListEntryTag) -> ValueBoxKey {
|
||||
let tagValue = tag.value
|
||||
let key = ValueBoxKey(length: 1 + tagValue.length)
|
||||
key.setUInt8(0, value: UnorderedItemListTableKeyspace.metaInfo.rawValue)
|
||||
memcpy(key.memory.advanced(by: 1), tagValue.memory, tagValue.length)
|
||||
return key
|
||||
}
|
||||
|
||||
private func entryKey(tag: UnorderedItemListEntryTag, id: ValueBoxKey) -> ValueBoxKey {
|
||||
let tagValue = tag.value
|
||||
let key = ValueBoxKey(length: 1 + tagValue.length + id.length)
|
||||
key.setUInt8(0, value: UnorderedItemListTableKeyspace.entries.rawValue)
|
||||
memcpy(key.memory.advanced(by: 1), tagValue.memory, tagValue.length)
|
||||
memcpy(key.memory.advanced(by: 1 + tagValue.length), id.memory, id.length)
|
||||
return key
|
||||
}
|
||||
|
||||
private func entryLowerBoundKey(tag: UnorderedItemListEntryTag) -> ValueBoxKey {
|
||||
let tagValue = tag.value
|
||||
let key = ValueBoxKey(length: 1 + tagValue.length)
|
||||
key.setUInt8(0, value: UnorderedItemListTableKeyspace.entries.rawValue)
|
||||
memcpy(key.memory.advanced(by: 1), tagValue.memory, tagValue.length)
|
||||
return key
|
||||
}
|
||||
|
||||
private func entryUpperBoundKey(tag: UnorderedItemListEntryTag) -> ValueBoxKey {
|
||||
let tagValue = tag.value.successor
|
||||
let key = ValueBoxKey(length: 1 + tagValue.length)
|
||||
key.setUInt8(0, value: UnorderedItemListTableKeyspace.entries.rawValue)
|
||||
memcpy(key.memory.advanced(by: 1), tagValue.memory, tagValue.length)
|
||||
return key
|
||||
}
|
||||
|
||||
private func getMetaInfo(tag: UnorderedItemListEntryTag) -> UnorderedItemListTagMetaInfo? {
|
||||
if let value = self.valueBox.get(self.table, key: self.metaInfoKey(tag: tag)), let info = Decoder(buffer: value).decodeRootObject() as? UnorderedItemListTagMetaInfo {
|
||||
return info
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
private func setMetaInfo(tag: UnorderedItemListEntryTag, info: UnorderedItemListTagMetaInfo) {
|
||||
let encoder = Encoder()
|
||||
encoder.encodeRootObject(info)
|
||||
self.valueBox.set(self.table, key: self.metaInfoKey(tag: tag), value: encoder.readBufferNoCopy())
|
||||
}
|
||||
|
||||
private func getEntryInfos(tag: UnorderedItemListEntryTag) -> [ValueBoxKey: UnorderedItemListEntryInfo] {
|
||||
var result: [ValueBoxKey: UnorderedItemListEntryInfo] = [:]
|
||||
let tagLength = tag.value.length
|
||||
self.valueBox.range(self.table, start: self.entryLowerBoundKey(tag: tag), end: self.entryUpperBoundKey(tag: tag), values: { key, value in
|
||||
result[extractEntryKey(tagLength: tagLength, key: key)] = extractEntryInfo(value)
|
||||
return true
|
||||
}, limit: 0)
|
||||
return result
|
||||
}
|
||||
|
||||
private func getEntry(tag: UnorderedItemListEntryTag, id: ValueBoxKey) -> UnorderedItemListEntry? {
|
||||
if let value = self.valueBox.get(self.table, key: self.entryKey(tag: tag, id: id)) {
|
||||
var hashValue: Int64 = 0
|
||||
value.read(&hashValue, offset: 0, length: 8)
|
||||
let tempBuffer = MemoryBuffer(memory: value.memory.advanced(by: 8), capacity: value.length - 8, length: value.length - 8, freeWhenDone: false)
|
||||
let contents = withExtendedLifetime(tempBuffer, {
|
||||
return Decoder(buffer: tempBuffer).decodeRootObject()
|
||||
})
|
||||
if let contents = contents {
|
||||
let entry = UnorderedItemListEntry(id: id, info: UnorderedItemListEntryInfo(hashValue: hashValue), contents: contents)
|
||||
return entry
|
||||
} else {
|
||||
assertionFailure()
|
||||
return nil
|
||||
}
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
private func setEntry(tag: UnorderedItemListEntryTag, entry: UnorderedItemListEntry, sharedBuffer: WriteBuffer, sharedEncoder: Encoder) {
|
||||
sharedBuffer.reset()
|
||||
sharedEncoder.reset()
|
||||
|
||||
var hashValue: Int64 = entry.info.hashValue
|
||||
sharedBuffer.write(&hashValue, offset: 0, length: 8)
|
||||
|
||||
sharedEncoder.encodeRootObject(entry.contents)
|
||||
let tempBuffer = sharedEncoder.readBufferNoCopy()
|
||||
withExtendedLifetime(tempBuffer, {
|
||||
sharedBuffer.write(tempBuffer.memory, offset: 0, length: tempBuffer.length)
|
||||
})
|
||||
|
||||
self.valueBox.set(self.table, key: self.entryKey(tag: tag, id: entry.id), value: sharedBuffer)
|
||||
}
|
||||
|
||||
func difference(tag: UnorderedItemListEntryTag, updatedEntryInfos: [ValueBoxKey: UnorderedItemListEntryInfo]) -> (metaInfo: UnorderedItemListTagMetaInfo?, added: [ValueBoxKey], removed: [UnorderedItemListEntry], updated: [UnorderedItemListEntry]) {
|
||||
let currentEntryInfos = self.getEntryInfos(tag: tag)
|
||||
var currentInfoIds = Set<ValueBoxKey>()
|
||||
for key in currentEntryInfos.keys {
|
||||
currentInfoIds.insert(key)
|
||||
}
|
||||
|
||||
var updatedInfoIds = Set<ValueBoxKey>()
|
||||
for key in updatedEntryInfos.keys {
|
||||
updatedInfoIds.insert(key)
|
||||
}
|
||||
|
||||
let addedKeys = updatedInfoIds.subtracting(currentInfoIds)
|
||||
let added: [ValueBoxKey] = Array(addedKeys)
|
||||
|
||||
let removedKeys = currentInfoIds.subtracting(updatedInfoIds)
|
||||
var removed: [UnorderedItemListEntry] = []
|
||||
for key in removedKeys {
|
||||
if let entry = self.getEntry(tag: tag, id: key) {
|
||||
removed.append(entry)
|
||||
} else {
|
||||
assertionFailure()
|
||||
}
|
||||
}
|
||||
|
||||
var updated: [UnorderedItemListEntry] = []
|
||||
for (key, info) in updatedEntryInfos {
|
||||
if !addedKeys.contains(key) {
|
||||
if let currentInfo = currentEntryInfos[key] {
|
||||
if info.hashValue != currentInfo.hashValue {
|
||||
if let entry = self.getEntry(tag: tag, id: key) {
|
||||
updated.append(entry)
|
||||
} else {
|
||||
assertionFailure()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
assertionFailure()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (self.getMetaInfo(tag: tag), added, removed, updated)
|
||||
}
|
||||
|
||||
func applyDifference(tag: UnorderedItemListEntryTag, previousInfo: UnorderedItemListTagMetaInfo?, updatedInfo: UnorderedItemListTagMetaInfo, setItems: [UnorderedItemListEntry], removeItemIds: [ValueBoxKey]) -> Bool {
|
||||
let currentInfo = self.getMetaInfo(tag: tag)
|
||||
if let currentInfo = currentInfo, let previousInfo = previousInfo {
|
||||
if !currentInfo.isEqual(to: previousInfo) {
|
||||
return false
|
||||
}
|
||||
} else if (currentInfo != nil) != (previousInfo != nil) {
|
||||
return false
|
||||
}
|
||||
|
||||
self.setMetaInfo(tag: tag, info: updatedInfo)
|
||||
|
||||
let sharedBuffer = WriteBuffer()
|
||||
let sharedEncoder = Encoder()
|
||||
for entry in setItems {
|
||||
self.setEntry(tag: tag, entry: entry, sharedBuffer: sharedBuffer, sharedEncoder: sharedEncoder)
|
||||
}
|
||||
|
||||
for id in removeItemIds {
|
||||
self.valueBox.remove(self.table, key: self.entryKey(tag: tag, id: id))
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
@ -190,6 +190,14 @@ public struct ValueBoxKey: Hashable, CustomStringConvertible, Comparable {
|
||||
return string as String
|
||||
}
|
||||
|
||||
public var stringValue: String {
|
||||
if let string = String(data: Data(bytes: self.memory, count: self.length), encoding: .utf8) {
|
||||
return string
|
||||
} else {
|
||||
return "<unavailable>"
|
||||
}
|
||||
}
|
||||
|
||||
public var hashValue: Int {
|
||||
var hash = 37
|
||||
let bytes = self.memory.assumingMemoryBound(to: Int8.self)
|
||||
|
@ -400,10 +400,10 @@ final class ViewTracker {
|
||||
}
|
||||
}
|
||||
|
||||
if !transaction.chatListOperations.isEmpty || !transaction.currentUpdatedPeerNotificationSettings.isEmpty {
|
||||
if !transaction.chatListOperations.isEmpty || !transaction.currentUpdatedPeerNotificationSettings.isEmpty || !transaction.currentUpdatedPeers.isEmpty {
|
||||
for (mutableView, pipe) in self.chatListViews.copyItems() {
|
||||
let context = MutableChatListViewReplayContext()
|
||||
if mutableView.replay(transaction.chatListOperations, updatedPeerNotificationSettings: transaction.currentUpdatedPeerNotificationSettings, context: context) {
|
||||
if mutableView.replay(transaction.chatListOperations, updatedPeerNotificationSettings: transaction.currentUpdatedPeerNotificationSettings, updatedPeers: transaction.currentUpdatedPeers, context: context) {
|
||||
mutableView.complete(context: context, fetchEarlier: self.fetchEarlierChatEntries, fetchLater: self.fetchLaterChatEntries)
|
||||
mutableView.render(self.renderMessage, getPeer: { id in
|
||||
return self.getPeer(id)
|
||||
|
Loading…
x
Reference in New Issue
Block a user