Swiftgram/Postbox/PeerView.swift
2015-08-10 12:02:20 +02:00

455 lines
16 KiB
Swift

import Foundation
public final class PeerViewEntry: Equatable, Comparable {
public let peerId: PeerId
public let peer: Peer?
public let messageIndex: MessageIndex
public let message: RenderedMessage?
public init(peer: Peer, message: RenderedMessage) {
self.peerId = peer.id
self.peer = peer
self.message = message
self.messageIndex = MessageIndex(message.message)
}
public init(peerId: PeerId, message: RenderedMessage) {
self.peerId = peerId
self.peer = nil
self.message = message
self.messageIndex = MessageIndex(message.message)
}
private init(peer: Peer?, peerId: PeerId, message: RenderedMessage) {
self.peer = peer
self.peerId = peerId
self.message = message
self.messageIndex = MessageIndex(message.message)
}
private init(peer: Peer?, peerId: PeerId, message: RenderedMessage?, messageIndex: MessageIndex) {
self.peer = peer
self.peerId = peerId
self.message = message
self.messageIndex = messageIndex
}
init(peer: Peer?, peerId: PeerId, messageIndex: MessageIndex) {
self.peer = peer
self.peerId = peerId
self.messageIndex = messageIndex
self.message = nil
}
}
public func ==(lhs: PeerViewEntry, rhs: PeerViewEntry) -> Bool {
return PeerViewEntryIndex(lhs) == PeerViewEntryIndex(rhs)
}
public func <(lhs: PeerViewEntry, rhs: PeerViewEntry) -> Bool {
return PeerViewEntryIndex(lhs) < PeerViewEntryIndex(rhs)
}
public struct PeerViewEntryIndex: Equatable, Comparable {
public let peerId: PeerId
public let messageIndex: MessageIndex
public init(_ entry: PeerViewEntry) {
self.peerId = entry.peerId
self.messageIndex = entry.messageIndex
}
public init(peerId: PeerId, messageIndex: MessageIndex) {
self.peerId = peerId
self.messageIndex = messageIndex
}
public func earlier() -> PeerViewEntryIndex {
return PeerViewEntryIndex(peerId: self.peerId, messageIndex: MessageIndex(id: MessageId(peerId: self.messageIndex.id.peerId, namespace: self.messageIndex.id.namespace, id: self.messageIndex.id.id - 1), timestamp: self.messageIndex.timestamp))
}
public func later() -> PeerViewEntryIndex {
return PeerViewEntryIndex(peerId: self.peerId, messageIndex: MessageIndex(id: MessageId(peerId: self.messageIndex.id.peerId, namespace: self.messageIndex.id.namespace, id: self.messageIndex.id.id + 1), timestamp: self.messageIndex.timestamp))
}
}
public func ==(lhs: PeerViewEntryIndex, rhs: PeerViewEntryIndex) -> Bool {
return lhs.peerId == rhs.peerId && lhs.messageIndex == rhs.messageIndex
}
public func <(lhs: PeerViewEntryIndex, rhs: PeerViewEntryIndex) -> Bool {
if lhs.messageIndex != rhs.messageIndex {
return lhs.messageIndex < rhs.messageIndex
}
return lhs.peerId < rhs.peerId
}
public final class MutablePeerView: CustomStringConvertible {
public struct RemoveContext {
var invalidEarlier = false
var invalidLater = false
var removedEntries = false
}
let count: Int
var earlier: PeerViewEntry?
var later: PeerViewEntry?
var entries: [PeerViewEntry]
public init(count: Int, earlier: PeerViewEntry?, entries: [PeerViewEntry], later: PeerViewEntry?) {
self.count = count
self.earlier = earlier
self.entries = entries
self.later = later
}
public func removeEntry(context: RemoveContext?, peerId: PeerId) -> RemoveContext {
var invalidationContext = context ?? RemoveContext()
if let earlier = self.earlier {
if peerId == earlier.peerId {
invalidationContext.invalidEarlier = true
}
}
if let later = self.later {
if peerId == later.peerId {
invalidationContext.invalidLater = true
}
}
var i = 0
while i < self.entries.count {
if self.entries[i].peerId == peerId {
self.entries.removeAtIndex(i)
invalidationContext.removedEntries = true
break
}
i++
}
return invalidationContext
}
public func addEntry(entry: PeerViewEntry) {
if self.entries.count == 0 {
self.entries.append(entry)
} else {
let first = PeerViewEntryIndex(self.entries[self.entries.count - 1])
let last = PeerViewEntryIndex(self.entries[0])
let index = PeerViewEntryIndex(entry)
var next: PeerViewEntryIndex?
if let later = self.later {
next = PeerViewEntryIndex(later)
}
if index < last {
let earlierEntry = self.earlier
if earlierEntry == nil || PeerViewEntryIndex(earlierEntry!) < index {
if self.entries.count < self.count {
self.entries.insert(entry, atIndex: 0)
} else {
self.earlier = entry
}
}
} else if index > first {
if next != nil && index > next! {
let laterEntry = self.later
if laterEntry == nil || PeerViewEntryIndex(laterEntry!) > index {
if self.entries.count < self.count {
self.entries.append(entry)
} else {
self.later = entry
}
}
} else {
self.entries.append(entry)
if self.entries.count > self.count {
let earliest = self.entries[0]
self.earlier = earliest
self.entries.removeAtIndex(0)
}
}
} else if index != last && index != first {
var i = self.entries.count
while i >= 1 {
if PeerViewEntryIndex(self.entries[i - 1]) < index {
break
}
i--
}
self.entries.insert(entry, atIndex: i)
if self.entries.count > self.count {
let earliest = self.entries[0]
self.earlier = earliest
self.entries.removeAtIndex(0)
}
}
}
}
public func complete(context: RemoveContext, fetchEarlier: (PeerViewEntryIndex?, Int) -> [PeerViewEntry], fetchLater: (PeerViewEntryIndex?, Int) -> [PeerViewEntry]) {
if context.removedEntries && self.entries.count != self.count {
var addedEntries: [PeerViewEntry] = []
var latestAnchor: PeerViewEntryIndex?
if self.entries.count != 0 {
latestAnchor = PeerViewEntryIndex(self.entries[self.entries.count - 1])
} else if let later = self.later {
latestAnchor = PeerViewEntryIndex(later)
}
if let later = self.later {
addedEntries += fetchLater(PeerViewEntryIndex(later).earlier(), self.count)
}
if let earlier = self.earlier {
addedEntries += fetchEarlier(PeerViewEntryIndex(earlier).later(), self.count)
}
addedEntries += self.entries
addedEntries.sortInPlace({ PeerViewEntryIndex($0) < PeerViewEntryIndex($1) })
var i = addedEntries.count - 1
while i >= 1 {
if PeerViewEntryIndex(addedEntries[i]) == PeerViewEntryIndex(addedEntries[i - 1]) {
addedEntries.removeAtIndex(i)
}
i--
}
self.entries = []
var anchorIndex = addedEntries.count - 1
if let latestAnchor = latestAnchor {
var i = addedEntries.count - 1
while i >= 0 {
if PeerViewEntryIndex(addedEntries[i]) <= latestAnchor {
anchorIndex = i
break
}
i--
}
}
self.later = nil
if anchorIndex + 1 < addedEntries.count {
let i = anchorIndex + 1
while i < addedEntries.count {
self.later = addedEntries[i]
break
}
}
i = anchorIndex
while i >= 0 && i > anchorIndex - self.count {
self.entries.insert(addedEntries[i], atIndex: 0)
i--
}
self.earlier = nil
if anchorIndex - self.count >= 0 {
i = anchorIndex - self.count
while i >= 0 {
self.earlier = addedEntries[i]
break
}
}
} else {
var earlyIndex: PeerViewEntryIndex?
if self.entries.count != 0 {
earlyIndex = PeerViewEntryIndex(self.entries[0])
}
let earlierEntries = fetchEarlier(earlyIndex, 1)
if earlierEntries.count == 0 {
self.earlier = nil
} else {
self.earlier = earlierEntries[0]
}
var lateIndex: PeerViewEntryIndex?
if self.entries.count != 0 {
lateIndex = PeerViewEntryIndex(self.entries[self.entries.count - 1])
}
let laterEntries = fetchLater(lateIndex, 1)
if laterEntries.count == 0 {
self.later = nil
} else {
self.later = laterEntries[0]
}
}
}
public func updatePeers(peers: [PeerId : Peer]) -> Bool {
var updated = false
if let earlier = self.earlier {
if let peer = peers[earlier.peerId] {
self.earlier = PeerViewEntry(peer: peer, peerId: earlier.peerId, message: earlier.message, messageIndex: earlier.messageIndex)
updated = true
}
}
if let later = self.later {
if let peer = peers[later.peerId] {
self.later = PeerViewEntry(peer: peer, peerId: later.peerId, message: later.message, messageIndex: later.messageIndex)
updated = true
}
}
var i = 0
while i < self.entries.count {
if let peer = peers[self.entries[i].peerId] {
let entry = self.entries[i]
self.entries[i] = PeerViewEntry(peer: peer, peerId: entry.peerId, message: entry.message, messageIndex: entry.messageIndex)
updated = true
}
i++
}
return updated
}
public func incompleteMessages() -> [Message] {
var result: [Message] = []
if let earlier = self.earlier {
if let message = earlier.message {
if message.incomplete {
result.append(message.message)
}
}
}
if let later = self.later {
if let message = later.message {
if message.incomplete {
result.append(message.message)
}
}
}
for entry in self.entries {
if let message = entry.message {
if message.incomplete {
result.append(message.message)
}
}
}
return result
}
public func completeMessages(messages: [MessageId : RenderedMessage]) {
if let earlier = self.earlier {
if let earlierMessage = earlier.message {
if let message = messages[earlierMessage.message.id] {
self.earlier = PeerViewEntry(peer: earlier.peer, peerId: earlier.peerId, message: message)
}
}
}
if let later = self.later {
if let laterMessage = later.message {
if let message = messages[laterMessage.message.id] {
self.later = PeerViewEntry(peer: later.peer, peerId: later.peerId, message: message)
}
}
}
var i = 0
while i < self.entries.count {
if let entryMessage = self.entries[i].message {
if let message = messages[entryMessage.message.id] {
self.entries[i] = PeerViewEntry(peer: self.entries[i].peer, peerId: self.entries[i].peerId, message: message)
}
}
i++
}
}
public var description: String {
var string = ""
if let earlier = self.earlier {
string += "more("
string += "(p \(earlier.peerId.namespace):\(earlier.peerId.id), m \(earlier.message?.message.id.namespace ?? 0):\(earlier.message?.message.id.id ?? 0)\(earlier.message?.message.timestamp ?? 0)"
string += ") "
}
string += "["
var first = true
for entry in self.entries {
if first {
first = false
} else {
string += ", "
}
string += "(p \(entry.peerId.namespace):\(entry.peerId.id), m \(entry.message?.message.id.namespace ?? 0):\(entry.message?.message.id.id ?? 0)\(entry.message?.message.timestamp ?? 0))"
}
string += "]"
if let later = self.later {
string += " more("
string += "(p \(later.peerId.namespace):\(later.peerId), m \(later.message?.message.id.namespace ?? 0):\(later.message?.message.id.id ?? 0)\(later.message?.message.timestamp ?? 0)"
string += ")"
}
return string
}
}
public final class PeerView: CustomStringConvertible {
let earlier: PeerViewEntryIndex?
let later: PeerViewEntryIndex?
public let entries: [PeerViewEntry]
init(_ mutableView: MutablePeerView) {
if let earlier = mutableView.earlier {
self.earlier = PeerViewEntryIndex(earlier)
} else {
self.earlier = nil
}
if let later = mutableView.later {
self.later = PeerViewEntryIndex(later)
} else {
self.later = nil
}
self.entries = mutableView.entries
}
public var description: String {
var string = ""
if let earlier = self.earlier {
string += "more("
string += "(p \(earlier.peerId.namespace):\(earlier.peerId.id), m \(earlier.messageIndex.id.namespace):\(earlier.messageIndex.id.id)\(earlier.messageIndex.timestamp)"
string += ") "
}
string += "["
var first = true
for entry in self.entries {
if first {
first = false
} else {
string += ", "
}
string += "(p \(entry.peerId.namespace):\(entry.peerId.id), m \(entry.message?.message.id.namespace ?? 0):\(entry.message?.message.id.id ?? 0)\(entry.message?.message.timestamp ?? 0))"
}
string += "]"
if let later = self.later {
string += " more("
string += "(p \(later.peerId.namespace):\(later.peerId), m \(later.messageIndex.id.namespace):\(later.messageIndex.id.id)\(later.messageIndex.timestamp)"
string += ")"
}
return string
}
}