no message

This commit is contained in:
Peter 2017-06-27 19:27:25 +03:00
parent 034531e433
commit aa5346e28a
8 changed files with 355 additions and 48 deletions

View File

@ -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 */,

View File

@ -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
}

View File

@ -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
}

View File

@ -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))
}

View File

@ -95,4 +95,3 @@ public struct SimpleDictionary<K: Hashable, V>: Sequence {
return true
}
}

View 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
}
}

View File

@ -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)

View File

@ -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)