From 1fe0d4a75b2fe72a3e8b97b3884e0de0c322c28b Mon Sep 17 00:00:00 2001 From: Ali <> Date: Fri, 3 Sep 2021 00:45:22 +0400 Subject: [PATCH 01/30] Temp --- .../Sources/InAppNotificationSettings.swift | 105 ----------- .../Telegram-iOS/en.lproj/Localizable.strings | 4 +- submodules/Postbox/BUILD | 3 + .../AccountManagerSharedDataTable.swift | 10 +- submodules/Postbox/Sources/ChatListHole.swift | 4 - .../Postbox/Sources/ChatListIndexTable.swift | 9 +- .../Postbox/Sources/ChatListTable.swift | 12 +- submodules/Postbox/Sources/ChatListView.swift | 22 +-- .../Postbox/Sources/ChatListViewState.swift | 169 +++++++++++------- submodules/Postbox/Sources/Coding.swift | 12 +- submodules/Postbox/Sources/IpcPipe.swift | 1 - .../Postbox/Sources/ItemCacheTable.swift | 11 +- .../Postbox/Sources/ItemCollection.swift | 4 - submodules/Postbox/Sources/ManagedFile.swift | 3 +- submodules/Postbox/Sources/Media.swift | 4 +- submodules/Postbox/Sources/MediaBox.swift | 5 +- submodules/Postbox/Sources/MediaBoxFile.swift | 13 +- .../MessageHistoryHoleIndexTable.swift | 3 - .../MessageHistoryReadStateTable.swift | 2 +- .../Postbox/Sources/MessageHistoryTable.swift | 6 +- .../MessageHistoryThreadHoleIndexTable.swift | 3 - .../Sources/MessageOfInterestHolesView.swift | 2 +- submodules/Postbox/Sources/NoticeTable.swift | 6 +- .../Sources/OrderedItemListTable.swift | 2 +- submodules/Postbox/Sources/Peer.swift | 4 +- .../Sources/PeerNotificationSettings.swift | 44 +++-- .../PeerNotificationSettingsTable.swift | 4 +- submodules/Postbox/Sources/PeerPresence.swift | 2 +- .../PendingMessageActionsMetadataTable.swift | 26 --- submodules/Postbox/Sources/Postbox.swift | 61 +++---- .../Sources/PostboxUpgrade_16to17.swift | 6 +- .../Postbox/Sources/PreferencesEntry.swift | 25 ++- .../Postbox/Sources/PreferencesTable.swift | 15 +- .../Postbox/Sources/PreferencesView.swift | 2 +- .../Sources/ReverseIndexReferenceTable.swift | 12 -- .../Postbox/Sources/SeedConfiguration.swift | 6 +- .../Postbox/Sources/SqliteValueBox.swift | 37 ++-- .../Postbox/Sources/TimeBasedCleanup.swift | 2 +- submodules/Postbox/Sources/ValueBoxKey.swift | 14 +- submodules/Postbox/Sources/ViewTracker.swift | 8 +- submodules/Postbox/Sources/Views.swift | 73 ++++---- .../Sources/Account/AccountManager.swift | 36 ++-- .../State/InitializeAccountAfterLogin.swift | 2 +- .../SyncCore/SyncCore_AppChangelogState.swift | 26 ++- .../SyncCore/SyncCore_AppConfiguration.swift | 9 +- .../SyncCore_AutodownloadSettings.swift | 72 ++++---- .../SyncCore_CacheStorageSettings.swift | 30 ++-- .../SyncCore/SyncCore_ContactsSettings.swift | 22 +-- .../SyncCore_ContentPrivacySettings.swift | 37 ++-- .../SyncCore_GlobalNotificationSettings.swift | 49 ++--- ...yncCore_StandaloneAccountTransaction.swift | 4 +- ...ore_TelegramPeerNotificationSettings.swift | 10 +- .../Sources/GroupCallContext.swift | 2 +- 53 files changed, 489 insertions(+), 566 deletions(-) diff --git a/Telegram/NotificationService/Sources/InAppNotificationSettings.swift b/Telegram/NotificationService/Sources/InAppNotificationSettings.swift index 8da59f2aaf..fecc4ab449 100644 --- a/Telegram/NotificationService/Sources/InAppNotificationSettings.swift +++ b/Telegram/NotificationService/Sources/InAppNotificationSettings.swift @@ -1,106 +1 @@ import Foundation -/*import PostboxCoding -import PreferencesTable -import MessageHistoryMetadataTable -import PostboxDataTypes - -public enum TotalUnreadCountDisplayStyle: Int32 { - case filtered = 0 - - var category: ChatListTotalUnreadStateCategory { - switch self { - case .filtered: - return .filtered - } - } -} - -public enum TotalUnreadCountDisplayCategory: Int32 { - case chats = 0 - case messages = 1 - - var statsType: ChatListTotalUnreadStateStats { - switch self { - case .chats: - return .chats - case .messages: - return .messages - } - } -} - -public struct InAppNotificationSettings: PreferencesEntry, Equatable { - public var playSounds: Bool - public var vibrate: Bool - public var displayPreviews: Bool - public var totalUnreadCountDisplayStyle: TotalUnreadCountDisplayStyle - public var totalUnreadCountDisplayCategory: TotalUnreadCountDisplayCategory - public var totalUnreadCountIncludeTags: PeerSummaryCounterTags - public var displayNameOnLockscreen: Bool - public var displayNotificationsFromAllAccounts: Bool - - public static var defaultSettings: InAppNotificationSettings { - return InAppNotificationSettings(playSounds: true, vibrate: false, displayPreviews: true, totalUnreadCountDisplayStyle: .filtered, totalUnreadCountDisplayCategory: .messages, totalUnreadCountIncludeTags: [.privateChat, .secretChat, .bot, .privateGroup], displayNameOnLockscreen: true, displayNotificationsFromAllAccounts: true) - } - - public init(playSounds: Bool, vibrate: Bool, displayPreviews: Bool, totalUnreadCountDisplayStyle: TotalUnreadCountDisplayStyle, totalUnreadCountDisplayCategory: TotalUnreadCountDisplayCategory, totalUnreadCountIncludeTags: PeerSummaryCounterTags, displayNameOnLockscreen: Bool, displayNotificationsFromAllAccounts: Bool) { - self.playSounds = playSounds - self.vibrate = vibrate - self.displayPreviews = displayPreviews - self.totalUnreadCountDisplayStyle = totalUnreadCountDisplayStyle - self.totalUnreadCountDisplayCategory = totalUnreadCountDisplayCategory - self.totalUnreadCountIncludeTags = totalUnreadCountIncludeTags - self.displayNameOnLockscreen = displayNameOnLockscreen - self.displayNotificationsFromAllAccounts = displayNotificationsFromAllAccounts - } - - public init(decoder: PostboxDecoder) { - self.playSounds = decoder.decodeInt32ForKey("s", orElse: 0) != 0 - self.vibrate = decoder.decodeInt32ForKey("v", orElse: 0) != 0 - self.displayPreviews = decoder.decodeInt32ForKey("p", orElse: 0) != 0 - self.totalUnreadCountDisplayStyle = TotalUnreadCountDisplayStyle(rawValue: decoder.decodeInt32ForKey("cds", orElse: 0)) ?? .filtered - self.totalUnreadCountDisplayCategory = TotalUnreadCountDisplayCategory(rawValue: decoder.decodeInt32ForKey("totalUnreadCountDisplayCategory", orElse: 1)) ?? .messages - if let value = decoder.decodeOptionalInt32ForKey("totalUnreadCountIncludeTags_2") { - self.totalUnreadCountIncludeTags = PeerSummaryCounterTags(rawValue: value) - } else if let value = decoder.decodeOptionalInt32ForKey("totalUnreadCountIncludeTags") { - var resultTags: PeerSummaryCounterTags = [] - for legacyTag in LegacyPeerSummaryCounterTags(rawValue: value) { - if legacyTag == .regularChatsAndPrivateGroups { - resultTags.insert(.privateChat) - resultTags.insert(.secretChat) - resultTags.insert(.bot) - resultTags.insert(.privateGroup) - } else if legacyTag == .publicGroups { - resultTags.insert(.publicGroup) - } else if legacyTag == .channels { - resultTags.insert(.channel) - } - } - self.totalUnreadCountIncludeTags = resultTags - } else { - self.totalUnreadCountIncludeTags = [.privateChat, .secretChat, .bot, .privateGroup] - } - self.displayNameOnLockscreen = decoder.decodeInt32ForKey("displayNameOnLockscreen", orElse: 1) != 0 - self.displayNotificationsFromAllAccounts = decoder.decodeInt32ForKey("displayNotificationsFromAllAccounts", orElse: 1) != 0 - } - - public func encode(_ encoder: PostboxEncoder) { - encoder.encodeInt32(self.playSounds ? 1 : 0, forKey: "s") - encoder.encodeInt32(self.vibrate ? 1 : 0, forKey: "v") - encoder.encodeInt32(self.displayPreviews ? 1 : 0, forKey: "p") - encoder.encodeInt32(self.totalUnreadCountDisplayStyle.rawValue, forKey: "cds") - encoder.encodeInt32(self.totalUnreadCountDisplayCategory.rawValue, forKey: "totalUnreadCountDisplayCategory") - encoder.encodeInt32(self.totalUnreadCountIncludeTags.rawValue, forKey: "totalUnreadCountIncludeTags_2") - encoder.encodeInt32(self.displayNameOnLockscreen ? 1 : 0, forKey: "displayNameOnLockscreen") - encoder.encodeInt32(self.displayNotificationsFromAllAccounts ? 1 : 0, forKey: "displayNotificationsFromAllAccounts") - } - - public func isEqual(to: PreferencesEntry) -> Bool { - if let to = to as? InAppNotificationSettings { - return self == to - } else { - return false - } - } -} -*/ diff --git a/Telegram/Telegram-iOS/en.lproj/Localizable.strings b/Telegram/Telegram-iOS/en.lproj/Localizable.strings index 236b64105b..a50d0d276c 100644 --- a/Telegram/Telegram-iOS/en.lproj/Localizable.strings +++ b/Telegram/Telegram-iOS/en.lproj/Localizable.strings @@ -6766,7 +6766,9 @@ Sorry for the inconvenience."; "Channel.AdminLog.MessageChangedThemeRemove" = "%1$@ disabled chat theme"; "SponsoredMessageMenu.Info" = "What are sponsored\nmessages?"; -"SponsoredMessageInfo.Text" = "See https://telegram.org"; +"SponsoredMessageInfo.Text" = "Unlike other apps, Telegram never uses your private data to target ads. No user data is mined or analyzed to display ads, and every user viewing a channel on Telegram sees the same sponsored message. We believe that everyone has the right to privacy, and technological platforms should respect that. + +More at: https://ads.telegram.org"; "SponsoredMessageInfo.Action" = "Learn More"; "SponsoredMessageInfo.ActionUrl" = "https://telegram.org"; diff --git a/submodules/Postbox/BUILD b/submodules/Postbox/BUILD index 6b5bb10a2d..7c870ad8ae 100644 --- a/submodules/Postbox/BUILD +++ b/submodules/Postbox/BUILD @@ -6,6 +6,9 @@ swift_library( srcs = glob([ "Sources/**/*.swift", ]), + copts = [ + "-warnings-as-errors", + ], deps = [ "//submodules/Crc32:Crc32", "//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit", diff --git a/submodules/Postbox/Sources/AccountManagerSharedDataTable.swift b/submodules/Postbox/Sources/AccountManagerSharedDataTable.swift index b6eacb5ca0..b5dc4f7b92 100644 --- a/submodules/Postbox/Sources/AccountManagerSharedDataTable.swift +++ b/submodules/Postbox/Sources/AccountManagerSharedDataTable.swift @@ -11,8 +11,8 @@ final class AccountManagerSharedDataTable: Table { func get(key: ValueBoxKey) -> PreferencesEntry? { if let object = self.values[key] { return object - } else if let value = self.valueBox.get(self.table, key: key), let object = PostboxDecoder(buffer: value).decodeRootObject() as? PreferencesEntry { - return object + } else if let value = self.valueBox.get(self.table, key: key) { + return PreferencesEntry(data: value.makeData()) } else { return nil } @@ -20,12 +20,10 @@ final class AccountManagerSharedDataTable: Table { func set(key: ValueBoxKey, value: PreferencesEntry?, updatedKeys: inout Set) { if let value = value { - if let current = self.get(key: key), current.isEqual(to: value) { + if let current = self.get(key: key), current == value { return } - let encoder = PostboxEncoder() - encoder.encodeRootObject(value) - self.valueBox.set(self.table, key: key, value: encoder.makeReadBufferAndReset()) + self.valueBox.set(self.table, key: key, value: ReadBuffer(data: value.data)) updatedKeys.insert(key) self.values[key] = value diff --git a/submodules/Postbox/Sources/ChatListHole.swift b/submodules/Postbox/Sources/ChatListHole.swift index c03ca3e1ca..8b3d00c6c9 100644 --- a/submodules/Postbox/Sources/ChatListHole.swift +++ b/submodules/Postbox/Sources/ChatListHole.swift @@ -10,10 +10,6 @@ public struct ChatListHole: Hashable, CustomStringConvertible { public var description: String { return "ChatListHole(\(self.index.id), \(self.index.timestamp))" } - - public var hashValue: Int { - return self.index.hashValue - } public static func <(lhs: ChatListHole, rhs: ChatListHole) -> Bool { return lhs.index < rhs.index diff --git a/submodules/Postbox/Sources/ChatListIndexTable.swift b/submodules/Postbox/Sources/ChatListIndexTable.swift index f44ade7157..c55218901f 100644 --- a/submodules/Postbox/Sources/ChatListIndexTable.swift +++ b/submodules/Postbox/Sources/ChatListIndexTable.swift @@ -170,7 +170,7 @@ final class ChatListIndexTable: Table { assert(self.updatedPreviousPeerCachedIndices.isEmpty) } - func commitWithTransaction(postbox: Postbox, alteredInitialPeerCombinedReadStates: [PeerId: CombinedPeerReadState], updatedPeers: [((Peer, Bool)?, (Peer, Bool))], transactionParticipationInTotalUnreadCountUpdates: (added: Set, removed: Set), updatedTotalUnreadStates: inout [PeerGroupId: ChatListTotalUnreadState], updatedGroupTotalUnreadSummaries: inout [PeerGroupId: PeerGroupUnreadCountersCombinedSummary], currentUpdatedGroupSummarySynchronizeOperations: inout [PeerGroupAndNamespace: Bool]) { + func commitWithTransaction(postbox: Postbox, currentTransaction: Transaction, alteredInitialPeerCombinedReadStates: [PeerId: CombinedPeerReadState], updatedPeers: [((Peer, Bool)?, (Peer, Bool))], transactionParticipationInTotalUnreadCountUpdates: (added: Set, removed: Set), updatedTotalUnreadStates: inout [PeerGroupId: ChatListTotalUnreadState], updatedGroupTotalUnreadSummaries: inout [PeerGroupId: PeerGroupUnreadCountersCombinedSummary], currentUpdatedGroupSummarySynchronizeOperations: inout [PeerGroupAndNamespace: Bool]) { var updatedPeerTags: [PeerId: (previous: PeerSummaryCounterTags, updated: PeerSummaryCounterTags)] = [:] for (previous, updated) in updatedPeers { let previousTags: PeerSummaryCounterTags @@ -339,7 +339,7 @@ final class ChatListIndexTable: Table { var updatedTotalStates: [PeerGroupId: ChatListTotalUnreadState] = [:] var updatedTotalUnreadSummaries: [PeerGroupId: PeerGroupUnreadCountersCombinedSummary] = [:] - let globalNotificationSettings = postbox.getGlobalNotificationSettings() + let globalNotificationSettings = postbox.getGlobalNotificationSettings(transaction: currentTransaction) for peerId in alteredPeerIds { guard let peer = postbox.peerTable.get(peerId) else { @@ -556,8 +556,8 @@ final class ChatListIndexTable: Table { assert(self.updatedPreviousPeerCachedIndices.isEmpty) } - func debugReindexUnreadCounts(postbox: Postbox) -> ([PeerGroupId: ChatListTotalUnreadState], [PeerGroupId: PeerGroupUnreadCountersCombinedSummary]) { - let globalNotificationSettings = postbox.getGlobalNotificationSettings() + func debugReindexUnreadCounts(postbox: Postbox, currentTransaction: Transaction) -> ([PeerGroupId: ChatListTotalUnreadState], [PeerGroupId: PeerGroupUnreadCountersCombinedSummary]) { + let globalNotificationSettings = postbox.getGlobalNotificationSettings(transaction: currentTransaction) var peerIds: [PeerId] = [] for groupId in postbox.chatListTable.existingGroups() + [.root] { @@ -575,7 +575,6 @@ final class ChatListIndexTable: Table { } let isContact = postbox.contactsTable.isContact(peerId: peerId) let notificationPeerId: PeerId = peer.associatedPeerId ?? peerId - let notificationSettings = postbox.peerNotificationSettingsTable.getEffective(notificationPeerId) let inclusion = self.get(peerId: peerId) if let (groupId, _) = inclusion.includedIndex(peerId: peerId) { if totalStates[groupId] == nil { diff --git a/submodules/Postbox/Sources/ChatListTable.swift b/submodules/Postbox/Sources/ChatListTable.swift index 107c7860d5..5c7428d278 100644 --- a/submodules/Postbox/Sources/ChatListTable.swift +++ b/submodules/Postbox/Sources/ChatListTable.swift @@ -115,8 +115,8 @@ public enum ChatListNamespaceEntry { public var index: ChatListIndex { switch self { - case let .peer(peer): - return peer.index + case let .peer(index, _, _, _, _): + return index case let .hole(index): return ChatListIndex(pinningIndex: nil, messageIndex: index) } @@ -245,8 +245,8 @@ final class ChatListTable: Table { } } - func getUnreadChatListPeerIds(postbox: Postbox, groupId: PeerGroupId, filterPredicate: ChatListFilterPredicate?) -> [PeerId] { - let globalNotificationSettings = postbox.getGlobalNotificationSettings() + func getUnreadChatListPeerIds(postbox: Postbox, currentTransaction: Transaction, groupId: PeerGroupId, filterPredicate: ChatListFilterPredicate?) -> [PeerId] { + let globalNotificationSettings = postbox.getGlobalNotificationSettings(transaction: currentTransaction) var result: [PeerId] = [] self.valueBox.range(self.table, start: self.upperBound(groupId: groupId), end: self.lowerBound(groupId: groupId), keys: { key in @@ -797,13 +797,13 @@ final class ChatListTable: Table { return entries } - func getRelativeUnreadChatListIndex(postbox: Postbox, filtered: Bool, position: ChatListRelativePosition, groupId: PeerGroupId) -> ChatListIndex? { + func getRelativeUnreadChatListIndex(postbox: Postbox, currentTransaction: Transaction, filtered: Bool, position: ChatListRelativePosition, groupId: PeerGroupId) -> ChatListIndex? { var result: ChatListIndex? let lower: ValueBoxKey let upper: ValueBoxKey - let globalNotificationSettings = postbox.getGlobalNotificationSettings() + let globalNotificationSettings = postbox.getGlobalNotificationSettings(transaction: currentTransaction) switch position { case let .earlier(index): diff --git a/submodules/Postbox/Sources/ChatListView.swift b/submodules/Postbox/Sources/ChatListView.swift index 4c32c8dce4..e4fc9fa249 100644 --- a/submodules/Postbox/Sources/ChatListView.swift +++ b/submodules/Postbox/Sources/ChatListView.swift @@ -337,7 +337,7 @@ final class MutableChatListView { private var additionalItems: [AdditionalChatListItem] = [] fileprivate var additionalItemEntries: [MutableChatListAdditionalItemEntry] = [] - init(postbox: Postbox, groupId: PeerGroupId, filterPredicate: ChatListFilterPredicate?, aroundIndex: ChatListIndex, count: Int, summaryComponents: ChatListEntrySummaryComponents) { + init(postbox: Postbox, currentTransaction: Transaction, groupId: PeerGroupId, filterPredicate: ChatListFilterPredicate?, aroundIndex: ChatListIndex, count: Int, summaryComponents: ChatListEntrySummaryComponents) { self.groupId = groupId self.filterPredicate = filterPredicate self.summaryComponents = summaryComponents @@ -358,8 +358,8 @@ final class MutableChatListView { spaces.append(.group(groupId: self.groupId, pinned: .includePinned, predicate: filterPredicate)) } self.spaces = spaces - self.state = ChatListViewState(postbox: postbox, spaces: self.spaces, anchorIndex: aroundIndex, summaryComponents: self.summaryComponents, halfLimit: count) - self.sampledState = self.state.sample(postbox: postbox) + self.state = ChatListViewState(postbox: postbox, currentTransaction: currentTransaction, spaces: self.spaces, anchorIndex: aroundIndex, summaryComponents: self.summaryComponents, halfLimit: count) + self.sampledState = self.state.sample(postbox: postbox, currentTransaction: currentTransaction) self.count = count @@ -451,11 +451,11 @@ final class MutableChatListView { } } - func refreshDueToExternalTransaction(postbox: Postbox) -> Bool { + func refreshDueToExternalTransaction(postbox: Postbox, currentTransaction: Transaction) -> Bool { var updated = false - self.state = ChatListViewState(postbox: postbox, spaces: self.spaces, anchorIndex: .absoluteUpperBound, summaryComponents: self.summaryComponents, halfLimit: self.count) - self.sampledState = self.state.sample(postbox: postbox) + self.state = ChatListViewState(postbox: postbox, currentTransaction: currentTransaction, spaces: self.spaces, anchorIndex: .absoluteUpperBound, summaryComponents: self.summaryComponents, halfLimit: self.count) + self.sampledState = self.state.sample(postbox: postbox, currentTransaction: currentTransaction) updated = true let currentGroupEntries = self.groupEntries @@ -469,16 +469,16 @@ final class MutableChatListView { return updated } - func replay(postbox: Postbox, operations: [PeerGroupId: [ChatListOperation]], updatedPeerNotificationSettings: [PeerId: (PeerNotificationSettings?, PeerNotificationSettings)], updatedPeers: [PeerId: Peer], updatedPeerPresences: [PeerId: PeerPresence], transaction: PostboxTransaction, context: MutableChatListViewReplayContext) -> Bool { + func replay(postbox: Postbox, currentTransaction: Transaction, operations: [PeerGroupId: [ChatListOperation]], updatedPeerNotificationSettings: [PeerId: (PeerNotificationSettings?, PeerNotificationSettings)], updatedPeers: [PeerId: Peer], updatedPeerPresences: [PeerId: PeerPresence], transaction: PostboxTransaction, context: MutableChatListViewReplayContext) -> Bool { var hasChanges = false if transaction.updatedGlobalNotificationSettings && self.filterPredicate != nil { - self.state = ChatListViewState(postbox: postbox, spaces: self.spaces, anchorIndex: .absoluteUpperBound, summaryComponents: self.summaryComponents, halfLimit: self.count) - self.sampledState = self.state.sample(postbox: postbox) + self.state = ChatListViewState(postbox: postbox, currentTransaction: currentTransaction, spaces: self.spaces, anchorIndex: .absoluteUpperBound, summaryComponents: self.summaryComponents, halfLimit: self.count) + self.sampledState = self.state.sample(postbox: postbox, currentTransaction: currentTransaction) hasChanges = true } else { - if self.state.replay(postbox: postbox, transaction: transaction) { - self.sampledState = self.state.sample(postbox: postbox) + if self.state.replay(postbox: postbox, currentTransaction: currentTransaction, transaction: transaction) { + self.sampledState = self.state.sample(postbox: postbox, currentTransaction: currentTransaction) hasChanges = true } } diff --git a/submodules/Postbox/Sources/ChatListViewState.swift b/submodules/Postbox/Sources/ChatListViewState.swift index 02b160bae6..473bc8f32b 100644 --- a/submodules/Postbox/Sources/ChatListViewState.swift +++ b/submodules/Postbox/Sources/ChatListViewState.swift @@ -53,8 +53,8 @@ enum ChatListViewSpace: Hashable { } } -private func mappedChatListFilterPredicate(postbox: Postbox, groupId: PeerGroupId, predicate: ChatListFilterPredicate) -> (ChatListIntermediateEntry) -> Bool { - let globalNotificationSettings = postbox.getGlobalNotificationSettings() +private func mappedChatListFilterPredicate(postbox: Postbox, currentTransaction: Transaction, groupId: PeerGroupId, predicate: ChatListFilterPredicate) -> (ChatListIntermediateEntry) -> Bool { + let globalNotificationSettings = postbox.getGlobalNotificationSettings(transaction: currentTransaction) return { entry in switch entry { case let .message(index, _): @@ -131,18 +131,18 @@ private final class ChatListViewSpaceState { var orderedEntries: OrderedChatListViewEntries - init(postbox: Postbox, space: ChatListViewSpace, anchorIndex: MutableChatListEntryIndex, summaryComponents: ChatListEntrySummaryComponents, halfLimit: Int) { + init(postbox: Postbox, currentTransaction: Transaction, space: ChatListViewSpace, anchorIndex: MutableChatListEntryIndex, summaryComponents: ChatListEntrySummaryComponents, halfLimit: Int) { self.space = space self.anchorIndex = anchorIndex self.summaryComponents = summaryComponents self.halfLimit = halfLimit self.orderedEntries = OrderedChatListViewEntries(anchorIndex: anchorIndex.index, lowerOrAtAnchor: [], higherThanAnchor: []) - self.fillSpace(postbox: postbox) + self.fillSpace(postbox: postbox, currentTransaction: currentTransaction) self.checkEntries(postbox: postbox) } - private func fillSpace(postbox: Postbox) { + private func fillSpace(postbox: Postbox, currentTransaction: Transaction) { switch self.space { case let .group(groupId, pinned, filterPredicate): let lowerBound: MutableChatListEntryIndex @@ -180,7 +180,7 @@ private final class ChatListViewSpaceState { let resolvedUnpinnedAnchorIndex = min(unpinnedUpperBound, max(self.anchorIndex, unpinnedLowerBound)) if lowerOrAtAnchorMessages.count < self.halfLimit || higherThanAnchorMessages.count < self.halfLimit { - let loadedMessages = postbox.chatListTable.entries(groupId: groupId, from: (ChatListIndex.pinnedLowerBound, true), to: (ChatListIndex.absoluteUpperBound, true), peerChatInterfaceStateTable: postbox.peerChatInterfaceStateTable, count: self.halfLimit * 2, predicate: filterPredicate.flatMap { mappedChatListFilterPredicate(postbox: postbox, groupId: groupId, predicate: $0) }).map(mapEntry).sorted(by: { $0.entryIndex < $1.entryIndex }) + let loadedMessages = postbox.chatListTable.entries(groupId: groupId, from: (ChatListIndex.pinnedLowerBound, true), to: (ChatListIndex.absoluteUpperBound, true), peerChatInterfaceStateTable: postbox.peerChatInterfaceStateTable, count: self.halfLimit * 2, predicate: filterPredicate.flatMap { mappedChatListFilterPredicate(postbox: postbox, currentTransaction: currentTransaction, groupId: groupId, predicate: $0) }).map(mapEntry).sorted(by: { $0.entryIndex < $1.entryIndex }) if lowerOrAtAnchorMessages.count < self.halfLimit { var nextLowerIndex: MutableChatListEntryIndex @@ -219,7 +219,7 @@ private final class ChatListViewSpaceState { } else { nextLowerIndex = resolvedAnchorIndex.successor } - let loadedLowerMessages = postbox.chatListTable.entries(groupId: groupId, from: (nextLowerIndex.index, nextLowerIndex.isMessage), to: (lowerBound.index, lowerBound.isMessage), peerChatInterfaceStateTable: postbox.peerChatInterfaceStateTable, count: self.halfLimit - lowerOrAtAnchorMessages.count, predicate: filterPredicate.flatMap { mappedChatListFilterPredicate(postbox: postbox, groupId: groupId, predicate: $0) }).map(mapEntry) + let loadedLowerMessages = postbox.chatListTable.entries(groupId: groupId, from: (nextLowerIndex.index, nextLowerIndex.isMessage), to: (lowerBound.index, lowerBound.isMessage), peerChatInterfaceStateTable: postbox.peerChatInterfaceStateTable, count: self.halfLimit - lowerOrAtAnchorMessages.count, predicate: filterPredicate.flatMap { mappedChatListFilterPredicate(postbox: postbox, currentTransaction: currentTransaction, groupId: groupId, predicate: $0) }).map(mapEntry) lowerOrAtAnchorMessages.append(contentsOf: loadedLowerMessages) } if higherThanAnchorMessages.count < self.halfLimit { @@ -229,7 +229,7 @@ private final class ChatListViewSpaceState { } else { nextHigherIndex = resolvedAnchorIndex } - let loadedHigherMessages = postbox.chatListTable.entries(groupId: groupId, from: (nextHigherIndex.index, nextHigherIndex.isMessage), to: (upperBound.index, upperBound.isMessage), peerChatInterfaceStateTable: postbox.peerChatInterfaceStateTable, count: self.halfLimit - higherThanAnchorMessages.count, predicate: filterPredicate.flatMap { mappedChatListFilterPredicate(postbox: postbox, groupId: groupId, predicate: $0) }).map(mapEntry) + let loadedHigherMessages = postbox.chatListTable.entries(groupId: groupId, from: (nextHigherIndex.index, nextHigherIndex.isMessage), to: (upperBound.index, upperBound.isMessage), peerChatInterfaceStateTable: postbox.peerChatInterfaceStateTable, count: self.halfLimit - higherThanAnchorMessages.count, predicate: filterPredicate.flatMap { mappedChatListFilterPredicate(postbox: postbox, currentTransaction: currentTransaction, groupId: groupId, predicate: $0) }).map(mapEntry) higherThanAnchorMessages.append(contentsOf: loadedHigherMessages) } } @@ -370,7 +370,7 @@ private final class ChatListViewSpaceState { assert(self.orderedEntries.higherThanAnchor.count <= self.halfLimit) } - func replay(postbox: Postbox, transaction: PostboxTransaction) -> Bool { + func replay(postbox: Postbox, currentTransaction: Transaction, transaction: PostboxTransaction) -> Bool { var hasUpdates = false var hadRemovals = false var globalNotificationSettings: PostboxGlobalNotificationSettings? @@ -396,7 +396,7 @@ private final class ChatListViewSpaceState { if let current = globalNotificationSettings { globalNotificationSettingsValue = current } else { - globalNotificationSettingsValue = postbox.getGlobalNotificationSettings() + globalNotificationSettingsValue = postbox.getGlobalNotificationSettings(transaction: currentTransaction) globalNotificationSettings = globalNotificationSettingsValue } @@ -502,15 +502,15 @@ private final class ChatListViewSpaceState { let entryPeer: Peer let entryNotificationsPeerId: PeerId switch entry { - case let .MessageEntry(messageEntry): - if let peer = messageEntry.renderedPeer.peer { + case let .MessageEntry(_, _, _, _, _, _, renderedPeer, _, _, _, _): + if let peer = renderedPeer.peer { entryPeer = peer entryNotificationsPeerId = peer.notificationSettingsPeerId ?? peer.id } else { return nil } - case let .IntermediateMessageEntry(intermediateMessageEntry): - if let peer = postbox.peerTable.get(intermediateMessageEntry.index.messageIndex.id.peerId) { + case let .IntermediateMessageEntry(index, _): + if let peer = postbox.peerTable.get(index.messageIndex.id.peerId) { entryPeer = peer entryNotificationsPeerId = peer.notificationSettingsPeerId ?? peer.id } else { @@ -526,7 +526,7 @@ private final class ChatListViewSpaceState { if let current = globalNotificationSettings { globalNotificationSettingsValue = current } else { - globalNotificationSettingsValue = postbox.getGlobalNotificationSettings() + globalNotificationSettingsValue = postbox.getGlobalNotificationSettings(transaction: currentTransaction) globalNotificationSettings = globalNotificationSettingsValue } @@ -564,7 +564,7 @@ private final class ChatListViewSpaceState { if let current = globalNotificationSettings { globalNotificationSettingsValue = current } else { - globalNotificationSettingsValue = postbox.getGlobalNotificationSettings() + globalNotificationSettingsValue = postbox.getGlobalNotificationSettings(transaction: currentTransaction) globalNotificationSettings = globalNotificationSettingsValue } @@ -600,11 +600,11 @@ private final class ChatListViewSpaceState { } if !transaction.currentUpdatedPeerNotificationSettings.isEmpty { - let globalNotificationSettings = postbox.getGlobalNotificationSettings() + let globalNotificationSettings = postbox.getGlobalNotificationSettings(transaction: currentTransaction) if self.orderedEntries.mutableScan({ entry in switch entry { - case let .MessageEntry(index, messages, readState, notificationSettings, isRemovedFromTotalUnreadCount, embeddedInterfaceState, renderedPeer, presence, tagSummaryInfo, hasFailedMessages, isContact): + case let .MessageEntry(index, messages, readState, _, _, embeddedInterfaceState, renderedPeer, presence, tagSummaryInfo, hasFailedMessages, isContact): if let peer = renderedPeer.peer { let notificationsPeerId = peer.notificationSettingsPeerId ?? peer.id if let (_, updated) = transaction.currentUpdatedPeerNotificationSettings[notificationsPeerId] { @@ -628,9 +628,21 @@ private final class ChatListViewSpaceState { if !transaction.updatedFailedMessagePeerIds.isEmpty { if self.orderedEntries.mutableScan({ entry in switch entry { - case let .MessageEntry(messageEntry): - if transaction.updatedFailedMessagePeerIds.contains(messageEntry.index.messageIndex.id.peerId) { - return .MessageEntry(index: messageEntry.index, messages: messageEntry.messages, readState: messageEntry.readState, notificationSettings: messageEntry.notificationSettings, isRemovedFromTotalUnreadCount: messageEntry.isRemovedFromTotalUnreadCount, embeddedInterfaceState: messageEntry.embeddedInterfaceState, renderedPeer: messageEntry.renderedPeer, presence: messageEntry.presence, tagSummaryInfo: messageEntry.tagSummaryInfo, hasFailedMessages: postbox.messageHistoryFailedTable.contains(peerId: messageEntry.index.messageIndex.id.peerId), isContact: messageEntry.isContact) + case let .MessageEntry(index, messages, readState, notificationSettings, isRemovedFromTotalUnreadCount, embeddedInterfaceState, renderedPeer, presence, tagSummaryInfo, _, isContact): + if transaction.updatedFailedMessagePeerIds.contains(index.messageIndex.id.peerId) { + return .MessageEntry( + index: index, + messages: messages, + readState: readState, + notificationSettings: notificationSettings, + isRemovedFromTotalUnreadCount: isRemovedFromTotalUnreadCount, + embeddedInterfaceState: embeddedInterfaceState, + renderedPeer: renderedPeer, + presence: presence, + tagSummaryInfo: tagSummaryInfo, + hasFailedMessages: postbox.messageHistoryFailedTable.contains(peerId: index.messageIndex.id.peerId), + isContact: isContact + ) } else { return nil } @@ -645,8 +657,8 @@ private final class ChatListViewSpaceState { if !transaction.currentUpdatedPeers.isEmpty { if self.orderedEntries.mutableScan({ entry in switch entry { - case let .MessageEntry(messageEntry): - var updatedMessages: [Message] = messageEntry.messages + case let .MessageEntry(index, messages, readState, notificationSettings, isRemovedFromTotalUnreadCount, embeddedInterfaceState, entryRenderedPeer, presence, tagSummaryInfo, hasFailedMessages, isContact): + var updatedMessages: [Message] = messages var hasUpdatedMessages = false for i in 0 ..< updatedMessages.count { if let updatedMessage = updateMessagePeers(updatedMessages[i], updatedPeers: transaction.currentUpdatedPeers) { @@ -654,10 +666,21 @@ private final class ChatListViewSpaceState { hasUpdatedMessages = true } } - let renderedPeer = updatedRenderedPeer(messageEntry.renderedPeer, updatedPeers: transaction.currentUpdatedPeers) + let renderedPeer = updatedRenderedPeer(entryRenderedPeer, updatedPeers: transaction.currentUpdatedPeers) if hasUpdatedMessages || renderedPeer != nil { - return .MessageEntry(index: messageEntry.index, messages: updatedMessages, readState: messageEntry.readState, notificationSettings: messageEntry.notificationSettings, isRemovedFromTotalUnreadCount: messageEntry.isRemovedFromTotalUnreadCount, embeddedInterfaceState: messageEntry.embeddedInterfaceState, renderedPeer: renderedPeer ?? messageEntry.renderedPeer, presence: messageEntry.presence, tagSummaryInfo: messageEntry.tagSummaryInfo, hasFailedMessages: messageEntry.hasFailedMessages, isContact: messageEntry.isContact) + return .MessageEntry( + index: index, + messages: updatedMessages, + readState: readState, + notificationSettings: notificationSettings, + isRemovedFromTotalUnreadCount: isRemovedFromTotalUnreadCount, + embeddedInterfaceState: embeddedInterfaceState, + renderedPeer: renderedPeer ?? entryRenderedPeer, + presence: presence, + tagSummaryInfo: tagSummaryInfo, + hasFailedMessages: hasFailedMessages, + isContact: isContact) } else { return nil } @@ -672,13 +695,25 @@ private final class ChatListViewSpaceState { if !transaction.currentUpdatedPeerPresences.isEmpty { if self.orderedEntries.mutableScan({ entry in switch entry { - case let .MessageEntry(messageEntry): - var presencePeerId = messageEntry.renderedPeer.peerId - if let peer = messageEntry.renderedPeer.peers[messageEntry.renderedPeer.peerId], let associatedPeerId = peer.associatedPeerId { + case let .MessageEntry(index, messages, readState, notificationSettings, isRemovedFromTotalUnreadCount, embeddedInterfaceState, entryRenderedPeer, _, tagSummaryInfo, hasFailedMessages, isContact): + var presencePeerId = entryRenderedPeer.peerId + if let peer = entryRenderedPeer.peers[entryRenderedPeer.peerId], let associatedPeerId = peer.associatedPeerId { presencePeerId = associatedPeerId } if let presence = transaction.currentUpdatedPeerPresences[presencePeerId] { - return .MessageEntry(index: messageEntry.index, messages: messageEntry.messages, readState: messageEntry.readState, notificationSettings: messageEntry.notificationSettings, isRemovedFromTotalUnreadCount: messageEntry.isRemovedFromTotalUnreadCount, embeddedInterfaceState: messageEntry.embeddedInterfaceState, renderedPeer: messageEntry.renderedPeer, presence: presence, tagSummaryInfo: messageEntry.tagSummaryInfo, hasFailedMessages: messageEntry.hasFailedMessages, isContact: messageEntry.isContact) + return .MessageEntry( + index: index, + messages: messages, + readState: readState, + notificationSettings: notificationSettings, + isRemovedFromTotalUnreadCount: isRemovedFromTotalUnreadCount, + embeddedInterfaceState: embeddedInterfaceState, + renderedPeer: entryRenderedPeer, + presence: presence, + tagSummaryInfo: tagSummaryInfo, + hasFailedMessages: hasFailedMessages, + isContact: isContact + ) } else { return nil } @@ -696,15 +731,15 @@ private final class ChatListViewSpaceState { let entryPeer: Peer let entryNotificationsPeerId: PeerId switch entry { - case let .MessageEntry(messageEntry): - if let peer = messageEntry.renderedPeer.peer { + case let .MessageEntry(_, _, _, _, _, _, entryRenderedPeer, _, _, _, _): + if let peer = entryRenderedPeer.peer { entryPeer = peer entryNotificationsPeerId = peer.notificationSettingsPeerId ?? peer.id } else { return nil } - case let .IntermediateMessageEntry(intermediateMessageEntry): - if let peer = postbox.peerTable.get(intermediateMessageEntry.index.messageIndex.id.peerId) { + case let .IntermediateMessageEntry(index, _): + if let peer = postbox.peerTable.get(index.messageIndex.id.peerId) { entryPeer = peer entryNotificationsPeerId = peer.notificationSettingsPeerId ?? peer.id } else { @@ -724,7 +759,7 @@ private final class ChatListViewSpaceState { if let current = globalNotificationSettings { globalNotificationSettingsValue = current } else { - globalNotificationSettingsValue = postbox.getGlobalNotificationSettings() + globalNotificationSettingsValue = postbox.getGlobalNotificationSettings(transaction: currentTransaction) globalNotificationSettings = globalNotificationSettingsValue } @@ -769,7 +804,7 @@ private final class ChatListViewSpaceState { if let current = globalNotificationSettings { globalNotificationSettingsValue = current } else { - globalNotificationSettingsValue = postbox.getGlobalNotificationSettings() + globalNotificationSettingsValue = postbox.getGlobalNotificationSettings(transaction: currentTransaction) globalNotificationSettings = globalNotificationSettingsValue } @@ -807,28 +842,40 @@ private final class ChatListViewSpaceState { if !transaction.currentUpdatedMessageTagSummaries.isEmpty || !transaction.currentUpdatedMessageActionsSummaries.isEmpty { if self.orderedEntries.mutableScan({ entry in switch entry { - case let .MessageEntry(messageEntry): + case let .MessageEntry(index, messages, readState, notificationSettings, isRemovedFromTotalUnreadCount, embeddedInterfaceState, entryRenderedPeer, presence, tagSummaryInfo, hasFailedMessages, isContact): var updatedTagSummaryCount: Int32? var updatedActionsSummaryCount: Int32? if let tagSummary = self.summaryComponents.tagSummary { - let key = MessageHistoryTagsSummaryKey(tag: tagSummary.tag, peerId: messageEntry.index.messageIndex.id.peerId, namespace: tagSummary.namespace) + let key = MessageHistoryTagsSummaryKey(tag: tagSummary.tag, peerId: index.messageIndex.id.peerId, namespace: tagSummary.namespace) if let summary = transaction.currentUpdatedMessageTagSummaries[key] { updatedTagSummaryCount = summary.count } } if let actionsSummary = self.summaryComponents.actionsSummary { - let key = PendingMessageActionsSummaryKey(type: actionsSummary.type, peerId: messageEntry.index.messageIndex.id.peerId, namespace: actionsSummary.namespace) + let key = PendingMessageActionsSummaryKey(type: actionsSummary.type, peerId: index.messageIndex.id.peerId, namespace: actionsSummary.namespace) if let count = transaction.currentUpdatedMessageActionsSummaries[key] { updatedActionsSummaryCount = count } } if updatedTagSummaryCount != nil || updatedActionsSummaryCount != nil { - let summaryInfo = ChatListMessageTagSummaryInfo(tagSummaryCount: updatedTagSummaryCount ?? messageEntry.tagSummaryInfo.tagSummaryCount, actionsSummaryCount: updatedActionsSummaryCount ?? messageEntry.tagSummaryInfo.actionsSummaryCount) + let summaryInfo = ChatListMessageTagSummaryInfo(tagSummaryCount: updatedTagSummaryCount ?? tagSummaryInfo.tagSummaryCount, actionsSummaryCount: updatedActionsSummaryCount ?? tagSummaryInfo.actionsSummaryCount) - return .MessageEntry(index: messageEntry.index, messages: messageEntry.messages, readState: messageEntry.readState, notificationSettings: messageEntry.notificationSettings, isRemovedFromTotalUnreadCount: messageEntry.isRemovedFromTotalUnreadCount, embeddedInterfaceState: messageEntry.embeddedInterfaceState, renderedPeer: messageEntry.renderedPeer, presence: messageEntry.presence, tagSummaryInfo: summaryInfo, hasFailedMessages: messageEntry.hasFailedMessages, isContact: messageEntry.isContact) + return .MessageEntry( + index: index, + messages: messages, + readState: readState, + notificationSettings: notificationSettings, + isRemovedFromTotalUnreadCount: isRemovedFromTotalUnreadCount, + embeddedInterfaceState: embeddedInterfaceState, + renderedPeer: entryRenderedPeer, + presence: presence, + tagSummaryInfo: summaryInfo, + hasFailedMessages: hasFailedMessages, + isContact: isContact + ) } else { return nil } @@ -841,7 +888,7 @@ private final class ChatListViewSpaceState { } if true || hadRemovals { - self.fillSpace(postbox: postbox) + self.fillSpace(postbox: postbox, currentTransaction: currentTransaction) } self.checkEntries(postbox: postbox) @@ -866,7 +913,7 @@ private final class ChatListViewSpaceState { } } - let loadedEntries = postbox.chatListTable.entries(groupId: .root, from: (allEntries[0].index.predecessor, true), to: (allEntries[allEntries.count - 1].index.successor, true), peerChatInterfaceStateTable: postbox.peerChatInterfaceStateTable, count: 1000, predicate: nil).map(mapEntry) + //let loadedEntries = postbox.chatListTable.entries(groupId: .root, from: (allEntries[0].index.predecessor, true), to: (allEntries[allEntries.count - 1].index.successor, true), peerChatInterfaceStateTable: postbox.peerChatInterfaceStateTable, count: 1000, predicate: nil).map(mapEntry) //assert(loadedEntries.map({ $0.index }) == allEntries.map({ $0.index })) } @@ -876,7 +923,7 @@ private final class ChatListViewSpaceState { private func checkReplayEntries(postbox: Postbox) { #if DEBUG - let cleanState = ChatListViewSpaceState(postbox: postbox, space: self.space, anchorIndex: self.anchorIndex, summaryComponents: self.summaryComponents, halfLimit: self.halfLimit) + //let cleanState = ChatListViewSpaceState(postbox: postbox, space: self.space, anchorIndex: self.anchorIndex, summaryComponents: self.summaryComponents, halfLimit: self.halfLimit) //assert(self.orderedEntries.lowerOrAtAnchor.map { $0.index } == cleanState.orderedEntries.lowerOrAtAnchor.map { $0.index }) //assert(self.orderedEntries.higherThanAnchor.map { $0.index } == cleanState.orderedEntries.higherThanAnchor.map { $0.index }) #endif @@ -959,10 +1006,10 @@ private enum MutableChatListEntryEntityId: Hashable { private extension MutableChatListEntry { var messagePeerId: PeerId? { switch self { - case let .IntermediateMessageEntry(intermediateMessageEntry): - return intermediateMessageEntry.0.messageIndex.id.peerId - case let .MessageEntry(messageEntry): - return messageEntry.0.messageIndex.id.peerId + case let .IntermediateMessageEntry(index, _): + return index.messageIndex.id.peerId + case let .MessageEntry(index, _, _, _, _, _, _, _, _, _, _): + return index.messageIndex.id.peerId case .HoleEntry: return nil } @@ -970,10 +1017,10 @@ private extension MutableChatListEntry { var entryIndex: MutableChatListEntryIndex { switch self { - case let .IntermediateMessageEntry(intermediateMessageEntry): - return MutableChatListEntryIndex(index: intermediateMessageEntry.index, isMessage: true) - case let .MessageEntry(messageEntry): - return MutableChatListEntryIndex(index: messageEntry.index, isMessage: true) + case let .IntermediateMessageEntry(index, _): + return MutableChatListEntryIndex(index: index, isMessage: true) + case let .MessageEntry(index, _, _, _, _, _, _, _, _, _, _): + return MutableChatListEntryIndex(index: index, isMessage: true) case let .HoleEntry(hole): return MutableChatListEntryIndex(index: ChatListIndex(pinningIndex: nil, messageIndex: hole.index), isMessage: false) } @@ -981,10 +1028,10 @@ private extension MutableChatListEntry { var entityId: MutableChatListEntryEntityId { switch self { - case let .IntermediateMessageEntry(intermediateMessageEntry): - return .peer(intermediateMessageEntry.index.messageIndex.id.peerId) - case let .MessageEntry(messageEntry): - return .peer(messageEntry.index.messageIndex.id.peerId) + case let .IntermediateMessageEntry(index, _): + return .peer(index.messageIndex.id.peerId) + case let .MessageEntry(index, _, _, _, _, _, _, _, _, _, _): + return .peer(index.messageIndex.id.peerId) case let .HoleEntry(hole): return .hole(hole.index) } @@ -1218,20 +1265,20 @@ struct ChatListViewState { private let halfLimit: Int private var stateBySpace: [ChatListViewSpace: ChatListViewSpaceState] = [:] - init(postbox: Postbox, spaces: [ChatListViewSpace], anchorIndex: ChatListIndex, summaryComponents: ChatListEntrySummaryComponents, halfLimit: Int) { + init(postbox: Postbox, currentTransaction: Transaction, spaces: [ChatListViewSpace], anchorIndex: ChatListIndex, summaryComponents: ChatListEntrySummaryComponents, halfLimit: Int) { self.anchorIndex = MutableChatListEntryIndex(index: anchorIndex, isMessage: true) self.summaryComponents = summaryComponents self.halfLimit = halfLimit for space in spaces { - self.stateBySpace[space] = ChatListViewSpaceState(postbox: postbox, space: space, anchorIndex: self.anchorIndex, summaryComponents: summaryComponents, halfLimit: halfLimit) + self.stateBySpace[space] = ChatListViewSpaceState(postbox: postbox, currentTransaction: currentTransaction, space: space, anchorIndex: self.anchorIndex, summaryComponents: summaryComponents, halfLimit: halfLimit) } } - func replay(postbox: Postbox, transaction: PostboxTransaction) -> Bool { + func replay(postbox: Postbox, currentTransaction: Transaction, transaction: PostboxTransaction) -> Bool { var updated = false for (_, state) in self.stateBySpace { - if state.replay(postbox: postbox, transaction: transaction) { + if state.replay(postbox: postbox, currentTransaction: currentTransaction, transaction: transaction) { updated = true } } @@ -1314,7 +1361,7 @@ struct ChatListViewState { return (backwardsResult.reversed(), result) } - func sample(postbox: Postbox) -> ChatListViewSample { + func sample(postbox: Postbox, currentTransaction: Transaction) -> ChatListViewSample { let combinedSpacesAndIndicesByDirection = self.sampleIndices() var result: [(ChatListViewSpace, MutableChatListEntry)] = [] @@ -1382,7 +1429,7 @@ struct ChatListViewState { let isRemovedFromTotalUnreadCount: Bool if let peer = renderedPeer.peers[notificationsPeerId] { - isRemovedFromTotalUnreadCount = resolvedIsRemovedFromTotalUnreadCount(globalSettings: postbox.getGlobalNotificationSettings(), peer: peer, peerSettings: notificationSettings) + isRemovedFromTotalUnreadCount = resolvedIsRemovedFromTotalUnreadCount(globalSettings: postbox.getGlobalNotificationSettings(transaction: currentTransaction), peer: peer, peerSettings: notificationSettings) } else { isRemovedFromTotalUnreadCount = false } diff --git a/submodules/Postbox/Sources/Coding.swift b/submodules/Postbox/Sources/Coding.swift index c7437d6cb9..ed733889cd 100644 --- a/submodules/Postbox/Sources/Coding.swift +++ b/submodules/Postbox/Sources/Coding.swift @@ -544,7 +544,8 @@ public final class PostboxEncoder { for object in value { var length: Int32 = Int32(object.count) self.buffer.write(&length, offset: 0, length: 4) - object.withUnsafeBytes { (bytes: UnsafePointer) -> Void in + object.withUnsafeBytes { rawBytes -> Void in + let bytes = rawBytes.baseAddress!.assumingMemoryBound(to: UInt8.self) self.buffer.write(bytes, offset: 0, length: Int(length)) } } @@ -637,7 +638,8 @@ public final class PostboxEncoder { self.buffer.write(&type, offset: 0, length: 1) var bytesLength: Int32 = Int32(data.count) self.buffer.write(&bytesLength, offset: 0, length: 4) - data.withUnsafeBytes { (bytes: UnsafePointer) -> Void in + data.withUnsafeBytes { rawBytes -> Void in + let bytes = rawBytes.baseAddress!.assumingMemoryBound(to: UInt8.self) self.buffer.write(bytes, offset: 0, length: Int(bytesLength)) } } @@ -812,7 +814,8 @@ public final class PostboxDecoder { let keyData = key.data(using: .utf8)! - return keyData.withUnsafeBytes { (keyBytes: UnsafePointer) -> Bool in + return keyData.withUnsafeBytes { rawBytes -> Bool in + let keyBytes = rawBytes.baseAddress!.assumingMemoryBound(to: UInt8.self) let keyLength: Int = keyData.count while (offset < maxOffset) { let readKeyLength = bytes[offset] @@ -1702,7 +1705,8 @@ public final class PostboxDecoder { memcpy(&length, self.buffer.memory + self.offset, 4) self.offset += 4 + Int(length) var result = Data(count: Int(length)) - result.withUnsafeMutableBytes { (bytes: UnsafeMutablePointer) -> Void in + result.withUnsafeMutableBytes { rawBytes -> Void in + let bytes = rawBytes.baseAddress!.assumingMemoryBound(to: UInt8.self) memcpy(bytes, self.buffer.memory.advanced(by: self.offset - Int(length)), Int(length)) } return result diff --git a/submodules/Postbox/Sources/IpcPipe.swift b/submodules/Postbox/Sources/IpcPipe.swift index 9c1280f61a..1753bfc0f0 100644 --- a/submodules/Postbox/Sources/IpcPipe.swift +++ b/submodules/Postbox/Sources/IpcPipe.swift @@ -24,7 +24,6 @@ func ipcNotifications(basePath: String) -> Signal { if fd != -1 { let readSource = DispatchSource.makeFileSystemObjectSource(fileDescriptor: fd, eventMask: [.write]) - var previousValue: Int64 = 0 readSource.setEventHandler(handler: { subscriber.putNext(Int64.max) /*lseek(fd, 0, SEEK_SET) diff --git a/submodules/Postbox/Sources/ItemCacheTable.swift b/submodules/Postbox/Sources/ItemCacheTable.swift index a4607cd63d..cb59ab21fe 100644 --- a/submodules/Postbox/Sources/ItemCacheTable.swift +++ b/submodules/Postbox/Sources/ItemCacheTable.swift @@ -8,14 +8,15 @@ public final class ItemCacheEntryId: Equatable, Hashable { 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 } - - public var hashValue: Int { - return self.collectionId.hashValue &* 31 &+ self.key.hashValue - } } private enum ItemCacheSection: Int8 { diff --git a/submodules/Postbox/Sources/ItemCollection.swift b/submodules/Postbox/Sources/ItemCollection.swift index c42322acc0..e0a2a4b939 100644 --- a/submodules/Postbox/Sources/ItemCollection.swift +++ b/submodules/Postbox/Sources/ItemCollection.swift @@ -24,10 +24,6 @@ public struct ItemCollectionId: Comparable, Hashable { } } - public var hashValue: Int { - return self.id.hashValue - } - public static func encodeArrayToBuffer(_ array: [ItemCollectionId], buffer: WriteBuffer) { var length: Int32 = Int32(array.count) buffer.write(&length, offset: 0, length: 4) diff --git a/submodules/Postbox/Sources/ManagedFile.swift b/submodules/Postbox/Sources/ManagedFile.swift index 5891e95e17..e2a7336074 100644 --- a/submodules/Postbox/Sources/ManagedFile.swift +++ b/submodules/Postbox/Sources/ManagedFile.swift @@ -73,7 +73,8 @@ public final class ManagedFile { assert(queue.isCurrent()) } var result = Data(count: count) - result.withUnsafeMutableBytes { (bytes: UnsafeMutablePointer) -> Void in + result.withUnsafeMutableBytes { rawBytes -> Void in + let bytes = rawBytes.baseAddress!.assumingMemoryBound(to: Int8.self) let readCount = self.read(bytes, count) assert(readCount == count) } diff --git a/submodules/Postbox/Sources/Media.swift b/submodules/Postbox/Sources/Media.swift index 66dfc45bfd..0673d04a03 100644 --- a/submodules/Postbox/Sources/Media.swift +++ b/submodules/Postbox/Sources/Media.swift @@ -68,11 +68,11 @@ public struct MediaId: Hashable, PostboxCoding, CustomStringConvertible, Codable } } -public protocol AssociatedMediaData: class, PostboxCoding { +public protocol AssociatedMediaData: AnyObject, PostboxCoding { func isEqual(to: AssociatedMediaData) -> Bool } -public protocol Media: class, PostboxCoding { +public protocol Media: AnyObject, PostboxCoding { var id: MediaId? { get } var peerIds: [PeerId] { get } diff --git a/submodules/Postbox/Sources/MediaBox.swift b/submodules/Postbox/Sources/MediaBox.swift index f0abfe8281..46be289cc3 100644 --- a/submodules/Postbox/Sources/MediaBox.swift +++ b/submodules/Postbox/Sources/MediaBox.swift @@ -915,8 +915,9 @@ public final class MediaBox { case let .data(dataPart): let file = ManagedFile(queue: strongSelf.dataQueue, path: paths.partial, mode: .append) let dataCount = dataPart.count - dataPart.withUnsafeBytes { (bytes: UnsafePointer) -> Void in - file?.write(bytes, count: dataCount) + dataPart.withUnsafeBytes { rawBytes -> Void in + let bytes = rawBytes.baseAddress!.assumingMemoryBound(to: UInt8.self) + let _ = file?.write(bytes, count: dataCount) } case .done: link(paths.partial, paths.complete) diff --git a/submodules/Postbox/Sources/MediaBoxFile.swift b/submodules/Postbox/Sources/MediaBoxFile.swift index a7bd7cce60..197613c33d 100644 --- a/submodules/Postbox/Sources/MediaBoxFile.swift +++ b/submodules/Postbox/Sources/MediaBoxFile.swift @@ -46,7 +46,9 @@ private final class MediaBoxFileMap { var data = Data(count: Int(4 + count * 2 * 4)) let dataCount = data.count - if !(data.withUnsafeMutableBytes { (bytes: UnsafeMutablePointer) -> Bool in + if !(data.withUnsafeMutableBytes { rawBytes -> Bool in + let bytes = rawBytes.baseAddress!.assumingMemoryBound(to: UInt8.self) + guard fd.read(bytes, dataCount) == dataCount else { return false } @@ -337,8 +339,6 @@ final class MediaBoxPartialFile { } else { assertionFailure() } - } catch { - assertionFailure() } } @@ -364,7 +364,9 @@ final class MediaBoxPartialFile { assert(self.queue.isCurrent()) self.fd.seek(position: Int64(offset)) - let written = data.withUnsafeBytes { (bytes: UnsafePointer) -> Int in + let written = data.withUnsafeBytes { rawBytes -> Int in + let bytes = rawBytes.baseAddress!.assumingMemoryBound(to: UInt8.self) + return self.fd.write(bytes.advanced(by: dataRange.lowerBound), count: dataRange.count) } assert(written == dataRange.count) @@ -457,7 +459,8 @@ final class MediaBoxPartialFile { self.fd.seek(position: Int64(actualRange.lowerBound)) var data = Data(count: actualRange.count) let dataCount = data.count - let readBytes = data.withUnsafeMutableBytes { (bytes: UnsafeMutablePointer) -> Int in + let readBytes = data.withUnsafeMutableBytes { rawBytes -> Int in + let bytes = rawBytes.baseAddress!.assumingMemoryBound(to: Int8.self) return self.fd.read(bytes, dataCount) } if readBytes == data.count { diff --git a/submodules/Postbox/Sources/MessageHistoryHoleIndexTable.swift b/submodules/Postbox/Sources/MessageHistoryHoleIndexTable.swift index d997c179b9..5f95fe4b65 100644 --- a/submodules/Postbox/Sources/MessageHistoryHoleIndexTable.swift +++ b/submodules/Postbox/Sources/MessageHistoryHoleIndexTable.swift @@ -296,7 +296,6 @@ final class MessageHistoryHoleIndexTable: Table { } let clippedRange = clippedLowerBound ... clippedUpperBound - var removedIndices = IndexSet() var insertedIndices = IndexSet() var removeKeys: [Int32] = [] var insertRanges = IndexSet() @@ -378,8 +377,6 @@ final class MessageHistoryHoleIndexTable: Table { } private func removeInternal(peerId: PeerId, namespace: MessageId.Namespace, space: MessageHistoryHoleSpace, range: ClosedRange, operations: inout [MessageHistoryIndexHoleOperationKey: [MessageHistoryIndexHoleOperation]]) { - var removedIndices = IndexSet() - var insertedIndices = IndexSet() var removeKeys: [Int32] = [] var insertRanges = IndexSet() diff --git a/submodules/Postbox/Sources/MessageHistoryReadStateTable.swift b/submodules/Postbox/Sources/MessageHistoryReadStateTable.swift index 15f2fb9af5..07f910245c 100644 --- a/submodules/Postbox/Sources/MessageHistoryReadStateTable.swift +++ b/submodules/Postbox/Sources/MessageHistoryReadStateTable.swift @@ -505,7 +505,7 @@ final class MessageHistoryReadStateTable: Table { override func beforeCommit() { if !self.updatedInitialPeerReadStates.isEmpty { let sharedBuffer = WriteBuffer() - for (id, initialNamespaces) in self.updatedInitialPeerReadStates { + for (id, _) in self.updatedInitialPeerReadStates { if let wrappedStates = self.cachedPeerReadStates[id], let states = wrappedStates { sharedBuffer.reset() var count: Int32 = Int32(states.namespaces.count) diff --git a/submodules/Postbox/Sources/MessageHistoryTable.swift b/submodules/Postbox/Sources/MessageHistoryTable.swift index 35f7affa81..3c20cf3822 100644 --- a/submodules/Postbox/Sources/MessageHistoryTable.swift +++ b/submodules/Postbox/Sources/MessageHistoryTable.swift @@ -20,7 +20,7 @@ private enum AdjacentEntryGroupInfo { private func getAdjacentEntryGroupInfo(_ entry: IntermediateMessageHistoryEntry?, key: Int64) -> (IntermediateMessageHistoryEntry?, AdjacentEntryGroupInfo) { if let entry = entry { - if let groupingKey = entry.message.groupingKey, let groupInfo = entry.message.groupInfo { + if let groupingKey = entry.message.groupingKey, let _ = entry.message.groupInfo { if groupingKey == key { if let groupInfo = entry.message.groupInfo { return (entry, .sameGroup(groupInfo)) @@ -2516,6 +2516,10 @@ final class MessageHistoryTable: Table { if let authorId = message.author?.id { author = peerTable.get(authorId) } + + if let author = author { + peers[author.id] = author + } if let chatPeer = peerTable.get(message.id.peerId) { peers[chatPeer.id] = chatPeer diff --git a/submodules/Postbox/Sources/MessageHistoryThreadHoleIndexTable.swift b/submodules/Postbox/Sources/MessageHistoryThreadHoleIndexTable.swift index 58987f71b7..00c2e0acfe 100644 --- a/submodules/Postbox/Sources/MessageHistoryThreadHoleIndexTable.swift +++ b/submodules/Postbox/Sources/MessageHistoryThreadHoleIndexTable.swift @@ -268,7 +268,6 @@ final class MessageHistoryThreadHoleIndexTable: Table { } let clippedRange = clippedLowerBound ... clippedUpperBound - var removedIndices = IndexSet() var insertedIndices = IndexSet() var removeKeys: [Int32] = [] var insertRanges = IndexSet() @@ -351,8 +350,6 @@ final class MessageHistoryThreadHoleIndexTable: Table { } private func removeInternal(peerId: PeerId, threadId: Int64, namespace: MessageId.Namespace, space: MessageHistoryHoleSpace, range: ClosedRange, operations: inout [MessageHistoryIndexHoleOperationKey: [MessageHistoryIndexHoleOperation]]) { - var removedIndices = IndexSet() - var insertedIndices = IndexSet() var removeKeys: [Int32] = [] var insertRanges = IndexSet() diff --git a/submodules/Postbox/Sources/MessageOfInterestHolesView.swift b/submodules/Postbox/Sources/MessageOfInterestHolesView.swift index 21a4b298d8..c2280459fb 100644 --- a/submodules/Postbox/Sources/MessageOfInterestHolesView.swift +++ b/submodules/Postbox/Sources/MessageOfInterestHolesView.swift @@ -113,7 +113,7 @@ final class MutableMessageOfInterestHolesView: MutablePostboxView { } var anchor: HistoryViewInputAnchor = self.anchor if transaction.alteredInitialPeerCombinedReadStates[peerId] != nil { - var updatedAnchor: HistoryViewInputAnchor = .upperBound + let updatedAnchor: HistoryViewInputAnchor = .upperBound if let combinedState = postbox.readStateTable.getCombinedState(peerId), let state = combinedState.states.first, state.1.count != 0 { switch state.1 { case let .idBased(maxIncomingReadId, _, _, _, _): diff --git a/submodules/Postbox/Sources/NoticeTable.swift b/submodules/Postbox/Sources/NoticeTable.swift index 5d4405c6ad..8b9fb22e6d 100644 --- a/submodules/Postbox/Sources/NoticeTable.swift +++ b/submodules/Postbox/Sources/NoticeTable.swift @@ -19,9 +19,9 @@ public struct NoticeEntryKey: Hashable { public static func ==(lhs: NoticeEntryKey, rhs: NoticeEntryKey) -> Bool { return lhs.combinedKey == rhs.combinedKey } - - public var hashValue: Int { - return self.combinedKey.hashValue + + public func hash(into hasher: inout Hasher) { + hasher.combine(self.combinedKey) } } diff --git a/submodules/Postbox/Sources/OrderedItemListTable.swift b/submodules/Postbox/Sources/OrderedItemListTable.swift index 66c90f3f3d..469316f141 100644 --- a/submodules/Postbox/Sources/OrderedItemListTable.swift +++ b/submodules/Postbox/Sources/OrderedItemListTable.swift @@ -205,7 +205,7 @@ final class OrderedItemListTable: Table { func remove(collectionId: Int32, itemId: MemoryBuffer, operations: inout [Int32: [OrderedItemListOperation]]) { if let index = self.getIndex(collectionId: collectionId, id: itemId) { - var orderedIds = self.getItemIds(collectionId: collectionId) + let orderedIds = self.getItemIds(collectionId: collectionId) if !orderedIds.isEmpty { self.valueBox.remove(self.table, key: self.keyIdToIndex(collectionId: collectionId, id: itemId), secure: false) diff --git a/submodules/Postbox/Sources/Peer.swift b/submodules/Postbox/Sources/Peer.swift index c85b4f1af9..3e8d30c338 100644 --- a/submodules/Postbox/Sources/Peer.swift +++ b/submodules/Postbox/Sources/Peer.swift @@ -154,7 +154,7 @@ public struct PeerId: Hashable, CustomStringConvertible, Comparable, Codable { let namespaceBits = ((data >> 32) & 0x7) self.namespace = Namespace(rawValue: UInt32(namespaceBits)) - let idHighBits = (data >> (32 + 3)) & 0xffffffff + //let idHighBits = (data >> (32 + 3)) & 0xffffffff //assert(idHighBits == 0) self.id = Id(rawValue: Int32(bitPattern: UInt32(clamping: idLowBits))) @@ -260,7 +260,7 @@ public struct PeerId: Hashable, CustomStringConvertible, Comparable, Codable { } } -public protocol Peer: class, PostboxCoding { +public protocol Peer: AnyObject, PostboxCoding { var id: PeerId { get } var indexName: PeerIndexNameRepresentation { get } var associatedPeerId: PeerId? { get } diff --git a/submodules/Postbox/Sources/PeerNotificationSettings.swift b/submodules/Postbox/Sources/PeerNotificationSettings.swift index 0cc7ee9c10..f924ffbdd5 100644 --- a/submodules/Postbox/Sources/PeerNotificationSettings.swift +++ b/submodules/Postbox/Sources/PeerNotificationSettings.swift @@ -1,14 +1,31 @@ +import Foundation + +public class PeerNotificationSettingsDecodeHelper { + public let decode: (_ data: Data) -> PeerNotificationSettings? + + public init(decode: @escaping (_ data: Data) -> PeerNotificationSettings?) { + self.decode = decode + } +} + +public enum PeerNotificationSettingsBehavior { + enum CodingKeys: String, CodingKey { + case _case = "_v" + case toValue + case atTimestamp + } -public enum PeerNotificationSettingsBehavior: PostboxCoding { case none case reset(atTimestamp: Int32, toValue: PeerNotificationSettings) - public init(decoder: PostboxDecoder) { + public init(from decoder: Decoder, helper: PeerNotificationSettingsDecodeHelper) throws { + let container = try decoder.container(keyedBy: StringCodingKey.self) + switch decoder.decodeInt32ForKey("_v", orElse: 0) { case 0: self = .none case 1: - if let toValue = decoder.decodeObjectForKey("toValue") as? PeerNotificationSettings { + if let toValue = helper.decode(PeerNotificationSettings.self, forKey: "toValue") { self = .reset(atTimestamp: decoder.decodeInt32ForKey("atTimestamp", orElse: 0), toValue: toValue) } else { assertionFailure() @@ -27,26 +44,29 @@ public enum PeerNotificationSettingsBehavior: PostboxCoding { case let .reset(atTimestamp, toValue): encoder.encodeInt32(1, forKey: "_v") encoder.encodeInt32(atTimestamp, forKey: "atTimestamp") - encoder.encodeObject(toValue, forKey: "toValue") + encoder.encode(toValue, forKey: "toValue") } } } -public protocol PeerNotificationSettings: PostboxCoding { +public protocol PeerNotificationSettings: Codable { func isRemovedFromTotalUnreadCount(`default`: Bool) -> Bool + var behavior: PeerNotificationSettingsBehavior { get } - - func isEqual(to: PeerNotificationSettings) -> Bool } -public protocol PostboxGlobalNotificationSettings: PostboxCoding { - func defaultIncludePeer(peer: Peer) -> Bool - - func isEqualInDefaultPeerInclusion(other: PostboxGlobalNotificationSettings) -> Bool +public final class PostboxGlobalNotificationSettings { + public let defaultIncludePeer: (_ peer: Peer) -> Bool + + public init( + defaultIncludePeer: @escaping (_ peer: Peer) -> Bool + ) { + self.defaultIncludePeer = defaultIncludePeer + } } public func resolvedIsRemovedFromTotalUnreadCount(globalSettings: PostboxGlobalNotificationSettings, peer: Peer, peerSettings: PeerNotificationSettings?) -> Bool { - let defaultValue = !globalSettings.defaultIncludePeer(peer: peer) + let defaultValue = !globalSettings.defaultIncludePeer(peer) if let peerSettings = peerSettings { return peerSettings.isRemovedFromTotalUnreadCount(default: defaultValue) } else { diff --git a/submodules/Postbox/Sources/PeerNotificationSettingsTable.swift b/submodules/Postbox/Sources/PeerNotificationSettingsTable.swift index 2f751e78a2..956d12bd8e 100644 --- a/submodules/Postbox/Sources/PeerNotificationSettingsTable.swift +++ b/submodules/Postbox/Sources/PeerNotificationSettingsTable.swift @@ -195,7 +195,7 @@ final class PeerNotificationSettingsTable: Table { self.updatedInitialSettings.removeAll() } - func transactionParticipationInTotalUnreadCountUpdates(postbox: Postbox) -> (added: Set, removed: Set) { + func transactionParticipationInTotalUnreadCountUpdates(postbox: Postbox, transaction: Transaction) -> (added: Set, removed: Set) { var added = Set() var removed = Set() @@ -210,7 +210,7 @@ final class PeerNotificationSettingsTable: Table { if let current = globalNotificationSettings { globalNotificationSettingsValue = current } else { - globalNotificationSettingsValue = postbox.getGlobalNotificationSettings() + globalNotificationSettingsValue = postbox.getGlobalNotificationSettings(transaction: transaction) globalNotificationSettings = globalNotificationSettingsValue } diff --git a/submodules/Postbox/Sources/PeerPresence.swift b/submodules/Postbox/Sources/PeerPresence.swift index 6e0ec83b2c..06ac9e7cc0 100644 --- a/submodules/Postbox/Sources/PeerPresence.swift +++ b/submodules/Postbox/Sources/PeerPresence.swift @@ -1,5 +1,5 @@ -public protocol PeerPresence: class, PostboxCoding { +public protocol PeerPresence: AnyObject, PostboxCoding { func isEqual(to: PeerPresence) -> Bool } diff --git a/submodules/Postbox/Sources/PendingMessageActionsMetadataTable.swift b/submodules/Postbox/Sources/PendingMessageActionsMetadataTable.swift index 02bc1d5fdf..ce8f8f3ffe 100644 --- a/submodules/Postbox/Sources/PendingMessageActionsMetadataTable.swift +++ b/submodules/Postbox/Sources/PendingMessageActionsMetadataTable.swift @@ -3,32 +3,6 @@ import Foundation enum PendingMessageActionsMetadataCountKey: Hashable { case peerNamespace(PeerId, MessageId.Namespace) case peerNamespaceAction(PeerId, MessageId.Namespace, PendingMessageActionType) - - static func ==(lhs: PendingMessageActionsMetadataCountKey, rhs: PendingMessageActionsMetadataCountKey) -> Bool { - switch lhs { - case let .peerNamespace(peerId, namespace): - if case .peerNamespace(peerId, namespace) = rhs { - return true - } else { - return false - } - case let .peerNamespaceAction(peerId, namespace, actionType): - if case .peerNamespaceAction(peerId, namespace, actionType) = rhs { - return true - } else { - return false - } - } - } - - var hashValue: Int { - switch self { - case let .peerNamespace(peerId, namespace): - return peerId.hashValue ^ namespace.hashValue - case let .peerNamespaceAction(peerId, namespace, actionType): - return peerId.hashValue ^ namespace.hashValue ^ actionType.hashValue - } - } } enum PendingMessageActionsMetadataKey { diff --git a/submodules/Postbox/Sources/Postbox.swift b/submodules/Postbox/Sources/Postbox.swift index b0222dc12a..8bb2ab8b58 100644 --- a/submodules/Postbox/Sources/Postbox.swift +++ b/submodules/Postbox/Sources/Postbox.swift @@ -269,7 +269,7 @@ public final class Transaction { public func getGlobalNotificationSettings() -> PostboxGlobalNotificationSettings { assert(!self.disposed) if let postbox = self.postbox { - return postbox.getGlobalNotificationSettings() + return postbox.getGlobalNotificationSettings(transaction: self) } else { preconditionFailure() } @@ -369,7 +369,7 @@ public final class Transaction { public func getUnreadChatListPeerIds(groupId: PeerGroupId, filterPredicate: ChatListFilterPredicate?) -> [PeerId] { assert(!self.disposed) if let postbox = self.postbox { - return postbox.chatListTable.getUnreadChatListPeerIds(postbox: postbox, groupId: groupId, filterPredicate: filterPredicate) + return postbox.chatListTable.getUnreadChatListPeerIds(postbox: postbox, currentTransaction: self, groupId: groupId, filterPredicate: filterPredicate) } else { return [] } @@ -805,6 +805,11 @@ public final class Transaction { assert(!self.disposed) self.postbox?.setPreferencesEntry(key: key, value: f(self.postbox?.getPreferencesEntry(key: key))) } + + public func globalNotificationSettingsUpdated() { + assert(!self.disposed) + self.postbox?.globalNotificationSettingsUpdated() + } public func getPinnedItemIds(groupId: PeerGroupId) -> [PinnedItemId] { assert(!self.disposed) @@ -1048,7 +1053,7 @@ public final class Transaction { public func getRelativeUnreadChatListIndex(filtered: Bool, position: ChatListRelativePosition, groupId: PeerGroupId) -> ChatListIndex? { assert(!self.disposed) - return self.postbox?.getRelativeUnreadChatListIndex(filtered: filtered, position: position, groupId: groupId) + return self.postbox?.getRelativeUnreadChatListIndex(currentTransaction: self, filtered: filtered, position: position, groupId: groupId) } public func getDeviceContactImportInfo(_ identifier: ValueBoxKey) -> PostboxCoding? { @@ -1110,7 +1115,7 @@ public final class Transaction { public func reindexUnreadCounters() { assert(!self.disposed) - self.postbox?.reindexUnreadCounters() + self.postbox?.reindexUnreadCounters(currentTransaction: self) } public func searchPeers(query: String) -> [RenderedPeer] { @@ -1215,7 +1220,7 @@ public func openPostbox(basePath: String, seedConfiguration: SeedConfiguration, let userVersion: Int32? = metadataTable.userVersion() let currentUserVersion: Int32 = 25 - postboxLog("openPostbox, current userVersion: \(userVersion ?? nil)") + postboxLog("openPostbox, current userVersion: \(String(describing: userVersion ?? nil))") if let userVersion = userVersion { if userVersion != currentUserVersion { @@ -1607,7 +1612,7 @@ public final class Postbox { if !isTemporary && self.messageHistoryMetadataTable.shouldReindexUnreadCounts() { self.groupMessageStatsTable.removeAll() let startTime = CFAbsoluteTimeGetCurrent() - let (totalStates, summaries) = self.chatListIndexTable.debugReindexUnreadCounts(postbox: self) + let (totalStates, summaries) = self.chatListIndexTable.debugReindexUnreadCounts(postbox: self, currentTransaction: transaction) self.messageHistoryMetadataTable.removeAllTotalUnreadStates() for (groupId, state) in totalStates { @@ -1924,13 +1929,13 @@ public final class Postbox { return renderedMessage } - private func afterBegin() { + private func afterBegin(transaction: Transaction) { let currentTransactionStateVersion = self.metadataTable.transactionStateVersion() if currentTransactionStateVersion != self.transactionStateVersion { for table in self.tables { table.clearMemoryCache() } - self.viewTracker.refreshViewsDueToExternalTransaction(postbox: self, fetchUnsentMessageIds: { + self.viewTracker.refreshViewsDueToExternalTransaction(postbox: self, currentTransaction: transaction, fetchUnsentMessageIds: { return self.messageHistoryUnsentTable.get() }, fetchSynchronizePeerReadStateOperations: { return self.synchronizeReadStateTable.get(getCombinedPeerReadState: { peerId in @@ -1943,7 +1948,7 @@ public final class Postbox { } } - private func beforeCommit() -> (updatedTransactionStateVersion: Int64?, updatedMasterClientId: Int64?) { + private func beforeCommit(currentTransaction: Transaction) -> (updatedTransactionStateVersion: Int64?, updatedMasterClientId: Int64?) { self.chatListTable.replay(historyOperationsByPeerId: self.currentOperationsByPeerId, updatedPeerChatListEmbeddedStates: self.currentUpdatedPeerChatListEmbeddedStates, updatedChatListInclusions: self.currentUpdatedChatListInclusions, messageHistoryTable: self.messageHistoryTable, peerChatInterfaceStateTable: self.peerChatInterfaceStateTable, operations: &self.currentChatListOperations) self.peerChatTopTaggedMessageIdsTable.replay(historyOperationsByPeerId: self.currentOperationsByPeerId) @@ -1969,18 +1974,18 @@ public final class Postbox { } } } - let transactionParticipationInTotalUnreadCountUpdates = self.peerNotificationSettingsTable.transactionParticipationInTotalUnreadCountUpdates(postbox: self) - self.chatListIndexTable.commitWithTransaction(postbox: self, alteredInitialPeerCombinedReadStates: alteredInitialPeerCombinedReadStates, updatedPeers: updatedPeers, transactionParticipationInTotalUnreadCountUpdates: transactionParticipationInTotalUnreadCountUpdates, updatedTotalUnreadStates: &self.currentUpdatedTotalUnreadStates, updatedGroupTotalUnreadSummaries: &self.currentUpdatedGroupTotalUnreadSummaries, currentUpdatedGroupSummarySynchronizeOperations: &self.currentUpdatedGroupSummarySynchronizeOperations) + let transactionParticipationInTotalUnreadCountUpdates = self.peerNotificationSettingsTable.transactionParticipationInTotalUnreadCountUpdates(postbox: self, transaction: currentTransaction) + self.chatListIndexTable.commitWithTransaction(postbox: self, currentTransaction: currentTransaction, alteredInitialPeerCombinedReadStates: alteredInitialPeerCombinedReadStates, updatedPeers: updatedPeers, transactionParticipationInTotalUnreadCountUpdates: transactionParticipationInTotalUnreadCountUpdates, updatedTotalUnreadStates: &self.currentUpdatedTotalUnreadStates, updatedGroupTotalUnreadSummaries: &self.currentUpdatedGroupTotalUnreadSummaries, currentUpdatedGroupSummarySynchronizeOperations: &self.currentUpdatedGroupSummarySynchronizeOperations) if self.currentNeedsReindexUnreadCounters { - self.reindexUnreadCounters() + self.reindexUnreadCounters(currentTransaction: currentTransaction) } let transaction = PostboxTransaction(currentUpdatedState: self.currentUpdatedState, currentPeerHoleOperations: self.currentPeerHoleOperations, currentOperationsByPeerId: self.currentOperationsByPeerId, chatListOperations: self.currentChatListOperations, currentUpdatedChatListInclusions: self.currentUpdatedChatListInclusions, currentUpdatedPeers: self.currentUpdatedPeers, currentUpdatedPeerNotificationSettings: self.currentUpdatedPeerNotificationSettings, currentUpdatedPeerNotificationBehaviorTimestamps: self.currentUpdatedPeerNotificationBehaviorTimestamps, currentUpdatedCachedPeerData: self.currentUpdatedCachedPeerData, currentUpdatedPeerPresences: currentUpdatedPeerPresences, currentUpdatedPeerChatListEmbeddedStates: self.currentUpdatedPeerChatListEmbeddedStates, currentUpdatedTotalUnreadStates: self.currentUpdatedTotalUnreadStates, currentUpdatedTotalUnreadSummaries: self.currentUpdatedGroupTotalUnreadSummaries, alteredInitialPeerCombinedReadStates: alteredInitialPeerCombinedReadStates, currentPeerMergedOperationLogOperations: self.currentPeerMergedOperationLogOperations, currentTimestampBasedMessageAttributesOperations: self.currentTimestampBasedMessageAttributesOperations, unsentMessageOperations: self.currentUnsentOperations, updatedSynchronizePeerReadStateOperations: self.currentUpdatedSynchronizeReadStateOperations, currentUpdatedGroupSummarySynchronizeOperations: self.currentUpdatedGroupSummarySynchronizeOperations, currentPreferencesOperations: self.currentPreferencesOperations, currentOrderedItemListOperations: self.currentOrderedItemListOperations, currentItemCollectionItemsOperations: self.currentItemCollectionItemsOperations, currentItemCollectionInfosOperations: self.currentItemCollectionInfosOperations, currentUpdatedPeerChatStates: self.currentUpdatedPeerChatStates, currentGlobalTagsOperations: self.currentGlobalTagsOperations, currentLocalTagsOperations: self.currentLocalTagsOperations, updatedMedia: self.currentUpdatedMedia, replaceRemoteContactCount: self.currentReplaceRemoteContactCount, replaceContactPeerIds: self.currentReplacedContactPeerIds, currentPendingMessageActionsOperations: self.currentPendingMessageActionsOperations, currentUpdatedMessageActionsSummaries: self.currentUpdatedMessageActionsSummaries, currentUpdatedMessageTagSummaries: self.currentUpdatedMessageTagSummaries, currentInvalidateMessageTagSummaries: self.currentInvalidateMessageTagSummaries, currentUpdatedPendingPeerNotificationSettings: self.currentUpdatedPendingPeerNotificationSettings, replacedAdditionalChatListItems: self.currentReplacedAdditionalChatListItems, updatedNoticeEntryKeys: self.currentUpdatedNoticeEntryKeys, updatedCacheEntryKeys: self.currentUpdatedCacheEntryKeys, currentUpdatedMasterClientId: currentUpdatedMasterClientId, updatedFailedMessagePeerIds: self.messageHistoryFailedTable.updatedPeerIds, updatedFailedMessageIds: self.messageHistoryFailedTable.updatedMessageIds, updatedGlobalNotificationSettings: self.currentNeedsReindexUnreadCounters) var updatedTransactionState: Int64? var updatedMasterClientId: Int64? if !transaction.isEmpty { - self.viewTracker.updateViews(postbox: self, transaction: transaction) + self.viewTracker.updateViews(postbox: self, currentTransaction: currentTransaction, transaction: transaction) self.transactionStateVersion = self.metadataTable.incrementTransactionStateVersion() updatedTransactionState = self.transactionStateVersion @@ -2466,11 +2471,11 @@ public final class Postbox { private func internalTransaction(_ f: (Transaction) -> T) -> (result: T, updatedTransactionStateVersion: Int64?, updatedMasterClientId: Int64?) { self.valueBox.begin() - self.afterBegin() let transaction = Transaction(postbox: self) + self.afterBegin(transaction: transaction) let result = f(transaction) + let (updatedTransactionState, updatedMasterClientId) = self.beforeCommit(currentTransaction: transaction) transaction.disposed = true - let (updatedTransactionState, updatedMasterClientId) = self.beforeCommit() self.valueBox.commit() if let currentUpdatedState = self.currentUpdatedState { @@ -2889,7 +2894,7 @@ public final class Postbox { public func aroundChatListView(groupId: PeerGroupId, filterPredicate: ChatListFilterPredicate? = nil, index: ChatListIndex, count: Int, summaryComponents: ChatListEntrySummaryComponents, userInteractive: Bool = false) -> Signal<(ChatListView, ViewUpdateType), NoError> { return self.transactionSignal(userInteractive: userInteractive, { subscriber, transaction in - let mutableView = MutableChatListView(postbox: self, groupId: groupId, filterPredicate: filterPredicate, aroundIndex: index, count: count, summaryComponents: summaryComponents) + let mutableView = MutableChatListView(postbox: self, currentTransaction: transaction, groupId: groupId, filterPredicate: filterPredicate, aroundIndex: index, count: count, summaryComponents: summaryComponents) mutableView.render(postbox: self) let (index, signal) = self.viewTracker.addChatListView(mutableView) @@ -3383,16 +3388,12 @@ public final class Postbox { } fileprivate func setPreferencesEntry(key: ValueBoxKey, value: PreferencesEntry?) { - if key == self.seedConfiguration.globalNotificationSettingsPreferencesKey { - let current = self.getGlobalNotificationSettings() - let updated = value as? PostboxGlobalNotificationSettings ?? self.seedConfiguration.defaultGlobalNotificationSettings - if !current.isEqualInDefaultPeerInclusion(other: updated) { - self.currentNeedsReindexUnreadCounters = true - } - } - self.preferencesTable.set(key: key, value: value, operations: &self.currentPreferencesOperations) } + + fileprivate func globalNotificationSettingsUpdated() { + self.currentNeedsReindexUnreadCounters = true + } fileprivate func replaceOrderedItemListItems(collectionId: Int32, items: [OrderedItemListEntry]) { self.orderedItemListTable.replaceItems(collectionId: collectionId, items: items, operations: &self.currentOrderedItemListOperations) @@ -3506,8 +3507,8 @@ public final class Postbox { self.invalidatedMessageHistoryTagsSummaryTable.remove(entry, operations: &self.currentInvalidateMessageTagSummaries) } - fileprivate func getRelativeUnreadChatListIndex(filtered: Bool, position: ChatListRelativePosition, groupId: PeerGroupId) -> ChatListIndex? { - return self.chatListTable.getRelativeUnreadChatListIndex(postbox: self, filtered: filtered, position: position, groupId: groupId) + fileprivate func getRelativeUnreadChatListIndex(currentTransaction: Transaction, filtered: Bool, position: ChatListRelativePosition, groupId: PeerGroupId) -> ChatListIndex? { + return self.chatListTable.getRelativeUnreadChatListIndex(postbox: self, currentTransaction: currentTransaction, filtered: filtered, position: position, groupId: groupId) } func getMessage(_ id: MessageId) -> Message? { @@ -3561,8 +3562,8 @@ public final class Postbox { } } - func getGlobalNotificationSettings() -> PostboxGlobalNotificationSettings { - return self.preferencesTable.get(key: self.seedConfiguration.globalNotificationSettingsPreferencesKey) as? PostboxGlobalNotificationSettings ?? self.seedConfiguration.defaultGlobalNotificationSettings + func getGlobalNotificationSettings(transaction: Transaction) -> PostboxGlobalNotificationSettings { + return self.seedConfiguration.getGlobalNotificationSettings(transaction) ?? self.seedConfiguration.defaultGlobalNotificationSettings } public func isMasterClient() -> Signal { @@ -3611,10 +3612,10 @@ public final class Postbox { self.timestampBasedMessageAttributesTable.remove(tag: tag, id: id, operations: &self.currentTimestampBasedMessageAttributesOperations) } - fileprivate func reindexUnreadCounters() { + fileprivate func reindexUnreadCounters(currentTransaction: Transaction) { self.groupMessageStatsTable.removeAll() let _ = CFAbsoluteTimeGetCurrent() - let (totalStates, summaries) = self.chatListIndexTable.debugReindexUnreadCounts(postbox: self) + let (totalStates, summaries) = self.chatListIndexTable.debugReindexUnreadCounts(postbox: self, currentTransaction: currentTransaction) self.messageHistoryMetadataTable.removeAllTotalUnreadStates() for (groupId, state) in totalStates { diff --git a/submodules/Postbox/Sources/PostboxUpgrade_16to17.swift b/submodules/Postbox/Sources/PostboxUpgrade_16to17.swift index 030c1fce46..9e8d6cef28 100644 --- a/submodules/Postbox/Sources/PostboxUpgrade_16to17.swift +++ b/submodules/Postbox/Sources/PostboxUpgrade_16to17.swift @@ -154,12 +154,10 @@ private func getReadStateCount(valueBox: ValueBox, table: ValueBoxTable, peerId: if let value = valueBox.get(table, key: key) { var count: Int32 = 0 value.read(&count, offset: 0, length: 4) - var stateByNamespace: [MessageId.Namespace: PeerReadState] = [:] for _ in 0 ..< count { var namespaceId: Int32 = 0 value.read(&namespaceId, offset: 0, length: 4) - - let state: PeerReadState + var kind: Int8 = 0 value.read(&kind, offset: 0, length: 1) if kind == 0 { @@ -207,8 +205,6 @@ private func getReadStateCount(valueBox: ValueBox, table: ValueBoxTable, peerId: func postboxUpgrade_16to17(metadataTable: MetadataTable, valueBox: ValueBox, progress: (Float) -> Void) { let chatListIndexTable = ValueBoxTable(id: 8, keyType: .int64, compactValuesOnCreation: false) - let notificationSettingsTable = ValueBoxTable(id: 19, keyType: .int64, compactValuesOnCreation: false) - let readStateTable = ValueBoxTable(id: 14, keyType: .int64, compactValuesOnCreation: false) let messageHistoryMetadataTable = ValueBoxTable(id: 10, keyType: .binary, compactValuesOnCreation: true) var includedPeerIds: [PeerId] = [] diff --git a/submodules/Postbox/Sources/PreferencesEntry.swift b/submodules/Postbox/Sources/PreferencesEntry.swift index 4997de7588..4d3e89714e 100644 --- a/submodules/Postbox/Sources/PreferencesEntry.swift +++ b/submodules/Postbox/Sources/PreferencesEntry.swift @@ -1,9 +1,26 @@ import Foundation -public protocol PreferencesEntry: PostboxCoding { - var relatedResources: [MediaResourceId] { get } - - func isEqual(to: PreferencesEntry) -> Bool +public final class PreferencesEntry: Equatable { + public let data: Data + + public init(data: Data) { + self.data = data + } + + public init?(_ value: T) { + let encoder = PostboxEncoder() + encoder.encode(value, forKey: "_") + self.data = encoder.makeData() + } + + public func get(_ type: T.Type) -> T? { + let decoder = PostboxDecoder(buffer: MemoryBuffer(data: self.data)) + return decoder.decode(T.self, forKey: "_") + } + + public static func ==(lhs: PreferencesEntry, rhs: PreferencesEntry) -> Bool { + return lhs.data == rhs.data + } } public extension PreferencesEntry { diff --git a/submodules/Postbox/Sources/PreferencesTable.swift b/submodules/Postbox/Sources/PreferencesTable.swift index 27522d688a..e76c862cee 100644 --- a/submodules/Postbox/Sources/PreferencesTable.swift +++ b/submodules/Postbox/Sources/PreferencesTable.swift @@ -18,11 +18,7 @@ final class PreferencesTable: Table { func enumerateEntries(_ f: (PreferencesEntry) -> Bool) { self.valueBox.scan(self.table, values: { _, value in - if let object = PostboxDecoder(buffer: value).decodeRootObject() as? PreferencesEntry { - return f(object) - } else { - return true - } + return f(PreferencesEntry(data: value.makeData())) }) } @@ -30,7 +26,8 @@ final class PreferencesTable: Table { if let cached = self.cachedEntries[key] { return cached.entry } else { - if let value = self.valueBox.get(self.table, key: key), let object = PostboxDecoder(buffer: value).decodeRootObject() as? PreferencesEntry { + if let value = self.valueBox.get(self.table, key: key) { + let object = PreferencesEntry(data: value.makeData()) self.cachedEntries[key] = CachedEntry(entry: object) return object } else { @@ -54,11 +51,7 @@ final class PreferencesTable: Table { if !self.updatedEntryKeys.isEmpty { for key in self.updatedEntryKeys { if let value = self.cachedEntries[key]?.entry { - let encoder = PostboxEncoder() - encoder.encodeRootObject(value) - withExtendedLifetime(encoder, { - self.valueBox.set(self.table, key: key, value: encoder.readBufferNoCopy()) - }) + self.valueBox.set(self.table, key: key, value: ReadBuffer(data: value.data)) } else { self.valueBox.remove(self.table, key: key, secure: false) } diff --git a/submodules/Postbox/Sources/PreferencesView.swift b/submodules/Postbox/Sources/PreferencesView.swift index 4a7b809e03..d322d2cfc8 100644 --- a/submodules/Postbox/Sources/PreferencesView.swift +++ b/submodules/Postbox/Sources/PreferencesView.swift @@ -24,7 +24,7 @@ final class MutablePreferencesView: MutablePostboxView { let currentValue = self.values[key] var updatedValue = false if let value = value, let currentValue = currentValue { - if !value.isEqual(to: currentValue) { + if value != currentValue { updatedValue = true } } else if (value != nil) != (currentValue != nil) { diff --git a/submodules/Postbox/Sources/ReverseIndexReferenceTable.swift b/submodules/Postbox/Sources/ReverseIndexReferenceTable.swift index 4e8b6f37a3..27d2130e22 100644 --- a/submodules/Postbox/Sources/ReverseIndexReferenceTable.swift +++ b/submodules/Postbox/Sources/ReverseIndexReferenceTable.swift @@ -77,18 +77,6 @@ struct ReverseIndexNamespace: Hashable { init(_ value: Int32?) { self.value = value } - - var hashValue: Int { - if let value = self.value { - return value.hashValue - } else { - return 0 - } - } - - static func ==(lhs: ReverseIndexNamespace, rhs: ReverseIndexNamespace) -> Bool { - return lhs.value == rhs.value - } } final class ReverseIndexReferenceTable: Table { diff --git a/submodules/Postbox/Sources/SeedConfiguration.swift b/submodules/Postbox/Sources/SeedConfiguration.swift index c8913cc2a9..e8b0a8520d 100644 --- a/submodules/Postbox/Sources/SeedConfiguration.swift +++ b/submodules/Postbox/Sources/SeedConfiguration.swift @@ -69,10 +69,10 @@ public final class SeedConfiguration { public let messageNamespacesRequiringGroupStatsValidation: Set public let defaultMessageNamespaceReadStates: [MessageId.Namespace: PeerReadState] public let chatMessagesNamespaces: Set - public let globalNotificationSettingsPreferencesKey: ValueBoxKey + public let getGlobalNotificationSettings: (Transaction) -> PostboxGlobalNotificationSettings? public let defaultGlobalNotificationSettings: PostboxGlobalNotificationSettings - public init(globalMessageIdsPeerIdNamespaces: Set, initializeChatListWithHole: (topLevel: ChatListHole?, groups: ChatListHole?), messageHoles: [PeerId.Namespace: [MessageId.Namespace: Set]], upgradedMessageHoles: [PeerId.Namespace: [MessageId.Namespace: Set]], messageThreadHoles: [PeerId.Namespace: [MessageId.Namespace]], existingMessageTags: MessageTags, messageTagsWithSummary: MessageTags, existingGlobalMessageTags: GlobalMessageTags, peerNamespacesRequiringMessageTextIndex: [PeerId.Namespace], peerSummaryCounterTags: @escaping (Peer, Bool) -> PeerSummaryCounterTags, additionalChatListIndexNamespace: MessageId.Namespace?, messageNamespacesRequiringGroupStatsValidation: Set, defaultMessageNamespaceReadStates: [MessageId.Namespace: PeerReadState], chatMessagesNamespaces: Set, globalNotificationSettingsPreferencesKey: ValueBoxKey, defaultGlobalNotificationSettings: PostboxGlobalNotificationSettings) { + public init(globalMessageIdsPeerIdNamespaces: Set, initializeChatListWithHole: (topLevel: ChatListHole?, groups: ChatListHole?), messageHoles: [PeerId.Namespace: [MessageId.Namespace: Set]], upgradedMessageHoles: [PeerId.Namespace: [MessageId.Namespace: Set]], messageThreadHoles: [PeerId.Namespace: [MessageId.Namespace]], existingMessageTags: MessageTags, messageTagsWithSummary: MessageTags, existingGlobalMessageTags: GlobalMessageTags, peerNamespacesRequiringMessageTextIndex: [PeerId.Namespace], peerSummaryCounterTags: @escaping (Peer, Bool) -> PeerSummaryCounterTags, additionalChatListIndexNamespace: MessageId.Namespace?, messageNamespacesRequiringGroupStatsValidation: Set, defaultMessageNamespaceReadStates: [MessageId.Namespace: PeerReadState], chatMessagesNamespaces: Set, getGlobalNotificationSettings: @escaping (Transaction) -> PostboxGlobalNotificationSettings?, defaultGlobalNotificationSettings: PostboxGlobalNotificationSettings) { self.globalMessageIdsPeerIdNamespaces = globalMessageIdsPeerIdNamespaces self.initializeChatListWithHole = initializeChatListWithHole self.messageHoles = messageHoles @@ -86,7 +86,7 @@ public final class SeedConfiguration { self.messageNamespacesRequiringGroupStatsValidation = messageNamespacesRequiringGroupStatsValidation self.defaultMessageNamespaceReadStates = defaultMessageNamespaceReadStates self.chatMessagesNamespaces = chatMessagesNamespaces - self.globalNotificationSettingsPreferencesKey = globalNotificationSettingsPreferencesKey + self.getGlobalNotificationSettings = getGlobalNotificationSettings self.defaultGlobalNotificationSettings = defaultGlobalNotificationSettings } } diff --git a/submodules/Postbox/Sources/SqliteValueBox.swift b/submodules/Postbox/Sources/SqliteValueBox.swift index b9409cecc4..de9169dac5 100644 --- a/submodules/Postbox/Sources/SqliteValueBox.swift +++ b/submodules/Postbox/Sources/SqliteValueBox.swift @@ -1326,19 +1326,23 @@ public final class SqliteValueBox: ValueBox { resultStatement.reset() - collectionId.withUnsafeBytes { (bytes: UnsafePointer) -> Void in + collectionId.withUnsafeBytes { rawBytes -> Void in + let bytes = rawBytes.baseAddress!.assumingMemoryBound(to: UInt8.self) resultStatement.bindText(1, data: bytes, length: collectionId.count) } - itemId.withUnsafeBytes { (bytes: UnsafePointer) -> Void in + itemId.withUnsafeBytes { rawBytes -> Void in + let bytes = rawBytes.baseAddress!.assumingMemoryBound(to: UInt8.self) resultStatement.bindText(2, data: bytes, length: itemId.count) } - contents.withUnsafeBytes { (bytes: UnsafePointer) -> Void in + contents.withUnsafeBytes { rawBytes -> Void in + let bytes = rawBytes.baseAddress!.assumingMemoryBound(to: UInt8.self) resultStatement.bindText(3, data: bytes, length: contents.count) } - tags.withUnsafeBytes { (bytes: UnsafePointer) -> Void in + tags.withUnsafeBytes { rawBytes -> Void in + let bytes = rawBytes.baseAddress!.assumingMemoryBound(to: UInt8.self) resultStatement.bindText(4, data: bytes, length: tags.count) } @@ -1361,7 +1365,8 @@ public final class SqliteValueBox: ValueBox { resultStatement.reset() - itemId.withUnsafeBytes { (bytes: UnsafePointer) -> Void in + itemId.withUnsafeBytes { rawBytes -> Void in + let bytes = rawBytes.baseAddress!.assumingMemoryBound(to: UInt8.self) resultStatement.bindText(1, data: bytes, length: itemId.count) } @@ -1387,7 +1392,8 @@ public final class SqliteValueBox: ValueBox { resultStatement.reset() - contents.withUnsafeBytes { (bytes: UnsafePointer) -> Void in + contents.withUnsafeBytes { rawBytes -> Void in + let bytes = rawBytes.baseAddress!.assumingMemoryBound(to: UInt8.self) resultStatement.bindText(1, data: bytes, length: contents.count) } @@ -1410,11 +1416,13 @@ public final class SqliteValueBox: ValueBox { resultStatement.reset() - contents.withUnsafeBytes { (bytes: UnsafePointer) -> Void in + contents.withUnsafeBytes { rawBytes -> Void in + let bytes = rawBytes.baseAddress!.assumingMemoryBound(to: UInt8.self) resultStatement.bindText(1, data: bytes, length: contents.count) } - collectionId.withUnsafeBytes { (bytes: UnsafePointer) -> Void in + collectionId.withUnsafeBytes { rawBytes -> Void in + let bytes = rawBytes.baseAddress!.assumingMemoryBound(to: UInt8.self) resultStatement.bindText(2, data: bytes, length: collectionId.count) } @@ -1437,15 +1445,18 @@ public final class SqliteValueBox: ValueBox { resultStatement.reset() - contents.withUnsafeBytes { (bytes: UnsafePointer) -> Void in + contents.withUnsafeBytes { rawBytes -> Void in + let bytes = rawBytes.baseAddress!.assumingMemoryBound(to: UInt8.self) resultStatement.bindText(1, data: bytes, length: contents.count) } - collectionId.withUnsafeBytes { (bytes: UnsafePointer) -> Void in + collectionId.withUnsafeBytes { rawBytes -> Void in + let bytes = rawBytes.baseAddress!.assumingMemoryBound(to: UInt8.self) resultStatement.bindText(2, data: bytes, length: collectionId.count) } - tags.withUnsafeBytes { (bytes: UnsafePointer) -> Void in + tags.withUnsafeBytes { rawBytes -> Void in + let bytes = rawBytes.baseAddress!.assumingMemoryBound(to: UInt8.self) resultStatement.bindText(3, data: bytes, length: tags.count) } @@ -1653,7 +1664,6 @@ public final class SqliteValueBox: ValueBox { hadStop = true return false } - return true }, limit: limit) if let lastKey = lastKey { currentStart = lastKey @@ -2229,7 +2239,8 @@ public final class SqliteValueBox: ValueBox { private func hexString(_ data: Data) -> String { let hexString = NSMutableString() - data.withUnsafeBytes { (bytes: UnsafePointer) -> Void in + data.withUnsafeBytes { rawBytes -> Void in + let bytes = rawBytes.baseAddress!.assumingMemoryBound(to: UInt8.self) for i in 0 ..< data.count { hexString.appendFormat("%02x", UInt(bytes.advanced(by: i).pointee)) } diff --git a/submodules/Postbox/Sources/TimeBasedCleanup.swift b/submodules/Postbox/Sources/TimeBasedCleanup.swift index 0230cca372..6f46d82a2c 100644 --- a/submodules/Postbox/Sources/TimeBasedCleanup.swift +++ b/submodules/Postbox/Sources/TimeBasedCleanup.swift @@ -173,7 +173,7 @@ private final class TimeBasedCleanupImpl { DispatchQueue.global(qos: .background).async { var removedShortLivedCount: Int = 0 var removedGeneralCount: Int = 0 - var removedGeneralLimitCount: Int = 0 + let removedGeneralLimitCount: Int = 0 let startTime = CFAbsoluteTimeGetCurrent() diff --git a/submodules/Postbox/Sources/ValueBoxKey.swift b/submodules/Postbox/Sources/ValueBoxKey.swift index 227a39207a..e73b21ddf7 100644 --- a/submodules/Postbox/Sources/ValueBoxKey.swift +++ b/submodules/Postbox/Sources/ValueBoxKey.swift @@ -41,7 +41,8 @@ public struct ValueBoxKey: Equatable, Hashable, CustomStringConvertible, Compara public func setData(_ offset: Int, value: Data) { assert(offset >= 0 && offset + value.count <= self.length) let valueLength = value.count - value.withUnsafeBytes { (bytes: UnsafePointer) -> Void in + value.withUnsafeBytes { rawBytes -> Void in + let bytes = rawBytes.baseAddress!.assumingMemoryBound(to: UInt8.self) memcpy(self.memory + offset, bytes, valueLength) } } @@ -222,14 +223,9 @@ public struct ValueBoxKey: Equatable, Hashable, CustomStringConvertible, Compara assert(range.lowerBound >= 0 && range.upperBound <= self.length) return String(data: Data(bytes: self.memory.advanced(by: range.lowerBound), count: range.count), encoding: .utf8) } - - public var hashValue: Int { - var hash = 37 - let bytes = self.memory.assumingMemoryBound(to: Int8.self) - for i in 0 ..< self.length { - hash = (hash &* 54059) ^ (Int(bytes[i]) &* 76963) - } - return hash + + public func hash(into hasher: inout Hasher) { + hasher.combine(bytes: UnsafeRawBufferPointer(start: self.memory, count: self.length)) } public static func ==(lhs: ValueBoxKey, rhs: ValueBoxKey) -> Bool { diff --git a/submodules/Postbox/Sources/ViewTracker.swift b/submodules/Postbox/Sources/ViewTracker.swift index c76ff7dd21..652be020f3 100644 --- a/submodules/Postbox/Sources/ViewTracker.swift +++ b/submodules/Postbox/Sources/ViewTracker.swift @@ -222,7 +222,7 @@ final class ViewTracker { self.combinedViews.remove(index) } - func refreshViewsDueToExternalTransaction(postbox: Postbox, fetchUnsentMessageIds: () -> [MessageId], fetchSynchronizePeerReadStateOperations: () -> [PeerId: PeerReadStateSynchronizationOperation]) { + func refreshViewsDueToExternalTransaction(postbox: Postbox, currentTransaction: Transaction, fetchUnsentMessageIds: () -> [MessageId], fetchSynchronizePeerReadStateOperations: () -> [PeerId: PeerReadStateSynchronizationOperation]) { var updateTrackedHoles = false for (mutableView, pipe) in self.messageHistoryViews.copyItems() { @@ -234,7 +234,7 @@ final class ViewTracker { } for (mutableView, pipe) in self.chatListViews.copyItems() { - if mutableView.refreshDueToExternalTransaction(postbox: postbox) { + if mutableView.refreshDueToExternalTransaction(postbox: postbox, currentTransaction: currentTransaction) { mutableView.render(postbox: postbox) pipe.putNext((ChatListView(mutableView), .Generic)) } @@ -259,7 +259,7 @@ final class ViewTracker { } } - func updateViews(postbox: Postbox, transaction: PostboxTransaction) { + func updateViews(postbox: Postbox, currentTransaction: Transaction, transaction: PostboxTransaction) { var updateTrackedHoles = false if let currentUpdatedState = transaction.currentUpdatedState { @@ -337,7 +337,7 @@ final class ViewTracker { for (mutableView, pipe) in self.chatListViews.copyItems() { let context = MutableChatListViewReplayContext() - if mutableView.replay(postbox: postbox, operations: transaction.chatListOperations, updatedPeerNotificationSettings: transaction.currentUpdatedPeerNotificationSettings, updatedPeers: transaction.currentUpdatedPeers, updatedPeerPresences: transaction.currentUpdatedPeerPresences, transaction: transaction, context: context) { + if mutableView.replay(postbox: postbox, currentTransaction: currentTransaction, operations: transaction.chatListOperations, updatedPeerNotificationSettings: transaction.currentUpdatedPeerNotificationSettings, updatedPeers: transaction.currentUpdatedPeers, updatedPeerPresences: transaction.currentUpdatedPeerPresences, transaction: transaction, context: context) { mutableView.complete(postbox: postbox, context: context) mutableView.render(postbox: postbox) pipe.putNext((ChatListView(mutableView), .Generic)) diff --git a/submodules/Postbox/Sources/Views.swift b/submodules/Postbox/Sources/Views.swift index 255489a3fe..af7220b8ca 100644 --- a/submodules/Postbox/Sources/Views.swift +++ b/submodules/Postbox/Sources/Views.swift @@ -31,69 +31,78 @@ public enum PostboxViewKey: Hashable { case allChatListHoles(PeerGroupId) case historyTagInfo(peerId: PeerId, tag: MessageTags) case topChatMessage(peerIds: [PeerId]) - - public var hashValue: Int { + + public func hash(into hasher: inout Hasher) { switch self { case .itemCollectionInfos: - return 0 + hasher.combine(0) case .itemCollectionIds: - return 1 + hasher.combine(1) case let .peerChatState(peerId): - return peerId.hashValue + hasher.combine(peerId) case let .itemCollectionInfo(id): - return id.hashValue + hasher.combine(id) case let .orderedItemList(id): - return id.hashValue + hasher.combine(id) case .preferences: - return 3 + hasher.combine(3) case .globalMessageTags: - return 4 + hasher.combine(4) case let .peer(peerId, _): - return peerId.hashValue + hasher.combine(peerId) case let .pendingMessageActions(type): - return type.hashValue + hasher.combine(type) case let .invalidatedMessageHistoryTagSummaries(tagMask, namespace): - return tagMask.rawValue.hashValue ^ namespace.hashValue + hasher.combine(tagMask) + hasher.combine(namespace) case let .pendingMessageActionsSummary(type, peerId, namespace): - return type.hashValue ^ peerId.hashValue ^ namespace.hashValue + hasher.combine(type) + hasher.combine(peerId) + hasher.combine(namespace) case let .historyTagSummaryView(tag, peerId, namespace): - return tag.rawValue.hashValue ^ peerId.hashValue ^ namespace.hashValue + hasher.combine(tag) + hasher.combine(peerId) + hasher.combine(namespace) case let .cachedPeerData(peerId): - return peerId.hashValue + hasher.combine(peerId) case .unreadCounts: - return 5 + hasher.combine(5) case .combinedReadState: - return 16 + hasher.combine(16) case .peerNotificationSettings: - return 6 + hasher.combine(6) case .pendingPeerNotificationSettings: - return 7 + hasher.combine(7) case let .messageOfInterestHole(location, namespace, count): - return 8 &+ 31 &* location.hashValue &+ 31 &* namespace.hashValue &+ 31 &* count.hashValue + hasher.combine(8) + hasher.combine(location) + hasher.combine(namespace) + hasher.combine(count) case let .localMessageTag(tag): - return tag.hashValue + hasher.combine(tag) case .messages: - return 10 + hasher.combine(10) case .additionalChatListItems: - return 11 + hasher.combine(11) case let .cachedItem(id): - return id.hashValue + hasher.combine(id) case .peerPresences: - return 13 + hasher.combine(13) case .synchronizeGroupMessageStats: - return 14 + hasher.combine(14) case .peerNotificationSettingsBehaviorTimestampView: - return 15 + hasher.combine(15) case let .peerChatInclusion(peerId): - return peerId.hashValue + hasher.combine(peerId) case let .basicPeer(peerId): - return peerId.hashValue + hasher.combine(peerId) case let .allChatListHoles(groupId): - return groupId.hashValue + hasher.combine(groupId) case let .historyTagInfo(peerId, tag): - return peerId.hashValue ^ tag.hashValue + hasher.combine(peerId) + hasher.combine(tag) case let .topChatMessage(peerIds): - return peerIds.hashValue + hasher.combine(peerIds) } } diff --git a/submodules/TelegramCore/Sources/Account/AccountManager.swift b/submodules/TelegramCore/Sources/Account/AccountManager.swift index 5952e75f13..e62e7dc6d2 100644 --- a/submodules/TelegramCore/Sources/Account/AccountManager.swift +++ b/submodules/TelegramCore/Sources/Account/AccountManager.swift @@ -151,7 +151,7 @@ private var declaredEncodables: Void = { declareEncodable(SynchronizeSavedGifsOperation.self, f: { SynchronizeSavedGifsOperation(decoder: $0) }) declareEncodable(SynchronizeSavedStickersOperation.self, f: { SynchronizeSavedStickersOperation(decoder: $0) }) declareEncodable(SynchronizeRecentlyUsedMediaOperation.self, f: { SynchronizeRecentlyUsedMediaOperation(decoder: $0) }) - declareEncodable(CacheStorageSettings.self, f: { CacheStorageSettings(decoder: $0) }) + /*declareEncodable(CacheStorageSettings.self, f: { CacheStorageSettings(decoder: $0) }) declareEncodable(LocalizationSettings.self, f: { LocalizationSettings(decoder: $0) }) declareEncodable(LocalizationListState.self, f: { LocalizationListState(decoder: $0) }) declareEncodable(ProxySettings.self, f: { ProxySettings(decoder: $0) }) @@ -159,7 +159,7 @@ private var declaredEncodables: Void = { declareEncodable(RemoteStorageConfiguration.self, f: { RemoteStorageConfiguration(decoder: $0) }) declareEncodable(LimitsConfiguration.self, f: { LimitsConfiguration(decoder: $0) }) declareEncodable(VoipConfiguration.self, f: { VoipConfiguration(decoder: $0) }) - declareEncodable(SuggestedLocalizationEntry.self, f: { SuggestedLocalizationEntry(decoder: $0) }) + declareEncodable(SuggestedLocalizationEntry.self, f: { SuggestedLocalizationEntry(decoder: $0) })*/ declareEncodable(SynchronizeLocalizationUpdatesOperation.self, f: { SynchronizeLocalizationUpdatesOperation(decoder: $0) }) declareEncodable(ChannelMessageStateVersionAttribute.self, f: { ChannelMessageStateVersionAttribute(decoder: $0) }) declareEncodable(PeerGroupMessageStateVersionAttribute.self, f: { PeerGroupMessageStateVersionAttribute(decoder: $0) }) @@ -171,31 +171,31 @@ private var declaredEncodables: Void = { declareEncodable(ConsumablePersonalMentionMessageAttribute.self, f: { ConsumablePersonalMentionMessageAttribute(decoder: $0) }) declareEncodable(ConsumePersonalMessageAction.self, f: { ConsumePersonalMessageAction(decoder: $0) }) declareEncodable(CachedStickerPack.self, f: { CachedStickerPack(decoder: $0) }) - declareEncodable(LoggingSettings.self, f: { LoggingSettings(decoder: $0) }) + //declareEncodable(LoggingSettings.self, f: { LoggingSettings(decoder: $0) }) declareEncodable(CachedLocalizationInfos.self, f: { CachedLocalizationInfos(decoder: $0) }) declareEncodable(CachedSecureIdConfiguration.self, f: { CachedSecureIdConfiguration(decoder: $0) }) declareEncodable(CachedWallpapersConfiguration.self, f: { CachedWallpapersConfiguration(decoder: $0) }) declareEncodable(CachedThemesConfiguration.self, f: { CachedThemesConfiguration(decoder: $0) }) declareEncodable(SynchronizeGroupedPeersOperation.self, f: { SynchronizeGroupedPeersOperation(decoder: $0) }) - declareEncodable(ContentPrivacySettings.self, f: { ContentPrivacySettings(decoder: $0) }) + //declareEncodable(ContentPrivacySettings.self, f: { ContentPrivacySettings(decoder: $0) }) declareEncodable(TelegramDeviceContactImportedData.self, f: { TelegramDeviceContactImportedData(decoder: $0) }) declareEncodable(SecureFileMediaResource.self, f: { SecureFileMediaResource(decoder: $0) }) declareEncodable(CachedStickerQueryResult.self, f: { CachedStickerQueryResult(decoder: $0) }) declareEncodable(TelegramWallpaper.self, f: { TelegramWallpaper(decoder: $0) }) declareEncodable(TelegramTheme.self, f: { TelegramTheme(decoder: $0) }) - declareEncodable(ThemeSettings.self, f: { ThemeSettings(decoder: $0) }) + //declareEncodable(ThemeSettings.self, f: { ThemeSettings(decoder: $0) }) declareEncodable(SynchronizeMarkAllUnseenPersonalMessagesOperation.self, f: { SynchronizeMarkAllUnseenPersonalMessagesOperation(decoder: $0) }) declareEncodable(SynchronizeAppLogEventsOperation.self, f: { SynchronizeAppLogEventsOperation(decoder: $0) }) declareEncodable(CachedRecentPeers.self, f: { CachedRecentPeers(decoder: $0) }) - declareEncodable(AppChangelogState.self, f: { AppChangelogState(decoder: $0) }) - declareEncodable(AppConfiguration.self, f: { AppConfiguration(decoder: $0) }) + //declareEncodable(AppChangelogState.self, f: { AppChangelogState(decoder: $0) }) + //declareEncodable(AppConfiguration.self, f: { AppConfiguration(decoder: $0) }) declareEncodable(JSON.self, f: { JSON(decoder: $0) }) - declareEncodable(SearchBotsConfiguration.self, f: { SearchBotsConfiguration(decoder: $0) }) - declareEncodable(AutodownloadSettings.self, f: { AutodownloadSettings(decoder: $0 )}) + //declareEncodable(SearchBotsConfiguration.self, f: { SearchBotsConfiguration(decoder: $0) }) + //declareEncodable(AutodownloadSettings.self, f: { AutodownloadSettings(decoder: $0 )}) declareEncodable(TelegramMediaPoll.self, f: { TelegramMediaPoll(decoder: $0) }) declareEncodable(TelegramMediaUnsupported.self, f: { TelegramMediaUnsupported(decoder: $0) }) - declareEncodable(ContactsSettings.self, f: { ContactsSettings(decoder: $0) }) - declareEncodable(SecretChatSettings.self, f: { SecretChatSettings(decoder: $0) }) + //declareEncodable(ContactsSettings.self, f: { ContactsSettings(decoder: $0) }) + //declareEncodable(SecretChatSettings.self, f: { SecretChatSettings(decoder: $0) }) declareEncodable(EmojiKeywordCollectionInfo.self, f: { EmojiKeywordCollectionInfo(decoder: $0) }) declareEncodable(EmojiKeywordItem.self, f: { EmojiKeywordItem(decoder: $0) }) declareEncodable(SynchronizeEmojiKeywordsOperation.self, f: { SynchronizeEmojiKeywordsOperation(decoder: $0) }) @@ -209,14 +209,14 @@ private var declaredEncodables: Void = { declareEncodable(UpdateMessageReactionsAction.self, f: { UpdateMessageReactionsAction(decoder: $0) }) declareEncodable(RestrictedContentMessageAttribute.self, f: { RestrictedContentMessageAttribute(decoder: $0) }) declareEncodable(SendScheduledMessageImmediatelyAction.self, f: { SendScheduledMessageImmediatelyAction(decoder: $0) }) - declareEncodable(WalletCollection.self, f: { WalletCollection(decoder: $0) }) + //declareEncodable(WalletCollection.self, f: { WalletCollection(decoder: $0) }) declareEncodable(EmbeddedMediaStickersMessageAttribute.self, f: { EmbeddedMediaStickersMessageAttribute(decoder: $0) }) declareEncodable(TelegramMediaWebpageAttribute.self, f: { TelegramMediaWebpageAttribute(decoder: $0) }) declareEncodable(CachedPollOptionResult.self, f: { CachedPollOptionResult(decoder: $0) }) - declareEncodable(ChatListFiltersState.self, f: { ChatListFiltersState(decoder: $0) }) - declareEncodable(PeersNearbyState.self, f: { PeersNearbyState(decoder: $0) }) + //declareEncodable(ChatListFiltersState.self, f: { ChatListFiltersState(decoder: $0) }) + //declareEncodable(PeersNearbyState.self, f: { PeersNearbyState(decoder: $0) }) declareEncodable(TelegramMediaDice.self, f: { TelegramMediaDice(decoder: $0) }) - declareEncodable(ChatListFiltersFeaturedState.self, f: { ChatListFiltersFeaturedState(decoder: $0) }) + //declareEncodable(ChatListFiltersFeaturedState.self, f: { ChatListFiltersFeaturedState(decoder: $0) }) declareEncodable(SynchronizeChatListFiltersOperation.self, f: { SynchronizeChatListFiltersOperation(decoder: $0) }) declareEncodable(PromoChatListItem.self, f: { PromoChatListItem(decoder: $0) }) declareEncodable(TelegramMediaFile.VideoThumbnail.self, f: { TelegramMediaFile.VideoThumbnail(decoder: $0) }) @@ -225,18 +225,18 @@ private var declaredEncodables: Void = { declareEncodable(TelegramMediaImage.VideoRepresentation.self, f: { TelegramMediaImage.VideoRepresentation(decoder: $0) }) declareEncodable(Country.self, f: { Country(decoder: $0) }) declareEncodable(Country.CountryCode.self, f: { Country.CountryCode(decoder: $0) }) - declareEncodable(CountriesList.self, f: { CountriesList(decoder: $0) }) + //declareEncodable(CountriesList.self, f: { CountriesList(decoder: $0) }) declareEncodable(ValidationMessageAttribute.self, f: { ValidationMessageAttribute(decoder: $0) }) declareEncodable(EmojiSearchQueryMessageAttribute.self, f: { EmojiSearchQueryMessageAttribute(decoder: $0) }) declareEncodable(CachedPeerInvitationImporters.self, f: { CachedPeerInvitationImporters(decoder: $0) }) declareEncodable(CachedPeerExportedInvitations.self, f: { CachedPeerExportedInvitations(decoder: $0) }) declareEncodable(ExportedInvitation.self, f: { ExportedInvitation(decoder: $0) }) declareEncodable(CachedDisplayAsPeers.self, f: { CachedDisplayAsPeers(decoder: $0) }) - declareEncodable(WallpapersState.self, f: { WallpapersState(decoder: $0) }) + //declareEncodable(WallpapersState.self, f: { WallpapersState(decoder: $0) }) declareEncodable(WallpaperDataResource.self, f: { WallpaperDataResource(decoder: $0) }) declareEncodable(ForwardOptionsMessageAttribute.self, f: { ForwardOptionsMessageAttribute(decoder: $0) }) declareEncodable(ChatTheme.self, f: { ChatTheme(decoder: $0) }) - declareEncodable(ChatThemes.self, f: { ChatThemes(decoder: $0) }) + //declareEncodable(ChatThemes.self, f: { ChatThemes(decoder: $0) }) return }() diff --git a/submodules/TelegramCore/Sources/State/InitializeAccountAfterLogin.swift b/submodules/TelegramCore/Sources/State/InitializeAccountAfterLogin.swift index 946c40d2c0..bc770965ed 100644 --- a/submodules/TelegramCore/Sources/State/InitializeAccountAfterLogin.swift +++ b/submodules/TelegramCore/Sources/State/InitializeAccountAfterLogin.swift @@ -11,7 +11,7 @@ func initializedAppSettingsAfterLogin(transaction: Transaction, appVersion: Stri return state }) transaction.updatePreferencesEntry(key: PreferencesKeys.contactsSettings, { _ in - return ContactsSettings(synchronizeContacts: syncContacts) + return PreferencesEntry(ContactsSettings(synchronizeContacts: syncContacts)) }) } diff --git a/submodules/TelegramCore/Sources/SyncCore/SyncCore_AppChangelogState.swift b/submodules/TelegramCore/Sources/SyncCore/SyncCore_AppChangelogState.swift index 5fb0600001..471f40619a 100644 --- a/submodules/TelegramCore/Sources/SyncCore/SyncCore_AppChangelogState.swift +++ b/submodules/TelegramCore/Sources/SyncCore/SyncCore_AppChangelogState.swift @@ -1,6 +1,6 @@ import Postbox -public struct AppChangelogState: PreferencesEntry, Equatable { +public struct AppChangelogState: Codable { public var checkedVersion: String public var previousVersion: String @@ -11,21 +11,17 @@ public struct AppChangelogState: PreferencesEntry, Equatable { self.previousVersion = previousVersion } - public init(decoder: PostboxDecoder) { - self.checkedVersion = decoder.decodeStringForKey("checkedVersion", orElse: "") - self.previousVersion = decoder.decodeStringForKey("previousVersion", orElse: "") + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: StringCodingKey.self) + + self.checkedVersion = (try? container.decode(String.self, forKey: "checkedVersion")) ?? "" + self.previousVersion = (try? container.decode(String.self, forKey: "previousVersion")) ?? "" } - public func encode(_ encoder: PostboxEncoder) { - encoder.encodeString(self.checkedVersion, forKey: "checkedVersion") - encoder.encodeString(self.previousVersion, forKey: "previousVersion") - } - - public func isEqual(to: PreferencesEntry) -> Bool { - guard let to = to as? AppChangelogState else { - return false - } - - return self == to + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: StringCodingKey.self) + + try container.encode(self.checkedVersion, forKey: "checkedVersion") + try container.encode(self.previousVersion, forKey: "previousVersion") } } diff --git a/submodules/TelegramCore/Sources/SyncCore/SyncCore_AppConfiguration.swift b/submodules/TelegramCore/Sources/SyncCore/SyncCore_AppConfiguration.swift index 745e36f5b3..e7e54e5fa7 100644 --- a/submodules/TelegramCore/Sources/SyncCore/SyncCore_AppConfiguration.swift +++ b/submodules/TelegramCore/Sources/SyncCore/SyncCore_AppConfiguration.swift @@ -1,7 +1,7 @@ import Foundation import Postbox -public struct AppConfiguration: PreferencesEntry, Equatable { +public struct AppConfiguration: Codable { public var data: JSON? public static var defaultValue: AppConfiguration { @@ -23,11 +23,4 @@ public struct AppConfiguration: PreferencesEntry, Equatable { encoder.encodeNil(forKey: "data") } } - - public func isEqual(to: PreferencesEntry) -> Bool { - guard let to = to as? AppConfiguration else { - return false - } - return self == to - } } diff --git a/submodules/TelegramCore/Sources/SyncCore/SyncCore_AutodownloadSettings.swift b/submodules/TelegramCore/Sources/SyncCore/SyncCore_AutodownloadSettings.swift index a8f2af62e2..5205865220 100644 --- a/submodules/TelegramCore/Sources/SyncCore/SyncCore_AutodownloadSettings.swift +++ b/submodules/TelegramCore/Sources/SyncCore/SyncCore_AutodownloadSettings.swift @@ -6,7 +6,7 @@ public enum AutodownloadPreset { case high } -public struct AutodownloadPresetSettings: PostboxCoding, Equatable { +public struct AutodownloadPresetSettings: Codable { public let disabled: Bool public let photoSizeMax: Int32 public let videoSizeMax: Int32 @@ -25,28 +25,32 @@ public struct AutodownloadPresetSettings: PostboxCoding, Equatable { self.videoUploadMaxbitrate = videoUploadMaxbitrate } - public init(decoder: PostboxDecoder) { - self.disabled = decoder.decodeInt32ForKey("disabled", orElse: 0) != 0 - self.photoSizeMax = decoder.decodeInt32ForKey("photoSizeMax", orElse: 0) - self.videoSizeMax = decoder.decodeInt32ForKey("videoSizeMax", orElse: 0) - self.fileSizeMax = decoder.decodeInt32ForKey("fileSizeMax", orElse: 0) - self.preloadLargeVideo = decoder.decodeInt32ForKey("preloadLargeVideo", orElse: 0) != 0 - self.lessDataForPhoneCalls = decoder.decodeInt32ForKey("lessDataForPhoneCalls", orElse: 0) != 0 - self.videoUploadMaxbitrate = decoder.decodeInt32ForKey("videoUploadMaxbitrate", orElse: 0) + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: StringCodingKey.self) + + self.disabled = ((try? container.decode(Int32.self, forKey: "disabled")) ?? 0) != 0 + self.photoSizeMax = (try? container.decode(Int32.self, forKey: "photoSizeMax")) ?? 0 + self.videoSizeMax = (try? container.decode(Int32.self, forKey: "videoSizeMax")) ?? 0 + self.fileSizeMax = (try? container.decode(Int32.self, forKey: "fileSizeMax")) ?? 0 + self.preloadLargeVideo = ((try? container.decode(Int32.self, forKey: "preloadLargeVideo")) ?? 0) != 0 + self.lessDataForPhoneCalls = ((try? container.decode(Int32.self, forKey: "lessDataForPhoneCalls")) ?? 0) != 0 + self.videoUploadMaxbitrate = (try? container.decode(Int32.self, forKey: "videoUploadMaxbitrate")) ?? 0 } - public func encode(_ encoder: PostboxEncoder) { - encoder.encodeInt32(self.disabled ? 1 : 0, forKey: "disabled") - encoder.encodeInt32(self.photoSizeMax, forKey: "photoSizeMax") - encoder.encodeInt32(self.videoSizeMax, forKey: "videoSizeMax") - encoder.encodeInt32(self.fileSizeMax, forKey: "fileSizeMax") - encoder.encodeInt32(self.preloadLargeVideo ? 1 : 0, forKey: "preloadLargeVideo") - encoder.encodeInt32(self.lessDataForPhoneCalls ? 1 : 0, forKey: "lessDataForPhoneCalls") - encoder.encodeInt32(self.videoUploadMaxbitrate, forKey: "videoUploadMaxbitrate") + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: StringCodingKey.self) + + try container.encode((self.disabled ? 1 : 0) as Int32, forKey: "disabled") + try container.encode(self.photoSizeMax, forKey: "photoSizeMax") + try container.encode(self.videoSizeMax, forKey: "videoSizeMax") + try container.encode(self.fileSizeMax, forKey: "fileSizeMax") + try container.encode((self.preloadLargeVideo ? 1 : 0) as Int32, forKey: "preloadLargeVideo") + try container.encode((self.lessDataForPhoneCalls ? 1 : 0) as Int32, forKey: "lessDataForPhoneCalls") + try container.encode(self.videoUploadMaxbitrate, forKey: "videoUploadMaxbitrate") } } -public struct AutodownloadSettings: PreferencesEntry, Equatable { +public struct AutodownloadSettings: Codable { public let lowPreset: AutodownloadPresetSettings public let mediumPreset: AutodownloadPresetSettings public let highPreset: AutodownloadPresetSettings @@ -64,27 +68,19 @@ public struct AutodownloadSettings: PreferencesEntry, Equatable { self.highPreset = highPreset } - public init(decoder: PostboxDecoder) { - self.lowPreset = decoder.decodeObjectForKey("lowPreset", decoder: AutodownloadPresetSettings.init(decoder:)) as! AutodownloadPresetSettings - self.mediumPreset = decoder.decodeObjectForKey("mediumPreset", decoder: AutodownloadPresetSettings.init(decoder:)) as! AutodownloadPresetSettings - self.highPreset = decoder.decodeObjectForKey("highPreset", decoder: AutodownloadPresetSettings.init(decoder:)) as! AutodownloadPresetSettings + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: StringCodingKey.self) + + self.lowPreset = (try? container.decode(AutodownloadPresetSettings.self, forKey: "lowPreset")) ?? AutodownloadSettings.defaultSettings.lowPreset + self.mediumPreset = (try? container.decode(AutodownloadPresetSettings.self, forKey: "mediumPreset")) ?? AutodownloadSettings.defaultSettings.mediumPreset + self.highPreset = (try? container.decode(AutodownloadPresetSettings.self, forKey: "highPreset")) ?? AutodownloadSettings.defaultSettings.highPreset } - public func encode(_ encoder: PostboxEncoder) { - encoder.encodeObject(self.lowPreset, forKey: "lowPreset") - encoder.encodeObject(self.mediumPreset, forKey: "mediumPreset") - encoder.encodeObject(self.highPreset, forKey: "highPreset") - } - - public func isEqual(to: PreferencesEntry) -> Bool { - if let to = to as? AutodownloadSettings { - return self == to - } else { - return false - } - } - - public static func ==(lhs: AutodownloadSettings, rhs: AutodownloadSettings) -> Bool { - return lhs.lowPreset == rhs.lowPreset && lhs.mediumPreset == rhs.mediumPreset && lhs.highPreset == rhs.highPreset + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: StringCodingKey.self) + + try container.encode(self.lowPreset, forKey: "lowPreset") + try container.encode(self.mediumPreset, forKey: "mediumPreset") + try container.encode(self.highPreset, forKey: "highPreset") } } diff --git a/submodules/TelegramCore/Sources/SyncCore/SyncCore_CacheStorageSettings.swift b/submodules/TelegramCore/Sources/SyncCore/SyncCore_CacheStorageSettings.swift index 7cb77ded9e..aad6e59bd1 100644 --- a/submodules/TelegramCore/Sources/SyncCore/SyncCore_CacheStorageSettings.swift +++ b/submodules/TelegramCore/Sources/SyncCore/SyncCore_CacheStorageSettings.swift @@ -1,6 +1,6 @@ import Postbox -public struct CacheStorageSettings: PreferencesEntry, Equatable { +public struct CacheStorageSettings: Codable { public let defaultCacheStorageTimeout: Int32 public let defaultCacheStorageLimitGigabytes: Int32 @@ -13,26 +13,18 @@ public struct CacheStorageSettings: PreferencesEntry, Equatable { self.defaultCacheStorageLimitGigabytes = defaultCacheStorageLimitGigabytes } - public init(decoder: PostboxDecoder) { - self.defaultCacheStorageTimeout = decoder.decodeInt32ForKey("dt", orElse: Int32.max) - self.defaultCacheStorageLimitGigabytes = decoder.decodeInt32ForKey("dl", orElse: Int32.max) + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: StringCodingKey.self) + + self.defaultCacheStorageTimeout = (try? container.decode(Int32.self, forKey: "dt")) ?? Int32.max + self.defaultCacheStorageLimitGigabytes = (try? container.decode(Int32.self, forKey: "dl")) ?? Int32.max } - public func encode(_ encoder: PostboxEncoder) { - encoder.encodeInt32(self.defaultCacheStorageTimeout, forKey: "dt") - encoder.encodeInt32(self.defaultCacheStorageLimitGigabytes, forKey: "dl") - } - - public func isEqual(to: PreferencesEntry) -> Bool { - if let to = to as? CacheStorageSettings { - return self == to - } else { - return false - } - } - - public static func ==(lhs: CacheStorageSettings, rhs: CacheStorageSettings) -> Bool { - return lhs.defaultCacheStorageTimeout == rhs.defaultCacheStorageTimeout && lhs.defaultCacheStorageLimitGigabytes == rhs.defaultCacheStorageLimitGigabytes + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: StringCodingKey.self) + + try container.encode(self.defaultCacheStorageTimeout, forKey: "dt") + try container.encode(self.defaultCacheStorageLimitGigabytes, forKey: "dl") } public func withUpdatedDefaultCacheStorageTimeout(_ defaultCacheStorageTimeout: Int32) -> CacheStorageSettings { diff --git a/submodules/TelegramCore/Sources/SyncCore/SyncCore_ContactsSettings.swift b/submodules/TelegramCore/Sources/SyncCore/SyncCore_ContactsSettings.swift index 015285012f..eb9be316f4 100644 --- a/submodules/TelegramCore/Sources/SyncCore/SyncCore_ContactsSettings.swift +++ b/submodules/TelegramCore/Sources/SyncCore/SyncCore_ContactsSettings.swift @@ -1,7 +1,7 @@ import Foundation import Postbox -public struct ContactsSettings: Equatable, PreferencesEntry { +public struct ContactsSettings: Codable { public var synchronizeContacts: Bool public static var defaultSettings: ContactsSettings { @@ -12,19 +12,15 @@ public struct ContactsSettings: Equatable, PreferencesEntry { self.synchronizeContacts = synchronizeContacts } - public init(decoder: PostboxDecoder) { - self.synchronizeContacts = decoder.decodeInt32ForKey("synchronizeContacts", orElse: 0) != 0 + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: StringCodingKey.self) + + self.synchronizeContacts = ((try? container.decode(Int32.self, forKey: "synchronizeContacts")) ?? 0) != 0 } - public func encode(_ encoder: PostboxEncoder) { - encoder.encodeInt32(self.synchronizeContacts ? 1 : 0, forKey: "synchronizeContacts") - } - - public func isEqual(to: PreferencesEntry) -> Bool { - if let to = to as? ContactsSettings { - return self == to - } else { - return false - } + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: StringCodingKey.self) + + try container.encode((self.synchronizeContacts ? 1 : 0) as Int32, forKey: "synchronizeContacts") } } diff --git a/submodules/TelegramCore/Sources/SyncCore/SyncCore_ContentPrivacySettings.swift b/submodules/TelegramCore/Sources/SyncCore/SyncCore_ContentPrivacySettings.swift index 36fb7b306f..f2d527ac42 100644 --- a/submodules/TelegramCore/Sources/SyncCore/SyncCore_ContentPrivacySettings.swift +++ b/submodules/TelegramCore/Sources/SyncCore/SyncCore_ContentPrivacySettings.swift @@ -1,6 +1,6 @@ import Postbox -public final class ContentPrivacySettings: PreferencesEntry, Equatable { +public final class ContentPrivacySettings: Codable { public let enableSecretChatWebpagePreviews: Bool? public static var defaultSettings = ContentPrivacySettings(enableSecretChatWebpagePreviews: nil) @@ -9,34 +9,27 @@ public final class ContentPrivacySettings: PreferencesEntry, Equatable { self.enableSecretChatWebpagePreviews = enableSecretChatWebpagePreviews } - public init(decoder: PostboxDecoder) { - self.enableSecretChatWebpagePreviews = decoder.decodeOptionalInt32ForKey("enableSecretChatWebpagePreviews").flatMap { $0 != 0 } + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: StringCodingKey.self) + + if let value = try? container.decodeIfPresent(Int32.self, forKey: "enableSecretChatWebpagePreviews") { + self.enableSecretChatWebpagePreviews = value != 0 + } else { + self.enableSecretChatWebpagePreviews = nil + } } - public func encode(_ encoder: PostboxEncoder) { + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: StringCodingKey.self) + if let enableSecretChatWebpagePreviews = self.enableSecretChatWebpagePreviews { - encoder.encodeInt32(enableSecretChatWebpagePreviews ? 1 : 0, forKey: "enableSecretChatWebpagePreviews") + try container.encode((enableSecretChatWebpagePreviews ? 1 : 0) as Int32, forKey: "enableSecretChatWebpagePreviews") } else { - encoder.encodeNil(forKey: "enableSecretChatWebpagePreviews") + try container.encodeNil(forKey: "enableSecretChatWebpagePreviews") } } public func withUpdatedEnableSecretChatWebpagePreviews(_ enableSecretChatWebpagePreviews: Bool) -> ContentPrivacySettings { return ContentPrivacySettings(enableSecretChatWebpagePreviews: enableSecretChatWebpagePreviews) } - - public func isEqual(to: PreferencesEntry) -> Bool { - guard let to = to as? ContentPrivacySettings else { - return false - } - - return self == to - } - - public static func ==(lhs: ContentPrivacySettings, rhs: ContentPrivacySettings) -> Bool { - if lhs.enableSecretChatWebpagePreviews != rhs.enableSecretChatWebpagePreviews { - return false - } - return true - } -} \ No newline at end of file +} diff --git a/submodules/TelegramCore/Sources/SyncCore/SyncCore_GlobalNotificationSettings.swift b/submodules/TelegramCore/Sources/SyncCore/SyncCore_GlobalNotificationSettings.swift index fb162cad7b..b578c5cfc4 100644 --- a/submodules/TelegramCore/Sources/SyncCore/SyncCore_GlobalNotificationSettings.swift +++ b/submodules/TelegramCore/Sources/SyncCore/SyncCore_GlobalNotificationSettings.swift @@ -1,6 +1,6 @@ import Postbox -public struct MessageNotificationSettings: PostboxCoding, Equatable { +public struct MessageNotificationSettings: Codable { public var enabled: Bool public var displayPreviews: Bool public var sound: PeerMessageSound @@ -15,10 +15,13 @@ public struct MessageNotificationSettings: PostboxCoding, Equatable { self.sound = sound } - public init(decoder: PostboxDecoder) { - self.enabled = decoder.decodeInt32ForKey("e", orElse: 0) != 0 - self.displayPreviews = decoder.decodeInt32ForKey("p", orElse: 0) != 0 - self.sound = PeerMessageSound.decodeInline(decoder) + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: StringCodingKey.self) + + self.enabled = ((try? container.decode(Int32.self, forKey: "e")) ?? 0) != 0 + self.displayPreviews = ((try? container.decode(Int32.self, forKey: "p")) ?? 0) != 0 + + self.sound = PeerMessageSound.decodeInline(container) } public func encode(_ encoder: PostboxEncoder) { @@ -28,7 +31,7 @@ public struct MessageNotificationSettings: PostboxCoding, Equatable { } } -public struct GlobalNotificationSettingsSet: PostboxCoding, Equatable { +public struct GlobalNotificationSettingsSet: Codable { public var privateChats: MessageNotificationSettings public var groupChats: MessageNotificationSettings public var channels: MessageNotificationSettings @@ -45,7 +48,9 @@ public struct GlobalNotificationSettingsSet: PostboxCoding, Equatable { self.contactsJoined = contactsJoined } - public init(decoder: PostboxDecoder) { + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: StringCodingKey.self) + self.privateChats = decoder.decodeObjectForKey("p", decoder: { MessageNotificationSettings(decoder: $0) }) as! MessageNotificationSettings self.groupChats = decoder.decodeObjectForKey("g", decoder: { MessageNotificationSettings(decoder: $0) }) as! MessageNotificationSettings self.channels = (decoder.decodeObjectForKey("c", decoder: { MessageNotificationSettings(decoder: $0) }) as? MessageNotificationSettings) ?? MessageNotificationSettings.defaultSettings @@ -60,7 +65,7 @@ public struct GlobalNotificationSettingsSet: PostboxCoding, Equatable { } } -public struct GlobalNotificationSettings: PreferencesEntry, Equatable, PostboxGlobalNotificationSettings { +public struct GlobalNotificationSettings: Codable { public var toBeSynchronized: GlobalNotificationSettingsSet? public var remote: GlobalNotificationSettingsSet @@ -73,8 +78,16 @@ public struct GlobalNotificationSettings: PreferencesEntry, Equatable, PostboxGl return self.remote } } + + public var postboxAccessor: PostboxGlobalNotificationSettings { + return PostboxGlobalNotificationSettings( + defaultIncludePeer: { peer in + return self.defaultIncludePeer(peer: peer) + } + ) + } - public func defaultIncludePeer(peer: Peer) -> Bool { + private func defaultIncludePeer(peer: Peer) -> Bool { let settings = self.effective if peer is TelegramUser || peer is TelegramSecretChat { return settings.privateChats.enabled @@ -92,7 +105,7 @@ public struct GlobalNotificationSettings: PreferencesEntry, Equatable, PostboxGl } } - public func isEqualInDefaultPeerInclusion(other: PostboxGlobalNotificationSettings) -> Bool { + /*public func isEqualInDefaultPeerInclusion(other: PostboxGlobalNotificationSettings) -> Bool { guard let other = other as? GlobalNotificationSettings else { return false } @@ -110,19 +123,21 @@ public struct GlobalNotificationSettings: PreferencesEntry, Equatable, PostboxGl } return true - } + }*/ public init(toBeSynchronized: GlobalNotificationSettingsSet?, remote: GlobalNotificationSettingsSet) { self.toBeSynchronized = toBeSynchronized self.remote = remote } - public init(decoder: PostboxDecoder) { + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: StringCodingKey.self) + self.toBeSynchronized = decoder.decodeObjectForKey("s", decoder: { GlobalNotificationSettingsSet(decoder: $0) }) as? GlobalNotificationSettingsSet self.remote = decoder.decodeObjectForKey("r", decoder: { GlobalNotificationSettingsSet(decoder: $0) }) as! GlobalNotificationSettingsSet } - public func encode(_ encoder: PostboxEncoder) { + public func encode(to encoder: Encoder) throws { if let toBeSynchronized = self.toBeSynchronized { encoder.encodeObject(toBeSynchronized, forKey: "s") } else { @@ -130,12 +145,4 @@ public struct GlobalNotificationSettings: PreferencesEntry, Equatable, PostboxGl } encoder.encodeObject(self.remote, forKey: "r") } - - public func isEqual(to: PreferencesEntry) -> Bool { - if let to = to as? GlobalNotificationSettings { - return self == to - } else { - return false - } - } } diff --git a/submodules/TelegramCore/Sources/SyncCore/SyncCore_StandaloneAccountTransaction.swift b/submodules/TelegramCore/Sources/SyncCore/SyncCore_StandaloneAccountTransaction.swift index 3fa2fbac52..c847557787 100644 --- a/submodules/TelegramCore/Sources/SyncCore/SyncCore_StandaloneAccountTransaction.swift +++ b/submodules/TelegramCore/Sources/SyncCore/SyncCore_StandaloneAccountTransaction.swift @@ -62,7 +62,9 @@ public let telegramPostboxSeedConfiguration: SeedConfiguration = { assertionFailure() return .nonContact } - }, additionalChatListIndexNamespace: Namespaces.Message.Cloud, messageNamespacesRequiringGroupStatsValidation: [Namespaces.Message.Cloud], defaultMessageNamespaceReadStates: [Namespaces.Message.Local: .idBased(maxIncomingReadId: 0, maxOutgoingReadId: 0, maxKnownId: 0, count: 0, markedUnread: false)], chatMessagesNamespaces: Set([Namespaces.Message.Cloud, Namespaces.Message.Local, Namespaces.Message.SecretIncoming]), globalNotificationSettingsPreferencesKey: PreferencesKeys.globalNotifications, defaultGlobalNotificationSettings: GlobalNotificationSettings.defaultSettings) + }, additionalChatListIndexNamespace: Namespaces.Message.Cloud, messageNamespacesRequiringGroupStatsValidation: [Namespaces.Message.Cloud], defaultMessageNamespaceReadStates: [Namespaces.Message.Local: .idBased(maxIncomingReadId: 0, maxOutgoingReadId: 0, maxKnownId: 0, count: 0, markedUnread: false)], chatMessagesNamespaces: Set([Namespaces.Message.Cloud, Namespaces.Message.Local, Namespaces.Message.SecretIncoming]), globalNotificationSettingsPreferencesKey: { transaction in + return transaction.getPreferencesEntry(PreferencesKeys.globalNotifications)?.get(GlobalNotificationSettings.self) + }, defaultGlobalNotificationSettings: GlobalNotificationSettings.defaultSettings) }() public enum AccountTransactionError { diff --git a/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramPeerNotificationSettings.swift b/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramPeerNotificationSettings.swift index 2a7fbe065c..3909c52596 100644 --- a/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramPeerNotificationSettings.swift +++ b/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramPeerNotificationSettings.swift @@ -44,14 +44,14 @@ public enum PeerMessageSound: Equatable { case bundledModern(id: Int32) case bundledClassic(id: Int32) - static func decodeInline(_ decoder: PostboxDecoder) -> PeerMessageSound { - switch decoder.decodeInt32ForKey("s.v", orElse: 0) { + static func decodeInline(_ container: KeyedDecodingContainer) throws -> PeerMessageSound { + switch try container.decode(Int32.self, forKey: "s.v") { case PeerMessageSoundValue.none.rawValue: return .none case PeerMessageSoundValue.bundledModern.rawValue: - return .bundledModern(id: decoder.decodeInt32ForKey("s.i", orElse: 0)) + return .bundledModern(id: (try? container.decode(Int32.self, forKey: "s.i")) ?? 0) case PeerMessageSoundValue.bundledClassic.rawValue: - return .bundledClassic(id: decoder.decodeInt32ForKey("s.i", orElse: 0)) + return .bundledClassic(id: (try? container.decode(Int32.self, forKey: "s.i")) ?? 0) case PeerMessageSoundValue.default.rawValue: return .default default: @@ -170,7 +170,7 @@ public final class TelegramPeerNotificationSettings: PeerNotificationSettings, E self.displayPreviews = displayPreviews } - public init(decoder: PostboxDecoder) { + public init() { self.muteState = PeerMuteState.decodeInline(decoder) self.messageSound = PeerMessageSound.decodeInline(decoder) self.displayPreviews = PeerNotificationDisplayPreviews.decodeInline(decoder) diff --git a/submodules/TelegramVoip/Sources/GroupCallContext.swift b/submodules/TelegramVoip/Sources/GroupCallContext.swift index 0f3be046b2..7ab35eaf4e 100644 --- a/submodules/TelegramVoip/Sources/GroupCallContext.swift +++ b/submodules/TelegramVoip/Sources/GroupCallContext.swift @@ -63,7 +63,7 @@ private final class NetworkBroadcastPartSource: BroadcastPartSource { if timestampMilliseconds != 0 { timestampIdMilliseconds = timestampMilliseconds } else { - timestampIdMilliseconds = (Int64(Date().timeIntervalSince1970 * 1000.0) / durationMilliseconds) * durationMilliseconds + timestampIdMilliseconds = (Int64((Date().timeIntervalSince1970) * 1000.0) / durationMilliseconds) * durationMilliseconds } let dataSource: Signal From 1141e09c1b29beaebd54dec30ed07e976d19f6d3 Mon Sep 17 00:00:00 2001 From: Ali <> Date: Tue, 7 Sep 2021 13:09:06 +0400 Subject: [PATCH 02/30] Refactoring --- submodules/AppLock/Sources/AppLock.swift | 2 +- .../Sources/CallListControllerNode.swift | 2 +- .../ChatListUI/Sources/ChatContextMenus.swift | 2 +- .../Sources/ChatListController.swift | 10 +- .../ChatListFilterPresetListController.swift | 4 +- .../Sources/ChatListSearchListPaneNode.swift | 4 +- .../Sources/Node/ChatListNode.swift | 4 +- .../Sources/ContactListNode.swift | 2 +- .../Sources/ContactsController.swift | 6 +- .../Sources/DebugController.swift | 60 ++--- .../GalleryUI/Sources/GalleryController.swift | 2 +- .../Sources/InstantPageController.swift | 4 +- .../Source/ObjCRuntimeUtils/RuntimeUtils.h | 2 + .../Source/ObjCRuntimeUtils/RuntimeUtils.m | 28 +-- .../Sources/ChannelInfoController.swift | 4 +- .../GroupStickerPackSetupController.swift | 2 +- .../Sources/PeersNearbyController.swift | 2 +- submodules/Postbox/Sources/Coding.swift | 60 ++++- .../Postbox/Sources/PreferencesEntry.swift | 30 ++- .../Postbox/Sources/SeedConfiguration.swift | 22 +- .../Utils/Decoder/AdaptedPostboxDecoder.swift | 7 +- ...aptedPostboxUnkeyedDecodingContainer.swift | 32 +++ .../Utils/Encoder/AdaptedPostboxEncoder.swift | 18 +- ...AdaptedPostboxKeyedEncodingContainer.swift | 25 +- ...dPostboxSingleValueEncodingContainer.swift | 2 +- ...aptedPostboxUnkeyedEncodingContainer.swift | 34 ++- ...AutodownloadConnectionTypeController.swift | 4 +- .../AutodownloadMediaCategoryController.swift | 6 +- .../DataAndStorageSettingsController.swift | 12 +- .../IntentsSettingsController.swift | 2 +- .../ProxyListSettingsController.swift | 2 +- .../SaveIncomingMediaController.swift | 2 +- .../StorageUsageController.swift | 2 +- .../VoiceCallDataSavingController.swift | 4 +- .../WebBrowserSettingsController.swift | 2 +- .../LocalizationListControllerNode.swift | 8 +- ...ificationExceptionSettingsController.swift | 2 +- .../NotificationsAndSounds.swift | 4 +- .../DataPrivacySettingsController.swift | 10 +- .../PasscodeOptionsController.swift | 4 +- .../PrivacyAndSecurityController.swift | 6 +- .../RecentSessionsController.swift | 2 +- .../Search/SettingsSearchableItems.swift | 12 +- .../ArchivedStickerPacksController.swift | 2 +- .../FeaturedStickerPacksController.swift | 2 +- .../InstalledStickerPacksController.swift | 2 +- .../Themes/ThemeAccentColorController.swift | 2 +- .../ThemeAutoNightSettingsController.swift | 4 +- .../Themes/ThemeColorsGridController.swift | 2 +- .../Themes/ThemeGridControllerNode.swift | 2 +- .../Themes/ThemePreviewController.swift | 4 +- .../Themes/ThemeSettingsController.swift | 14 +- .../Watch/WatchSettingsController.swift | 2 +- .../StickerPackPreviewController.swift | 2 +- .../Sources/TelegramBaseController.swift | 4 +- .../Sources/CallController.swift | 2 +- .../Sources/PresentationCallManager.swift | 28 +-- .../Sources/VoiceChatController.swift | 2 +- submodules/TelegramCore/BUILD | 3 + .../Sources/Account/Account.swift | 60 +++-- .../Account/AccountIntermediateState.swift | 2 +- .../Sources/Account/AccountManager.swift | 2 +- .../ReplyMarkupMessageAttribute.swift | 2 +- .../ApiUtils/StoreMessage_Telegram.swift | 12 +- .../TelegramCore/Sources/Authorization.swift | 4 +- .../Network/FetchedMediaResource.swift | 16 +- .../Sources/Network/MultipartFetch.swift | 9 +- .../Sources/Network/MultipartUpload.swift | 19 +- .../Sources/Network/Network.swift | 19 +- .../TelegramCore/Sources/PeerStatistics.swift | 3 +- .../PendingMessages/EnqueueMessage.swift | 4 +- .../PendingMessageUploadedContent.swift | 19 +- .../PendingMessages/RequestEditMessage.swift | 5 +- .../StandaloneSendMessage.swift | 3 +- .../StandaloneUploadedMedia.swift | 4 +- .../SecretChats/SecretChatEncryption.swift | 86 ++++--- .../SecretChats/SecretChatRekeySession.swift | 6 +- .../SecretChats/UpdateSecretChat.swift | 8 +- .../Sources/Settings/ContentSettings.swift | 4 +- .../State/AccountStateManagementUtils.swift | 36 +-- .../Sources/State/AccountStateManager.swift | 21 +- .../Sources/State/AccountViewTracker.swift | 6 +- .../Sources/State/AppChangelog.swift | 2 +- .../Sources/State/AppChangelogState.swift | 2 +- .../Sources/State/ApplyUpdateMessage.swift | 8 +- .../State/CachedSentMediaReferences.swift | 6 +- .../Sources/State/CallSessionManager.swift | 14 +- .../State/ChatHistoryPreloadManager.swift | 2 +- .../Sources/State/ContactSyncManager.swift | 5 +- .../Sources/State/FetchChatList.swift | 8 +- .../State/HistoryViewStateValidation.swift | 6 +- .../Sources/State/ManagedChatListHoles.swift | 2 +- .../State/ManagedConfigurationUpdates.swift | 22 +- .../ManagedGlobalNotificationSettings.swift | 3 + .../State/ManagedProxyInfoUpdates.swift | 2 +- .../ManagedSecretChatOutgoingOperations.swift | 6 +- .../ManagedSynchronizeGroupMessageStats.swift | 8 +- ...onizeInstalledStickerPacksOperations.swift | 9 +- ...kAllUnseenPersonalMessagesOperations.swift | 8 +- ...agedSynchronizePinnedChatsOperations.swift | 6 +- .../Sources/State/PendingMessageManager.swift | 3 - ...ecretChatIncomingDecryptedOperations.swift | 14 +- .../Sources/State/Serialization.swift | 4 +- .../Sources/State/StickerManagement.swift | 8 +- ...onizeConsumeMessageContentsOperation.swift | 2 +- .../State/SynchronizePeerReadState.swift | 2 - .../SynchronizeSavedStickersOperation.swift | 4 +- .../Sources/State/UpdatesApiUtils.swift | 40 ++- .../TelegramCore/Sources/Suggestions.swift | 2 +- .../SyncCore/SyncCore_AppConfiguration.swift | 16 +- .../SyncCore_CachedResolvedByNamePeer.swift | 4 +- .../SyncCore_CloudFileMediaResource.swift | 18 +- .../SyncCore_GlobalNotificationSettings.swift | 45 ++-- .../Sources/SyncCore/SyncCore_JSON.swift | 74 ++++-- .../SyncCore_LimitsConfiguration.swift | 2 +- .../SyncCore/SyncCore_MediaReference.swift | 2 +- .../SyncCore/SyncCore_SecretChatState.swift | 24 +- ...yncCore_StandaloneAccountTransaction.swift | 80 ++++-- ...ore_SynchronizeAppLogEventsOperation.swift | 59 +++-- ...ore_TelegramPeerNotificationSettings.swift | 31 +++ .../SyncCore/SyncCore_TelegramTheme.swift | 45 +--- .../SyncCore/SyncCore_ThemeSettings.swift | 13 +- .../ChangeAccountPhoneNumber.swift | 2 +- .../TelegramEngine/Auth/AuthTransfer.swift | 10 +- .../Auth/TwoStepVerification.swift | 8 +- .../Contacts/ContactManagement.swift | 4 +- .../Contacts/UpdateContactName.swift | 2 +- .../TelegramEngine/Data/Configuration.swift | 2 +- .../Localization/LocalizationInfo.swift | 4 +- .../Localization/Localizations.swift | 4 +- .../TelegramEngine/Messages/ChatList.swift | 2 +- .../Messages/ExportMessageLink.swift | 2 +- ...OutgoingMessageWithChatContextResult.swift | 2 +- .../TelegramEngine/Messages/Polls.swift | 8 +- .../Messages/RequestChatContextResults.swift | 2 +- .../Messages/RequestStartBot.swift | 8 +- .../Messages/SearchMessages.swift | 2 - .../Messages/UpdatePinnedMessage.swift | 3 - .../Payments/BotPaymentForm.swift | 2 +- .../Peers/ChannelOwnershipTransfer.swift | 7 +- .../Peers/ChatListFiltering.swift | 6 +- .../Peers/ConvertGroupToSupergroup.swift | 3 +- .../Peers/CreateSecretChat.swift | 6 +- .../Peers/InactiveChannels.swift | 8 +- .../Peers/InvitationLinks.swift | 4 +- .../TelegramEngine/Peers/JoinLink.swift | 6 +- .../Peers/ManageChannelDiscussionGroup.swift | 2 +- .../Peers/PeerPhotoUpdater.swift | 10 +- .../Peers/RequestUserPhotos.swift | 10 +- .../TelegramEngine/Peers/SearchPeers.swift | 4 +- .../Peers/TogglePeerChatPinned.swift | 2 +- .../Peers/UpdateCachedPeerData.swift | 74 +++--- .../TelegramEngine/Peers/UpdatePeerInfo.swift | 8 +- .../UpdatedAccountPrivacySettings.swift | 4 +- .../Resources/CollectCacheUsageStats.swift | 14 +- .../SecureId/AccessSecureId.swift | 24 +- .../SecureId/RequestSecureIdForm.swift | 2 +- .../SecureId/SaveSecureIdValue.swift | 4 +- .../SecureId/SecureIdPadding.swift | 8 +- .../SecureId/SecureIdValueAccessContext.swift | 4 +- .../SecureId/UploadSecureIdFile.swift | 1 - .../Stickers/ImportStickers.swift | 2 +- .../Stickers/SearchStickers.swift | 2 +- .../Stickers/StickerSetInstallation.swift | 8 +- .../TelegramEngine/Themes/ChatThemes.swift | 12 +- .../TelegramCore/Sources/UpdatePeers.swift | 6 +- .../TelegramCore/Sources/Utils/Log.swift | 12 +- .../Sources/Utils/PeerUtils.swift | 21 +- .../TelegramCore/Sources/Wallpapers.swift | 2 +- .../Sources/TelegramIntents.swift | 2 +- .../Sources/PermissionSplitTest.swift | 2 +- .../Sources/PresentationData.swift | 24 +- submodules/TelegramUI/BUILD | 3 + .../TelegramUI/Sources/AccountContext.swift | 6 +- .../TelegramUI/Sources/AppDelegate.swift | 33 +-- .../Sources/ApplicationContext.swift | 6 +- .../TelegramUI/Sources/AudioWaveform.swift | 14 +- .../Sources/AudioWaveformNode.swift | 4 +- ...uthorizationSequenceSplashController.swift | 4 +- .../TelegramUI/Sources/ChatController.swift | 14 +- .../Sources/ChatControllerNode.swift | 2 +- .../Sources/ChatHistoryListNode.swift | 2 +- .../Sources/ChatHistoryViewForLocation.swift | 8 +- .../ChatInterfaceStateContextMenus.swift | 16 +- .../ChatInterfaceStateContextQueries.swift | 4 +- .../Sources/ChatMediaInputNode.swift | 2 +- .../ChatMessageAnimatedStickerItemNode.swift | 2 +- .../ChatMessageAvatarAccessoryItem.swift | 4 +- .../Sources/ChatMessageBackground.swift | 1 - .../Sources/ChatMessageBubbleItemNode.swift | 39 ++- .../Sources/ChatMessageDateHeader.swift | 4 +- .../ChatMessageInteractiveMediaNode.swift | 9 +- .../TelegramUI/Sources/ChatMessageItem.swift | 8 +- .../Sources/ChatMessageItemView.swift | 24 +- .../ChatMessageWebpageBubbleContentNode.swift | 2 +- .../ChatSearchResultsContollerNode.swift | 6 +- ...TextInputAudioRecordingOverlayButton.swift | 3 +- .../Sources/ChatTextInputPanelNode.swift | 9 +- .../ContactMultiselectionController.swift | 4 +- .../Sources/CreateGroupController.swift | 1 - .../Sources/DeclareEncodables.swift | 46 ++-- .../Sources/DrawingStickersScreen.swift | 2 +- .../TelegramUI/Sources/EmojiResources.swift | 8 +- .../TelegramUI/Sources/FetchManager.swift | 11 +- .../Sources/FetchVideoMediaResource.swift | 4 +- ...textResultsChatInputContextPanelNode.swift | 6 +- .../Sources/HorizontalStickerGridItem.swift | 15 +- .../TelegramUI/Sources/ID3ArtworkReader.swift | 4 +- .../Sources/ManageSharedAccountInfo.swift | 2 +- .../Sources/ManagedAudioRecorder.swift | 21 +- .../Sources/ManagedDiceAnimationNode.swift | 2 +- .../TelegramUI/Sources/MediaManager.swift | 2 +- .../TelegramUI/Sources/OpenResolvedUrl.swift | 6 +- submodules/TelegramUI/Sources/OpenUrl.swift | 6 +- .../PeerInfo/Panes/PeerInfoListPaneNode.swift | 4 +- .../Sources/PeerInfo/PeerInfoData.swift | 24 +- .../Sources/PeerInfo/PeerInfoHeaderNode.swift | 8 +- .../Sources/PeerInfo/PeerInfoMembers.swift | 40 ++- .../Sources/PeerInfo/PeerInfoScreen.swift | 23 +- .../PeerSelectionTextInputPanelNode.swift | 9 +- .../Sources/PeersNearbyManager.swift | 10 +- .../Sources/PollResultsController.swift | 50 ++-- .../TelegramUI/Sources/PrefetchManager.swift | 2 +- .../Sources/ShareExtensionContext.swift | 6 +- .../Sources/SharedAccountContext.swift | 18 +- .../Sources/StoreDownloadedMedia.swift | 2 +- .../Sources/ThemeUpdateManager.swift | 6 +- .../TelegramUI/Sources/UpgradedAccounts.swift | 15 +- ...textResultsChatInputContextPanelNode.swift | 6 +- ...ListContextResultsChatInputPanelItem.swift | 4 +- .../Sources/ChatArchiveSettings.swift | 7 +- .../ContactSynchronizationSettings.swift | 4 +- .../Sources/ExperimentalUISettings.swift | 77 +++--- .../Sources/GeneratedMediaStoreSettings.swift | 30 +-- .../Sources/InAppNotificationSettings.swift | 56 ++--- .../InstantPagePresentationSettings.swift | 42 ++-- .../Sources/IntentsSettings.swift | 54 ++-- ...LegacyAutomaticMediaDownloadSettings.swift | 128 ---------- .../Sources/MediaAutoDownloadSettings.swift | 171 +++++++------ .../Sources/MediaInputSettings.swift | 26 +- .../Sources/MusicPlaybackSettings.swift | 34 ++- .../PresentationPasscodeSettings.swift | 50 ++-- .../Sources/PresentationThemeSettings.swift | 234 +++++++++++------- .../Sources/RenderedTotalUnreadCount.swift | 2 +- .../Sources/StickerSettings.swift | 30 +-- .../Sources/VoiceCallSettings.swift | 30 +-- .../Sources/VoipDerivedState.swift | 27 +- .../Sources/WatchPresetSettings.swift | 30 +-- .../Sources/WebBrowserSettings.swift | 30 +-- .../Sources/WebSearchSettings.swift | 26 +- .../Sources/WidgetSettings.swift | 32 ++- .../UIViewController+Navigation.h | 7 + .../UIViewController+Navigation.m | 18 ++ .../UrlHandling/Sources/UrlHandling.swift | 2 +- .../Sources/WatchCommunicationManager.swift | 2 +- .../Sources/WebSearchController.swift | 4 +- .../Sources/WidgetSetupScreen.swift | 2 +- 257 files changed, 1894 insertions(+), 1720 deletions(-) delete mode 100644 submodules/TelegramUIPreferences/Sources/LegacyAutomaticMediaDownloadSettings.swift diff --git a/submodules/AppLock/Sources/AppLock.swift b/submodules/AppLock/Sources/AppLock.swift index 51e480825e..ccaceca2ac 100644 --- a/submodules/AppLock/Sources/AppLock.swift +++ b/submodules/AppLock/Sources/AppLock.swift @@ -120,7 +120,7 @@ public final class AppLockContextImpl: AppLockContext { return } - let passcodeSettings: PresentationPasscodeSettings = sharedData.entries[ApplicationSpecificSharedDataKeys.presentationPasscodeSettings] as? PresentationPasscodeSettings ?? .defaultSettings + let passcodeSettings: PresentationPasscodeSettings = sharedData.entries[ApplicationSpecificSharedDataKeys.presentationPasscodeSettings]?.get(PresentationPasscodeSettings.self) ?? .defaultSettings let timestamp = CFAbsoluteTimeGetCurrent() var becameActiveRecently = false diff --git a/submodules/CallListUI/Sources/CallListControllerNode.swift b/submodules/CallListUI/Sources/CallListControllerNode.swift index bd995283c0..fee8c3a6bc 100644 --- a/submodules/CallListUI/Sources/CallListControllerNode.swift +++ b/submodules/CallListUI/Sources/CallListControllerNode.swift @@ -453,7 +453,7 @@ final class CallListControllerNode: ASDisplayNode { let showCallsTab = context.sharedContext.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.callListSettings]) |> map { sharedData -> Bool in var value = CallListSettings.defaultSettings.showTab - if let settings = sharedData.entries[ApplicationSpecificSharedDataKeys.callListSettings] as? CallListSettings { + if let settings = sharedData.entries[ApplicationSpecificSharedDataKeys.callListSettings]?.get(CallListSettings.self) { value = settings.showTab } return value diff --git a/submodules/ChatListUI/Sources/ChatContextMenus.swift b/submodules/ChatListUI/Sources/ChatContextMenus.swift index 52f12478f7..6c44f427ad 100644 --- a/submodules/ChatListUI/Sources/ChatContextMenus.swift +++ b/submodules/ChatListUI/Sources/ChatContextMenus.swift @@ -29,7 +29,7 @@ func archiveContextMenuItems(context: AccountContext, groupId: PeerGroupId, chat }))) } - let settings = transaction.getPreferencesEntry(key: ApplicationSpecificPreferencesKeys.chatArchiveSettings) as? ChatArchiveSettings ?? ChatArchiveSettings.default + let settings = transaction.getPreferencesEntry(key: ApplicationSpecificPreferencesKeys.chatArchiveSettings)?.get(ChatArchiveSettings.self) ?? ChatArchiveSettings.default let isPinned = !settings.isHiddenByDefault items.append(.action(ContextMenuActionItem(text: isPinned ? strings.ChatList_Context_HideArchive : strings.ChatList_Context_UnhideArchive, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: isPinned ? "Chat/Context Menu/Unpin": "Chat/Context Menu/Pin"), color: theme.contextMenu.primaryColor) }, action: { [weak chatListController] _, f in chatListController?.toggleArchivedFolderHiddenByDefault() diff --git a/submodules/ChatListUI/Sources/ChatListController.swift b/submodules/ChatListUI/Sources/ChatListController.swift index 5e20fd528e..304eef16ea 100644 --- a/submodules/ChatListUI/Sources/ChatListController.swift +++ b/submodules/ChatListUI/Sources/ChatListController.swift @@ -262,7 +262,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController let hasProxy = context.sharedContext.accountManager.sharedData(keys: [SharedDataKeys.proxySettings]) |> map { sharedData -> (Bool, Bool) in - if let settings = sharedData.entries[SharedDataKeys.proxySettings] as? ProxySettings { + if let settings = sharedData.entries[SharedDataKeys.proxySettings]?.get(ProxySettings.self) { return (!settings.servers.isEmpty, settings.enabled) } else { return (false, false) @@ -1192,7 +1192,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController let context = self.context let signal = combineLatest(self.context.sharedContext.accountManager.transaction { transaction -> String in let languageCode: String - if let current = transaction.getSharedData(SharedDataKeys.localizationSettings) as? LocalizationSettings { + if let current = transaction.getSharedData(SharedDataKeys.localizationSettings)?.get(LocalizationSettings.self) { let code = current.primaryComponent.languageCode let rawSuffix = "-raw" if code.hasSuffix(rawSuffix) { @@ -1206,7 +1206,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController return languageCode }, self.context.account.postbox.transaction { transaction -> SuggestedLocalizationEntry? in var suggestedLocalization: SuggestedLocalizationEntry? - if let localization = transaction.getPreferencesEntry(key: PreferencesKeys.suggestedLocalization) as? SuggestedLocalizationEntry { + if let localization = transaction.getPreferencesEntry(key: PreferencesKeys.suggestedLocalization)?.get(SuggestedLocalizationEntry.self) { suggestedLocalization = localization } return suggestedLocalization @@ -1291,7 +1291,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController PreferencesKeys.chatListFiltersFeaturedState ]) |> mapToSignal { view -> Signal in - if let entry = view.values[PreferencesKeys.chatListFiltersFeaturedState] as? ChatListFiltersFeaturedState { + if let entry = view.values[PreferencesKeys.chatListFiltersFeaturedState]?.get(ChatListFiltersFeaturedState.self) { return .single(!entry.filters.isEmpty && !entry.isSeen) } else { return .complete() @@ -1537,7 +1537,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController let experimentalUISettingsKey: ValueBoxKey = ApplicationSpecificSharedDataKeys.experimentalUISettings let displayTabsAtBottom = self.context.sharedContext.accountManager.sharedData(keys: Set([experimentalUISettingsKey])) |> map { sharedData -> Bool in - let settings: ExperimentalUISettings = sharedData.entries[experimentalUISettingsKey] as? ExperimentalUISettings ?? ExperimentalUISettings.defaultSettings + let settings: ExperimentalUISettings = sharedData.entries[experimentalUISettingsKey]?.get(ExperimentalUISettings.self) ?? ExperimentalUISettings.defaultSettings return settings.foldersTabAtBottom } |> distinctUntilChanged diff --git a/submodules/ChatListUI/Sources/ChatListFilterPresetListController.swift b/submodules/ChatListUI/Sources/ChatListFilterPresetListController.swift index e9a86e85ff..0d4529588c 100644 --- a/submodules/ChatListUI/Sources/ChatListFilterPresetListController.swift +++ b/submodules/ChatListUI/Sources/ChatListFilterPresetListController.swift @@ -307,7 +307,7 @@ public func chatListFilterPresetListController(context: AccountContext, mode: Ch let featuredFilters = context.account.postbox.preferencesView(keys: [PreferencesKeys.chatListFiltersFeaturedState]) |> map { preferences -> [ChatListFeaturedFilter] in - guard let state = preferences.values[PreferencesKeys.chatListFiltersFeaturedState] as? ChatListFiltersFeaturedState else { + guard let state = preferences.values[PreferencesKeys.chatListFiltersFeaturedState]?.get(ChatListFiltersFeaturedState.self) else { return [] } return state.filters @@ -330,7 +330,7 @@ public func chatListFilterPresetListController(context: AccountContext, mode: Ch featuredFilters ) |> map { presentationData, state, filtersWithCountsValue, preferences, updatedFilterOrderValue, suggestedFilters -> (ItemListControllerState, (ItemListNodeState, Any)) in - let filterSettings = preferences.values[ApplicationSpecificPreferencesKeys.chatListFilterSettings] as? ChatListFilterSettings ?? ChatListFilterSettings.default + let filterSettings = preferences.values[ApplicationSpecificPreferencesKeys.chatListFilterSettings]?.get(ChatListFilterSettings.self) ?? ChatListFilterSettings.default let leftNavigationButton: ItemListNavigationButton? switch mode { case .default: diff --git a/submodules/ChatListUI/Sources/ChatListSearchListPaneNode.swift b/submodules/ChatListUI/Sources/ChatListSearchListPaneNode.swift index 30b18e6ca3..9e17ca6471 100644 --- a/submodules/ChatListUI/Sources/ChatListSearchListPaneNode.swift +++ b/submodules/ChatListUI/Sources/ChatListSearchListPaneNode.swift @@ -1743,10 +1743,10 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode { return } let _ = (strongSelf.context.sharedContext.accountManager.transaction { transaction -> AudioPlaybackRate in - let settings = transaction.getSharedData(ApplicationSpecificSharedDataKeys.musicPlaybackSettings) as? MusicPlaybackSettings ?? MusicPlaybackSettings.defaultSettings + let settings = transaction.getSharedData(ApplicationSpecificSharedDataKeys.musicPlaybackSettings)?.get(MusicPlaybackSettings.self) ?? MusicPlaybackSettings.defaultSettings transaction.updateSharedData(ApplicationSpecificSharedDataKeys.musicPlaybackSettings, { _ in - return settings.withUpdatedVoicePlaybackRate(rate) + return PreferencesEntry(settings.withUpdatedVoicePlaybackRate(rate)) }) return rate } diff --git a/submodules/ChatListUI/Sources/Node/ChatListNode.swift b/submodules/ChatListUI/Sources/Node/ChatListNode.swift index 7bae52d5e5..0a8889f411 100644 --- a/submodules/ChatListUI/Sources/Node/ChatListNode.swift +++ b/submodules/ChatListUI/Sources/Node/ChatListNode.swift @@ -806,7 +806,7 @@ public final class ChatListNode: ListView { let hideArchivedFolderByDefault = context.account.postbox.preferencesView(keys: [ApplicationSpecificPreferencesKeys.chatArchiveSettings]) |> map { view -> Bool in - let settings: ChatArchiveSettings = view.values[ApplicationSpecificPreferencesKeys.chatArchiveSettings] as? ChatArchiveSettings ?? .default + let settings: ChatArchiveSettings = view.values[ApplicationSpecificPreferencesKeys.chatArchiveSettings]?.get(ChatArchiveSettings.self) ?? .default return settings.isHiddenByDefault } |> distinctUntilChanged @@ -1759,7 +1759,7 @@ public final class ChatListNode: ListView { let postbox = self.context.account.postbox return self.context.sharedContext.accountManager.transaction { transaction -> Signal in var filter = true - if let inAppNotificationSettings = transaction.getSharedData(ApplicationSpecificSharedDataKeys.inAppNotificationSettings) as? InAppNotificationSettings { + if let inAppNotificationSettings = transaction.getSharedData(ApplicationSpecificSharedDataKeys.inAppNotificationSettings)?.get(InAppNotificationSettings.self) { switch inAppNotificationSettings.totalUnreadCountDisplayStyle { case .filtered: filter = true diff --git a/submodules/ContactListUI/Sources/ContactListNode.swift b/submodules/ContactListUI/Sources/ContactListNode.swift index 63b019afa2..8763324c68 100644 --- a/submodules/ContactListUI/Sources/ContactListNode.swift +++ b/submodules/ContactListUI/Sources/ContactListNode.swift @@ -904,7 +904,7 @@ public final class ContactListNode: ASDisplayNode { |> then( combineLatest(context.sharedContext.accountManager.noticeEntry(key: ApplicationSpecificNotice.permissionWarningKey(permission: .contacts)!), context.account.postbox.preferencesView(keys: [PreferencesKeys.contactsSettings])) |> map { noticeView, preferences -> (Bool, Bool) in - let settings: ContactsSettings = preferences.values[PreferencesKeys.contactsSettings] as? ContactsSettings ?? ContactsSettings.defaultSettings + let settings: ContactsSettings = preferences.values[PreferencesKeys.contactsSettings]?.get(ContactsSettings.self) ?? ContactsSettings.defaultSettings let synchronizeDeviceContacts: Bool = settings.synchronizeContacts let suppressed: Bool let timestamp = noticeView.value.flatMap({ ApplicationSpecificNotice.getTimestampValue($0) }) diff --git a/submodules/ContactListUI/Sources/ContactsController.swift b/submodules/ContactListUI/Sources/ContactsController.swift index 7b83ff45d2..3b94c6845e 100644 --- a/submodules/ContactListUI/Sources/ContactsController.swift +++ b/submodules/ContactListUI/Sources/ContactsController.swift @@ -146,10 +146,10 @@ public class ContactsController: ViewController { if #available(iOSApplicationExtension 10.0, iOS 10.0, *) { self.authorizationDisposable = (combineLatest(DeviceAccess.authorizationStatus(subject: .contacts), combineLatest(context.sharedContext.accountManager.noticeEntry(key: ApplicationSpecificNotice.permissionWarningKey(permission: .contacts)!), context.account.postbox.preferencesView(keys: [PreferencesKeys.contactsSettings]), context.sharedContext.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.contactSynchronizationSettings])) |> map { noticeView, preferences, sharedData -> (Bool, ContactsSortOrder) in - let settings: ContactsSettings = preferences.values[PreferencesKeys.contactsSettings] as? ContactsSettings ?? ContactsSettings.defaultSettings + let settings: ContactsSettings = preferences.values[PreferencesKeys.contactsSettings]?.get(ContactsSettings.self) ?? ContactsSettings.defaultSettings let synchronizeDeviceContacts: Bool = settings.synchronizeContacts - let contactsSettings = sharedData.entries[ApplicationSpecificSharedDataKeys.contactSynchronizationSettings] as? ContactSynchronizationSettings + let contactsSettings = sharedData.entries[ApplicationSpecificSharedDataKeys.contactSynchronizationSettings]?.get(ContactSynchronizationSettings.self) let sortOrder: ContactsSortOrder = contactsSettings?.sortOrder ?? .presence if !synchronizeDeviceContacts { @@ -172,7 +172,7 @@ public class ContactsController: ViewController { } else { self.sortOrderPromise.set(context.sharedContext.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.contactSynchronizationSettings]) |> map { sharedData -> ContactsSortOrder in - let settings = sharedData.entries[ApplicationSpecificSharedDataKeys.contactSynchronizationSettings] as? ContactSynchronizationSettings + let settings = sharedData.entries[ApplicationSpecificSharedDataKeys.contactSynchronizationSettings]?.get(ContactSynchronizationSettings.self) return settings?.sortOrder ?? .presence }) } diff --git a/submodules/DebugSettingsUI/Sources/DebugController.swift b/submodules/DebugSettingsUI/Sources/DebugController.swift index 10f86849f8..af88301644 100644 --- a/submodules/DebugSettingsUI/Sources/DebugController.swift +++ b/submodules/DebugSettingsUI/Sources/DebugController.swift @@ -76,7 +76,6 @@ private enum DebugControllerEntry: ItemListNodeEntry { case optimizeDatabase(PresentationTheme) case photoPreview(PresentationTheme, Bool) case knockoutWallpaper(PresentationTheme, Bool) - case demoVideoChats(Bool) case experimentalCompatibility(Bool) case enableDebugDataDisplay(Bool) case playerEmbedding(Bool) @@ -100,7 +99,7 @@ private enum DebugControllerEntry: ItemListNodeEntry { return DebugControllerSection.logging.rawValue case .enableRaiseToSpeak, .keepChatNavigationStack, .skipReadHistory, .crashOnSlowQueries: return DebugControllerSection.experiments.rawValue - case .clearTips, .crash, .resetData, .resetDatabase, .resetDatabaseAndCache, .resetHoles, .reindexUnread, .resetBiometricsData, .optimizeDatabase, .photoPreview, .knockoutWallpaper, .demoVideoChats, .playerEmbedding, .playlistPlayback, .voiceConference, .experimentalCompatibility, .enableDebugDataDisplay: + case .clearTips, .crash, .resetData, .resetDatabase, .resetDatabaseAndCache, .resetHoles, .reindexUnread, .resetBiometricsData, .optimizeDatabase, .photoPreview, .knockoutWallpaper, .playerEmbedding, .playlistPlayback, .voiceConference, .experimentalCompatibility, .enableDebugDataDisplay: return DebugControllerSection.experiments.rawValue case .preferredVideoCodec: return DebugControllerSection.videoExperiments.rawValue @@ -163,8 +162,6 @@ private enum DebugControllerEntry: ItemListNodeEntry { return 23 case .knockoutWallpaper: return 24 - case .demoVideoChats: - return 25 case .experimentalCompatibility: return 26 case .enableDebugDataDisplay: @@ -703,9 +700,9 @@ private enum DebugControllerEntry: ItemListNodeEntry { return ItemListSwitchItem(presentationData: presentationData, title: "Media Preview (Updated)", value: value, sectionId: self.section, style: .blocks, updated: { value in let _ = arguments.sharedContext.accountManager.transaction ({ transaction in transaction.updateSharedData(ApplicationSpecificSharedDataKeys.experimentalUISettings, { settings in - var settings = settings as? ExperimentalUISettings ?? ExperimentalUISettings.defaultSettings + var settings = settings?.get(ExperimentalUISettings.self) ?? ExperimentalUISettings.defaultSettings settings.chatListPhotos = value - return settings + return PreferencesEntry(settings) }) }).start() }) @@ -713,19 +710,9 @@ private enum DebugControllerEntry: ItemListNodeEntry { return ItemListSwitchItem(presentationData: presentationData, title: "Knockout Wallpaper", value: value, sectionId: self.section, style: .blocks, updated: { value in let _ = arguments.sharedContext.accountManager.transaction ({ transaction in transaction.updateSharedData(ApplicationSpecificSharedDataKeys.experimentalUISettings, { settings in - var settings = settings as? ExperimentalUISettings ?? ExperimentalUISettings.defaultSettings + var settings = settings?.get(ExperimentalUISettings.self) ?? ExperimentalUISettings.defaultSettings settings.knockoutWallpaper = value - return settings - }) - }).start() - }) - case let .demoVideoChats(value): - return ItemListSwitchItem(presentationData: presentationData, title: "Demo Video", value: value, sectionId: self.section, style: .blocks, updated: { value in - let _ = arguments.sharedContext.accountManager.transaction ({ transaction in - transaction.updateSharedData(ApplicationSpecificSharedDataKeys.experimentalUISettings, { settings in - var settings = settings as? ExperimentalUISettings ?? ExperimentalUISettings.defaultSettings - settings.demoVideoChats = value - return settings + return PreferencesEntry(settings) }) }).start() }) @@ -733,9 +720,9 @@ private enum DebugControllerEntry: ItemListNodeEntry { return ItemListSwitchItem(presentationData: presentationData, title: "Experimental Compatibility", value: value, sectionId: self.section, style: .blocks, updated: { value in let _ = arguments.sharedContext.accountManager.transaction ({ transaction in transaction.updateSharedData(ApplicationSpecificSharedDataKeys.experimentalUISettings, { settings in - var settings = settings as? ExperimentalUISettings ?? ExperimentalUISettings.defaultSettings + var settings = settings?.get(ExperimentalUISettings.self) ?? ExperimentalUISettings.defaultSettings settings.experimentalCompatibility = value - return settings + return PreferencesEntry(settings) }) }).start() }) @@ -743,9 +730,9 @@ private enum DebugControllerEntry: ItemListNodeEntry { return ItemListSwitchItem(presentationData: presentationData, title: "Debug Data Display", value: value, sectionId: self.section, style: .blocks, updated: { value in let _ = arguments.sharedContext.accountManager.transaction ({ transaction in transaction.updateSharedData(ApplicationSpecificSharedDataKeys.experimentalUISettings, { settings in - var settings = settings as? ExperimentalUISettings ?? ExperimentalUISettings.defaultSettings + var settings = settings?.get(ExperimentalUISettings.self) ?? ExperimentalUISettings.defaultSettings settings.enableDebugDataDisplay = value - return settings + return PreferencesEntry(settings) }) }).start() }) @@ -753,9 +740,9 @@ private enum DebugControllerEntry: ItemListNodeEntry { return ItemListSwitchItem(presentationData: presentationData, title: "Player Embedding", value: value, sectionId: self.section, style: .blocks, updated: { value in let _ = arguments.sharedContext.accountManager.transaction ({ transaction in transaction.updateSharedData(ApplicationSpecificSharedDataKeys.experimentalUISettings, { settings in - var settings = settings as? ExperimentalUISettings ?? ExperimentalUISettings.defaultSettings + var settings = settings?.get(ExperimentalUISettings.self) ?? ExperimentalUISettings.defaultSettings settings.playerEmbedding = value - return settings + return PreferencesEntry(settings) }) }).start() }) @@ -763,9 +750,9 @@ private enum DebugControllerEntry: ItemListNodeEntry { return ItemListSwitchItem(presentationData: presentationData, title: "Playlist Playback", value: value, sectionId: self.section, style: .blocks, updated: { value in let _ = arguments.sharedContext.accountManager.transaction ({ transaction in transaction.updateSharedData(ApplicationSpecificSharedDataKeys.experimentalUISettings, { settings in - var settings = settings as? ExperimentalUISettings ?? ExperimentalUISettings.defaultSettings + var settings = settings?.get(ExperimentalUISettings.self) ?? ExperimentalUISettings.defaultSettings settings.playlistPlayback = value - return settings + return PreferencesEntry(settings) }) }).start() }) @@ -779,9 +766,9 @@ private enum DebugControllerEntry: ItemListNodeEntry { return ItemListCheckboxItem(presentationData: presentationData, title: title, style: .right, checked: isSelected, zeroSeparatorInsets: false, sectionId: self.section, action: { let _ = arguments.sharedContext.accountManager.transaction ({ transaction in transaction.updateSharedData(ApplicationSpecificSharedDataKeys.experimentalUISettings, { settings in - var settings = settings as? ExperimentalUISettings ?? ExperimentalUISettings.defaultSettings + var settings = settings?.get(ExperimentalUISettings.self) ?? ExperimentalUISettings.defaultSettings settings.preferredVideoCodec = value - return settings + return PreferencesEntry(settings) }) }).start() }) @@ -789,9 +776,9 @@ private enum DebugControllerEntry: ItemListNodeEntry { return ItemListSwitchItem(presentationData: presentationData, title: "Video Cropping Optimization", value: !value, sectionId: self.section, style: .blocks, updated: { value in let _ = arguments.sharedContext.accountManager.transaction ({ transaction in transaction.updateSharedData(ApplicationSpecificSharedDataKeys.experimentalUISettings, { settings in - var settings = settings as? ExperimentalUISettings ?? ExperimentalUISettings.defaultSettings + var settings = settings?.get(ExperimentalUISettings.self) ?? ExperimentalUISettings.defaultSettings settings.disableVideoAspectScaling = !value - return settings + return PreferencesEntry(settings) }) }).start() }) @@ -799,9 +786,9 @@ private enum DebugControllerEntry: ItemListNodeEntry { return ItemListSwitchItem(presentationData: presentationData, title: "Enable VoIP TCP", value: !value, sectionId: self.section, style: .blocks, updated: { value in let _ = arguments.sharedContext.accountManager.transaction ({ transaction in transaction.updateSharedData(ApplicationSpecificSharedDataKeys.experimentalUISettings, { settings in - var settings = settings as? ExperimentalUISettings ?? ExperimentalUISettings.defaultSettings + var settings = settings?.get(ExperimentalUISettings.self) ?? ExperimentalUISettings.defaultSettings settings.enableVoipTcp = value - return settings + return PreferencesEntry(settings) }) }).start() }) @@ -858,7 +845,6 @@ private func debugControllerEntries(sharedContext: SharedAccountContext, present entries.append(.optimizeDatabase(presentationData.theme)) if isMainApp { entries.append(.knockoutWallpaper(presentationData.theme, experimentalSettings.knockoutWallpaper)) - entries.append(.demoVideoChats(experimentalSettings.demoVideoChats)) entries.append(.experimentalCompatibility(experimentalSettings.experimentalCompatibility)) entries.append(.enableDebugDataDisplay(experimentalSettings.enableDebugDataDisplay)) entries.append(.playerEmbedding(experimentalSettings.playerEmbedding)) @@ -927,22 +913,22 @@ public func debugController(sharedContext: SharedAccountContext, context: Accoun let signal = combineLatest(sharedContext.presentationData, sharedContext.accountManager.sharedData(keys: Set([SharedDataKeys.loggingSettings, ApplicationSpecificSharedDataKeys.mediaInputSettings, ApplicationSpecificSharedDataKeys.experimentalUISettings])), preferencesSignal) |> map { presentationData, sharedData, preferences -> (ItemListControllerState, (ItemListNodeState, Any)) in let loggingSettings: LoggingSettings - if let value = sharedData.entries[SharedDataKeys.loggingSettings] as? LoggingSettings { + if let value = sharedData.entries[SharedDataKeys.loggingSettings]?.get(LoggingSettings.self) { loggingSettings = value } else { loggingSettings = LoggingSettings.defaultSettings } let mediaInputSettings: MediaInputSettings - if let value = sharedData.entries[ApplicationSpecificSharedDataKeys.mediaInputSettings] as? MediaInputSettings { + if let value = sharedData.entries[ApplicationSpecificSharedDataKeys.mediaInputSettings]?.get(MediaInputSettings.self) { mediaInputSettings = value } else { mediaInputSettings = MediaInputSettings.defaultSettings } - let experimentalSettings: ExperimentalUISettings = (sharedData.entries[ApplicationSpecificSharedDataKeys.experimentalUISettings] as? ExperimentalUISettings) ?? ExperimentalUISettings.defaultSettings + let experimentalSettings: ExperimentalUISettings = sharedData.entries[ApplicationSpecificSharedDataKeys.experimentalUISettings]?.get(ExperimentalUISettings.self) ?? ExperimentalUISettings.defaultSettings - let networkSettings: NetworkSettings? = preferences?.values[PreferencesKeys.networkSettings] as? NetworkSettings + let networkSettings: NetworkSettings? = preferences?.values[PreferencesKeys.networkSettings]?.get(NetworkSettings.self) var leftNavigationButton: ItemListNavigationButton? if modal { diff --git a/submodules/GalleryUI/Sources/GalleryController.swift b/submodules/GalleryUI/Sources/GalleryController.swift index df117ca2e1..6042c2c2e6 100644 --- a/submodules/GalleryUI/Sources/GalleryController.swift +++ b/submodules/GalleryUI/Sources/GalleryController.swift @@ -488,7 +488,7 @@ public class GalleryController: ViewController, StandalonePresentableController let f: () -> Void = { if let strongSelf = self { if let view = view { - let appConfiguration: AppConfiguration = preferencesView.values[PreferencesKeys.appConfiguration] as? AppConfiguration ?? .defaultValue + let appConfiguration: AppConfiguration = preferencesView.values[PreferencesKeys.appConfiguration]?.get(AppConfiguration.self) ?? .defaultValue let configuration = GalleryConfiguration.with(appConfiguration: appConfiguration) strongSelf.configuration = configuration diff --git a/submodules/InstantPageUI/Sources/InstantPageController.swift b/submodules/InstantPageUI/Sources/InstantPageController.swift index 776dcfb509..c5a2bb408f 100644 --- a/submodules/InstantPageUI/Sources/InstantPageController.swift +++ b/submodules/InstantPageUI/Sources/InstantPageController.swift @@ -109,13 +109,13 @@ public final class InstantPageController: ViewController { |> deliverOnMainQueue).start(next: { [weak self] sharedData in if let strongSelf = self { let settings: InstantPagePresentationSettings - if let current = sharedData.entries[ApplicationSpecificSharedDataKeys.instantPagePresentationSettings] as? InstantPagePresentationSettings { + if let current = sharedData.entries[ApplicationSpecificSharedDataKeys.instantPagePresentationSettings]?.get(InstantPagePresentationSettings.self) { settings = current } else { settings = InstantPagePresentationSettings.defaultSettings } let themeSettings: PresentationThemeSettings - if let current = sharedData.entries[ApplicationSpecificSharedDataKeys.presentationThemeSettings] as? PresentationThemeSettings { + if let current = sharedData.entries[ApplicationSpecificSharedDataKeys.presentationThemeSettings]?.get(PresentationThemeSettings.self) { themeSettings = current } else { themeSettings = PresentationThemeSettings.defaultSettings diff --git a/submodules/ObjCRuntimeUtils/Source/ObjCRuntimeUtils/RuntimeUtils.h b/submodules/ObjCRuntimeUtils/Source/ObjCRuntimeUtils/RuntimeUtils.h index 3a06e3c3bf..f60b4f83d8 100644 --- a/submodules/ObjCRuntimeUtils/Source/ObjCRuntimeUtils/RuntimeUtils.h +++ b/submodules/ObjCRuntimeUtils/Source/ObjCRuntimeUtils/RuntimeUtils.h @@ -23,6 +23,8 @@ typedef enum { - (bool)checkObjectIsKindOfClass:(Class _Nonnull)targetClass; - (void)setClass:(Class _Nonnull)newClass; +- (NSNumber * _Nullable)floatValueForKeyPath:(NSString * _Nonnull)keyPath; + @end SEL _Nonnull makeSelectorFromString(NSString * _Nonnull string); diff --git a/submodules/ObjCRuntimeUtils/Source/ObjCRuntimeUtils/RuntimeUtils.m b/submodules/ObjCRuntimeUtils/Source/ObjCRuntimeUtils/RuntimeUtils.m index 060faf64d0..742c98fb6c 100644 --- a/submodules/ObjCRuntimeUtils/Source/ObjCRuntimeUtils/RuntimeUtils.m +++ b/submodules/ObjCRuntimeUtils/Source/ObjCRuntimeUtils/RuntimeUtils.m @@ -98,27 +98,17 @@ object_setClass(self, newClass); } -static Class freedomMakeClass(Class superclass, Class subclass, SEL *copySelectors, int copySelectorsCount) -{ - if (superclass == Nil || subclass == Nil) - return nil; - - Class decoratedClass = objc_allocateClassPair(superclass, [[NSString alloc] initWithFormat:@"%@_%@", NSStringFromClass(superclass), NSStringFromClass(subclass)].UTF8String, 0); - - unsigned int count = 0; - Method *methodList = class_copyMethodList(subclass, &count); - if (methodList != NULL) { - for (unsigned int i = 0; i < count; i++) { - SEL methodName = method_getName(methodList[i]); - class_addMethod(decoratedClass, methodName, method_getImplementation(methodList[i]), method_getTypeEncoding(methodList[i])); +- (NSNumber * _Nullable)floatValueForKeyPath:(NSString * _Nonnull)keyPath { + id value = [self valueForKeyPath:keyPath]; + if (value != nil) { + if ([value respondsToSelector:@selector(floatValue)]) { + return @([value floatValue]); + } else { + return nil; } - - free(methodList); + } else { + return nil; } - - objc_registerClassPair(decoratedClass); - - return decoratedClass; } @end diff --git a/submodules/PeerInfoUI/Sources/ChannelInfoController.swift b/submodules/PeerInfoUI/Sources/ChannelInfoController.swift index cfdba3954f..917209a4f7 100644 --- a/submodules/PeerInfoUI/Sources/ChannelInfoController.swift +++ b/submodules/PeerInfoUI/Sources/ChannelInfoController.swift @@ -823,7 +823,7 @@ public func channelInfoController(context: AccountContext, peerId: PeerId) -> Vi let presentationData = context.sharedContext.currentPresentationData.with { $0 } let _ = (context.account.postbox.transaction { transaction -> (TelegramPeerNotificationSettings, GlobalNotificationSettings) in let peerSettings: TelegramPeerNotificationSettings = (transaction.getPeerNotificationSettings(peerId) as? TelegramPeerNotificationSettings) ?? TelegramPeerNotificationSettings.defaultSettings - let globalSettings: GlobalNotificationSettings = (transaction.getPreferencesEntry(key: PreferencesKeys.globalNotifications) as? GlobalNotificationSettings) ?? GlobalNotificationSettings.defaultSettings + let globalSettings: GlobalNotificationSettings = transaction.getPreferencesEntry(key: PreferencesKeys.globalNotifications)?.get(GlobalNotificationSettings.self) ?? GlobalNotificationSettings.defaultSettings return (peerSettings, globalSettings) } |> deliverOnMainQueue).start(next: { peerSettings, globalSettings in @@ -929,7 +929,7 @@ public func channelInfoController(context: AccountContext, peerId: PeerId) -> Vi var globalNotificationSettings: GlobalNotificationSettings = GlobalNotificationSettings.defaultSettings if let preferencesView = combinedView.views[globalNotificationsKey] as? PreferencesView { - if let settings = preferencesView.values[PreferencesKeys.globalNotifications] as? GlobalNotificationSettings { + if let settings = preferencesView.values[PreferencesKeys.globalNotifications]?.get(GlobalNotificationSettings.self) { globalNotificationSettings = settings } } diff --git a/submodules/PeerInfoUI/Sources/GroupStickerPackSetupController.swift b/submodules/PeerInfoUI/Sources/GroupStickerPackSetupController.swift index 7dc0927e21..42ab698ded 100644 --- a/submodules/PeerInfoUI/Sources/GroupStickerPackSetupController.swift +++ b/submodules/PeerInfoUI/Sources/GroupStickerPackSetupController.swift @@ -405,7 +405,7 @@ public func groupStickerPackSetupController(context: AccountContext, peerId: Pee let signal = combineLatest(context.sharedContext.presentationData, statePromise.get() |> deliverOnMainQueue, initialData.get() |> deliverOnMainQueue, stickerPacks.get() |> deliverOnMainQueue, searchState.get() |> deliverOnMainQueue, context.sharedContext.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.stickerSettings]) |> deliverOnMainQueue) |> map { presentationData, state, initialData, view, searchState, sharedData -> (ItemListControllerState, (ItemListNodeState, Any)) in var stickerSettings = StickerSettings.defaultSettings - if let value = sharedData.entries[ApplicationSpecificSharedDataKeys.stickerSettings] as? StickerSettings { + if let value = sharedData.entries[ApplicationSpecificSharedDataKeys.stickerSettings]?.get(StickerSettings.self) { stickerSettings = value } diff --git a/submodules/PeersNearbyUI/Sources/PeersNearbyController.swift b/submodules/PeersNearbyUI/Sources/PeersNearbyController.swift index 13bb221089..e266e24cef 100644 --- a/submodules/PeersNearbyUI/Sources/PeersNearbyController.swift +++ b/submodules/PeersNearbyUI/Sources/PeersNearbyController.swift @@ -573,7 +573,7 @@ public func peersNearbyController(context: AccountContext) -> ViewController { |> deliverOnMainQueue |> map { presentationData, data, chatLocation, displayLoading, expanded, view -> (ItemListControllerState, (ItemListNodeState, Any)) in let previous = previousData.swap(data) - let state = view.values[PreferencesKeys.peersNearby] as? PeersNearbyState ?? .default + let state = view.values[PreferencesKeys.peersNearby]?.get(PeersNearbyState.self) ?? .default var crossfade = false if (data?.users.isEmpty ?? true) != (previous?.users.isEmpty ?? true) { diff --git a/submodules/Postbox/Sources/Coding.swift b/submodules/Postbox/Sources/Coding.swift index ed733889cd..8e1c769ddf 100644 --- a/submodules/Postbox/Sources/Coding.swift +++ b/submodules/Postbox/Sources/Coding.swift @@ -444,6 +444,15 @@ public final class PostboxEncoder { return } } + + public func encodeObjectToRawData(_ value: T) -> AdaptedPostboxEncoder.RawObjectData { + let typeHash: Int32 = murMurHashString32("\(type(of: value))") + + let innerEncoder = PostboxEncoder() + value.encode(innerEncoder) + + return AdaptedPostboxEncoder.RawObjectData(typeHash: typeHash, data: innerEncoder.makeData()) + } public func encodeObjectArray(_ value: [T], forKey key: String) { self.encodeKey(key) @@ -649,7 +658,7 @@ public final class PostboxEncoder { let innerEncoder = _AdaptedPostboxEncoder(typeHash: typeHash) try! value.encode(to: innerEncoder) - let (data, valueType) = innerEncoder.makeData(addHeader: true) + let (data, valueType) = innerEncoder.makeData(addHeader: true, isDictionary: false) self.encodeInnerObjectData(data, valueType: valueType, forKey: key) } @@ -1011,6 +1020,10 @@ public final class PostboxDecoder { public func decodeRootObject() -> PostboxCoding? { return self.decodeObjectForKey("_") } + + public func decodeRootObjectWithHash(hash: Int32) -> PostboxCoding? { + return typeStore.decode(hash, decoder: self) + } public func decodeCodable(_ type: T.Type, forKey key: String) -> T? { if let data = self.decodeDataForKey(key) { @@ -1651,6 +1664,43 @@ public final class PostboxDecoder { return [:] } } + + public func decodeObjectDataDictRaw() -> [(Data, Data)] { + var dict: [(Data, Data)] = [] + + var length: Int32 = 0 + memcpy(&length, self.buffer.memory + self.offset, 4) + self.offset += 4 + + var i: Int32 = 0 + while i < length { + var keyHash: Int32 = 0 + memcpy(&keyHash, self.buffer.memory + self.offset, 4) + self.offset += 4 + + var keyLength: Int32 = 0 + memcpy(&keyLength, self.buffer.memory + self.offset, 4) + + let keyData = ReadBuffer(memory: self.buffer.memory + (self.offset + 4), length: Int(keyLength), freeWhenDone: false).makeData() + self.offset += 4 + Int(keyLength) + + var valueHash: Int32 = 0 + memcpy(&valueHash, self.buffer.memory + self.offset, 4) + self.offset += 4 + + var valueLength: Int32 = 0 + memcpy(&valueLength, self.buffer.memory + self.offset, 4) + + let objectData = ReadBuffer(memory: self.buffer.memory + (self.offset + 4), length: Int(valueLength), freeWhenDone: false).makeData() + self.offset += 4 + Int(valueLength) + + dict.append((keyData, objectData)) + + i += 1 + } + + return dict + } public func decodeBytesForKeyNoCopy(_ key: String) -> ReadBuffer? { if PostboxDecoder.positionOnKey(self.buffer.memory, offset: &self.offset, maxOffset: self.buffer.length, length: self.buffer.length, key: key, valueType: .Bytes) { @@ -1728,7 +1778,13 @@ public final class PostboxDecoder { let innerData = innerBuffer.makeData() self.offset += 4 + Int(length) - return try? AdaptedPostboxDecoder().decode(T.self, from: innerData) + do { + let result = try AdaptedPostboxDecoder().decode(T.self, from: innerData) + return result + } catch let error { + assertionFailure("Decoding error: \(error)") + return nil + } } else { return nil } diff --git a/submodules/Postbox/Sources/PreferencesEntry.swift b/submodules/Postbox/Sources/PreferencesEntry.swift index 4d3e89714e..a38f5cae4b 100644 --- a/submodules/Postbox/Sources/PreferencesEntry.swift +++ b/submodules/Postbox/Sources/PreferencesEntry.swift @@ -1,6 +1,6 @@ import Foundation -public final class PreferencesEntry: Equatable { +public final class CodableEntry: Equatable { public let data: Data public init(data: Data) { @@ -18,6 +18,34 @@ public final class PreferencesEntry: Equatable { return decoder.decode(T.self, forKey: "_") } + public static func ==(lhs: CodableEntry, rhs: CodableEntry) -> Bool { + return lhs.data == rhs.data + } +} + +public final class PreferencesEntry: Equatable { + public let data: Data + + public init(data: Data) { + self.data = data + } + + public init?(_ value: T?) { + guard let value = value else { + return nil + } + let encoder = PostboxEncoder() + encoder.encode(value, forKey: "_") + self.data = encoder.makeData() + } + + public func get(_ type: T.Type) -> T? { + let decoder = PostboxDecoder(buffer: MemoryBuffer(data: self.data)) + let result = decoder.decode(T.self, forKey: "_") + assert(result != nil) + return result + } + public static func ==(lhs: PreferencesEntry, rhs: PreferencesEntry) -> Bool { return lhs.data == rhs.data } diff --git a/submodules/Postbox/Sources/SeedConfiguration.swift b/submodules/Postbox/Sources/SeedConfiguration.swift index e8b0a8520d..4b9fd4e475 100644 --- a/submodules/Postbox/Sources/SeedConfiguration.swift +++ b/submodules/Postbox/Sources/SeedConfiguration.swift @@ -72,7 +72,27 @@ public final class SeedConfiguration { public let getGlobalNotificationSettings: (Transaction) -> PostboxGlobalNotificationSettings? public let defaultGlobalNotificationSettings: PostboxGlobalNotificationSettings - public init(globalMessageIdsPeerIdNamespaces: Set, initializeChatListWithHole: (topLevel: ChatListHole?, groups: ChatListHole?), messageHoles: [PeerId.Namespace: [MessageId.Namespace: Set]], upgradedMessageHoles: [PeerId.Namespace: [MessageId.Namespace: Set]], messageThreadHoles: [PeerId.Namespace: [MessageId.Namespace]], existingMessageTags: MessageTags, messageTagsWithSummary: MessageTags, existingGlobalMessageTags: GlobalMessageTags, peerNamespacesRequiringMessageTextIndex: [PeerId.Namespace], peerSummaryCounterTags: @escaping (Peer, Bool) -> PeerSummaryCounterTags, additionalChatListIndexNamespace: MessageId.Namespace?, messageNamespacesRequiringGroupStatsValidation: Set, defaultMessageNamespaceReadStates: [MessageId.Namespace: PeerReadState], chatMessagesNamespaces: Set, getGlobalNotificationSettings: @escaping (Transaction) -> PostboxGlobalNotificationSettings?, defaultGlobalNotificationSettings: PostboxGlobalNotificationSettings) { + public init( + globalMessageIdsPeerIdNamespaces: Set, + initializeChatListWithHole: ( + topLevel: ChatListHole?, + groups: ChatListHole? + ), + messageHoles: [PeerId.Namespace: [MessageId.Namespace: Set]], + upgradedMessageHoles: [PeerId.Namespace: [MessageId.Namespace: Set]], + messageThreadHoles: [PeerId.Namespace: [MessageId.Namespace]], + existingMessageTags: MessageTags, + messageTagsWithSummary: MessageTags, + existingGlobalMessageTags: GlobalMessageTags, + peerNamespacesRequiringMessageTextIndex: [PeerId.Namespace], + peerSummaryCounterTags: @escaping (Peer, Bool) -> PeerSummaryCounterTags, + additionalChatListIndexNamespace: MessageId.Namespace?, + messageNamespacesRequiringGroupStatsValidation: Set, + defaultMessageNamespaceReadStates: [MessageId.Namespace: PeerReadState], + chatMessagesNamespaces: Set, + getGlobalNotificationSettings: @escaping (Transaction) -> PostboxGlobalNotificationSettings?, + defaultGlobalNotificationSettings: PostboxGlobalNotificationSettings + ) { self.globalMessageIdsPeerIdNamespaces = globalMessageIdsPeerIdNamespaces self.initializeChatListWithHole = initializeChatListWithHole self.messageHoles = messageHoles diff --git a/submodules/Postbox/Sources/Utils/Decoder/AdaptedPostboxDecoder.swift b/submodules/Postbox/Sources/Utils/Decoder/AdaptedPostboxDecoder.swift index 23e6b1475d..4f25acfd9c 100644 --- a/submodules/Postbox/Sources/Utils/Decoder/AdaptedPostboxDecoder.swift +++ b/submodules/Postbox/Sources/Utils/Decoder/AdaptedPostboxDecoder.swift @@ -8,9 +8,10 @@ final public class AdaptedPostboxDecoder { case objectArray case stringArray case dataArray + case objectDict } - public final class RawObjectData: Codable { + public final class RawObjectData: Decodable { public let data: Data public let typeHash: Int32 @@ -55,7 +56,7 @@ extension AdaptedPostboxDecoder.ContentType { case .ObjectArray: self = .objectArray case .ObjectDictionary: - return nil + self = .objectDict case .Bytes: return nil case .Nil: @@ -117,6 +118,8 @@ extension _AdaptedPostboxDecoder: Decoder { content = .stringArray(decoder.decodeStringArrayRaw()) case .dataArray: content = .dataArray(decoder.decodeBytesArrayRaw().map { $0.makeData() }) + case .objectDict: + content = .objectDict(decoder.decodeObjectDataDictRaw()) } if let content = content { diff --git a/submodules/Postbox/Sources/Utils/Decoder/AdaptedPostboxUnkeyedDecodingContainer.swift b/submodules/Postbox/Sources/Utils/Decoder/AdaptedPostboxUnkeyedDecodingContainer.swift index 27bdeddcfd..e9a15f2705 100644 --- a/submodules/Postbox/Sources/Utils/Decoder/AdaptedPostboxUnkeyedDecodingContainer.swift +++ b/submodules/Postbox/Sources/Utils/Decoder/AdaptedPostboxUnkeyedDecodingContainer.swift @@ -8,6 +8,7 @@ extension _AdaptedPostboxDecoder { case objectArray([Data]) case stringArray([String]) case dataArray([Data]) + case objectDict([(Data, Data)]) var count: Int { switch self { @@ -21,6 +22,8 @@ extension _AdaptedPostboxDecoder { return array.count case let .dataArray(array): return array.count + case let .objectDict(dict): + return dict.count * 2 } } } @@ -64,6 +67,7 @@ extension _AdaptedPostboxDecoder.UnkeyedContainer: UnkeyedDecodingContainer { self._currentIndex += 1 return array[index] as! T default: + assertionFailure() throw DecodingError.typeMismatch(Data.self, DecodingError.Context(codingPath: self.codingPath, debugDescription: "")) } } else { @@ -74,7 +78,35 @@ extension _AdaptedPostboxDecoder.UnkeyedContainer: UnkeyedDecodingContainer { let data = array[index] return try AdaptedPostboxDecoder().decode(T.self, from: data) + case let .objectDict(dict): + let index = self._currentIndex + self._currentIndex += 1 + + let dataPair = dict[index / 2] + let data: Data + if index % 2 == 0 { + data = dataPair.0 + } else { + data = dataPair.1 + } + return try AdaptedPostboxDecoder().decode(T.self, from: data) + case let .int32Array(array): + let index = self._currentIndex + self._currentIndex += 1 + + return array[index] as! T + case let .int64Array(array): + let index = self._currentIndex + self._currentIndex += 1 + + return array[index] as! T + case let .stringArray(array): + let index = self._currentIndex + self._currentIndex += 1 + + return array[index] as! T default: + assertionFailure() throw DecodingError.typeMismatch(T.self, DecodingError.Context(codingPath: self.codingPath, debugDescription: "")) } } diff --git a/submodules/Postbox/Sources/Utils/Encoder/AdaptedPostboxEncoder.swift b/submodules/Postbox/Sources/Utils/Encoder/AdaptedPostboxEncoder.swift index 5c46082034..3851657b9e 100644 --- a/submodules/Postbox/Sources/Utils/Encoder/AdaptedPostboxEncoder.swift +++ b/submodules/Postbox/Sources/Utils/Encoder/AdaptedPostboxEncoder.swift @@ -2,6 +2,16 @@ import Foundation import MurMurHash32 public class AdaptedPostboxEncoder { + public final class RawObjectData: Encodable { + public let typeHash: Int32 + public let data: Data + + public init(typeHash: Int32, data: Data) { + self.typeHash = typeHash + self.data = data + } + } + public init() { } @@ -10,7 +20,7 @@ public class AdaptedPostboxEncoder { let encoder = _AdaptedPostboxEncoder(typeHash: typeHash) try value.encode(to: encoder) - return encoder.makeData(addHeader: false).0 + return encoder.makeData(addHeader: false, isDictionary: false).0 } } @@ -27,8 +37,8 @@ final class _AdaptedPostboxEncoder { self.typeHash = typeHash } - func makeData(addHeader: Bool) -> (Data, ValueType) { - return self.container!.makeData(addHeader: addHeader) + func makeData(addHeader: Bool, isDictionary: Bool) -> (Data, ValueType) { + return self.container!.makeData(addHeader: addHeader, isDictionary: isDictionary) } } @@ -61,5 +71,5 @@ extension _AdaptedPostboxEncoder: Encoder { } protocol AdaptedPostboxEncodingContainer: AnyObject { - func makeData(addHeader: Bool) -> (Data, ValueType) + func makeData(addHeader: Bool, isDictionary: Bool) -> (Data, ValueType) } diff --git a/submodules/Postbox/Sources/Utils/Encoder/AdaptedPostboxKeyedEncodingContainer.swift b/submodules/Postbox/Sources/Utils/Encoder/AdaptedPostboxKeyedEncodingContainer.swift index 311d3edcf2..cd152c85e1 100644 --- a/submodules/Postbox/Sources/Utils/Encoder/AdaptedPostboxKeyedEncodingContainer.swift +++ b/submodules/Postbox/Sources/Utils/Encoder/AdaptedPostboxKeyedEncodingContainer.swift @@ -17,7 +17,7 @@ extension _AdaptedPostboxEncoder { self.encoder = PostboxEncoder() } - func makeData(addHeader: Bool) -> (Data, ValueType) { + func makeData(addHeader: Bool, isDictionary: Bool) -> (Data, ValueType) { let buffer = WriteBuffer() if addHeader { @@ -43,12 +43,27 @@ extension _AdaptedPostboxEncoder.KeyedContainer: KeyedEncodingContainerProtocol func encode(_ value: T, forKey key: Key) throws where T : Encodable { if let value = value as? Data { self.encoder.encodeData(value, forKey: key.stringValue) + } else if let value = value as? AdaptedPostboxEncoder.RawObjectData { + let typeHash: Int32 = value.typeHash + let innerEncoder = _AdaptedPostboxEncoder(typeHash: typeHash) + try! value.encode(to: innerEncoder) + + let (data, valueType) = innerEncoder.makeData(addHeader: true, isDictionary: false) + self.encoder.encodeInnerObjectData(data, valueType: valueType, forKey: key.stringValue) } else { let typeHash: Int32 = murMurHashString32("\(type(of: value))") let innerEncoder = _AdaptedPostboxEncoder(typeHash: typeHash) try! value.encode(to: innerEncoder) - let (data, valueType) = innerEncoder.makeData(addHeader: true) + let type = type(of: value) + let typeString = "\(type)" + var isDictionary = false + if typeString.hasPrefix("Dictionary<") { + isDictionary = true + } + + let (data, valueType) = innerEncoder.makeData(addHeader: true, isDictionary: isDictionary) + self.encoder.encodeInnerObjectData(data, valueType: valueType, forKey: key.stringValue) } } @@ -65,6 +80,12 @@ extension _AdaptedPostboxEncoder.KeyedContainer: KeyedEncodingContainerProtocol self.encoder.encodeInt64(value, forKey: key.stringValue) } + func encode(_ value: Int, forKey key: Key) throws { + assertionFailure() + + self.encoder.encodeInt32(Int32(value), forKey: key.stringValue) + } + func encode(_ value: Bool, forKey key: Key) throws { self.encoder.encodeBool(value, forKey: key.stringValue) } diff --git a/submodules/Postbox/Sources/Utils/Encoder/AdaptedPostboxSingleValueEncodingContainer.swift b/submodules/Postbox/Sources/Utils/Encoder/AdaptedPostboxSingleValueEncodingContainer.swift index 5ae52729e9..3bba11f5b1 100644 --- a/submodules/Postbox/Sources/Utils/Encoder/AdaptedPostboxSingleValueEncodingContainer.swift +++ b/submodules/Postbox/Sources/Utils/Encoder/AdaptedPostboxSingleValueEncodingContainer.swift @@ -79,7 +79,7 @@ extension _AdaptedPostboxEncoder.SingleValueContainer: SingleValueEncodingContai } extension _AdaptedPostboxEncoder.SingleValueContainer: AdaptedPostboxEncodingContainer { - func makeData(addHeader: Bool) -> (Data, ValueType) { + func makeData(addHeader: Bool, isDictionary: Bool) -> (Data, ValueType) { preconditionFailure() } } diff --git a/submodules/Postbox/Sources/Utils/Encoder/AdaptedPostboxUnkeyedEncodingContainer.swift b/submodules/Postbox/Sources/Utils/Encoder/AdaptedPostboxUnkeyedEncodingContainer.swift index 568db0689a..c9dc3ce412 100644 --- a/submodules/Postbox/Sources/Utils/Encoder/AdaptedPostboxUnkeyedEncodingContainer.swift +++ b/submodules/Postbox/Sources/Utils/Encoder/AdaptedPostboxUnkeyedEncodingContainer.swift @@ -25,7 +25,7 @@ extension _AdaptedPostboxEncoder { self.userInfo = userInfo } - func makeData(addHeader: Bool) -> (Data, ValueType) { + func makeData(addHeader: Bool, isDictionary: Bool) -> (Data, ValueType) { precondition(addHeader) if self.items.isEmpty { @@ -53,7 +53,7 @@ extension _AdaptedPostboxEncoder { buffer.write(&length, offset: 0, length: 4) for case .int64(var value) in self.items { - buffer.write(&value, offset: 0, length: 4) + buffer.write(&value, offset: 0, length: 8) } return (buffer.makeData(), .Int64Array) @@ -75,13 +75,17 @@ extension _AdaptedPostboxEncoder { let buffer = WriteBuffer() var length: Int32 = Int32(self.items.count) + if isDictionary { + precondition(length % 2 == 0) + length /= 2 + } buffer.write(&length, offset: 0, length: 4) for case .object(let data) in self.items { buffer.write(data) } - return (buffer.makeData(), .ObjectArray) + return (buffer.makeData(), isDictionary ? .ObjectDictionary : .ObjectArray) } else if self.items.allSatisfy({ if case .data = $0 { return true } else { return false } }) { let buffer = WriteBuffer() @@ -108,18 +112,28 @@ extension _AdaptedPostboxEncoder.UnkeyedContainer: UnkeyedEncodingContainer { } func encode(_ value: T) throws where T : Encodable { - let typeHash: Int32 = murMurHashString32("\(type(of: value))") + if value is Int32 { + try self.encode(value as! Int32) + } else if value is Int64 { + try self.encode(value as! Int64) + } else if value is String { + try self.encode(value as! String) + } else if value is Data { + try self.encode(value as! Data) + } else { + let typeHash: Int32 = murMurHashString32("\(type(of: value))") - let innerEncoder = _AdaptedPostboxEncoder(typeHash: typeHash) - try! value.encode(to: innerEncoder) + let innerEncoder = _AdaptedPostboxEncoder(typeHash: typeHash) + try! value.encode(to: innerEncoder) - let (data, _) = innerEncoder.makeData(addHeader: true) + let (data, _) = innerEncoder.makeData(addHeader: true, isDictionary: false) - let buffer = WriteBuffer() + let buffer = WriteBuffer() - buffer.write(data) + buffer.write(data) - self.items.append(.object(buffer.makeData())) + self.items.append(.object(buffer.makeData())) + } } func encode(_ value: Int32) throws { diff --git a/submodules/SettingsUI/Sources/Data and Storage/AutodownloadConnectionTypeController.swift b/submodules/SettingsUI/Sources/Data and Storage/AutodownloadConnectionTypeController.swift index 3dd56dfd48..32fab6c784 100644 --- a/submodules/SettingsUI/Sources/Data and Storage/AutodownloadConnectionTypeController.swift +++ b/submodules/SettingsUI/Sources/Data and Storage/AutodownloadConnectionTypeController.swift @@ -321,14 +321,14 @@ func autodownloadMediaConnectionTypeController(context: AccountContext, connecti |> deliverOnMainQueue |> map { presentationData, sharedData -> (ItemListControllerState, (ItemListNodeState, Any)) in var automaticMediaDownloadSettings: MediaAutoDownloadSettings - if let value = sharedData.entries[ApplicationSpecificSharedDataKeys.automaticMediaDownloadSettings] as? MediaAutoDownloadSettings { + if let value = sharedData.entries[ApplicationSpecificSharedDataKeys.automaticMediaDownloadSettings]?.get(MediaAutoDownloadSettings.self) { automaticMediaDownloadSettings = value } else { automaticMediaDownloadSettings = MediaAutoDownloadSettings.defaultSettings } var autodownloadSettings: AutodownloadSettings - if let value = sharedData.entries[SharedDataKeys.autodownloadSettings] as? AutodownloadSettings { + if let value = sharedData.entries[SharedDataKeys.autodownloadSettings]?.get(AutodownloadSettings.self) { autodownloadSettings = value automaticMediaDownloadSettings = automaticMediaDownloadSettings.updatedWithAutodownloadSettings(autodownloadSettings) } else { diff --git a/submodules/SettingsUI/Sources/Data and Storage/AutodownloadMediaCategoryController.swift b/submodules/SettingsUI/Sources/Data and Storage/AutodownloadMediaCategoryController.swift index 9b3ef25c59..a225ee9fa1 100644 --- a/submodules/SettingsUI/Sources/Data and Storage/AutodownloadMediaCategoryController.swift +++ b/submodules/SettingsUI/Sources/Data and Storage/AutodownloadMediaCategoryController.swift @@ -388,7 +388,7 @@ func autodownloadMediaCategoryController(context: AccountContext, connectionType return context.sharedContext.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.automaticMediaDownloadSettings]) |> take(1) |> map { sharedData -> MediaAutoDownloadSettings in - if let value = sharedData.entries[ApplicationSpecificSharedDataKeys.automaticMediaDownloadSettings] as? MediaAutoDownloadSettings { + if let value = sharedData.entries[ApplicationSpecificSharedDataKeys.automaticMediaDownloadSettings]?.get(MediaAutoDownloadSettings.self) { return value } else { return .defaultSettings @@ -402,14 +402,14 @@ func autodownloadMediaCategoryController(context: AccountContext, connectionType let signal = combineLatest(context.sharedContext.presentationData, context.sharedContext.accountManager.sharedData(keys: [SharedDataKeys.autodownloadSettings, ApplicationSpecificSharedDataKeys.automaticMediaDownloadSettings])) |> deliverOnMainQueue |> map { presentationData, sharedData -> (ItemListControllerState, (ItemListNodeState, Any)) in var automaticMediaDownloadSettings: MediaAutoDownloadSettings - if let value = sharedData.entries[ApplicationSpecificSharedDataKeys.automaticMediaDownloadSettings] as? MediaAutoDownloadSettings { + if let value = sharedData.entries[ApplicationSpecificSharedDataKeys.automaticMediaDownloadSettings]?.get(MediaAutoDownloadSettings.self) { automaticMediaDownloadSettings = value } else { automaticMediaDownloadSettings = .defaultSettings } var autodownloadSettings: AutodownloadSettings - if let value = sharedData.entries[SharedDataKeys.autodownloadSettings] as? AutodownloadSettings { + if let value = sharedData.entries[SharedDataKeys.autodownloadSettings]?.get(AutodownloadSettings.self) { autodownloadSettings = value automaticMediaDownloadSettings = automaticMediaDownloadSettings.updatedWithAutodownloadSettings(autodownloadSettings) } else { diff --git a/submodules/SettingsUI/Sources/Data and Storage/DataAndStorageSettingsController.swift b/submodules/SettingsUI/Sources/Data and Storage/DataAndStorageSettingsController.swift index fa1918458e..7b3b219bb9 100644 --- a/submodules/SettingsUI/Sources/Data and Storage/DataAndStorageSettingsController.swift +++ b/submodules/SettingsUI/Sources/Data and Storage/DataAndStorageSettingsController.swift @@ -561,14 +561,14 @@ public func dataAndStorageController(context: AccountContext, focusOnItemTag: Da dataAndStorageDataPromise.set(context.sharedContext.accountManager.sharedData(keys: [SharedDataKeys.autodownloadSettings, ApplicationSpecificSharedDataKeys.automaticMediaDownloadSettings, ApplicationSpecificSharedDataKeys.generatedMediaStoreSettings, ApplicationSpecificSharedDataKeys.voiceCallSettings, SharedDataKeys.proxySettings]) |> map { sharedData -> DataAndStorageData in var automaticMediaDownloadSettings: MediaAutoDownloadSettings - if let value = sharedData.entries[ApplicationSpecificSharedDataKeys.automaticMediaDownloadSettings] as? MediaAutoDownloadSettings { + if let value = sharedData.entries[ApplicationSpecificSharedDataKeys.automaticMediaDownloadSettings]?.get(MediaAutoDownloadSettings.self) { automaticMediaDownloadSettings = value } else { automaticMediaDownloadSettings = .defaultSettings } var autodownloadSettings: AutodownloadSettings - if let value = sharedData.entries[SharedDataKeys.autodownloadSettings] as? AutodownloadSettings { + if let value = sharedData.entries[SharedDataKeys.autodownloadSettings]?.get(AutodownloadSettings.self) { autodownloadSettings = value automaticMediaDownloadSettings = automaticMediaDownloadSettings.updatedWithAutodownloadSettings(autodownloadSettings) } else { @@ -576,21 +576,21 @@ public func dataAndStorageController(context: AccountContext, focusOnItemTag: Da } let generatedMediaStoreSettings: GeneratedMediaStoreSettings - if let value = sharedData.entries[ApplicationSpecificSharedDataKeys.generatedMediaStoreSettings] as? GeneratedMediaStoreSettings { + if let value = sharedData.entries[ApplicationSpecificSharedDataKeys.generatedMediaStoreSettings]?.get(GeneratedMediaStoreSettings.self) { generatedMediaStoreSettings = value } else { generatedMediaStoreSettings = GeneratedMediaStoreSettings.defaultSettings } let voiceCallSettings: VoiceCallSettings - if let value = sharedData.entries[ApplicationSpecificSharedDataKeys.voiceCallSettings] as? VoiceCallSettings { + if let value = sharedData.entries[ApplicationSpecificSharedDataKeys.voiceCallSettings]?.get(VoiceCallSettings.self) { voiceCallSettings = value } else { voiceCallSettings = VoiceCallSettings.defaultSettings } var proxySettings: ProxySettings? - if let value = sharedData.entries[SharedDataKeys.proxySettings] as? ProxySettings { + if let value = sharedData.entries[SharedDataKeys.proxySettings]?.get(ProxySettings.self) { proxySettings = value } @@ -682,7 +682,7 @@ public func dataAndStorageController(context: AccountContext, focusOnItemTag: Da contentSettingsConfiguration.get() ) |> map { presentationData, state, dataAndStorageData, sharedData, contentSettingsConfiguration -> (ItemListControllerState, (ItemListNodeState, Any)) in - let webBrowserSettings = (sharedData.entries[ApplicationSpecificSharedDataKeys.webBrowserSettings] as? WebBrowserSettings) ?? WebBrowserSettings.defaultSettings + let webBrowserSettings = sharedData.entries[ApplicationSpecificSharedDataKeys.webBrowserSettings]?.get(WebBrowserSettings.self) ?? WebBrowserSettings.defaultSettings let options = availableOpenInOptions(context: context, item: .url(url: "https://telegram.org")) let defaultWebBrowser: String if let option = options.first(where: { $0.identifier == webBrowserSettings.defaultWebBrowser }) { diff --git a/submodules/SettingsUI/Sources/Data and Storage/IntentsSettingsController.swift b/submodules/SettingsUI/Sources/Data and Storage/IntentsSettingsController.swift index 755b4e3860..200c1aa23e 100644 --- a/submodules/SettingsUI/Sources/Data and Storage/IntentsSettingsController.swift +++ b/submodules/SettingsUI/Sources/Data and Storage/IntentsSettingsController.swift @@ -305,7 +305,7 @@ public func intentsSettingsController(context: AccountContext) -> ViewController let signal = combineLatest(context.sharedContext.presentationData, context.sharedContext.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.intentsSettings]), activeAccountsAndPeers(context: context, includePrimary: true)) |> deliverOnMainQueue |> map { presentationData, sharedData, accounts -> (ItemListControllerState, (ItemListNodeState, Any)) in - let settings = (sharedData.entries[ApplicationSpecificSharedDataKeys.intentsSettings] as? IntentsSettings) ?? IntentsSettings.defaultSettings + let settings = sharedData.entries[ApplicationSpecificSharedDataKeys.intentsSettings]?.get(IntentsSettings.self) ?? IntentsSettings.defaultSettings let controllerState = ItemListControllerState(presentationData: ItemListPresentationData(presentationData), title: .text(presentationData.strings.IntentsSettings_Title), leftNavigationButton: nil, rightNavigationButton: nil, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back)) let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: intentsSettingsControllerEntries(context: context, presentationData: presentationData, settings: settings, accounts: accounts.1.map { ($0.0.account, $0.1) }), style: .blocks, animateChanges: false) diff --git a/submodules/SettingsUI/Sources/Data and Storage/ProxyListSettingsController.swift b/submodules/SettingsUI/Sources/Data and Storage/ProxyListSettingsController.swift index 9d46e3f156..6dac2550dd 100644 --- a/submodules/SettingsUI/Sources/Data and Storage/ProxyListSettingsController.swift +++ b/submodules/SettingsUI/Sources/Data and Storage/ProxyListSettingsController.swift @@ -388,7 +388,7 @@ public func proxySettingsController(accountManager: AccountManager() proxySettings.set(accountManager.sharedData(keys: [SharedDataKeys.proxySettings]) |> map { sharedData -> ProxySettings in - if let value = sharedData.entries[SharedDataKeys.proxySettings] as? ProxySettings { + if let value = sharedData.entries[SharedDataKeys.proxySettings]?.get(ProxySettings.self) { return value } else { return ProxySettings.defaultSettings diff --git a/submodules/SettingsUI/Sources/Data and Storage/SaveIncomingMediaController.swift b/submodules/SettingsUI/Sources/Data and Storage/SaveIncomingMediaController.swift index b06e56bfb9..61850cd630 100644 --- a/submodules/SettingsUI/Sources/Data and Storage/SaveIncomingMediaController.swift +++ b/submodules/SettingsUI/Sources/Data and Storage/SaveIncomingMediaController.swift @@ -118,7 +118,7 @@ func saveIncomingMediaController(context: AccountContext) -> ViewController { |> deliverOnMainQueue |> map { presentationData, sharedData -> (ItemListControllerState, (ItemListNodeState, Any)) in let automaticMediaDownloadSettings: MediaAutoDownloadSettings - if let value = sharedData.entries[ApplicationSpecificSharedDataKeys.automaticMediaDownloadSettings] as? MediaAutoDownloadSettings { + if let value = sharedData.entries[ApplicationSpecificSharedDataKeys.automaticMediaDownloadSettings]?.get(MediaAutoDownloadSettings.self) { automaticMediaDownloadSettings = value } else { automaticMediaDownloadSettings = MediaAutoDownloadSettings.defaultSettings diff --git a/submodules/SettingsUI/Sources/Data and Storage/StorageUsageController.swift b/submodules/SettingsUI/Sources/Data and Storage/StorageUsageController.swift index b5d0018ab7..18a0675ad9 100644 --- a/submodules/SettingsUI/Sources/Data and Storage/StorageUsageController.swift +++ b/submodules/SettingsUI/Sources/Data and Storage/StorageUsageController.swift @@ -408,7 +408,7 @@ public func storageUsageController(context: AccountContext, cacheUsagePromise: P cacheSettingsPromise.set(context.sharedContext.accountManager.sharedData(keys: [SharedDataKeys.cacheStorageSettings]) |> map { sharedData -> CacheStorageSettings in let cacheSettings: CacheStorageSettings - if let value = sharedData.entries[SharedDataKeys.cacheStorageSettings] as? CacheStorageSettings { + if let value = sharedData.entries[SharedDataKeys.cacheStorageSettings]?.get(CacheStorageSettings.self) { cacheSettings = value } else { cacheSettings = CacheStorageSettings.defaultSettings diff --git a/submodules/SettingsUI/Sources/Data and Storage/VoiceCallDataSavingController.swift b/submodules/SettingsUI/Sources/Data and Storage/VoiceCallDataSavingController.swift index fe684bb32e..2fd37c6d3e 100644 --- a/submodules/SettingsUI/Sources/Data and Storage/VoiceCallDataSavingController.swift +++ b/submodules/SettingsUI/Sources/Data and Storage/VoiceCallDataSavingController.swift @@ -125,14 +125,14 @@ func voiceCallDataSavingController(context: AccountContext) -> ViewController { let sharedSettings = context.sharedContext.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.voiceCallSettings]) |> map { sharedData -> (VoiceCallSettings, AutodownloadSettings) in let voiceCallSettings: VoiceCallSettings - if let value = sharedData.entries[ApplicationSpecificSharedDataKeys.voiceCallSettings] as? VoiceCallSettings { + if let value = sharedData.entries[ApplicationSpecificSharedDataKeys.voiceCallSettings]?.get(VoiceCallSettings.self) { voiceCallSettings = value } else { voiceCallSettings = VoiceCallSettings.defaultSettings } let autodownloadSettings: AutodownloadSettings - if let value = sharedData.entries[SharedDataKeys.autodownloadSettings] as? AutodownloadSettings { + if let value = sharedData.entries[SharedDataKeys.autodownloadSettings]?.get(AutodownloadSettings.self) { autodownloadSettings = value } else { autodownloadSettings = AutodownloadSettings.defaultSettings diff --git a/submodules/SettingsUI/Sources/Data and Storage/WebBrowserSettingsController.swift b/submodules/SettingsUI/Sources/Data and Storage/WebBrowserSettingsController.swift index 02ee92d985..cf9b815d8c 100644 --- a/submodules/SettingsUI/Sources/Data and Storage/WebBrowserSettingsController.swift +++ b/submodules/SettingsUI/Sources/Data and Storage/WebBrowserSettingsController.swift @@ -103,7 +103,7 @@ public func webBrowserSettingsController(context: AccountContext) -> ViewControl let signal = combineLatest(context.sharedContext.presentationData, context.sharedContext.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.webBrowserSettings])) |> deliverOnMainQueue |> map { presentationData, sharedData -> (ItemListControllerState, (ItemListNodeState, Any)) in - let settings = (sharedData.entries[ApplicationSpecificSharedDataKeys.webBrowserSettings] as? WebBrowserSettings) ?? WebBrowserSettings.defaultSettings + let settings = sharedData.entries[ApplicationSpecificSharedDataKeys.webBrowserSettings]?.get(WebBrowserSettings.self) ?? WebBrowserSettings.defaultSettings let controllerState = ItemListControllerState(presentationData: ItemListPresentationData(presentationData), title: .text(presentationData.strings.WebBrowser_Title), leftNavigationButton: nil, rightNavigationButton: nil, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back)) let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: webBrowserSettingsControllerEntries(context: context, presentationData: presentationData, selectedBrowser: settings.defaultWebBrowser), style: .blocks, animateChanges: false) diff --git a/submodules/SettingsUI/Sources/Language Selection/LocalizationListControllerNode.swift b/submodules/SettingsUI/Sources/Language Selection/LocalizationListControllerNode.swift index 6eee101e54..334e236664 100644 --- a/submodules/SettingsUI/Sources/Language Selection/LocalizationListControllerNode.swift +++ b/submodules/SettingsUI/Sources/Language Selection/LocalizationListControllerNode.swift @@ -338,9 +338,9 @@ final class LocalizationListControllerNode: ViewControllerTracingNode { let removeItem: (String) -> Void = { id in let _ = (context.account.postbox.transaction { transaction -> Signal in removeSavedLocalization(transaction: transaction, languageCode: id) - let state = transaction.getPreferencesEntry(key: PreferencesKeys.localizationListState) as? LocalizationListState + let state = transaction.getPreferencesEntry(key: PreferencesKeys.localizationListState)?.get(LocalizationListState.self) return context.sharedContext.accountManager.transaction { transaction -> LocalizationInfo? in - if let settings = transaction.getSharedData(SharedDataKeys.localizationSettings) as? LocalizationSettings, let state = state { + if let settings = transaction.getSharedData(SharedDataKeys.localizationSettings)?.get(LocalizationSettings.self), let state = state { if settings.primaryComponent.languageCode == id { for item in state.availableOfficialLocalizations { if item.languageCode == "en" { @@ -374,12 +374,12 @@ final class LocalizationListControllerNode: ViewControllerTracingNode { var entries: [LanguageListEntry] = [] var activeLanguageCode: String? - if let localizationSettings = sharedData.entries[SharedDataKeys.localizationSettings] as? LocalizationSettings { + if let localizationSettings = sharedData.entries[SharedDataKeys.localizationSettings]?.get(LocalizationSettings.self) { activeLanguageCode = localizationSettings.primaryComponent.languageCode } var existingIds = Set() - let localizationListState = (view.views[preferencesKey] as? PreferencesView)?.values[PreferencesKeys.localizationListState] as? LocalizationListState + let localizationListState = (view.views[preferencesKey] as? PreferencesView)?.values[PreferencesKeys.localizationListState]?.get(LocalizationListState.self) if let localizationListState = localizationListState, !localizationListState.availableOfficialLocalizations.isEmpty { strongSelf.currentListState = localizationListState diff --git a/submodules/SettingsUI/Sources/Notifications/Exceptions/NotificationExceptionSettingsController.swift b/submodules/SettingsUI/Sources/Notifications/Exceptions/NotificationExceptionSettingsController.swift index 9638dd5ef2..5813c3dc1c 100644 --- a/submodules/SettingsUI/Sources/Notifications/Exceptions/NotificationExceptionSettingsController.swift +++ b/submodules/SettingsUI/Sources/Notifications/Exceptions/NotificationExceptionSettingsController.swift @@ -351,7 +351,7 @@ public func notificationPeerExceptionController(context: AccountContext, peer: P statePromise.set(context.account.postbox.transaction { transaction -> NotificationExceptionPeerState in var state = NotificationExceptionPeerState(canRemove: mode.peerIds.contains(peer.id), notifications: transaction.getPeerNotificationSettings(peer.id) as? TelegramPeerNotificationSettings) - let globalSettings: GlobalNotificationSettings = (transaction.getPreferencesEntry(key: PreferencesKeys.globalNotifications) as? GlobalNotificationSettings) ?? GlobalNotificationSettings.defaultSettings + let globalSettings: GlobalNotificationSettings = transaction.getPreferencesEntry(key: PreferencesKeys.globalNotifications)?.get(GlobalNotificationSettings.self) ?? GlobalNotificationSettings.defaultSettings switch mode { case .channels: state = state.withUpdatedDefaultSound(globalSettings.effective.channels.sound) diff --git a/submodules/SettingsUI/Sources/Notifications/NotificationsAndSounds.swift b/submodules/SettingsUI/Sources/Notifications/NotificationsAndSounds.swift index 27412b4a81..2cb49c5ecb 100644 --- a/submodules/SettingsUI/Sources/Notifications/NotificationsAndSounds.swift +++ b/submodules/SettingsUI/Sources/Notifications/NotificationsAndSounds.swift @@ -1077,14 +1077,14 @@ public func notificationsAndSoundsController(context: AccountContext, exceptions |> map { presentationData, sharedData, view, exceptions, authorizationStatus, warningSuppressed, hasMoreThanOneAccount -> (ItemListControllerState, (ItemListNodeState, Any)) in let viewSettings: GlobalNotificationSettingsSet - if let settings = view.values[PreferencesKeys.globalNotifications] as? GlobalNotificationSettings { + if let settings = view.values[PreferencesKeys.globalNotifications]?.get(GlobalNotificationSettings.self) { viewSettings = settings.effective } else { viewSettings = GlobalNotificationSettingsSet.defaultSettings } let inAppSettings: InAppNotificationSettings - if let settings = sharedData.entries[ApplicationSpecificSharedDataKeys.inAppNotificationSettings] as? InAppNotificationSettings { + if let settings = sharedData.entries[ApplicationSpecificSharedDataKeys.inAppNotificationSettings]?.get(InAppNotificationSettings.self) { inAppSettings = settings } else { inAppSettings = InAppNotificationSettings.defaultSettings diff --git a/submodules/SettingsUI/Sources/Privacy and Security/DataPrivacySettingsController.swift b/submodules/SettingsUI/Sources/Privacy and Security/DataPrivacySettingsController.swift index 755ce09724..be32e52dcf 100644 --- a/submodules/SettingsUI/Sources/Privacy and Security/DataPrivacySettingsController.swift +++ b/submodules/SettingsUI/Sources/Privacy and Security/DataPrivacySettingsController.swift @@ -419,9 +419,9 @@ public func dataPrivacyController(context: AccountContext) -> ViewController { let _ = context.account.postbox.transaction({ transaction in transaction.updatePreferencesEntry(key: PreferencesKeys.contactsSettings, { current in - var settings = current as? ContactsSettings ?? ContactsSettings.defaultSettings + var settings = current?.get(ContactsSettings.self) ?? ContactsSettings.defaultSettings settings.synchronizeContacts = false - return settings + return PreferencesEntry(settings) }) }).start() @@ -440,9 +440,9 @@ public func dataPrivacyController(context: AccountContext) -> ViewController { }, updateSyncContacts: { value in let _ = context.account.postbox.transaction({ transaction in transaction.updatePreferencesEntry(key: PreferencesKeys.contactsSettings, { current in - var settings = current as? ContactsSettings ?? ContactsSettings.defaultSettings + var settings = current?.get(ContactsSettings.self) ?? ContactsSettings.defaultSettings settings.synchronizeContacts = value - return settings + return PreferencesEntry(settings) }) }).start() }, updateSuggestFrequentContacts: { value in @@ -506,7 +506,7 @@ public func dataPrivacyController(context: AccountContext) -> ViewController { |> map { presentationData, state, noticeView, sharedData, preferences, recentPeers -> (ItemListControllerState, (ItemListNodeState, Any)) in let secretChatLinkPreviews = noticeView.value.flatMap({ ApplicationSpecificNotice.getSecretChatLinkPreviews($0) }) - let settings: ContactsSettings = preferences.values[PreferencesKeys.contactsSettings] as? ContactsSettings ?? ContactsSettings.defaultSettings + let settings: ContactsSettings = preferences.values[PreferencesKeys.contactsSettings]?.get(ContactsSettings.self) ?? ContactsSettings.defaultSettings let synchronizeDeviceContacts: Bool = settings.synchronizeContacts diff --git a/submodules/SettingsUI/Sources/Privacy and Security/PasscodeOptionsController.swift b/submodules/SettingsUI/Sources/Privacy and Security/PasscodeOptionsController.swift index 0d0814e639..5d34e5e2f6 100644 --- a/submodules/SettingsUI/Sources/Privacy and Security/PasscodeOptionsController.swift +++ b/submodules/SettingsUI/Sources/Privacy and Security/PasscodeOptionsController.swift @@ -220,7 +220,7 @@ func passcodeOptionsController(context: AccountContext) -> ViewController { let passcodeOptionsDataPromise = Promise() passcodeOptionsDataPromise.set(context.sharedContext.accountManager.transaction { transaction -> (PostboxAccessChallengeData, PresentationPasscodeSettings) in - let passcodeSettings = transaction.getSharedData(ApplicationSpecificSharedDataKeys.presentationPasscodeSettings) as? PresentationPasscodeSettings ?? PresentationPasscodeSettings.defaultSettings + let passcodeSettings = transaction.getSharedData(ApplicationSpecificSharedDataKeys.presentationPasscodeSettings)?.get(PresentationPasscodeSettings.self) ?? PresentationPasscodeSettings.defaultSettings return (transaction.getAccessChallengeData(), passcodeSettings) } |> map { accessChallenge, passcodeSettings -> PasscodeOptionsData in @@ -444,7 +444,7 @@ public func passcodeEntryController(context: AccountContext, animateIn: Bool = t } |> mapToSignal { accessChallengeData -> Signal<(PostboxAccessChallengeData, PresentationPasscodeSettings?), NoError> in return context.sharedContext.accountManager.transaction { transaction -> (PostboxAccessChallengeData, PresentationPasscodeSettings?) in - let passcodeSettings = transaction.getSharedData(ApplicationSpecificSharedDataKeys.presentationPasscodeSettings) as? PresentationPasscodeSettings + let passcodeSettings = transaction.getSharedData(ApplicationSpecificSharedDataKeys.presentationPasscodeSettings)?.get(PresentationPasscodeSettings.self) return (accessChallengeData, passcodeSettings) } } diff --git a/submodules/SettingsUI/Sources/Privacy and Security/PrivacyAndSecurityController.swift b/submodules/SettingsUI/Sources/Privacy and Security/PrivacyAndSecurityController.swift index 7be99cbb75..3dbf6ebb52 100644 --- a/submodules/SettingsUI/Sources/Privacy and Security/PrivacyAndSecurityController.swift +++ b/submodules/SettingsUI/Sources/Privacy and Security/PrivacyAndSecurityController.swift @@ -616,8 +616,8 @@ public func privacyAndSecurityController(context: AccountContext, initialSetting let callsSignal = combineLatest(context.sharedContext.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.voiceCallSettings]), context.account.postbox.preferencesView(keys: [PreferencesKeys.voipConfiguration])) |> take(1) |> map { sharedData, view -> (VoiceCallSettings, VoipConfiguration) in - let voiceCallSettings: VoiceCallSettings = sharedData.entries[ApplicationSpecificSharedDataKeys.voiceCallSettings] as? VoiceCallSettings ?? .defaultSettings - let voipConfiguration = view.values[PreferencesKeys.voipConfiguration] as? VoipConfiguration ?? .defaultValue + let voiceCallSettings: VoiceCallSettings = sharedData.entries[ApplicationSpecificSharedDataKeys.voiceCallSettings]?.get(VoiceCallSettings.self) ?? .defaultSettings + let voipConfiguration = view.values[PreferencesKeys.voipConfiguration]?.get(VoipConfiguration.self) ?? .defaultValue return (voiceCallSettings, voipConfiguration) } @@ -850,7 +850,7 @@ public func privacyAndSecurityController(context: AccountContext, initialSetting let signal = combineLatest(queue: .mainQueue(), context.sharedContext.presentationData, statePromise.get(), privacySettingsPromise.get(), context.sharedContext.accountManager.noticeEntry(key: ApplicationSpecificNotice.secretChatLinkPreviewsKey()), context.sharedContext.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.contactSynchronizationSettings]), context.engine.peers.recentPeers(), blockedPeersState.get(), webSessionsContext.state, context.sharedContext.accountManager.accessChallengeData(), combineLatest(twoStepAuth.get(), twoStepAuthDataValue.get()), context.account.postbox.combinedView(keys: [preferencesKey])) |> map { presentationData, state, privacySettings, noticeView, sharedData, recentPeers, blockedPeersState, activeWebsitesState, accessChallengeData, twoStepAuth, preferences -> (ItemListControllerState, (ItemListNodeState, Any)) in var canAutoarchive = false - if let view = preferences.views[preferencesKey] as? PreferencesView, let appConfiguration = view.values[PreferencesKeys.appConfiguration] as? AppConfiguration, let data = appConfiguration.data, let hasAutoarchive = data["autoarchive_setting_available"] as? Bool { + if let view = preferences.views[preferencesKey] as? PreferencesView, let appConfiguration = view.values[PreferencesKeys.appConfiguration]?.get(AppConfiguration.self), let data = appConfiguration.data, let hasAutoarchive = data["autoarchive_setting_available"] as? Bool { canAutoarchive = hasAutoarchive } diff --git a/submodules/SettingsUI/Sources/Privacy and Security/Recent Sessions/RecentSessionsController.swift b/submodules/SettingsUI/Sources/Privacy and Security/Recent Sessions/RecentSessionsController.swift index b7671b73fe..077b146e40 100644 --- a/submodules/SettingsUI/Sources/Privacy and Security/Recent Sessions/RecentSessionsController.swift +++ b/submodules/SettingsUI/Sources/Privacy and Security/Recent Sessions/RecentSessionsController.swift @@ -639,7 +639,7 @@ public func recentSessionsController(context: AccountContext, activeSessionsCont let enableQRLogin = context.account.postbox.preferencesView(keys: [PreferencesKeys.appConfiguration]) |> map { view -> Bool in - guard let appConfiguration = view.values[PreferencesKeys.appConfiguration] as? AppConfiguration else { + guard let appConfiguration = view.values[PreferencesKeys.appConfiguration]?.get(AppConfiguration.self) else { return false } guard let data = appConfiguration.data, let enableQR = data["qr_login_camera"] as? Bool, enableQR else { diff --git a/submodules/SettingsUI/Sources/Search/SettingsSearchableItems.swift b/submodules/SettingsUI/Sources/Search/SettingsSearchableItems.swift index 9f5c93c37f..2f66459456 100644 --- a/submodules/SettingsUI/Sources/Search/SettingsSearchableItems.swift +++ b/submodules/SettingsUI/Sources/Search/SettingsSearchableItems.swift @@ -436,8 +436,8 @@ private func privacySearchableItems(context: AccountContext, privacySettings: Ac callsSignal = combineLatest(context.sharedContext.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.voiceCallSettings]), context.account.postbox.preferencesView(keys: [PreferencesKeys.voipConfiguration])) |> take(1) |> map { sharedData, view -> (VoiceCallSettings, VoipConfiguration)? in - let voiceCallSettings: VoiceCallSettings = sharedData.entries[ApplicationSpecificSharedDataKeys.voiceCallSettings] as? VoiceCallSettings ?? .defaultSettings - let voipConfiguration = view.values[PreferencesKeys.voipConfiguration] as? VoipConfiguration ?? .defaultValue + let voiceCallSettings: VoiceCallSettings = sharedData.entries[ApplicationSpecificSharedDataKeys.voiceCallSettings]?.get(VoiceCallSettings.self) ?? .defaultSettings + let voipConfiguration = view.values[PreferencesKeys.voipConfiguration]?.get(VoipConfiguration.self) ?? .defaultValue return (voiceCallSettings, voipConfiguration) } } else { @@ -742,7 +742,7 @@ func settingsSearchableItems(context: AccountContext, notificationExceptionsList |> take(1) |> map { view -> GlobalNotificationSettingsSet in let viewSettings: GlobalNotificationSettingsSet - if let settings = view.values[PreferencesKeys.globalNotifications] as? GlobalNotificationSettings { + if let settings = view.values[PreferencesKeys.globalNotifications]?.get(GlobalNotificationSettings.self) { viewSettings = settings.effective } else { viewSettings = GlobalNotificationSettingsSet.defaultSettings @@ -758,7 +758,7 @@ func settingsSearchableItems(context: AccountContext, notificationExceptionsList let proxyServers = context.sharedContext.accountManager.sharedData(keys: [SharedDataKeys.proxySettings]) |> map { sharedData -> ProxySettings in - if let value = sharedData.entries[SharedDataKeys.proxySettings] as? ProxySettings { + if let value = sharedData.entries[SharedDataKeys.proxySettings]?.get(ProxySettings.self) { return value } else { return ProxySettings.defaultSettings @@ -771,13 +771,13 @@ func settingsSearchableItems(context: AccountContext, notificationExceptionsList let localizationPreferencesKey: PostboxViewKey = .preferences(keys: Set([PreferencesKeys.localizationListState])) let localizations = combineLatest(context.account.postbox.combinedView(keys: [localizationPreferencesKey]), context.sharedContext.accountManager.sharedData(keys: [SharedDataKeys.localizationSettings])) |> map { view, sharedData -> [LocalizationInfo] in - if let localizationListState = (view.views[localizationPreferencesKey] as? PreferencesView)?.values[PreferencesKeys.localizationListState] as? LocalizationListState, !localizationListState.availableOfficialLocalizations.isEmpty { + if let localizationListState = (view.views[localizationPreferencesKey] as? PreferencesView)?.values[PreferencesKeys.localizationListState]?.get(LocalizationListState.self), !localizationListState.availableOfficialLocalizations.isEmpty { var existingIds = Set() let availableSavedLocalizations = localizationListState.availableSavedLocalizations.filter({ info in !localizationListState.availableOfficialLocalizations.contains(where: { $0.languageCode == info.languageCode }) }) var activeLanguageCode: String? - if let localizationSettings = sharedData.entries[SharedDataKeys.localizationSettings] as? LocalizationSettings { + if let localizationSettings = sharedData.entries[SharedDataKeys.localizationSettings]?.get(LocalizationSettings.self) { activeLanguageCode = localizationSettings.primaryComponent.languageCode } diff --git a/submodules/SettingsUI/Sources/Stickers/ArchivedStickerPacksController.swift b/submodules/SettingsUI/Sources/Stickers/ArchivedStickerPacksController.swift index bd86306f87..f2c88adb1e 100644 --- a/submodules/SettingsUI/Sources/Stickers/ArchivedStickerPacksController.swift +++ b/submodules/SettingsUI/Sources/Stickers/ArchivedStickerPacksController.swift @@ -378,7 +378,7 @@ public func archivedStickerPacksController(context: AccountContext, mode: Archiv |> deliverOnMainQueue |> map { presentationData, state, packs, installedView, sharedData -> (ItemListControllerState, (ItemListNodeState, Any)) in var stickerSettings = StickerSettings.defaultSettings - if let value = sharedData.entries[ApplicationSpecificSharedDataKeys.stickerSettings] as? StickerSettings { + if let value = sharedData.entries[ApplicationSpecificSharedDataKeys.stickerSettings]?.get(StickerSettings.self) { stickerSettings = value } diff --git a/submodules/SettingsUI/Sources/Stickers/FeaturedStickerPacksController.swift b/submodules/SettingsUI/Sources/Stickers/FeaturedStickerPacksController.swift index 3d17794f75..aac83cf4fb 100644 --- a/submodules/SettingsUI/Sources/Stickers/FeaturedStickerPacksController.swift +++ b/submodules/SettingsUI/Sources/Stickers/FeaturedStickerPacksController.swift @@ -191,7 +191,7 @@ public func featuredStickerPacksController(context: AccountContext) -> ViewContr |> deliverOnMainQueue |> map { presentationData, state, view, featured, sharedData -> (ItemListControllerState, (ItemListNodeState, Any)) in var stickerSettings = StickerSettings.defaultSettings - if let value = sharedData.entries[ApplicationSpecificSharedDataKeys.stickerSettings] as? StickerSettings { + if let value = sharedData.entries[ApplicationSpecificSharedDataKeys.stickerSettings]?.get(StickerSettings.self) { stickerSettings = value } diff --git a/submodules/SettingsUI/Sources/Stickers/InstalledStickerPacksController.swift b/submodules/SettingsUI/Sources/Stickers/InstalledStickerPacksController.swift index bf40f089ae..39977f31bd 100644 --- a/submodules/SettingsUI/Sources/Stickers/InstalledStickerPacksController.swift +++ b/submodules/SettingsUI/Sources/Stickers/InstalledStickerPacksController.swift @@ -644,7 +644,7 @@ public func installedStickerPacksController(context: AccountContext, mode: Insta |> deliverOnMainQueue |> map { presentationData, state, view, temporaryPackOrder, featuredAndArchived, sharedData -> (ItemListControllerState, (ItemListNodeState, Any)) in var stickerSettings = StickerSettings.defaultSettings - if let value = sharedData.entries[ApplicationSpecificSharedDataKeys.stickerSettings] as? StickerSettings { + if let value = sharedData.entries[ApplicationSpecificSharedDataKeys.stickerSettings]?.get(StickerSettings.self) { stickerSettings = value } diff --git a/submodules/SettingsUI/Sources/Themes/ThemeAccentColorController.swift b/submodules/SettingsUI/Sources/Themes/ThemeAccentColorController.swift index 62f2e4888b..37d636eab6 100644 --- a/submodules/SettingsUI/Sources/Themes/ThemeAccentColorController.swift +++ b/submodules/SettingsUI/Sources/Themes/ThemeAccentColorController.swift @@ -368,7 +368,7 @@ final class ThemeAccentColorController: ViewController { guard let strongSelf = self else { return } - let settings = (sharedData.entries[ApplicationSpecificSharedDataKeys.presentationThemeSettings] as? PresentationThemeSettings) ?? PresentationThemeSettings.defaultSettings + let settings = sharedData.entries[ApplicationSpecificSharedDataKeys.presentationThemeSettings]?.get(PresentationThemeSettings.self) ?? PresentationThemeSettings.defaultSettings let accentColor: UIColor var initialWallpaper: TelegramWallpaper? diff --git a/submodules/SettingsUI/Sources/Themes/ThemeAutoNightSettingsController.swift b/submodules/SettingsUI/Sources/Themes/ThemeAutoNightSettingsController.swift index 2064eeab5f..7d62ed2119 100644 --- a/submodules/SettingsUI/Sources/Themes/ThemeAutoNightSettingsController.swift +++ b/submodules/SettingsUI/Sources/Themes/ThemeAutoNightSettingsController.swift @@ -369,7 +369,7 @@ public func themeAutoNightSettingsController(context: AccountContext) -> ViewCon let _ = (combineLatest(stagingSettingsPromise.get(), sharedData) |> take(1) |> deliverOnMainQueue).start(next: { stagingSettings, sharedData in - let settings = (sharedData.entries[ApplicationSpecificSharedDataKeys.presentationThemeSettings] as? PresentationThemeSettings) ?? PresentationThemeSettings.defaultSettings + let settings = sharedData.entries[ApplicationSpecificSharedDataKeys.presentationThemeSettings]?.get(PresentationThemeSettings.self) ?? PresentationThemeSettings.defaultSettings let updated = f(stagingSettings ?? settings.automaticThemeSwitchSetting) stagingSettingsPromise.set(updated) if areSettingsValid(updated) { @@ -569,7 +569,7 @@ public func themeAutoNightSettingsController(context: AccountContext) -> ViewCon let signal = combineLatest(context.sharedContext.presentationData |> deliverOnMainQueue, sharedData |> deliverOnMainQueue, cloudThemes.get() |> deliverOnMainQueue, stagingSettingsPromise.get() |> deliverOnMainQueue) |> map { presentationData, sharedData, cloudThemes, stagingSettings -> (ItemListControllerState, (ItemListNodeState, Any)) in - let settings = (sharedData.entries[ApplicationSpecificSharedDataKeys.presentationThemeSettings] as? PresentationThemeSettings) ?? PresentationThemeSettings.defaultSettings + let settings = sharedData.entries[ApplicationSpecificSharedDataKeys.presentationThemeSettings]?.get(PresentationThemeSettings.self) ?? PresentationThemeSettings.defaultSettings let defaultThemes: [PresentationThemeReference] = [.builtin(.night), .builtin(.nightAccent)] let cloudThemes: [PresentationThemeReference] = cloudThemes.map { .cloud(PresentationCloudTheme(theme: $0, resolvedWallpaper: nil, creatorAccountId: $0.isCreator ? context.account.id : nil)) } diff --git a/submodules/SettingsUI/Sources/Themes/ThemeColorsGridController.swift b/submodules/SettingsUI/Sources/Themes/ThemeColorsGridController.swift index 54640c18c0..563df18433 100644 --- a/submodules/SettingsUI/Sources/Themes/ThemeColorsGridController.swift +++ b/submodules/SettingsUI/Sources/Themes/ThemeColorsGridController.swift @@ -182,7 +182,7 @@ final class ThemeColorsGridController: ViewController { guard let strongSelf = self else { return } - let settings = (sharedData.entries[ApplicationSpecificSharedDataKeys.presentationThemeSettings] as? PresentationThemeSettings) ?? PresentationThemeSettings.defaultSettings + let settings = sharedData.entries[ApplicationSpecificSharedDataKeys.presentationThemeSettings]?.get(PresentationThemeSettings.self) ?? PresentationThemeSettings.defaultSettings let autoNightModeTriggered = strongSelf.presentationData.autoNightModeTriggered let themeReference: PresentationThemeReference diff --git a/submodules/SettingsUI/Sources/Themes/ThemeGridControllerNode.swift b/submodules/SettingsUI/Sources/Themes/ThemeGridControllerNode.swift index 762f26a144..cb9dd1e9f7 100644 --- a/submodules/SettingsUI/Sources/Themes/ThemeGridControllerNode.swift +++ b/submodules/SettingsUI/Sources/Themes/ThemeGridControllerNode.swift @@ -504,7 +504,7 @@ final class ThemeGridControllerNode: ASDisplayNode { self.context.sharedContext.accountManager.sharedData(keys: [SharedDataKeys.wallapersState]) ) |> map { remoteWallpapers, sharedData -> [Wallpaper] in - let localState = (sharedData.entries[SharedDataKeys.wallapersState] as? WallpapersState) ?? WallpapersState.default + let localState = sharedData.entries[SharedDataKeys.wallapersState]?.get(WallpapersState.self) ?? WallpapersState.default var wallpapers: [Wallpaper] = [] for wallpaper in localState.wallpapers { diff --git a/submodules/SettingsUI/Sources/Themes/ThemePreviewController.swift b/submodules/SettingsUI/Sources/Themes/ThemePreviewController.swift index 8feb895a04..3fdbcd6e6c 100644 --- a/submodules/SettingsUI/Sources/Themes/ThemePreviewController.swift +++ b/submodules/SettingsUI/Sources/Themes/ThemePreviewController.swift @@ -356,7 +356,7 @@ public final class ThemePreviewController: ViewController { var previousDefaultTheme: (PresentationThemeReference, PresentationThemeAccentColor?, Bool, PresentationThemeReference, Bool)? transaction.updateSharedData(ApplicationSpecificSharedDataKeys.presentationThemeSettings, { entry in let currentSettings: PresentationThemeSettings - if let entry = entry as? PresentationThemeSettings { + if let entry = entry?.get(PresentationThemeSettings.self) { currentSettings = entry } else { currentSettings = PresentationThemeSettings.defaultSettings @@ -387,7 +387,7 @@ public final class ThemePreviewController: ViewController { var themeSpecificChatWallpapers = updatedSettings.themeSpecificChatWallpapers themeSpecificChatWallpapers[updatedTheme.index] = nil - return updatedSettings.withUpdatedThemeSpecificChatWallpapers(themeSpecificChatWallpapers).withUpdatedThemeSpecificAccentColors(themeSpecificAccentColors) + return PreferencesEntry(updatedSettings.withUpdatedThemeSpecificChatWallpapers(themeSpecificChatWallpapers).withUpdatedThemeSpecificAccentColors(themeSpecificAccentColors)) }) return previousDefaultTheme } diff --git a/submodules/SettingsUI/Sources/Themes/ThemeSettingsController.swift b/submodules/SettingsUI/Sources/Themes/ThemeSettingsController.swift index 025604f09a..5cf7242638 100644 --- a/submodules/SettingsUI/Sources/Themes/ThemeSettingsController.swift +++ b/submodules/SettingsUI/Sources/Themes/ThemeSettingsController.swift @@ -600,14 +600,14 @@ public func themeSettingsController(context: AccountContext, focusOnItemTag: The let _ = (context.sharedContext.accountManager.sharedData(keys: Set([ApplicationSpecificSharedDataKeys.presentationThemeSettings])) |> take(1) |> deliverOnMainQueue).start(next: { view in - let settings = (view.entries[ApplicationSpecificSharedDataKeys.presentationThemeSettings] as? PresentationThemeSettings) ?? PresentationThemeSettings.defaultSettings + let settings = view.entries[ApplicationSpecificSharedDataKeys.presentationThemeSettings]?.get(PresentationThemeSettings.self) ?? PresentationThemeSettings.defaultSettings pushControllerImpl?(TextSizeSelectionController(context: context, presentationThemeSettings: settings)) }) }, openBubbleSettings: { let _ = (context.sharedContext.accountManager.sharedData(keys: Set([ApplicationSpecificSharedDataKeys.presentationThemeSettings])) |> take(1) |> deliverOnMainQueue).start(next: { view in - let settings = (view.entries[ApplicationSpecificSharedDataKeys.presentationThemeSettings] as? PresentationThemeSettings) ?? PresentationThemeSettings.defaultSettings + let settings = view.entries[ApplicationSpecificSharedDataKeys.presentationThemeSettings]?.get(PresentationThemeSettings.self) ?? PresentationThemeSettings.defaultSettings pushControllerImpl?(BubbleSettingsController(context: context, presentationThemeSettings: settings)) }) }, toggleLargeEmoji: { largeEmoji in @@ -631,7 +631,7 @@ public func themeSettingsController(context: AccountContext, focusOnItemTag: The pushControllerImpl?(controller) }, themeContextAction: { isCurrent, reference, node, gesture in let _ = (context.sharedContext.accountManager.transaction { transaction -> (PresentationThemeAccentColor?, TelegramWallpaper?) in - let settings = transaction.getSharedData(ApplicationSpecificSharedDataKeys.presentationThemeSettings) as? PresentationThemeSettings ?? PresentationThemeSettings.defaultSettings + let settings = transaction.getSharedData(ApplicationSpecificSharedDataKeys.presentationThemeSettings)?.get(PresentationThemeSettings.self) ?? PresentationThemeSettings.defaultSettings let accentColor = settings.themeSpecificAccentColors[reference.index] var wallpaper: TelegramWallpaper? if let accentColor = accentColor { @@ -808,7 +808,7 @@ public func themeSettingsController(context: AccountContext, focusOnItemTag: The }) }, colorContextAction: { isCurrent, reference, accentColor, node, gesture in let _ = (context.sharedContext.accountManager.transaction { transaction -> (ThemeSettingsColorOption?, TelegramWallpaper?) in - let settings = transaction.getSharedData(ApplicationSpecificSharedDataKeys.presentationThemeSettings) as? PresentationThemeSettings ?? PresentationThemeSettings.defaultSettings + let settings = transaction.getSharedData(ApplicationSpecificSharedDataKeys.presentationThemeSettings)?.get(PresentationThemeSettings.self) ?? PresentationThemeSettings.defaultSettings var wallpaper: TelegramWallpaper? if let accentColor = accentColor { switch accentColor { @@ -1041,7 +1041,7 @@ public func themeSettingsController(context: AccountContext, focusOnItemTag: The let signal = combineLatest(queue: .mainQueue(), context.sharedContext.presentationData, context.sharedContext.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.presentationThemeSettings]), cloudThemes.get(), availableAppIcons, currentAppIconName.get(), removedThemeIndexesPromise.get()) |> map { presentationData, sharedData, cloudThemes, availableAppIcons, currentAppIconName, removedThemeIndexes -> (ItemListControllerState, (ItemListNodeState, Any)) in - let settings = (sharedData.entries[ApplicationSpecificSharedDataKeys.presentationThemeSettings] as? PresentationThemeSettings) ?? PresentationThemeSettings.defaultSettings + let settings = sharedData.entries[ApplicationSpecificSharedDataKeys.presentationThemeSettings]?.get(PresentationThemeSettings.self) ?? PresentationThemeSettings.defaultSettings let themeReference: PresentationThemeReference if presentationData.autoNightModeTriggered { @@ -1189,7 +1189,7 @@ public func themeSettingsController(context: AccountContext, focusOnItemTag: The let _ = applyTheme(accountManager: context.sharedContext.accountManager, account: context.account, theme: cloudTheme).start() let currentTheme = context.sharedContext.accountManager.transaction { transaction -> (PresentationThemeReference) in - let settings = transaction.getSharedData(ApplicationSpecificSharedDataKeys.presentationThemeSettings) as? PresentationThemeSettings ?? PresentationThemeSettings.defaultSettings + let settings = transaction.getSharedData(ApplicationSpecificSharedDataKeys.presentationThemeSettings)?.get(PresentationThemeSettings.self) ?? PresentationThemeSettings.defaultSettings if autoNightModeTriggered { return settings.automaticThemeSwitchSetting.theme } else { @@ -1322,7 +1322,7 @@ public func themeSettingsController(context: AccountContext, focusOnItemTag: The actionSheet?.dismissAnimated() let _ = (context.sharedContext.accountManager.transaction { transaction -> PresentationThemeReference in - let settings = transaction.getSharedData(ApplicationSpecificSharedDataKeys.presentationThemeSettings) as? PresentationThemeSettings ?? PresentationThemeSettings.defaultSettings + let settings = transaction.getSharedData(ApplicationSpecificSharedDataKeys.presentationThemeSettings)?.get(PresentationThemeSettings.self) ?? PresentationThemeSettings.defaultSettings let themeReference: PresentationThemeReference let autoNightModeTriggered = context.sharedContext.currentPresentationData.with { $0 }.autoNightModeTriggered diff --git a/submodules/SettingsUI/Sources/Watch/WatchSettingsController.swift b/submodules/SettingsUI/Sources/Watch/WatchSettingsController.swift index 3584a1b00d..e863dd1dae 100644 --- a/submodules/SettingsUI/Sources/Watch/WatchSettingsController.swift +++ b/submodules/SettingsUI/Sources/Watch/WatchSettingsController.swift @@ -129,7 +129,7 @@ public func watchSettingsController(context: AccountContext) -> ViewController { let signal = combineLatest(context.sharedContext.presentationData, context.sharedContext.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.watchPresetSettings])) |> deliverOnMainQueue |> map { presentationData, sharedData -> (ItemListControllerState, (ItemListNodeState, Any)) in - let settings = (sharedData.entries[ApplicationSpecificSharedDataKeys.watchPresetSettings] as? WatchPresetSettings) ?? WatchPresetSettings.defaultSettings + let settings = sharedData.entries[ApplicationSpecificSharedDataKeys.watchPresetSettings]?.get(WatchPresetSettings.self) ?? WatchPresetSettings.defaultSettings let controllerState = ItemListControllerState(presentationData: ItemListPresentationData(presentationData), title: .text(presentationData.strings.AppleWatch_Title), leftNavigationButton: nil, rightNavigationButton: nil, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back)) let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: watchSettingsControllerEntries(presentationData: presentationData, customPresets: settings.customPresets), style: .blocks, animateChanges: false) diff --git a/submodules/StickerPackPreviewUI/Sources/StickerPackPreviewController.swift b/submodules/StickerPackPreviewUI/Sources/StickerPackPreviewController.swift index cfddc92382..93161b1a19 100644 --- a/submodules/StickerPackPreviewUI/Sources/StickerPackPreviewController.swift +++ b/submodules/StickerPackPreviewUI/Sources/StickerPackPreviewController.swift @@ -173,7 +173,7 @@ public final class StickerPackPreviewController: ViewController, StandalonePrese self.stickerPackDisposable.set((combineLatest(self.stickerPackContents.get(), self.context.sharedContext.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.stickerSettings]) |> take(1)) |> mapToSignal { next, sharedData -> Signal<(LoadedStickerPack, StickerSettings), NoError> in var stickerSettings = StickerSettings.defaultSettings - if let value = sharedData.entries[ApplicationSpecificSharedDataKeys.stickerSettings] as? StickerSettings { + if let value = sharedData.entries[ApplicationSpecificSharedDataKeys.stickerSettings]?.get(StickerSettings.self) { stickerSettings = value } diff --git a/submodules/TelegramBaseController/Sources/TelegramBaseController.swift b/submodules/TelegramBaseController/Sources/TelegramBaseController.swift index a1848a92fe..a9750aba2b 100644 --- a/submodules/TelegramBaseController/Sources/TelegramBaseController.swift +++ b/submodules/TelegramBaseController/Sources/TelegramBaseController.swift @@ -676,10 +676,10 @@ open class TelegramBaseController: ViewController, KeyShortcutResponder { return } let _ = (strongSelf.context.sharedContext.accountManager.transaction { transaction -> AudioPlaybackRate in - let settings = transaction.getSharedData(ApplicationSpecificSharedDataKeys.musicPlaybackSettings) as? MusicPlaybackSettings ?? MusicPlaybackSettings.defaultSettings + let settings = transaction.getSharedData(ApplicationSpecificSharedDataKeys.musicPlaybackSettings)?.get(MusicPlaybackSettings.self) ?? MusicPlaybackSettings.defaultSettings transaction.updateSharedData(ApplicationSpecificSharedDataKeys.musicPlaybackSettings, { _ in - return settings.withUpdatedVoicePlaybackRate(rate) + return PreferencesEntry(settings.withUpdatedVoicePlaybackRate(rate)) }) return rate } diff --git a/submodules/TelegramCallsUI/Sources/CallController.swift b/submodules/TelegramCallsUI/Sources/CallController.swift index dc1a46bbf3..5845fc5d36 100644 --- a/submodules/TelegramCallsUI/Sources/CallController.swift +++ b/submodules/TelegramCallsUI/Sources/CallController.swift @@ -274,7 +274,7 @@ public final class CallController: ViewController { let _ = (combineLatest(strongSelf.sharedContext.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.callListSettings]), ApplicationSpecificNotice.getCallsTabTip(accountManager: strongSelf.sharedContext.accountManager)) |> map { sharedData, callsTabTip -> Int32 in var value = false - if let settings = sharedData.entries[ApplicationSpecificSharedDataKeys.callListSettings] as? CallListSettings { + if let settings = sharedData.entries[ApplicationSpecificSharedDataKeys.callListSettings]?.get(CallListSettings.self) { value = settings.showTab } if value { diff --git a/submodules/TelegramCallsUI/Sources/PresentationCallManager.swift b/submodules/TelegramCallsUI/Sources/PresentationCallManager.swift index f1ddbbb019..07c4eb7ba1 100644 --- a/submodules/TelegramCallsUI/Sources/PresentationCallManager.swift +++ b/submodules/TelegramCallsUI/Sources/PresentationCallManager.swift @@ -149,7 +149,7 @@ public final class PresentationCallManagerImpl: PresentationCallManager { let enableCallKit = accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.voiceCallSettings]) |> map { sharedData -> Bool in - let settings = sharedData.entries[ApplicationSpecificSharedDataKeys.voiceCallSettings] as? VoiceCallSettings ?? .defaultSettings + let settings = sharedData.entries[ApplicationSpecificSharedDataKeys.voiceCallSettings]?.get(VoiceCallSettings.self) ?? .defaultSettings return settings.enableSystemIntegration } |> distinctUntilChanged @@ -245,7 +245,7 @@ public final class PresentationCallManagerImpl: PresentationCallManager { self.proxyServerDisposable = (accountManager.sharedData(keys: [SharedDataKeys.proxySettings]) |> deliverOnMainQueue).start(next: { [weak self] sharedData in - if let strongSelf = self, let settings = sharedData.entries[SharedDataKeys.proxySettings] as? ProxySettings { + if let strongSelf = self, let settings = sharedData.entries[SharedDataKeys.proxySettings]?.get(ProxySettings.self) { if settings.enabled && settings.useForCalls { strongSelf.proxyServer = settings.activeServer } else { @@ -257,7 +257,7 @@ public final class PresentationCallManagerImpl: PresentationCallManager { self.callSettingsDisposable = (accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.voiceCallSettings]) |> deliverOnMainQueue).start(next: { [weak self] sharedData in if let strongSelf = self { - strongSelf.callSettings = sharedData.entries[ApplicationSpecificSharedDataKeys.voiceCallSettings] as? VoiceCallSettings ?? .defaultSettings + strongSelf.callSettings = sharedData.entries[ApplicationSpecificSharedDataKeys.voiceCallSettings]?.get(VoiceCallSettings.self) ?? .defaultSettings } }) } @@ -281,11 +281,11 @@ public final class PresentationCallManagerImpl: PresentationCallManager { return } - let configuration = preferences.values[PreferencesKeys.voipConfiguration] as? VoipConfiguration ?? .defaultValue - let derivedState = preferences.values[ApplicationSpecificPreferencesKeys.voipDerivedState] as? VoipDerivedState ?? .default - let autodownloadSettings = sharedData.entries[SharedDataKeys.autodownloadSettings] as? AutodownloadSettings ?? .defaultSettings - let experimentalSettings = sharedData.entries[ApplicationSpecificSharedDataKeys.experimentalUISettings] as? ExperimentalUISettings ?? .defaultSettings - let appConfiguration = preferences.values[PreferencesKeys.appConfiguration] as? AppConfiguration ?? AppConfiguration.defaultValue + let configuration = preferences.values[PreferencesKeys.voipConfiguration]?.get(VoipConfiguration.self) ?? .defaultValue + let derivedState = preferences.values[ApplicationSpecificPreferencesKeys.voipDerivedState]?.get(VoipDerivedState.self) ?? .default + let autodownloadSettings = sharedData.entries[SharedDataKeys.autodownloadSettings]?.get(AutodownloadSettings.self) ?? .defaultSettings + let experimentalSettings = sharedData.entries[ApplicationSpecificSharedDataKeys.experimentalUISettings]?.get(ExperimentalUISettings.self) ?? .defaultSettings + let appConfiguration = preferences.values[PreferencesKeys.appConfiguration]?.get(AppConfiguration.self) ?? AppConfiguration.defaultValue let call = PresentationCallImpl( context: firstState.0, @@ -486,7 +486,7 @@ public final class PresentationCallManagerImpl: PresentationCallManager { } let request = context.account.postbox.transaction { transaction -> (VideoCallsConfiguration, CachedUserData?) in - let appConfiguration: AppConfiguration = transaction.getPreferencesEntry(key: PreferencesKeys.appConfiguration) as? AppConfiguration ?? AppConfiguration.defaultValue + let appConfiguration: AppConfiguration = transaction.getPreferencesEntry(key: PreferencesKeys.appConfiguration)?.get(AppConfiguration.self) ?? AppConfiguration.defaultValue return (VideoCallsConfiguration(appConfiguration: appConfiguration), transaction.getPeerCachedData(peerId: peerId) as? CachedUserData) } |> mapToSignal { callsConfiguration, cachedUserData -> Signal in @@ -521,10 +521,10 @@ public final class PresentationCallManagerImpl: PresentationCallManager { currentCall.rejectBusy() } - let configuration = preferences.values[PreferencesKeys.voipConfiguration] as? VoipConfiguration ?? .defaultValue - let derivedState = preferences.values[ApplicationSpecificPreferencesKeys.voipDerivedState] as? VoipDerivedState ?? .default - let autodownloadSettings = sharedData.entries[SharedDataKeys.autodownloadSettings] as? AutodownloadSettings ?? .defaultSettings - let appConfiguration = preferences.values[PreferencesKeys.appConfiguration] as? AppConfiguration ?? AppConfiguration.defaultValue + let configuration = preferences.values[PreferencesKeys.voipConfiguration]?.get(VoipConfiguration.self) ?? .defaultValue + let derivedState = preferences.values[ApplicationSpecificPreferencesKeys.voipDerivedState]?.get(VoipDerivedState.self) ?? .default + let autodownloadSettings = sharedData.entries[SharedDataKeys.autodownloadSettings]?.get(AutodownloadSettings.self) ?? .defaultSettings + let appConfiguration = preferences.values[PreferencesKeys.appConfiguration]?.get(AppConfiguration.self) ?? AppConfiguration.defaultValue let callsConfiguration = VideoCallsConfiguration(appConfiguration: appConfiguration) var isVideoPossible: Bool @@ -541,7 +541,7 @@ public final class PresentationCallManagerImpl: PresentationCallManager { isVideoPossible = false } - let experimentalSettings = sharedData.entries[ApplicationSpecificSharedDataKeys.experimentalUISettings] as? ExperimentalUISettings ?? .defaultSettings + let experimentalSettings = sharedData.entries[ApplicationSpecificSharedDataKeys.experimentalUISettings]?.get(ExperimentalUISettings.self) ?? .defaultSettings let call = PresentationCallImpl( context: context, diff --git a/submodules/TelegramCallsUI/Sources/VoiceChatController.swift b/submodules/TelegramCallsUI/Sources/VoiceChatController.swift index 022c0d24ef..303f4211d7 100644 --- a/submodules/TelegramCallsUI/Sources/VoiceChatController.swift +++ b/submodules/TelegramCallsUI/Sources/VoiceChatController.swift @@ -1899,7 +1899,7 @@ public final class VoiceChatController: ViewController { return } - let appConfiguration: AppConfiguration = preferencesView.values[PreferencesKeys.appConfiguration] as? AppConfiguration ?? .defaultValue + let appConfiguration: AppConfiguration = preferencesView.values[PreferencesKeys.appConfiguration]?.get(AppConfiguration.self) ?? .defaultValue let configuration = VoiceChatConfiguration.with(appConfiguration: appConfiguration) strongSelf.configuration = configuration diff --git a/submodules/TelegramCore/BUILD b/submodules/TelegramCore/BUILD index f3c1fbc643..28436f87e6 100644 --- a/submodules/TelegramCore/BUILD +++ b/submodules/TelegramCore/BUILD @@ -6,6 +6,9 @@ swift_library( srcs = glob([ "Sources/**/*.swift", ]), + copts = [ + "-warnings-as-errors", + ], deps = [ "//submodules/TelegramApi:TelegramApi", "//submodules/MtProtoKit:MtProtoKit", diff --git a/submodules/TelegramCore/Sources/Account/Account.swift b/submodules/TelegramCore/Sources/Account/Account.swift index f514da28e5..dcb0ea6f78 100644 --- a/submodules/TelegramCore/Sources/Account/Account.swift +++ b/submodules/TelegramCore/Sources/Account/Account.swift @@ -129,11 +129,11 @@ public class UnauthorizedAccount { let keychain = makeExclusiveKeychain(id: self.id, postbox: self.postbox) return accountManager.transaction { transaction -> (LocalizationSettings?, ProxySettings?) in - return (transaction.getSharedData(SharedDataKeys.localizationSettings) as? LocalizationSettings, transaction.getSharedData(SharedDataKeys.proxySettings) as? ProxySettings) + return (transaction.getSharedData(SharedDataKeys.localizationSettings)?.get(LocalizationSettings.self), transaction.getSharedData(SharedDataKeys.proxySettings)?.get(ProxySettings.self)) } |> mapToSignal { localizationSettings, proxySettings -> Signal<(LocalizationSettings?, ProxySettings?, NetworkSettings?), NoError> in return self.postbox.transaction { transaction -> (LocalizationSettings?, ProxySettings?, NetworkSettings?) in - return (localizationSettings, proxySettings, transaction.getPreferencesEntry(key: PreferencesKeys.networkSettings) as? NetworkSettings) + return (localizationSettings, proxySettings, transaction.getPreferencesEntry(key: PreferencesKeys.networkSettings)?.get(NetworkSettings.self)) } } |> mapToSignal { (localizationSettings, proxySettings, networkSettings) -> Signal in @@ -251,7 +251,7 @@ public func accountWithId(accountManager: AccountManager (LocalizationSettings?, ProxySettings?) in - return (transaction.getSharedData(SharedDataKeys.localizationSettings) as? LocalizationSettings, transaction.getSharedData(SharedDataKeys.proxySettings) as? ProxySettings) + return (transaction.getSharedData(SharedDataKeys.localizationSettings)?.get(LocalizationSettings.self), transaction.getSharedData(SharedDataKeys.proxySettings)?.get(ProxySettings.self)) } |> mapToSignal { localizationSettings, proxySettings -> Signal in return postbox.transaction { transaction -> (PostboxCoding?, LocalizationSettings?, ProxySettings?, NetworkSettings?) in @@ -266,7 +266,7 @@ public func accountWithId(accountManager: AccountManager mapToSignal { (accountState, localizationSettings, proxySettings, networkSettings) -> Signal in let keychain = makeExclusiveKeychain(id: id, postbox: postbox) @@ -407,7 +407,8 @@ func _internal_twoStepAuthData(_ network: Network) -> Signal String { let hexString = NSMutableString() - data.withUnsafeBytes { (bytes: UnsafePointer) -> Void in + data.withUnsafeBytes { rawBytes -> Void in + let bytes = rawBytes.baseAddress!.assumingMemoryBound(to: UInt8.self) for i in 0 ..< data.count { hexString.appendFormat("%02x", UInt(bytes.advanced(by: i).pointee)) } @@ -437,19 +438,22 @@ public func dataWithHexString(_ string: String) -> Data { } func sha1Digest(_ data : Data) -> Data { - return data.withUnsafeBytes { bytes -> Data in + return data.withUnsafeBytes { rawBytes -> Data in + let bytes = rawBytes.baseAddress! return CryptoSHA1(bytes, Int32(data.count)) } } func sha256Digest(_ data : Data) -> Data { - return data.withUnsafeBytes { bytes -> Data in + return data.withUnsafeBytes { rawBytes -> Data in + let bytes = rawBytes.baseAddress! return CryptoSHA256(bytes, Int32(data.count)) } } func sha512Digest(_ data : Data) -> Data { - return data.withUnsafeBytes { bytes -> Data in + return data.withUnsafeBytes { rawBytes -> Data in + let bytes = rawBytes.baseAddress! return CryptoSHA512(bytes, Int32(data.count)) } } @@ -466,7 +470,8 @@ func passwordUpdateKDF(encryptionProvider: EncryptionProvider, password: String, var nextSalt1 = salt1 var randomSalt1 = Data() randomSalt1.count = 32 - randomSalt1.withUnsafeMutableBytes { (bytes: UnsafeMutablePointer) -> Void in + randomSalt1.withUnsafeMutableBytes { rawBytes -> Void in + let bytes = rawBytes.baseAddress!.assumingMemoryBound(to: Int8.self) arc4random_buf(bytes, 32) } nextSalt1.append(randomSalt1) @@ -474,7 +479,8 @@ func passwordUpdateKDF(encryptionProvider: EncryptionProvider, password: String, let nextSalt2 = salt2 var g = Data(count: 4) - g.withUnsafeMutableBytes { (bytes: UnsafeMutablePointer) -> Void in + g.withUnsafeMutableBytes { rawBytes -> Void in + let bytes = rawBytes.baseAddress!.assumingMemoryBound(to: Int8.self) var gValue = gValue withUnsafeBytes(of: &gValue, { (sourceBuffer: UnsafeRawBufferPointer) -> Void in let sourceBytes = sourceBuffer.bindMemory(to: Int8.self).baseAddress! @@ -526,8 +532,10 @@ private func paddedXor(_ a: Data, _ b: Data) -> Data { while b.count < count { b.insert(0, at: 0) } - a.withUnsafeMutableBytes { (aBytes: UnsafeMutablePointer) -> Void in - b.withUnsafeBytes { (bBytes: UnsafePointer) -> Void in + a.withUnsafeMutableBytes { rawABytes -> Void in + let aBytes = rawABytes.baseAddress!.assumingMemoryBound(to: UInt8.self) + b.withUnsafeBytes { rawBBytes -> Void in + let bBytes = rawBBytes.baseAddress!.assumingMemoryBound(to: UInt8.self) for i in 0 ..< count { aBytes.advanced(by: i).pointee = aBytes.advanced(by: i).pointee ^ bBytes.advanced(by: i).pointee } @@ -547,12 +555,14 @@ func passwordKDF(encryptionProvider: EncryptionProvider, password: String, deriv case let .sha256_sha256_PBKDF2_HMAC_sha512_sha256_srp(salt1, salt2, iterations, gValue, p): var a = Data(count: p.count) let aLength = a.count - a.withUnsafeMutableBytes { (bytes: UnsafeMutablePointer) -> Void in + a.withUnsafeMutableBytes { rawBytes -> Void in + let bytes = rawBytes.baseAddress!.assumingMemoryBound(to: UInt8.self) let _ = SecRandomCopyBytes(nil, aLength, bytes) } var g = Data(count: 4) - g.withUnsafeMutableBytes { (bytes: UnsafeMutablePointer) -> Void in + g.withUnsafeMutableBytes { rawBytes -> Void in + let bytes = rawBytes.baseAddress!.assumingMemoryBound(to: Int8.self) var gValue = gValue withUnsafeBytes(of: &gValue, { (sourceBuffer: UnsafeRawBufferPointer) -> Void in let sourceBytes = sourceBuffer.bindMemory(to: Int8.self).baseAddress! @@ -616,7 +626,8 @@ func securePasswordUpdateKDF(password: String, derivation: TwoStepSecurePassword var nextSalt = salt var randomSalt = Data() randomSalt.count = 32 - randomSalt.withUnsafeMutableBytes { (bytes: UnsafeMutablePointer) -> Void in + randomSalt.withUnsafeMutableBytes { rawBytes -> Void in + let bytes = rawBytes.baseAddress!.assumingMemoryBound(to: Int8.self) arc4random_buf(bytes, 32) } nextSalt.append(randomSalt) @@ -630,7 +641,8 @@ func securePasswordUpdateKDF(password: String, derivation: TwoStepSecurePassword var nextSalt = salt var randomSalt = Data() randomSalt.count = 32 - randomSalt.withUnsafeMutableBytes { (bytes: UnsafeMutablePointer) -> Void in + randomSalt.withUnsafeMutableBytes { rawBytes -> Void in + let bytes = rawBytes.baseAddress!.assumingMemoryBound(to: Int8.self) arc4random_buf(bytes, 32) } nextSalt.append(randomSalt) @@ -746,7 +758,8 @@ private func masterNotificationsKey(masterNotificationKeyValue: Atomic) -> Bool in + if !secretData.withUnsafeMutableBytes({ rawBytes -> Bool in + let bytes = rawBytes.baseAddress!.assumingMemoryBound(to: Int8.self) let copyResult = SecRandomCopyBytes(nil, secretDataCount, bytes) return copyResult == errSecSuccess }) { @@ -785,7 +798,8 @@ public func decryptedNotificationPayload(key: MasterNotificationKey, data: Data) } var dataLength: Int32 = 0 - data.withUnsafeBytes { (bytes: UnsafePointer) -> Void in + data.withUnsafeBytes { rawBytes -> Void in + let bytes = rawBytes.baseAddress!.assumingMemoryBound(to: Int8.self) memcpy(&dataLength, bytes, 4) } @@ -1087,7 +1101,7 @@ public class Account { })) self.managedOperationsDisposable.add((accountManager.sharedData(keys: [SharedDataKeys.proxySettings]) |> map { sharedData -> ProxyServerSettings? in - if let settings = sharedData.entries[SharedDataKeys.proxySettings] as? ProxySettings { + if let settings = sharedData.entries[SharedDataKeys.proxySettings]?.get(ProxySettings.self) { return settings.effectiveActiveServer } else { return nil @@ -1138,7 +1152,7 @@ public class Account { guard let mediaBox = mediaBox else { return } - let settings: CacheStorageSettings = sharedData.entries[SharedDataKeys.cacheStorageSettings] as? CacheStorageSettings ?? CacheStorageSettings.defaultSettings + let settings: CacheStorageSettings = sharedData.entries[SharedDataKeys.cacheStorageSettings]?.get(CacheStorageSettings.self) ?? CacheStorageSettings.defaultSettings mediaBox.setMaxStoreTimes(general: settings.defaultCacheStorageTimeout, shortLived: 60 * 60, gigabytesLimit: settings.defaultCacheStorageLimitGigabytes) }) } @@ -1238,9 +1252,9 @@ public class Account { } public func addUpdates(serializedData: Data) -> Void { - if let object = Api.parse(Buffer(data: serializedData)) { - //self.stateManager.addUpdates() - } + /*if let object = Api.parse(Buffer(data: serializedData)) { + self.stateManager.addUpdates() + }*/ } } diff --git a/submodules/TelegramCore/Sources/Account/AccountIntermediateState.swift b/submodules/TelegramCore/Sources/Account/AccountIntermediateState.swift index 194cf5a28c..99c1264e63 100644 --- a/submodules/TelegramCore/Sources/Account/AccountIntermediateState.swift +++ b/submodules/TelegramCore/Sources/Account/AccountIntermediateState.swift @@ -591,7 +591,7 @@ struct AccountMutableState { self.readInboxMaxIds[peerId] = MessageId(peerId: peerId, namespace: namespace, id: maxIncomingReadId) } } - case let .ResetMessageTagSummary(peerId, namespace, count, range): + case .ResetMessageTagSummary: break } diff --git a/submodules/TelegramCore/Sources/Account/AccountManager.swift b/submodules/TelegramCore/Sources/Account/AccountManager.swift index 815540377f..52b68a2775 100644 --- a/submodules/TelegramCore/Sources/Account/AccountManager.swift +++ b/submodules/TelegramCore/Sources/Account/AccountManager.swift @@ -189,7 +189,7 @@ private var declaredEncodables: Void = { declareEncodable(CachedRecentPeers.self, f: { CachedRecentPeers(decoder: $0) }) //declareEncodable(AppChangelogState.self, f: { AppChangelogState(decoder: $0) }) //declareEncodable(AppConfiguration.self, f: { AppConfiguration(decoder: $0) }) - declareEncodable(JSON.self, f: { JSON(decoder: $0) }) + //declareEncodable(JSON.self, f: { JSON(decoder: $0) }) //declareEncodable(SearchBotsConfiguration.self, f: { SearchBotsConfiguration(decoder: $0) }) //declareEncodable(AutodownloadSettings.self, f: { AutodownloadSettings(decoder: $0 )}) declareEncodable(TelegramMediaPoll.self, f: { TelegramMediaPoll(decoder: $0) }) diff --git a/submodules/TelegramCore/Sources/ApiUtils/ReplyMarkupMessageAttribute.swift b/submodules/TelegramCore/Sources/ApiUtils/ReplyMarkupMessageAttribute.swift index 6068ef3655..82c7ed5789 100644 --- a/submodules/TelegramCore/Sources/ApiUtils/ReplyMarkupMessageAttribute.swift +++ b/submodules/TelegramCore/Sources/ApiUtils/ReplyMarkupMessageAttribute.swift @@ -30,7 +30,7 @@ extension ReplyMarkupButton { case let .inputKeyboardButtonUrlAuth(_, text, fwdText, url, _): self.init(title: text, titleWhenForwarded: fwdText, action: .urlAuth(url: url, buttonId: 0)) case let .keyboardButtonRequestPoll(_, quiz, text): - var isQuiz: Bool? = quiz.flatMap { quiz in + let isQuiz: Bool? = quiz.flatMap { quiz in if case .boolTrue = quiz { return true } else { diff --git a/submodules/TelegramCore/Sources/ApiUtils/StoreMessage_Telegram.swift b/submodules/TelegramCore/Sources/ApiUtils/StoreMessage_Telegram.swift index 1e15edb319..9eb5c48031 100644 --- a/submodules/TelegramCore/Sources/ApiUtils/StoreMessage_Telegram.swift +++ b/submodules/TelegramCore/Sources/ApiUtils/StoreMessage_Telegram.swift @@ -116,8 +116,8 @@ public func tagsForStoreMessage(incoming: Bool, attributes: [MessageAttribute], func apiMessagePeerId(_ messsage: Api.Message) -> PeerId? { switch messsage { - case let .message(message): - let chatPeerId = message.peerId + case let .message(_, _, _, messagePeerId, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _): + let chatPeerId = messagePeerId return chatPeerId.peerId case let .messageEmpty(_, _, peerId): if let peerId = peerId { @@ -132,7 +132,7 @@ func apiMessagePeerId(_ messsage: Api.Message) -> PeerId? { func apiMessagePeerIds(_ message: Api.Message) -> [PeerId] { switch message { - case let .message(flags, _, fromId, chatPeerId, fwdHeader, viaBotId, _, _, _, media, _, entities, _, _, _, _, _, _, _, _): + case let .message(_, _, fromId, chatPeerId, fwdHeader, viaBotId, _, _, _, media, _, entities, _, _, _, _, _, _, _, _): let peerId: PeerId = chatPeerId.peerId var result = [peerId] @@ -145,11 +145,11 @@ func apiMessagePeerIds(_ message: Api.Message) -> [PeerId] { if let fwdHeader = fwdHeader { switch fwdHeader { - case let .messageFwdHeader(messageFwdHeader): - if let fromId = messageFwdHeader.fromId { + case let .messageFwdHeader(_, fromId, _, _, _, _, savedFromPeer, _, _): + if let fromId = fromId { result.append(fromId.peerId) } - if let savedFromPeer = messageFwdHeader.savedFromPeer { + if let savedFromPeer = savedFromPeer { result.append(savedFromPeer.peerId) } } diff --git a/submodules/TelegramCore/Sources/Authorization.swift b/submodules/TelegramCore/Sources/Authorization.swift index 17dde9f772..bccf7ce12d 100644 --- a/submodules/TelegramCore/Sources/Authorization.swift +++ b/submodules/TelegramCore/Sources/Authorization.swift @@ -227,8 +227,8 @@ public func authorizeWithCode(accountManager: AccountManager mapToSignal { result -> Signal in switch result { - case let .password(password): - return .single(.password(hint: password.hint ?? "")) + case let .password(_, _, _, _, hint, _, _, _, _, _): + return .single(.password(hint: hint ?? "")) } } case let (_, errorDescription): diff --git a/submodules/TelegramCore/Sources/Network/FetchedMediaResource.swift b/submodules/TelegramCore/Sources/Network/FetchedMediaResource.swift index 08bbca5c45..9c5b99c7a5 100644 --- a/submodules/TelegramCore/Sources/Network/FetchedMediaResource.swift +++ b/submodules/TelegramCore/Sources/Network/FetchedMediaResource.swift @@ -48,7 +48,7 @@ public func fetchedMediaResource(mediaBox: MediaBox, reference: MediaResourceRef } return combineLatest(signals) |> ignoreValues - |> map { _ -> FetchResourceSourceType in .local } + |> map { _ -> FetchResourceSourceType in } |> then(.single(.local)) } else { return mediaBox.fetchedResource(reference.resource, parameters: MediaResourceFetchParameters(tag: TelegramMediaResourceFetchTag(statsCategory: statsCategory), info: TelegramCloudMediaResourceFetchInfo(reference: reference, preferBackgroundReferenceRevalidation: preferBackgroundReferenceRevalidation, continueInBackground: continueInBackground), isRandomAccessAllowed: isRandomAccessAllowed), implNext: reportResultStatus) @@ -61,7 +61,7 @@ enum RevalidateMediaReferenceError { public func stickerPackFileReference(_ file: TelegramMediaFile) -> FileMediaReference { for attribute in file.attributes { - if case let .Sticker(sticker) = attribute, let stickerPack = sticker.packReference { + if case let .Sticker(_, packReferenceValue, _) = attribute, let stickerPack = packReferenceValue { return .stickerPack(stickerPack: stickerPack, media: file) } } @@ -292,8 +292,6 @@ final class MediaReferenceRevalidationContext { } else { error(.generic) } - }, error: { _ in - error(.generic) }) }) |> mapToSignal { next -> Signal in if let next = next as? Message { @@ -308,7 +306,6 @@ final class MediaReferenceRevalidationContext { return self.genericItem(key: .stickerPack(stickerPack: stickerPack), background: background, request: { next, error in return (updatedRemoteStickerPack(postbox: postbox, network: network, reference: stickerPack) |> mapError { _ -> RevalidateMediaReferenceError in - return .generic }).start(next: { value in if let value = value { next(value) @@ -331,7 +328,6 @@ final class MediaReferenceRevalidationContext { return self.genericItem(key: .webPage(webPage: webPage), background: background, request: { next, error in return (updatedRemoteWebpage(postbox: postbox, network: network, webPage: webPage) |> mapError { _ -> RevalidateMediaReferenceError in - return .generic }).start(next: { value in if let value = value { next(value) @@ -443,7 +439,6 @@ final class MediaReferenceRevalidationContext { return (telegramThemes(postbox: postbox, network: network, accountManager: nil, forceUpdate: true) |> take(1) |> mapError { _ -> RevalidateMediaReferenceError in - return .generic }).start(next: { value in next(value) }, error: { _ in @@ -462,7 +457,6 @@ final class MediaReferenceRevalidationContext { return self.genericItem(key: .peerAvatars(peer: peer), background: background, request: { next, error in return (_internal_requestPeerPhotos(postbox: postbox, network: network, peerId: peer.id) |> mapError { _ -> RevalidateMediaReferenceError in - return .generic }).start(next: { value in next(value) }, error: { _ in @@ -504,8 +498,8 @@ func revalidateMediaResourceReference(postbox: Postbox, network: Network, revali if revalidateWithStickerpack { var stickerPackReference: StickerPackReference? for attribute in file.attributes { - if case let .Sticker(sticker) = attribute { - if let packReference = sticker.packReference { + if case let .Sticker(_, packReferenceValue, _) = attribute { + if let packReference = packReferenceValue { stickerPackReference = packReference } } @@ -599,7 +593,7 @@ func revalidateMediaResourceReference(postbox: Postbox, network: Network, revali case let .standalone(media): if let file = media as? TelegramMediaFile { for attribute in file.attributes { - if case let .Sticker(sticker) = attribute, let stickerPack = sticker.packReference { + if case let .Sticker(_, packReferenceValue, _) = attribute, let stickerPack = packReferenceValue { return revalidationContext.stickerPack(postbox: postbox, network: network, background: info.preferBackgroundReferenceRevalidation, stickerPack: stickerPack) |> mapToSignal { result -> Signal in for item in result.1 { diff --git a/submodules/TelegramCore/Sources/Network/MultipartFetch.swift b/submodules/TelegramCore/Sources/Network/MultipartFetch.swift index 3d0ff61557..993fb735d7 100644 --- a/submodules/TelegramCore/Sources/Network/MultipartFetch.swift +++ b/submodules/TelegramCore/Sources/Network/MultipartFetch.swift @@ -32,8 +32,10 @@ private final class MultipartDownloadState { assert(decryptedData.count % 16 == 0) let decryptedDataCount = decryptedData.count assert(offset == Int(self.currentSize)) - decryptedData.withUnsafeMutableBytes { (bytes: UnsafeMutablePointer) -> Void in - self.aesIv.withUnsafeMutableBytes { (iv: UnsafeMutablePointer) -> Void in + decryptedData.withUnsafeMutableBytes { rawBytes -> Void in + let bytes = rawBytes.baseAddress!.assumingMemoryBound(to: UInt8.self) + self.aesIv.withUnsafeMutableBytes { rawIv -> Void in + let iv = rawIv.baseAddress!.assumingMemoryBound(to: UInt8.self) MTAesDecryptBytesInplaceAndModifyIv(bytes, decryptedDataCount, self.aesKey, iv) } } @@ -507,7 +509,8 @@ private enum MultipartFetchSource { } else { var partIv = iv let partIvCount = partIv.count - partIv.withUnsafeMutableBytes { (bytes: UnsafeMutablePointer) -> Void in + partIv.withUnsafeMutableBytes { rawBytes -> Void in + let bytes = rawBytes.baseAddress!.assumingMemoryBound(to: UInt8.self) var ivOffset: Int32 = (offset / 16).bigEndian memcpy(bytes.advanced(by: partIvCount - 4), &ivOffset, 4) } diff --git a/submodules/TelegramCore/Sources/Network/MultipartUpload.swift b/submodules/TelegramCore/Sources/Network/MultipartUpload.swift index 3a40dc91da..c4eba9f13e 100644 --- a/submodules/TelegramCore/Sources/Network/MultipartUpload.swift +++ b/submodules/TelegramCore/Sources/Network/MultipartUpload.swift @@ -17,7 +17,8 @@ private struct UploadPart { } private func md5(_ data: Data) -> Data { - return data.withUnsafeBytes { bytes -> Data in + return data.withUnsafeBytes { rawBytes -> Data in + let bytes = rawBytes.baseAddress! return CryptoMD5(bytes, Int32(data.count)) } } @@ -54,11 +55,13 @@ private final class MultipartUploadState { encryptedData.count = encryptedData.count + paddingSize } let encryptedDataCount = encryptedData.count - encryptedData.withUnsafeMutableBytes { (bytes: UnsafeMutablePointer) -> Void in + encryptedData.withUnsafeMutableBytes { rawBytes -> Void in + let bytes = rawBytes.baseAddress!.assumingMemoryBound(to: UInt8.self) if paddingSize != 0 { arc4random_buf(bytes.advanced(by: encryptedDataCount - paddingSize), paddingSize) } - self.aesIv.withUnsafeMutableBytes { (iv: UnsafeMutablePointer) -> Void in + self.aesIv.withUnsafeMutableBytes { rawIv -> Void in + let iv = rawIv.baseAddress!.assumingMemoryBound(to: UInt8.self) MTAesEncryptBytesInplaceAndModifyIv(bytes, encryptedDataCount, self.aesKey, iv) } } @@ -411,10 +414,12 @@ func multipartUpload(network: Network, postbox: Postbox, source: MultipartUpload aesKey.count = 32 var aesIv = Data() aesIv.count = 32 - aesKey.withUnsafeMutableBytes { (bytes: UnsafeMutablePointer) -> Void in + aesKey.withUnsafeMutableBytes { rawBytes -> Void in + let bytes = rawBytes.baseAddress! arc4random_buf(bytes, 32) } - aesIv.withUnsafeMutableBytes { (bytes: UnsafeMutablePointer) -> Void in + aesIv.withUnsafeMutableBytes { rawBytes -> Void in + let bytes = rawBytes.baseAddress! arc4random_buf(bytes, 32) } encryptionKey = SecretFileEncryptionKey(aesKey: aesKey, aesIv: aesIv) @@ -466,7 +471,9 @@ func multipartUpload(network: Network, postbox: Postbox, source: MultipartUpload if let encryptionKey = encryptionKey { let keyDigest = md5(encryptionKey.aesKey + encryptionKey.aesIv) var fingerprint: Int32 = 0 - keyDigest.withUnsafeBytes { (bytes: UnsafePointer) -> Void in + keyDigest.withUnsafeBytes { rawBytes -> Void in + let bytes = rawBytes.baseAddress!.assumingMemoryBound(to: UInt8.self) + withUnsafeMutableBytes(of: &fingerprint, { ptr -> Void in let uintPtr = ptr.baseAddress!.assumingMemoryBound(to: UInt8.self) uintPtr[0] = bytes[0] ^ bytes[4] diff --git a/submodules/TelegramCore/Sources/Network/Network.swift b/submodules/TelegramCore/Sources/Network/Network.swift index 00d91651f6..af638d717a 100644 --- a/submodules/TelegramCore/Sources/Network/Network.swift +++ b/submodules/TelegramCore/Sources/Network/Network.swift @@ -480,13 +480,10 @@ func initializedNetwork(accountId: AccountRecordId, arguments: NetworkInitializa let key = SharedContextStore.Key(accountId: accountId) let context: MTContext - if false, let current = store.contexts[key] { - context = current - context.updateApiEnvironment({ _ in return apiEnvironment}) - } else { - context = MTContext(serialization: serialization, encryptionProvider: arguments.encryptionProvider, apiEnvironment: apiEnvironment, isTestingEnvironment: testingEnvironment, useTempAuthKeys: useTempAuthKeys) - store.contexts[key] = context - } + + context = MTContext(serialization: serialization, encryptionProvider: arguments.encryptionProvider, apiEnvironment: apiEnvironment, isTestingEnvironment: testingEnvironment, useTempAuthKeys: useTempAuthKeys) + store.contexts[key] = context + contextValue = context } @@ -627,7 +624,7 @@ private final class NetworkHelper: NSObject, MTContextChangeListener { self.contextLoggedOutUpdated = contextLoggedOutUpdated } - func fetchContextDatacenterPublicKeys(_ context: MTContext!, datacenterId: Int) -> MTSignal! { + func fetchContextDatacenterPublicKeys(_ context: MTContext, datacenterId: Int) -> MTSignal { return MTSignal { subscriber in let disposable = self.requestPublicKeys(datacenterId).start(next: { next in subscriber?.putNext(next) @@ -640,7 +637,7 @@ private final class NetworkHelper: NSObject, MTContextChangeListener { } } - func isContextNetworkAccessAllowed(_ context: MTContext!) -> MTSignal! { + func isContextNetworkAccessAllowed(_ context: MTContext) -> MTSignal { return MTSignal { subscriber in let disposable = self.isContextNetworkAccessAllowedImpl().start(next: { next in subscriber?.putNext(next as NSNumber) @@ -653,12 +650,12 @@ private final class NetworkHelper: NSObject, MTContextChangeListener { } } - func contextApiEnvironmentUpdated(_ context: MTContext!, apiEnvironment: MTApiEnvironment!) { + func contextApiEnvironmentUpdated(_ context: MTContext, apiEnvironment: MTApiEnvironment) { let settings: MTSocksProxySettings? = apiEnvironment.socksProxySettings self.contextProxyIdUpdated(settings.flatMap(NetworkContextProxyId.init(settings:))) } - func contextLoggedOut(_ context: MTContext!) { + func contextLoggedOut(_ context: MTContext) { self.contextLoggedOutUpdated() } } diff --git a/submodules/TelegramCore/Sources/PeerStatistics.swift b/submodules/TelegramCore/Sources/PeerStatistics.swift index adb54cbb4a..97e85702a1 100644 --- a/submodules/TelegramCore/Sources/PeerStatistics.swift +++ b/submodules/TelegramCore/Sources/PeerStatistics.swift @@ -1090,9 +1090,8 @@ extension GroupStatsTopInviter { extension GroupStats { convenience init(apiMegagroupStats: Api.stats.MegagroupStats) { switch apiMegagroupStats { - case let .megagroupStats(period, members, messages, viewers, posters, apiGrowthGraph, apiMembersGraph, apiNewMembersBySourceGraph, apiLanguagesGraph, apiMessagesGraph, apiActionsGraph, apiTopHoursGraph, apiTopWeekdaysGraph, topPosters, topAdmins, topInviters, users): + case let .megagroupStats(period, members, messages, viewers, posters, apiGrowthGraph, apiMembersGraph, apiNewMembersBySourceGraph, apiLanguagesGraph, apiMessagesGraph, apiActionsGraph, apiTopHoursGraph, apiTopWeekdaysGraph, topPosters, topAdmins, topInviters, _): let growthGraph = StatsGraph(apiStatsGraph: apiGrowthGraph) - let isEmpty = growthGraph.isEmpty self.init(period: StatsDateRange(apiStatsDateRangeDays: period), members: StatsValue(apiStatsAbsValueAndPrev: members), messages: StatsValue(apiStatsAbsValueAndPrev: messages), viewers: StatsValue(apiStatsAbsValueAndPrev: viewers), posters: StatsValue(apiStatsAbsValueAndPrev: posters), growthGraph: growthGraph, membersGraph: StatsGraph(apiStatsGraph: apiMembersGraph), newMembersBySourceGraph: StatsGraph(apiStatsGraph: apiNewMembersBySourceGraph), languagesGraph: StatsGraph(apiStatsGraph: apiLanguagesGraph), messagesGraph: StatsGraph(apiStatsGraph: apiMessagesGraph), actionsGraph: StatsGraph(apiStatsGraph: apiActionsGraph), topHoursGraph: StatsGraph(apiStatsGraph: apiTopHoursGraph), topWeekdaysGraph: StatsGraph(apiStatsGraph: apiTopWeekdaysGraph), topPosters: topPosters.map { GroupStatsTopPoster(apiStatsGroupTopPoster: $0) }, topAdmins: topAdmins.map { GroupStatsTopAdmin(apiStatsGroupTopAdmin: $0) }, topInviters: topInviters.map { GroupStatsTopInviter(apiStatsGroupTopInviter: $0) }) } diff --git a/submodules/TelegramCore/Sources/PendingMessages/EnqueueMessage.swift b/submodules/TelegramCore/Sources/PendingMessages/EnqueueMessage.swift index 28f62f891c..aa6f2933ba 100644 --- a/submodules/TelegramCore/Sources/PendingMessages/EnqueueMessage.swift +++ b/submodules/TelegramCore/Sources/PendingMessages/EnqueueMessage.swift @@ -345,7 +345,7 @@ func enqueueMessages(transaction: Transaction, account: Account, peerId: PeerId, globallyUniqueIds.append(randomId) switch message { - case let .message(text, requestedAttributes, mediaReference, replyToMessageId, localGroupingKey, correlationId): + case let .message(text, requestedAttributes, mediaReference, replyToMessageId, localGroupingKey, _): var peerAutoremoveTimeout: Int32? if let peer = peer as? TelegramSecretChat { var isAction = false @@ -517,7 +517,7 @@ func enqueueMessages(transaction: Transaction, account: Account, peerId: PeerId, } storeMessages.append(StoreMessage(peerId: peerId, namespace: messageNamespace, globallyUniqueId: randomId, groupingKey: localGroupingKey, threadId: threadId, timestamp: effectiveTimestamp, flags: flags, tags: tags, globalTags: globalTags, localTags: localTags, forwardInfo: nil, authorId: authorId, text: text, attributes: attributes, media: mediaList)) - case let .forward(source, grouping, requestedAttributes, correlationId): + case let .forward(source, grouping, requestedAttributes, _): let sourceMessage = transaction.getMessage(source) if let sourceMessage = sourceMessage, let author = sourceMessage.author ?? sourceMessage.peers[sourceMessage.id.peerId] { var messageText = sourceMessage.text diff --git a/submodules/TelegramCore/Sources/PendingMessages/PendingMessageUploadedContent.swift b/submodules/TelegramCore/Sources/PendingMessages/PendingMessageUploadedContent.swift index e1b71406a3..61cdf3b326 100644 --- a/submodules/TelegramCore/Sources/PendingMessages/PendingMessageUploadedContent.swift +++ b/submodules/TelegramCore/Sources/PendingMessages/PendingMessageUploadedContent.swift @@ -107,8 +107,8 @@ func mediaContentToUpload(network: Network, postbox: Postbox, auxiliaryMethods: if let resource = file.resource as? CloudDocumentMediaResource { if peerId.namespace == Namespaces.Peer.SecretChat { for attribute in file.attributes { - if case let .Sticker(sticker) = attribute { - if let _ = sticker.packReference { + if case let .Sticker(_, packReferenceValue, _) = attribute { + if let _ = packReferenceValue { return .single(.content(PendingMessageUploadedContentAndReuploadInfo(content: PendingMessageUploadedContent.text(text), reuploadInfo: nil))) } } @@ -234,7 +234,9 @@ private func maybePredownloadedImageResource(postbox: Postbox, peerId: PeerId, r if data.complete { if data.size < 5 * 1024 * 1024, let fileData = try? Data(contentsOf: URL(fileURLWithPath: data.path), options: .mappedRead) { let md5 = IncrementalMD5() - fileData.withUnsafeBytes { (bytes: UnsafePointer) -> Void in + fileData.withUnsafeBytes { rawBytes -> Void in + let bytes = rawBytes.baseAddress!.assumingMemoryBound(to: Int8.self) + var offset = 0 let bufferSize = 32 * 1024 @@ -252,7 +254,7 @@ private func maybePredownloadedImageResource(postbox: Postbox, peerId: PeerId, r subscriber.putNext(.single(.localReference(reference))) } else { subscriber.putNext(cachedSentMediaReference(postbox: postbox, key: reference) - |> mapError { _ -> PendingMessageUploadError in return .generic } |> map { media -> PredownloadedResource in + |> mapError { _ -> PendingMessageUploadError in } |> map { media -> PredownloadedResource in if let media = media { return .media(media) } else { @@ -302,7 +304,7 @@ private func maybePredownloadedFileResource(postbox: Postbox, auxiliaryMethods: return .single(.localReference(nil)) } } - |> mapError { _ -> PendingMessageUploadError in return .generic } + |> mapError { _ -> PendingMessageUploadError in } } private func maybeCacheUploadedResource(postbox: Postbox, key: CachedSentMediaReferenceKey?, result: PendingMessageUploadedContentResult, media: Media) -> Signal { @@ -310,7 +312,7 @@ private func maybeCacheUploadedResource(postbox: Postbox, key: CachedSentMediaRe return postbox.transaction { transaction -> PendingMessageUploadedContentResult in storeCachedSentMediaReference(transaction: transaction, key: key, media: media) return result - } |> mapError { _ -> PendingMessageUploadError in return .generic } + } |> mapError { _ -> PendingMessageUploadError in } } else { return .single(result) } @@ -391,7 +393,6 @@ private func uploadedMediaImageContent(network: Network, postbox: Postbox, trans return transform |> mapError { _ -> PendingMessageUploadError in - return .generic } |> mapToSignal { transformResult -> Signal in switch transformResult { @@ -440,7 +441,7 @@ private func uploadedMediaImageContent(network: Network, postbox: Postbox, trans return postbox.transaction { transaction -> Api.InputPeer? in return transaction.getPeer(peerId).flatMap(apiInputPeer) } - |> mapError { _ -> PendingMessageUploadError in return .generic } + |> mapError { _ -> PendingMessageUploadError in } |> mapToSignal { inputPeer -> Signal in if let inputPeer = inputPeer { if autoclearMessageAttribute != nil { @@ -774,7 +775,7 @@ private func uploadedMediaFileContent(network: Network, postbox: Postbox, auxili return postbox.transaction { transaction -> Api.InputPeer? in return transaction.getPeer(peerId).flatMap(apiInputPeer) } - |> mapError { _ -> PendingMessageUploadError in return .generic } + |> mapError { _ -> PendingMessageUploadError in } |> mapToSignal { inputPeer -> Signal in if let inputPeer = inputPeer { return network.request(Api.functions.messages.uploadMedia(peer: inputPeer, media: .inputMediaUploadedDocument(flags: flags, file: inputFile, thumb: thumbnailFile, mimeType: file.mimeType, attributes: inputDocumentAttributesFromFileAttributes(file.attributes), stickers: stickers, ttlSeconds: ttlSeconds))) diff --git a/submodules/TelegramCore/Sources/PendingMessages/RequestEditMessage.swift b/submodules/TelegramCore/Sources/PendingMessages/RequestEditMessage.swift index d567df6d1f..155e3ef164 100644 --- a/submodules/TelegramCore/Sources/PendingMessages/RequestEditMessage.swift +++ b/submodules/TelegramCore/Sources/PendingMessages/RequestEditMessage.swift @@ -80,7 +80,7 @@ private func requestEditMessageInternal(postbox: Postbox, network: Network, stat } } return uploadedMedia - |> mapError { _ -> RequestEditMessageInternalError in return .error(.generic) } + |> mapError { _ -> RequestEditMessageInternalError in } |> mapToSignal { uploadedMediaResult -> Signal in var pendingMediaContent: PendingMessageUploadedContent? if let uploadedMediaResult = uploadedMediaResult { @@ -122,7 +122,7 @@ private func requestEditMessageInternal(postbox: Postbox, network: Network, stat } return (transaction.getPeer(messageId.peerId), message, peers) } - |> mapError { _ -> RequestEditMessageInternalError in return .error(.generic) } + |> mapError { _ -> RequestEditMessageInternalError in } |> mapToSignal { peer, message, associatedPeers -> Signal in if let peer = peer, let message = message, let inputPeer = apiInputPeer(peer) { var flags: Int32 = 1 << 11 @@ -241,7 +241,6 @@ private func requestEditMessageInternal(postbox: Postbox, network: Network, stat return .done(true) } |> mapError { _ -> RequestEditMessageInternalError in - return .error(.generic) } } else { return .single(.done(false)) diff --git a/submodules/TelegramCore/Sources/PendingMessages/StandaloneSendMessage.swift b/submodules/TelegramCore/Sources/PendingMessages/StandaloneSendMessage.swift index 1651211765..21f2c86f31 100644 --- a/submodules/TelegramCore/Sources/PendingMessages/StandaloneSendMessage.swift +++ b/submodules/TelegramCore/Sources/PendingMessages/StandaloneSendMessage.swift @@ -62,7 +62,7 @@ public func standaloneSendMessage(account: Account, peerId: PeerId, text: String return .single(progress) case let .result(result): let sendContent = sendMessageContent(account: account, peerId: peerId, attributes: attributes, content: result) |> map({ _ -> Float in return 1.0 }) - return .single(1.0) |> then(sendContent |> mapError { _ -> StandaloneSendMessageError in return .generic }) + return .single(1.0) |> then(sendContent |> mapError { _ -> StandaloneSendMessageError in }) } } @@ -128,7 +128,6 @@ private func sendMessageContent(account: Account, peerId: PeerId, attributes: [M return .complete() } |> `catch` { _ -> Signal in - return .complete() } } else { return .complete() diff --git a/submodules/TelegramCore/Sources/PendingMessages/StandaloneUploadedMedia.swift b/submodules/TelegramCore/Sources/PendingMessages/StandaloneUploadedMedia.swift index d5c485279c..f05dfd4f19 100644 --- a/submodules/TelegramCore/Sources/PendingMessages/StandaloneUploadedMedia.swift +++ b/submodules/TelegramCore/Sources/PendingMessages/StandaloneUploadedMedia.swift @@ -61,7 +61,7 @@ public func standaloneUploadedImage(account: Account, peerId: PeerId, text: Stri return account.postbox.transaction { transaction -> Api.InputPeer? in return transaction.getPeer(peerId).flatMap(apiInputPeer) } - |> mapError { _ -> StandaloneUploadMediaError in return .generic } + |> mapError { _ -> StandaloneUploadMediaError in } |> mapToSignal { inputPeer -> Signal in if let inputPeer = inputPeer { return account.network.request(Api.functions.messages.uploadMedia(peer: inputPeer, media: Api.InputMedia.inputMediaUploadedPhoto(flags: 0, file: inputFile, stickers: nil, ttlSeconds: nil))) @@ -150,7 +150,7 @@ public func standaloneUploadedFile(account: Account, peerId: PeerId, text: Strin return account.postbox.transaction { transaction -> Api.InputPeer? in return transaction.getPeer(peerId).flatMap(apiInputPeer) } - |> mapError { _ -> StandaloneUploadMediaError in return .generic } + |> mapError { _ -> StandaloneUploadMediaError in } |> mapToSignal { inputPeer -> Signal in if let inputPeer = inputPeer { var flags: Int32 = 0 diff --git a/submodules/TelegramCore/Sources/SecretChats/SecretChatEncryption.swift b/submodules/TelegramCore/Sources/SecretChats/SecretChatEncryption.swift index 376bca7183..90b410ebff 100644 --- a/submodules/TelegramCore/Sources/SecretChats/SecretChatEncryption.swift +++ b/submodules/TelegramCore/Sources/SecretChats/SecretChatEncryption.swift @@ -10,7 +10,9 @@ private func messageKey(key: SecretChatKey, msgKey: UnsafeRawPointer, mode: Secr var sha1AData = Data() sha1AData.count = 16 + 32 - sha1AData.withUnsafeMutableBytes { (bytes: UnsafeMutablePointer) -> Void in + sha1AData.withUnsafeMutableBytes { rawBytes -> Void in + let bytes = rawBytes.baseAddress!.assumingMemoryBound(to: UInt8.self) + memcpy(bytes, msgKey, 16) memcpy(bytes.advanced(by: 16), key.key.memory.advanced(by: x), 32) } @@ -18,7 +20,9 @@ private func messageKey(key: SecretChatKey, msgKey: UnsafeRawPointer, mode: Secr var sha1BData = Data() sha1BData.count = 16 + 16 + 16 - sha1BData.withUnsafeMutableBytes { (bytes: UnsafeMutablePointer) -> Void in + sha1BData.withUnsafeMutableBytes { rawBytes -> Void in + let bytes = rawBytes.baseAddress!.assumingMemoryBound(to: UInt8.self) + memcpy(bytes, key.key.memory.advanced(by: 32 + x), 16) memcpy(bytes.advanced(by: 16), msgKey, 16) memcpy(bytes.advanced(by: 16 + 16), key.key.memory.advanced(by: 48 + x), 16) @@ -27,7 +31,9 @@ private func messageKey(key: SecretChatKey, msgKey: UnsafeRawPointer, mode: Secr var sha1CData = Data() sha1CData.count = 32 + 16 - sha1CData.withUnsafeMutableBytes { (bytes: UnsafeMutablePointer) -> Void in + sha1CData.withUnsafeMutableBytes { rawBytes -> Void in + let bytes = rawBytes.baseAddress!.assumingMemoryBound(to: UInt8.self) + memcpy(bytes, key.key.memory.advanced(by: 64 + x), 32) memcpy(bytes.advanced(by: 32), msgKey, 16) } @@ -35,7 +41,9 @@ private func messageKey(key: SecretChatKey, msgKey: UnsafeRawPointer, mode: Secr var sha1DData = Data() sha1DData.count = 16 + 32 - sha1DData.withUnsafeMutableBytes { (bytes: UnsafeMutablePointer) -> Void in + sha1DData.withUnsafeMutableBytes { rawBytes -> Void in + let bytes = rawBytes.baseAddress!.assumingMemoryBound(to: UInt8.self) + memcpy(bytes, msgKey, 16) memcpy(bytes.advanced(by: 16), key.key.memory.advanced(by: 96 + x), 32) } @@ -43,32 +51,36 @@ private func messageKey(key: SecretChatKey, msgKey: UnsafeRawPointer, mode: Secr var aesKey = Data() aesKey.count = 8 + 12 + 12 - aesKey.withUnsafeMutableBytes { (bytes: UnsafeMutablePointer) -> Void in - sha1A.withUnsafeBytes { (sha1A: UnsafePointer) -> Void in - memcpy(bytes, sha1A, 8) + aesKey.withUnsafeMutableBytes { rawBytes -> Void in + let bytes = rawBytes.baseAddress!.assumingMemoryBound(to: UInt8.self) + + sha1A.withUnsafeBytes { sha1A -> Void in + memcpy(bytes, sha1A.baseAddress!.assumingMemoryBound(to: UInt8.self), 8) } - sha1B.withUnsafeBytes { (sha1B: UnsafePointer) -> Void in - memcpy(bytes.advanced(by: 8), sha1B.advanced(by: 8), 12) + sha1B.withUnsafeBytes { sha1B -> Void in + memcpy(bytes.advanced(by: 8), sha1B.baseAddress!.assumingMemoryBound(to: UInt8.self).advanced(by: 8), 12) } - sha1C.withUnsafeBytes { (sha1C: UnsafePointer) -> Void in - memcpy(bytes.advanced(by: 8 + 12), sha1C.advanced(by: 4), 12) + sha1C.withUnsafeBytes { sha1C -> Void in + memcpy(bytes.advanced(by: 8 + 12), sha1C.baseAddress!.assumingMemoryBound(to: UInt8.self).advanced(by: 4), 12) } } var aesIv = Data() aesIv.count = 12 + 8 + 4 + 8 - aesIv.withUnsafeMutableBytes { (bytes: UnsafeMutablePointer) -> Void in - sha1A.withUnsafeBytes { (sha1A: UnsafePointer) -> Void in - memcpy(bytes, sha1A.advanced(by: 8), 12) + aesIv.withUnsafeMutableBytes { rawBytes -> Void in + let bytes = rawBytes.baseAddress!.assumingMemoryBound(to: UInt8.self) + + sha1A.withUnsafeBytes { sha1A -> Void in + memcpy(bytes, sha1A.baseAddress!.assumingMemoryBound(to: UInt8.self).advanced(by: 8), 12) } - sha1B.withUnsafeBytes { (sha1B: UnsafePointer) -> Void in - memcpy(bytes.advanced(by: 12), sha1B, 8) + sha1B.withUnsafeBytes { sha1B -> Void in + memcpy(bytes.advanced(by: 12), sha1B.baseAddress!.assumingMemoryBound(to: UInt8.self), 8) } - sha1C.withUnsafeBytes { (sha1C: UnsafePointer) -> Void in - memcpy(bytes.advanced(by: 12 + 8), sha1C.advanced(by: 16), 4) + sha1C.withUnsafeBytes { sha1C -> Void in + memcpy(bytes.advanced(by: 12 + 8), sha1C.baseAddress!.assumingMemoryBound(to: UInt8.self).advanced(by: 16), 4) } - sha1D.withUnsafeBytes { (sha1D: UnsafePointer) -> Void in - memcpy(bytes.advanced(by: 12 + 8 + 4), sha1D, 8) + sha1D.withUnsafeBytes { sha1D -> Void in + memcpy(bytes.advanced(by: 12 + 8 + 4), sha1D.baseAddress!.assumingMemoryBound(to: UInt8.self), 8) } } return (aesKey, aesIv) @@ -127,7 +139,9 @@ func withDecryptedMessageContents(parameters: SecretChatEncryptionParameters, da } var payloadLength: Int32 = 0 - decryptedData.withUnsafeBytes { (bytes: UnsafePointer) -> Void in + decryptedData.withUnsafeBytes { rawBytes -> Void in + let bytes = rawBytes.baseAddress!.assumingMemoryBound(to: UInt8.self) + memcpy(&payloadLength, bytes, 4) } @@ -137,7 +151,9 @@ func withDecryptedMessageContents(parameters: SecretChatEncryptionParameters, da } let calculatedMsgKeyData = MTSubdataSha1(decryptedData, 0, UInt(payloadLength) + 4) - let msgKeyMatches = calculatedMsgKeyData.withUnsafeBytes { (bytes: UnsafePointer) -> Bool in + let msgKeyMatches = calculatedMsgKeyData.withUnsafeBytes { rawBytes -> Bool in + let bytes = rawBytes.baseAddress!.assumingMemoryBound(to: UInt8.self) + return memcmp(bytes.advanced(by: calculatedMsgKeyData.count - 16), msgKey, 16) == 0 } @@ -145,7 +161,9 @@ func withDecryptedMessageContents(parameters: SecretChatEncryptionParameters, da return nil } - let result = decryptedData.withUnsafeBytes { (bytes: UnsafePointer) -> Data in + let result = decryptedData.withUnsafeBytes { rawBytes -> Data in + let bytes = rawBytes.baseAddress!.assumingMemoryBound(to: UInt8.self) + return Data(bytes: bytes.advanced(by: 4), count: Int(payloadLength)) } return MemoryBuffer(data: result) @@ -166,7 +184,9 @@ func withDecryptedMessageContents(parameters: SecretChatEncryptionParameters, da } var payloadLength: Int32 = 0 - decryptedData.withUnsafeBytes { (bytes: UnsafePointer) -> Void in + decryptedData.withUnsafeBytes { rawBytes -> Void in + let bytes = rawBytes.baseAddress!.assumingMemoryBound(to: UInt8.self) + memcpy(&payloadLength, bytes, 4) } @@ -203,7 +223,9 @@ func withDecryptedMessageContents(parameters: SecretChatEncryptionParameters, da return nil } - let result = decryptedData.withUnsafeBytes { (bytes: UnsafePointer) -> Data in + let result = decryptedData.withUnsafeBytes { rawBytes -> Data in + let bytes = rawBytes.baseAddress!.assumingMemoryBound(to: UInt8.self) + return Data(bytes: bytes.advanced(by: 4), count: Int(payloadLength)) } return MemoryBuffer(data: result) @@ -233,7 +255,7 @@ func encryptedMessageContents(parameters: SecretChatEncryptionParameters, data: var msgKey = MTSha1(payloadData) msgKey.replaceSubrange(0 ..< (msgKey.count - 16), with: Data()) - var randomBuf = malloc(16)! + let randomBuf = malloc(16)! defer { free(randomBuf) } @@ -246,7 +268,9 @@ func encryptedMessageContents(parameters: SecretChatEncryptionParameters, data: randomIndex += 1 } - let (aesKey, aesIv) = msgKey.withUnsafeBytes { (bytes: UnsafePointer) -> (Data, Data) in + let (aesKey, aesIv) = msgKey.withUnsafeBytes { rawBytes -> (Data, Data) in + let bytes = rawBytes.baseAddress!.assumingMemoryBound(to: UInt8.self) + return messageKey(key: parameters.key, msgKey: bytes, mode: parameters.mode) } @@ -262,7 +286,9 @@ func encryptedMessageContents(parameters: SecretChatEncryptionParameters, data: case let .v2(role): var randomBytes = Data(count: 128) let randomBytesCount = randomBytes.count - randomBytes.withUnsafeMutableBytes { (bytes: UnsafeMutablePointer) -> Void in + randomBytes.withUnsafeMutableBytes { rawBytes -> Void in + let bytes = rawBytes.baseAddress!.assumingMemoryBound(to: Int8.self) + arc4random_buf(bytes, randomBytesCount) } @@ -305,7 +331,9 @@ func encryptedMessageContents(parameters: SecretChatEncryptionParameters, data: let msgKey = keyLarge.subdata(in: 8 ..< (8 + 16)) - let (aesKey, aesIv) = msgKey.withUnsafeBytes { (bytes: UnsafePointer) -> (Data, Data) in + let (aesKey, aesIv) = msgKey.withUnsafeBytes { rawBytes -> (Data, Data) in + let bytes = rawBytes.baseAddress!.assumingMemoryBound(to: UInt8.self) + return messageKey(key: parameters.key, msgKey: bytes, mode: parameters.mode) } diff --git a/submodules/TelegramCore/Sources/SecretChats/SecretChatRekeySession.swift b/submodules/TelegramCore/Sources/SecretChats/SecretChatRekeySession.swift index 2230accf37..095406d421 100644 --- a/submodules/TelegramCore/Sources/SecretChats/SecretChatRekeySession.swift +++ b/submodules/TelegramCore/Sources/SecretChats/SecretChatRekeySession.swift @@ -41,7 +41,7 @@ func secretChatAdvanceRekeySessionIfNeeded(encryptionProvider: EncryptionProvide if let rekeySession = sequenceState.rekeyState, rekeySession.id == rekeySessionId { switch rekeySession.data { case let .requested(a, config): - var gValue: Int32 = config.g.byteSwapped + //var gValue: Int32 = config.g.byteSwapped let p = config.p.makeData() let aData = a.makeData() @@ -62,7 +62,9 @@ func secretChatAdvanceRekeySessionIfNeeded(encryptionProvider: EncryptionProvide let keyHash = MTSha1(key) var keyFingerprint: Int64 = 0 - keyHash.withUnsafeBytes { (bytes: UnsafePointer) -> Void in + keyHash.withUnsafeBytes { rawBytes -> Void in + let bytes = rawBytes.baseAddress!.assumingMemoryBound(to: UInt8.self) + memcpy(&keyFingerprint, bytes.advanced(by: keyHash.count - 8), 8) } diff --git a/submodules/TelegramCore/Sources/SecretChats/UpdateSecretChat.swift b/submodules/TelegramCore/Sources/SecretChats/UpdateSecretChat.swift index 759ee4495d..6e44cf5760 100644 --- a/submodules/TelegramCore/Sources/SecretChats/UpdateSecretChat.swift +++ b/submodules/TelegramCore/Sources/SecretChats/UpdateSecretChat.swift @@ -14,10 +14,10 @@ struct SecretChatRequestData { func updateSecretChat(encryptionProvider: EncryptionProvider, accountPeerId: PeerId, transaction: Transaction, mediaBox: MediaBox, chat: Api.EncryptedChat, requestData: SecretChatRequestData?) { let currentPeer = transaction.getPeer(chat.peerId) as? TelegramSecretChat let currentState = transaction.getPeerChatState(chat.peerId) as? SecretChatState - let settings = transaction.getPreferencesEntry(key: PreferencesKeys.secretChatSettings) as? SecretChatSettings ?? SecretChatSettings.defaultSettings + let settings = transaction.getPreferencesEntry(key: PreferencesKeys.secretChatSettings)?.get(SecretChatSettings.self) ?? SecretChatSettings.defaultSettings assert((currentPeer == nil) == (currentState == nil)) switch chat { - case let .encryptedChat(_, _, _, adminId, _, gAOrB, remoteKeyFingerprint): + case let .encryptedChat(_, _, _, adminId, _, gAOrB, _): if let currentPeer = currentPeer, let currentState = currentState, adminId == accountPeerId.id._internalGetInt64Value() { if case let .handshake(handshakeState) = currentState.embeddedState, case let .requested(_, p, a) = handshakeState { let pData = p.makeData() @@ -43,7 +43,9 @@ func updateSecretChat(encryptionProvider: EncryptionProvider, accountPeerId: Pee let keyHash = MTSha1(key) var keyFingerprint: Int64 = 0 - keyHash.withUnsafeBytes { (bytes: UnsafePointer) -> Void in + keyHash.withUnsafeBytes { rawBytes -> Void in + let bytes = rawBytes.baseAddress!.assumingMemoryBound(to: UInt8.self) + memcpy(&keyFingerprint, bytes.advanced(by: keyHash.count - 8), 8) } diff --git a/submodules/TelegramCore/Sources/Settings/ContentSettings.swift b/submodules/TelegramCore/Sources/Settings/ContentSettings.swift index ba16ddabe3..b3b0b9d160 100644 --- a/submodules/TelegramCore/Sources/Settings/ContentSettings.swift +++ b/submodules/TelegramCore/Sources/Settings/ContentSettings.swift @@ -24,14 +24,14 @@ private extension ContentSettings { } public func getContentSettings(transaction: Transaction) -> ContentSettings { - let appConfiguration: AppConfiguration = transaction.getPreferencesEntry(key: PreferencesKeys.appConfiguration) as? AppConfiguration ?? AppConfiguration.defaultValue + let appConfiguration: AppConfiguration = transaction.getPreferencesEntry(key: PreferencesKeys.appConfiguration)?.get(AppConfiguration.self) ?? AppConfiguration.defaultValue return ContentSettings(appConfiguration: appConfiguration) } public func getContentSettings(postbox: Postbox) -> Signal { return postbox.preferencesView(keys: [PreferencesKeys.appConfiguration]) |> map { view -> ContentSettings in - let appConfiguration: AppConfiguration = view.values[PreferencesKeys.appConfiguration] as? AppConfiguration ?? AppConfiguration.defaultValue + let appConfiguration: AppConfiguration = view.values[PreferencesKeys.appConfiguration]?.get(AppConfiguration.self) ?? AppConfiguration.defaultValue return ContentSettings(appConfiguration: appConfiguration) } |> distinctUntilChanged diff --git a/submodules/TelegramCore/Sources/State/AccountStateManagementUtils.swift b/submodules/TelegramCore/Sources/State/AccountStateManagementUtils.swift index 0cff5f6b0a..3837d876e2 100644 --- a/submodules/TelegramCore/Sources/State/AccountStateManagementUtils.swift +++ b/submodules/TelegramCore/Sources/State/AccountStateManagementUtils.swift @@ -215,12 +215,12 @@ private func activeChannelsFromDifference(_ difference: Api.updates.Difference) var chats: [Api.Chat] = [] switch difference { - case let .difference(difference): - chats = difference.chats + case let .difference(_, _, _, differenceChats, _, _): + chats = differenceChats case .differenceEmpty: break - case let .differenceSlice(differenceSlice): - chats = differenceSlice.chats + case let .differenceSlice(_, _, _, differenceChats, _, _): + chats = differenceChats case .differenceTooLong: break } @@ -466,7 +466,7 @@ private func initialStateWithPeerIds(_ transaction: Transaction, peerIds: Set [Api.Update] { rhsPts = pts case let .updateEditChannelMessage(_, pts, _): rhsPts = pts - case let .updatePinnedChannelMessages(_, channelId, _, pts, _): + case let .updatePinnedChannelMessages(_, _, _, pts, _): rhsPts = pts default: break @@ -1190,7 +1190,7 @@ private func finalStateWithUpdatesAndServerTime(postbox: Postbox, network: Netwo }) case let .updateUserStatus(userId, status): updatedState.mergePeerPresences([PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(userId)): status], explicit: true) - case let .updateUserName(userId, firstName, lastName, username): + case let .updateUserName(userId, _, _, username): //TODO add contact checking for apply first and last name updatedState.updatePeer(PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(userId)), { peer in if let user = peer as? TelegramUser { @@ -1375,8 +1375,8 @@ private func finalStateWithUpdatesAndServerTime(postbox: Postbox, network: Netwo case let .updateLangPack(difference): let langCode: String switch difference { - case let .langPackDifference(langPackDifference): - langCode = langPackDifference.langCode + case let .langPackDifference(langCodeValue, _, _, _): + langCode = langCodeValue } updatedState.updateLangPack(langCode: langCode, difference: difference) case let .updateMessagePoll(_, pollId, poll, results): @@ -1521,6 +1521,7 @@ private func resolveAssociatedMessages(network: Network, state: AccountMutableSt return .single(state) } else { var missingPeers = false + let _ = missingPeers var signals: [Signal<([Api.Message], [Api.Chat], [Api.User]), NoError>] = [] for (peerId, messageIds) in messagesIdsGroupedByPeerId(missingMessageIds) { @@ -2027,7 +2028,7 @@ private func pollChannel(network: Network, peer: Peer, state: AccountMutableStat apiTimeout = timeout let channelPts: Int32 - if let previousState = updatedState.channelStates[peer.id] { + if let _ = updatedState.channelStates[peer.id] { channelPts = pts } else { channelPts = pts @@ -2039,7 +2040,7 @@ private func pollChannel(network: Network, peer: Peer, state: AccountMutableStat var parameters: (peer: Api.Peer, pts: Int32, topMessage: Int32, readInboxMaxId: Int32, readOutboxMaxId: Int32, unreadCount: Int32, unreadMentionsCount: Int32)? switch dialog { - case let .dialog(_, peer, topMessage, readInboxMaxId, readOutboxMaxId, unreadCount, unreadMentionsCount, notifySettings, pts, draft, folderId): + case let .dialog(_, peer, topMessage, readInboxMaxId, readOutboxMaxId, unreadCount, unreadMentionsCount, _, pts, _, _): if let pts = pts { parameters = (peer, pts, topMessage, readInboxMaxId, readOutboxMaxId, unreadCount, unreadMentionsCount) } @@ -2592,8 +2593,8 @@ func replayFinalState(accountManager: AccountManager take(1) |> mapToSignal { [weak self] state -> Signal<(difference: Api.updates.Difference?, finalStatte: AccountReplayedFinalState?, skipBecauseOfError: Bool), NoError> in if let authorizedState = state.state { - var flags: Int32 = 0 - var ptsTotalLimit: Int32? = nil + let flags: Int32 = 0 + let ptsTotalLimit: Int32? = nil #if DEBUG //flags = 1 << 0 //ptsTotalLimit = 1000 @@ -533,9 +533,6 @@ public final class AccountStateManager { assertionFailure() } } - }, error: { _ in - assertionFailure() - Logger.shared.log("AccountStateManager", "processUpdateGroups signal completed with error") }) case let .collectUpdateGroups(_, timeout): self.operationTimer?.invalidate() @@ -634,9 +631,7 @@ public final class AccountStateManager { } } } - let _ = (signal |> deliverOn(self.queue)).start(error: { _ in - completed() - }, completed: { + let _ = (signal |> deliverOn(self.queue)).start(completed: { completed() }) case let .processEvents(operationId, events): @@ -737,8 +732,6 @@ public final class AccountStateManager { if let strongSelf = self { strongSelf.notificationMessagesPipe.putNext(messages) } - }, error: { _ in - completed() }, completed: { completed() }) @@ -833,10 +826,6 @@ public final class AccountStateManager { } completion() } - }, error: { _ in - assertionFailure() - Logger.shared.log("AccountStateManager", "processUpdateGroups signal completed with error") - completion() }) } } @@ -1053,7 +1042,7 @@ public final class AccountStateManager { if let updates = Api.parse(Buffer(data: rawData)) as? Api.Updates { switch updates { - case let .updates(updates, users, chats, date, seq): + case let .updates(updates, _, _, _, _): for update in updates { switch update { case let .updatePhoneCall(phoneCall): @@ -1122,7 +1111,7 @@ public func messagesForNotification(transaction: Transaction, id: MessageId, alw if let notificationSettings = transaction.getPeerNotificationSettings(notificationPeerId) as? TelegramPeerNotificationSettings { var defaultSound: PeerMessageSound = .bundledModern(id: 0) var defaultNotify: Bool = true - if let globalNotificationSettings = transaction.getPreferencesEntry(key: PreferencesKeys.globalNotifications) as? GlobalNotificationSettings { + if let globalNotificationSettings = transaction.getPreferencesEntry(key: PreferencesKeys.globalNotifications)?.get(GlobalNotificationSettings.self) { if id.peerId.namespace == Namespaces.Peer.CloudUser { defaultNotify = globalNotificationSettings.effective.privateChats.enabled defaultSound = globalNotificationSettings.effective.privateChats.sound diff --git a/submodules/TelegramCore/Sources/State/AccountViewTracker.swift b/submodules/TelegramCore/Sources/State/AccountViewTracker.swift index 992161c9c6..db38aa4c90 100644 --- a/submodules/TelegramCore/Sources/State/AccountViewTracker.swift +++ b/submodules/TelegramCore/Sources/State/AccountViewTracker.swift @@ -1172,7 +1172,7 @@ public final class AccountViewTracker { return ids } - |> deliverOn(self.queue)).start(next: { [weak self] messageIds in + |> deliverOn(self.queue)).start(next: { _ in //self?.updateMarkMentionsSeenForMessageIds(messageIds: messageIds) }) } @@ -1585,8 +1585,6 @@ public final class AccountViewTracker { } else { subscriber.putNext([]) } - }, error: { error in - subscriber.putError(error) }, completed: { subscriber.putCompletion() }) @@ -1721,7 +1719,7 @@ public final class AccountViewTracker { var currentMessages: [Message] = [] for entry in view.entries { switch entry { - case let .hole(index): + case .hole: if !currentMessages.isEmpty { entries.append(.message(currentMessages[currentMessages.count - 1], currentMessages)) currentMessages.removeAll() diff --git a/submodules/TelegramCore/Sources/State/AppChangelog.swift b/submodules/TelegramCore/Sources/State/AppChangelog.swift index 502a510c7f..49049f1db1 100644 --- a/submodules/TelegramCore/Sources/State/AppChangelog.swift +++ b/submodules/TelegramCore/Sources/State/AppChangelog.swift @@ -10,7 +10,7 @@ func managedAppChangelog(postbox: Postbox, network: Network, stateManager: Accou |> take(1) |> mapToSignal { _ -> Signal in return postbox.transaction { transaction -> AppChangelogState in - return transaction.getPreferencesEntry(key: PreferencesKeys.appChangelogState) as? AppChangelogState ?? AppChangelogState.default + return transaction.getPreferencesEntry(key: PreferencesKeys.appChangelogState)?.get(AppChangelogState.self) ?? AppChangelogState.default } |> mapToSignal { appChangelogState -> Signal in let appChangelogState = appChangelogState diff --git a/submodules/TelegramCore/Sources/State/AppChangelogState.swift b/submodules/TelegramCore/Sources/State/AppChangelogState.swift index ce6cd6da98..85858cd126 100644 --- a/submodules/TelegramCore/Sources/State/AppChangelogState.swift +++ b/submodules/TelegramCore/Sources/State/AppChangelogState.swift @@ -6,6 +6,6 @@ import MtProtoKit func updateAppChangelogState(transaction: Transaction, _ f: @escaping (AppChangelogState) -> AppChangelogState) { transaction.updatePreferencesEntry(key: PreferencesKeys.appChangelogState, { current in - return PreferencesEntry(f((current as? AppChangelogState) ?? AppChangelogState.default)) + return PreferencesEntry(f((current?.get(AppChangelogState.self)) ?? AppChangelogState.default)) }) } diff --git a/submodules/TelegramCore/Sources/State/ApplyUpdateMessage.swift b/submodules/TelegramCore/Sources/State/ApplyUpdateMessage.swift index 57de860b2e..8fed6be810 100644 --- a/submodules/TelegramCore/Sources/State/ApplyUpdateMessage.swift +++ b/submodules/TelegramCore/Sources/State/ApplyUpdateMessage.swift @@ -64,12 +64,12 @@ func applyUpdateMessage(postbox: Postbox, stateManager: AccountStateManager, mes var updatedTimestamp: Int32? if let apiMessage = apiMessage { switch apiMessage { - case let .message(message): - updatedTimestamp = message.date + case let .message(_, _, _, _, _, _, _, date, _, _, _, _, _, _, _, _, _, _, _, _): + updatedTimestamp = date case .messageEmpty: break - case let .messageService(messageService): - updatedTimestamp = messageService.date + case let .messageService(_, _, _, _, _, date, _, _): + updatedTimestamp = date } } else { switch result { diff --git a/submodules/TelegramCore/Sources/State/CachedSentMediaReferences.swift b/submodules/TelegramCore/Sources/State/CachedSentMediaReferences.swift index 4f112c6fd5..d7af4e5d03 100644 --- a/submodules/TelegramCore/Sources/State/CachedSentMediaReferences.swift +++ b/submodules/TelegramCore/Sources/State/CachedSentMediaReferences.swift @@ -14,14 +14,16 @@ enum CachedSentMediaReferenceKey { case let .image(hash): let result = ValueBoxKey(length: 1 + hash.count) result.setUInt8(0, value: 0) - hash.withUnsafeBytes { (bytes: UnsafePointer) -> Void in + hash.withUnsafeBytes { rawBytes -> Void in + let bytes = rawBytes.baseAddress!.assumingMemoryBound(to: Int8.self) memcpy(result.memory.advanced(by: 1), bytes, hash.count) } return result case let .file(hash): let result = ValueBoxKey(length: 1 + hash.count) result.setUInt8(0, value: 1) - hash.withUnsafeBytes { (bytes: UnsafePointer) -> Void in + hash.withUnsafeBytes { rawBytes -> Void in + let bytes = rawBytes.baseAddress!.assumingMemoryBound(to: Int8.self) memcpy(result.memory.advanced(by: 1), bytes, hash.count) } return result diff --git a/submodules/TelegramCore/Sources/State/CallSessionManager.swift b/submodules/TelegramCore/Sources/State/CallSessionManager.swift index 82ed3e0ab0..65ad4a5c5d 100644 --- a/submodules/TelegramCore/Sources/State/CallSessionManager.swift +++ b/submodules/TelegramCore/Sources/State/CallSessionManager.swift @@ -562,7 +562,7 @@ private final class CallSessionManagerContext { |> timeout(5.0, queue: strongSelf.queue, alternate: .single(nil)) |> deliverOnMainQueue).start(next: { debugLog in if let debugLog = debugLog { - _internal_saveCallDebugLog(network: network, callId: CallId(id: id, accessHash: accessHash), log: debugLog).start() + let _ = _internal_saveCallDebugLog(network: network, callId: CallId(id: id, accessHash: accessHash), log: debugLog).start() } }) } @@ -688,7 +688,8 @@ private final class CallSessionManagerContext { let keyHash = MTSha1(key) var keyId: Int64 = 0 - keyHash.withUnsafeBytes { (bytes: UnsafePointer) -> Void in + keyHash.withUnsafeBytes { rawBytes -> Void in + let bytes = rawBytes.baseAddress!.assumingMemoryBound(to: UInt8.self) memcpy(&keyId, bytes.advanced(by: keyHash.count - 8), 8) } @@ -891,7 +892,8 @@ private final class CallSessionManagerContext { let keyHash = MTSha1(key) var keyId: Int64 = 0 - keyHash.withUnsafeBytes { (bytes: UnsafePointer) -> Void in + keyHash.withUnsafeBytes { rawBytes -> Void in + let bytes = rawBytes.baseAddress!.assumingMemoryBound(to: UInt8.self) memcpy(&keyId, bytes.advanced(by: keyHash.count - 8), 8) } @@ -1267,9 +1269,9 @@ private func dropCallSession(network: Network, addUpdates: @escaping (Api.Update switch update { case .updatePhoneCall(let phoneCall): switch phoneCall { - case.phoneCallDiscarded(let values): - reportRating = (values.flags & (1 << 2)) != 0 - sendDebugLogs = (values.flags & (1 << 3)) != 0 + case let .phoneCallDiscarded(flags, _, _, _): + reportRating = (flags & (1 << 2)) != 0 + sendDebugLogs = (flags & (1 << 3)) != 0 default: break } diff --git a/submodules/TelegramCore/Sources/State/ChatHistoryPreloadManager.swift b/submodules/TelegramCore/Sources/State/ChatHistoryPreloadManager.swift index f20a18ac61..252e688601 100644 --- a/submodules/TelegramCore/Sources/State/ChatHistoryPreloadManager.swift +++ b/submodules/TelegramCore/Sources/State/ChatHistoryPreloadManager.swift @@ -447,7 +447,7 @@ final class ChatHistoryPreloadManager { switch index.entity { case let .peer(peerId): - Logger.shared.log("HistoryPreload", "view \(peerId) hole \(updatedHole) isUpdated: \(holeIsUpdated)") + Logger.shared.log("HistoryPreload", "view \(peerId) hole \(String(describing: updatedHole)) isUpdated: \(holeIsUpdated)") } if previousHole != updatedHole { diff --git a/submodules/TelegramCore/Sources/State/ContactSyncManager.swift b/submodules/TelegramCore/Sources/State/ContactSyncManager.swift index c7ceaded56..f4388c6d3c 100644 --- a/submodules/TelegramCore/Sources/State/ContactSyncManager.swift +++ b/submodules/TelegramCore/Sources/State/ContactSyncManager.swift @@ -197,7 +197,6 @@ private final class ContactSyncManagerImpl { disposable.add( (syncContactsOnce(network: self.network, postbox: self.postbox, accountPeerId: self.accountPeerId) |> mapToSignal { _ -> Signal in - return .complete() } |> then(importSignal) |> deliverOn(self.queue) @@ -250,8 +249,8 @@ private func pushDeviceContacts(postbox: Postbox, network: Network, importableCo if let updatedData = importableContacts[number] { if let value = value as? TelegramDeviceContactImportedData { switch value { - case let .imported(imported): - if imported.data != updatedData { + case let .imported(data, _): + if data != updatedData { updatedDataIdentifiers.insert(identifier) } case .retryLater: diff --git a/submodules/TelegramCore/Sources/State/FetchChatList.swift b/submodules/TelegramCore/Sources/State/FetchChatList.swift index 3bf3163eeb..addfcbae94 100644 --- a/submodules/TelegramCore/Sources/State/FetchChatList.swift +++ b/submodules/TelegramCore/Sources/State/FetchChatList.swift @@ -134,10 +134,10 @@ private func parseDialogs(apiDialogs: [Api.Dialog], apiMessages: [Api.Message], } notificationSettings[peerId] = TelegramPeerNotificationSettings(apiSettings: apiNotificationSettings) - case let .dialogFolder(dialogFolder): - switch dialogFolder.folder { - case let .folder(folder): - referencedFolders[PeerGroupId(rawValue: folder.id)] = PeerGroupUnreadCountersSummary(all: PeerGroupUnreadCounters(messageCount: dialogFolder.unreadMutedMessagesCount, chatCount: dialogFolder.unreadMutedPeersCount)) + case let .dialogFolder(_, folder, _, _, unreadMutedPeersCount, _, unreadMutedMessagesCount, _): + switch folder { + case let .folder(_, id, _, _): + referencedFolders[PeerGroupId(rawValue: id)] = PeerGroupUnreadCountersSummary(all: PeerGroupUnreadCounters(messageCount: unreadMutedMessagesCount, chatCount: unreadMutedPeersCount)) } } } diff --git a/submodules/TelegramCore/Sources/State/HistoryViewStateValidation.swift b/submodules/TelegramCore/Sources/State/HistoryViewStateValidation.swift index ea190a7647..ddcde51c86 100644 --- a/submodules/TelegramCore/Sources/State/HistoryViewStateValidation.swift +++ b/submodules/TelegramCore/Sources/State/HistoryViewStateValidation.swift @@ -228,9 +228,9 @@ final class HistoryViewStateValidationContexts { completedMessageIds.append(messageId) } } - for messageId in completedMessageIds { - //context.batchReferences.removeValue(forKey: messageId) - } + /*for messageId in completedMessageIds { + context.batchReferences.removeValue(forKey: messageId) + }*/ } })) } diff --git a/submodules/TelegramCore/Sources/State/ManagedChatListHoles.swift b/submodules/TelegramCore/Sources/State/ManagedChatListHoles.swift index eecc2c16ca..920f6040ac 100644 --- a/submodules/TelegramCore/Sources/State/ManagedChatListHoles.swift +++ b/submodules/TelegramCore/Sources/State/ManagedChatListHoles.swift @@ -50,7 +50,7 @@ func managedChatListHoles(network: Network, postbox: Postbox, accountPeerId: Pee return lhs.hole.index > rhs.hole.index }) - if let preferencesView = combinedView.views[filtersKey] as? PreferencesView, let filtersState = preferencesView.values[PreferencesKeys.chatListFilters] as? ChatListFiltersState, !filtersState.filters.isEmpty { + if let preferencesView = combinedView.views[filtersKey] as? PreferencesView, let filtersState = preferencesView.values[PreferencesKeys.chatListFilters]?.get(ChatListFiltersState.self), !filtersState.filters.isEmpty { if let topRootHole = combinedView.views[topRootHoleKey] as? AllChatListHolesView, let hole = topRootHole.latestHole { let entry = ChatListHolesEntry(groupId: .root, hole: hole) if !entries.contains(entry) { diff --git a/submodules/TelegramCore/Sources/State/ManagedConfigurationUpdates.swift b/submodules/TelegramCore/Sources/State/ManagedConfigurationUpdates.swift index 657ff3f395..bbe40b75f0 100644 --- a/submodules/TelegramCore/Sources/State/ManagedConfigurationUpdates.swift +++ b/submodules/TelegramCore/Sources/State/ManagedConfigurationUpdates.swift @@ -12,9 +12,9 @@ func managedConfigurationUpdates(accountManager: AccountManager mapToSignal { result -> Signal in return postbox.transaction { transaction -> Signal in switch result { - case let .config(config): + case let .config(flags, _, _, _, _, dcOptions, _, chatSizeMax, megagroupSizeMax, forwardedCountMax, _, _, _, _, _, _, _, _, savedGifsLimit, editTimeLimit, revokeTimeLimit, revokePmTimeLimit, _, stickersRecentLimit, _, _, _, pinnedDialogsCountMax, pinnedInfolderCountMax, _, _, _, _, _, autoupdateUrlPrefix, gifSearchUsername, venueSearchUsername, imgSearchUsername, _, captionLengthMax, _, webfileDcId, suggestedLangCode, langPackVersion, baseLangPackVersion): var addressList: [Int: [MTDatacenterAddress]] = [:] - for option in config.dcOptions { + for option in dcOptions { switch option { case let .dcOption(flags, id, ipAddress, port, secret): let preferForMedia = (flags & (1 << 1)) != 0 @@ -33,24 +33,24 @@ func managedConfigurationUpdates(accountManager: AccountManager Signal in let (primary, secondary) = getLocalization(transaction) var invalidateLocalization = false - if primary.version != config.langPackVersion { + if primary.version != langPackVersion { invalidateLocalization = true } - if let secondary = secondary, let baseLangPackVersion = config.baseLangPackVersion { + if let secondary = secondary, let baseLangPackVersion = baseLangPackVersion { if secondary.version != baseLangPackVersion { invalidateLocalization = true } diff --git a/submodules/TelegramCore/Sources/State/ManagedGlobalNotificationSettings.swift b/submodules/TelegramCore/Sources/State/ManagedGlobalNotificationSettings.swift index ec6e9b2609..04f174b2a0 100644 --- a/submodules/TelegramCore/Sources/State/ManagedGlobalNotificationSettings.swift +++ b/submodules/TelegramCore/Sources/State/ManagedGlobalNotificationSettings.swift @@ -15,6 +15,7 @@ public func updateGlobalNotificationSettingsInteractively(postbox: Postbox, _ f: return PreferencesEntry(GlobalNotificationSettings(toBeSynchronized: settings, remote: settings)) } }) + transaction.globalNotificationSettingsUpdated() } } @@ -83,6 +84,7 @@ func managedGlobalNotificationSettings(postbox: Postbox, network: Network) -> Si return PreferencesEntry(GlobalNotificationSettings(toBeSynchronized: nil, remote: settings)) } }) + transaction.globalNotificationSettingsUpdated() } } case let .push(settings): @@ -95,6 +97,7 @@ func managedGlobalNotificationSettings(postbox: Postbox, network: Network) -> Si return current } }) + transaction.globalNotificationSettingsUpdated() }) } } diff --git a/submodules/TelegramCore/Sources/State/ManagedProxyInfoUpdates.swift b/submodules/TelegramCore/Sources/State/ManagedProxyInfoUpdates.swift index 9d1f803070..7f7dfd8d33 100644 --- a/submodules/TelegramCore/Sources/State/ManagedProxyInfoUpdates.swift +++ b/submodules/TelegramCore/Sources/State/ManagedProxyInfoUpdates.swift @@ -88,7 +88,7 @@ func managedPromoInfoUpdates(postbox: Postbox, network: Network, viewTracker: Ac switch data { case .promoDataEmpty: transaction.replaceAdditionalChatListItems([]) - case let .promoData(_, expires, peer, chats, users, psaType, psaMessage): + case let .promoData(_, _, peer, chats, users, psaType, psaMessage): var peers: [Peer] = [] var peerPresences: [PeerId: PeerPresence] = [:] for chat in chats { diff --git a/submodules/TelegramCore/Sources/State/ManagedSecretChatOutgoingOperations.swift b/submodules/TelegramCore/Sources/State/ManagedSecretChatOutgoingOperations.swift index 146d0ac618..43f2a25c32 100644 --- a/submodules/TelegramCore/Sources/State/ManagedSecretChatOutgoingOperations.swift +++ b/submodules/TelegramCore/Sources/State/ManagedSecretChatOutgoingOperations.swift @@ -222,7 +222,8 @@ private func initialHandshakeAccept(postbox: Postbox, network: Network, peerId: let keyHash = MTSha1(key) var keyFingerprint: Int64 = 0 - keyHash.withUnsafeBytes { (bytes: UnsafePointer) -> Void in + keyHash.withUnsafeBytes { rawBytes -> Void in + let bytes = rawBytes.baseAddress!.assumingMemoryBound(to: UInt8.self) memcpy(&keyFingerprint, bytes.advanced(by: keyHash.count - 8), 8) } @@ -324,7 +325,8 @@ private func pfsAcceptKey(postbox: Postbox, network: Network, peerId: PeerId, la let keyHash = MTSha1(key) var keyFingerprint: Int64 = 0 - keyHash.withUnsafeBytes { (bytes: UnsafePointer) -> Void in + keyHash.withUnsafeBytes { rawBytes -> Void in + let bytes = rawBytes.baseAddress!.assumingMemoryBound(to: UInt8.self) memcpy(&keyFingerprint, bytes.advanced(by: keyHash.count - 8), 8) } diff --git a/submodules/TelegramCore/Sources/State/ManagedSynchronizeGroupMessageStats.swift b/submodules/TelegramCore/Sources/State/ManagedSynchronizeGroupMessageStats.swift index f780347062..9284272950 100644 --- a/submodules/TelegramCore/Sources/State/ManagedSynchronizeGroupMessageStats.swift +++ b/submodules/TelegramCore/Sources/State/ManagedSynchronizeGroupMessageStats.swift @@ -88,11 +88,11 @@ private func synchronizeGroupMessageStats(postbox: Postbox, network: Network, gr return postbox.transaction { transaction in if let result = result { switch result { - case let .peerDialogs(peerDialogs): - for dialog in peerDialogs.dialogs { + case let .peerDialogs(dialogs, _, _, _, _): + for dialog in dialogs { switch dialog { - case let .dialogFolder(dialogFolder): - transaction.resetPeerGroupSummary(groupId: groupId, namespace: namespace, summary: PeerGroupUnreadCountersSummary(all: PeerGroupUnreadCounters(messageCount: dialogFolder.unreadMutedMessagesCount, chatCount: dialogFolder.unreadMutedPeersCount))) + case let .dialogFolder(_, _, _, _, unreadMutedPeersCount, _, unreadMutedMessagesCount, _): + transaction.resetPeerGroupSummary(groupId: groupId, namespace: namespace, summary: PeerGroupUnreadCountersSummary(all: PeerGroupUnreadCounters(messageCount: unreadMutedMessagesCount, chatCount: unreadMutedPeersCount))) case .dialog: assertionFailure() break diff --git a/submodules/TelegramCore/Sources/State/ManagedSynchronizeInstalledStickerPacksOperations.swift b/submodules/TelegramCore/Sources/State/ManagedSynchronizeInstalledStickerPacksOperations.swift index b482aa427f..b5f921c7db 100644 --- a/submodules/TelegramCore/Sources/State/ManagedSynchronizeInstalledStickerPacksOperations.swift +++ b/submodules/TelegramCore/Sources/State/ManagedSynchronizeInstalledStickerPacksOperations.swift @@ -396,7 +396,6 @@ private func continueSynchronizeInstalledStickerPacks(transaction: Transaction, let sequence = request |> retryRequest |> mapError { _ -> SynchronizeInstalledStickerPacksError in - return .restart } |> mapToSignal { result -> Signal in return postbox.transaction { transaction -> Signal in @@ -444,7 +443,6 @@ private func continueSynchronizeInstalledStickerPacks(transaction: Transaction, } return resolveStickerPacks(network: network, remoteInfos: resolveRemoteInfos, localInfos: localInfos) |> mapError { _ -> SynchronizeInstalledStickerPacksError in - return .restart } |> mapToSignal { replaceItems -> Signal in return postbox.transaction { transaction -> Signal in @@ -481,8 +479,7 @@ private func continueSynchronizeInstalledStickerPacks(transaction: Transaction, return ( storeSignal - |> mapError { _ -> SynchronizeInstalledStickerPacksError in return .restart - } + |> mapError { _ -> SynchronizeInstalledStickerPacksError in } ) |> then(.fail(.done)) } @@ -567,7 +564,7 @@ private func continueSynchronizeInstalledStickerPacks(transaction: Transaction, let resolvedItems = resolveStickerPacks(network: network, remoteInfos: resultingInfos, localInfos: localInfos) return combineLatest(archivedOrRemovedIds, resolvedItems) - |> mapError { _ -> SynchronizeInstalledStickerPacksError in return .restart } + |> mapError { _ -> SynchronizeInstalledStickerPacksError in } |> mapToSignal { archivedOrRemovedIds, replaceItems -> Signal in return (postbox.transaction { transaction -> Signal in let finalCheckLocalCollectionInfos = transaction.getItemCollectionsInfos(namespace: collectionNamespace).map { $0.1 as! StickerPackCollectionInfo } @@ -590,7 +587,6 @@ private func continueSynchronizeInstalledStickerPacks(transaction: Transaction, return .complete() } |> mapError { _ -> SynchronizeInstalledStickerPacksError in - return .restart }) |> switchToLatest |> then(.fail(.done)) @@ -598,7 +594,6 @@ private func continueSynchronizeInstalledStickerPacks(transaction: Transaction, } } |> mapError { _ -> SynchronizeInstalledStickerPacksError in - return .restart } |> switchToLatest } diff --git a/submodules/TelegramCore/Sources/State/ManagedSynchronizeMarkAllUnseenPersonalMessagesOperations.swift b/submodules/TelegramCore/Sources/State/ManagedSynchronizeMarkAllUnseenPersonalMessagesOperations.swift index e2955b7659..bdbf6a3984 100644 --- a/submodules/TelegramCore/Sources/State/ManagedSynchronizeMarkAllUnseenPersonalMessagesOperations.swift +++ b/submodules/TelegramCore/Sources/State/ManagedSynchronizeMarkAllUnseenPersonalMessagesOperations.swift @@ -128,12 +128,12 @@ private func synchronizeMarkAllUnseen(transaction: Transaction, postbox: Postbox switch result { case let .messages(messages, _, _): return .single(messages.compactMap({ $0.id() })) - case let .channelMessages(channelMessages): - return .single(channelMessages.messages.compactMap({ $0.id() })) + case let .channelMessages(_, _, _, _, messages, _, _): + return .single(messages.compactMap({ $0.id() })) case .messagesNotModified: return .single([]) - case let .messagesSlice(messagesSlice): - return .single(messagesSlice.messages.compactMap({ $0.id() })) + case let .messagesSlice(_, _, _, _, messages, _, _): + return .single(messages.compactMap({ $0.id() })) } } |> mapToSignal { ids -> Signal in diff --git a/submodules/TelegramCore/Sources/State/ManagedSynchronizePinnedChatsOperations.swift b/submodules/TelegramCore/Sources/State/ManagedSynchronizePinnedChatsOperations.swift index bac5ff138d..0c45508c65 100644 --- a/submodules/TelegramCore/Sources/State/ManagedSynchronizePinnedChatsOperations.swift +++ b/submodules/TelegramCore/Sources/State/ManagedSynchronizePinnedChatsOperations.swift @@ -115,8 +115,6 @@ private func synchronizePinnedChats(transaction: Transaction, postbox: Postbox, switch item { case let .peer(peerId): return peerId.namespace != Namespaces.Peer.SecretChat - default: - return true } } let localItemIds = transaction.getPinnedItemIds(groupId: groupId) @@ -124,8 +122,6 @@ private func synchronizePinnedChats(transaction: Transaction, postbox: Postbox, switch item { case let .peer(peerId): return peerId.namespace != Namespaces.Peer.SecretChat - default: - return true } } @@ -167,7 +163,7 @@ private func synchronizePinnedChats(transaction: Transaction, postbox: Postbox, var apiChannelPts: Int32? let apiNotificationSettings: Api.PeerNotifySettings switch dialog { - case let .dialog(flags, peer, topMessage, readInboxMaxId, readOutboxMaxId, unreadCount, unreadMentionsCount, peerNotificationSettings, pts, _, _): + case let .dialog(flags, peer, topMessage, readInboxMaxId, readOutboxMaxId, unreadCount, _, peerNotificationSettings, pts, _, _): apiPeer = peer apiTopMessage = topMessage apiReadInboxMaxId = readInboxMaxId diff --git a/submodules/TelegramCore/Sources/State/PendingMessageManager.swift b/submodules/TelegramCore/Sources/State/PendingMessageManager.swift index f2fc31cf0c..c04143b6cd 100644 --- a/submodules/TelegramCore/Sources/State/PendingMessageManager.swift +++ b/submodules/TelegramCore/Sources/State/PendingMessageManager.swift @@ -816,7 +816,6 @@ public final class PendingMessageManager { if let strongSelf = self { return strongSelf.applySentGroupMessages(postbox: postbox, stateManager: stateManager, messages: messages.map { $0.0 }, result: result) |> mapError { _ -> MTRpcError in - return MTRpcError(errorCode: 400, errorDescription: "empty") } } else { return .never() @@ -1058,12 +1057,10 @@ public final class PendingMessageManager { case .acknowledged: return strongSelf.applyAcknowledgedMessage(postbox: postbox, message: message) |> mapError { _ -> MTRpcError in - return MTRpcError(errorCode: 400, errorDescription: "internal") } case let .result(result): return strongSelf.applySentMessage(postbox: postbox, stateManager: stateManager, message: message, result: result) |> mapError { _ -> MTRpcError in - return MTRpcError(errorCode: 400, errorDescription: "internal") } } } diff --git a/submodules/TelegramCore/Sources/State/ProcessSecretChatIncomingDecryptedOperations.swift b/submodules/TelegramCore/Sources/State/ProcessSecretChatIncomingDecryptedOperations.swift index 80816b4681..17d268279b 100644 --- a/submodules/TelegramCore/Sources/State/ProcessSecretChatIncomingDecryptedOperations.swift +++ b/submodules/TelegramCore/Sources/State/ProcessSecretChatIncomingDecryptedOperations.swift @@ -510,17 +510,17 @@ extension SecretChatServiceAction { extension StoreMessage { convenience init?(peerId: PeerId, authorId: PeerId, tagLocalIndex: Int32, timestamp: Int32, apiMessage: SecretApi8.DecryptedMessage, file: SecretChatFileReference?) { switch apiMessage { - case let .decryptedMessage(randomId, _, message, media): + case let .decryptedMessage(randomId, _, message, _): self.init(id: MessageId(peerId: peerId, namespace: Namespaces.Message.SecretIncoming, id: tagLocalIndex), globallyUniqueId: randomId, groupingKey: nil, threadId: nil, timestamp: timestamp, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, authorId: authorId, text: message, attributes: [], media: []) case let .decryptedMessageService(randomId, _, action): switch action { - case let .decryptedMessageActionDeleteMessages(randomIds): + case .decryptedMessageActionDeleteMessages: return nil case .decryptedMessageActionFlushHistory: return nil - case let .decryptedMessageActionNotifyLayer(layer): + case .decryptedMessageActionNotifyLayer: return nil - case let .decryptedMessageActionReadMessages(randomIds): + case .decryptedMessageActionReadMessages: return nil case .decryptedMessageActionScreenshotMessages: self.init(id: MessageId(peerId: peerId, namespace: Namespaces.Message.SecretIncoming, id: tagLocalIndex), globallyUniqueId: randomId, groupingKey: nil, threadId: nil, timestamp: timestamp, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, authorId: authorId, text: "", attributes: [], media: [TelegramMediaAction(action: .historyScreenshot)]) @@ -824,7 +824,7 @@ private func parseMessage(peerId: PeerId, authorId: PeerId, tagLocalIndex: Int32 return (StoreMessage(id: MessageId(peerId: peerId, namespace: Namespaces.Message.SecretIncoming, id: tagLocalIndex), globallyUniqueId: randomId, groupingKey: nil, threadId: nil, timestamp: timestamp, flags: [.Incoming], tags: tags, globalTags: globalTags, localTags: [], forwardInfo: nil, authorId: authorId, text: text, attributes: attributes, media: parsedMedia), resources) case let .decryptedMessageService(randomId, action): switch action { - case let .decryptedMessageActionDeleteMessages(randomIds): + case .decryptedMessageActionDeleteMessages: return nil case .decryptedMessageActionFlushHistory: return nil @@ -977,7 +977,7 @@ private func parseMessage(peerId: PeerId, authorId: PeerId, tagLocalIndex: Int32 let fileMedia = TelegramMediaFile(fileId: MediaId(namespace: Namespaces.Media.CloudSecretFile, id: file.id), partialReference: nil, resource: file.resource(key: SecretFileEncryptionKey(aesKey: key.makeData(), aesIv: iv.makeData()), decryptedSize: size), previewRepresentations: previewRepresentations, videoThumbnails: [], immediateThumbnailData: nil, mimeType: mimeType, size: Int(size), attributes: parsedAttributes) parsedMedia.append(fileMedia) } - case let .decryptedMessageMediaExternalDocument(id, accessHash, date, mimeType, size, thumb, dcId, attributes): + case let .decryptedMessageMediaExternalDocument(id, accessHash, _, mimeType, size, thumb, dcId, attributes): var parsedAttributes: [TelegramMediaFileAttribute] = [] for attribute in attributes { if let parsedAttribute = TelegramMediaFileAttribute(attribute) { @@ -1215,7 +1215,7 @@ private func parseMessage(peerId: PeerId, authorId: PeerId, tagLocalIndex: Int32 let fileMedia = TelegramMediaFile(fileId: MediaId(namespace: Namespaces.Media.CloudSecretFile, id: file.id), partialReference: nil, resource: file.resource(key: SecretFileEncryptionKey(aesKey: key.makeData(), aesIv: iv.makeData()), decryptedSize: size), previewRepresentations: previewRepresentations, videoThumbnails: [], immediateThumbnailData: nil, mimeType: mimeType, size: Int(size), attributes: parsedAttributes) parsedMedia.append(fileMedia) } - case let .decryptedMessageMediaExternalDocument(id, accessHash, date, mimeType, size, thumb, dcId, attributes): + case let .decryptedMessageMediaExternalDocument(id, accessHash, _, mimeType, size, thumb, dcId, attributes): var parsedAttributes: [TelegramMediaFileAttribute] = [] for attribute in attributes { if let parsedAttribute = TelegramMediaFileAttribute(attribute) { diff --git a/submodules/TelegramCore/Sources/State/Serialization.swift b/submodules/TelegramCore/Sources/State/Serialization.swift index 6186d380d5..06a364da91 100644 --- a/submodules/TelegramCore/Sources/State/Serialization.swift +++ b/submodules/TelegramCore/Sources/State/Serialization.swift @@ -246,9 +246,9 @@ public class Serialization: NSObject, MTSerialization { return { response -> MTDatacenterAddressListData? in if let config = parser.parse(Buffer(data: response)) { switch config { - case let .config(config): + case let .config(_, _, _, _, _, dcOptions, _, _, _, _, _, _,_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _): var addressDict: [NSNumber: [Any]] = [:] - for option in config.dcOptions { + for option in dcOptions { switch option { case let .dcOption(flags, id, ipAddress, port, secret): if addressDict[id as NSNumber] == nil { diff --git a/submodules/TelegramCore/Sources/State/StickerManagement.swift b/submodules/TelegramCore/Sources/State/StickerManagement.swift index f6109865d7..34a65ab014 100644 --- a/submodules/TelegramCore/Sources/State/StickerManagement.swift +++ b/submodules/TelegramCore/Sources/State/StickerManagement.swift @@ -4,13 +4,13 @@ import Postbox import SwiftSignalKit -private func hashForIdsReverse(_ ids: [Int64]) -> Int32 { +private func hashForIdsReverse(_ ids: [Int64]) -> Int64 { var acc: UInt64 = 0 for id in ids { combineInt64Hash(&acc, with: UInt64(bitPattern: id)) } - return Int32(bitPattern: UInt32(clamping: acc & UInt64(0x7FFFFFFF))) + return Int64(bitPattern: acc) } func manageStickerPacks(network: Network, postbox: Postbox) -> Signal { @@ -35,8 +35,8 @@ func updatedFeaturedStickerPacks(network: Network, postbox: Postbox) -> Signal retryRequest |> mapToSignal { result -> Signal in return postbox.transaction { transaction -> Void in diff --git a/submodules/TelegramCore/Sources/State/SynchronizeConsumeMessageContentsOperation.swift b/submodules/TelegramCore/Sources/State/SynchronizeConsumeMessageContentsOperation.swift index 62b40f9239..e2b071778d 100644 --- a/submodules/TelegramCore/Sources/State/SynchronizeConsumeMessageContentsOperation.swift +++ b/submodules/TelegramCore/Sources/State/SynchronizeConsumeMessageContentsOperation.swift @@ -2,7 +2,7 @@ import Postbox func addSynchronizeConsumeMessageContentsOperation(transaction: Transaction, messageIds: [MessageId]) { for (peerId, messageIds) in messagesIdsGroupedByPeerId(Set(messageIds)) { - var updateLocalIndex: Int32? + let updateLocalIndex: Int32? = nil /*transaction.operationLogEnumerateEntries(peerId: peerId, tag: OperationLogTags.SynchronizeConsumeMessageContents, { entry in updateLocalIndex = entry.tagLocalIndex return false diff --git a/submodules/TelegramCore/Sources/State/SynchronizePeerReadState.swift b/submodules/TelegramCore/Sources/State/SynchronizePeerReadState.swift index 1cfa73aaa3..c704b5cd74 100644 --- a/submodules/TelegramCore/Sources/State/SynchronizePeerReadState.swift +++ b/submodules/TelegramCore/Sources/State/SynchronizePeerReadState.swift @@ -247,7 +247,6 @@ private func pushPeerReadState(network: Network, postbox: Postbox, stateManager: } return pushSignal |> mapError { _ -> PeerReadStateValidationError in - return .retry } |> mapToSignal { _ -> Signal in return .complete() @@ -287,7 +286,6 @@ private func pushPeerReadState(network: Network, postbox: Postbox, stateManager: return pushSignal |> mapError { _ -> PeerReadStateValidationError in - return .retry } |> mapToSignal { _ -> Signal in return .complete() diff --git a/submodules/TelegramCore/Sources/State/SynchronizeSavedStickersOperation.swift b/submodules/TelegramCore/Sources/State/SynchronizeSavedStickersOperation.swift index cb24371e7f..34eeb16369 100644 --- a/submodules/TelegramCore/Sources/State/SynchronizeSavedStickersOperation.swift +++ b/submodules/TelegramCore/Sources/State/SynchronizeSavedStickersOperation.swift @@ -92,7 +92,7 @@ public func addSavedSticker(postbox: Postbox, network: Network, file: TelegramMe if let stickerStringRepresentations = stickerStringRepresentations { return postbox.transaction { transaction -> Void in addSavedSticker(transaction: transaction, file: file, stringRepresentations: stickerStringRepresentations) - } |> mapError { _ in return AddSavedStickerError.generic } + } |> mapError { _ -> AddSavedStickerError in } } else { return .fail(.notFound) } @@ -102,7 +102,7 @@ public func addSavedSticker(postbox: Postbox, network: Network, file: TelegramMe } } return .complete() - } |> mapError { _ in return AddSavedStickerError.generic } |> switchToLatest + } |> mapError { _ -> AddSavedStickerError in } |> switchToLatest } public func addSavedSticker(transaction: Transaction, file: TelegramMediaFile, stringRepresentations: [String]) { diff --git a/submodules/TelegramCore/Sources/State/UpdatesApiUtils.swift b/submodules/TelegramCore/Sources/State/UpdatesApiUtils.swift index 91dcb3b5ef..7cd9d2e01a 100644 --- a/submodules/TelegramCore/Sources/State/UpdatesApiUtils.swift +++ b/submodules/TelegramCore/Sources/State/UpdatesApiUtils.swift @@ -60,8 +60,8 @@ extension Api.MessageMedia { case let .messageMediaWebPage(webPage): var result: [(MediaResource, Data)]? switch webPage { - case let .webPage(content): - if let photo = content.photo { + case let .webPage(_, _, _, _, _, _, _, _, _, photo, _, _, _, _, _, _, document, _, _): + if let photo = photo { if let photoResult = collectPreCachedResources(for: photo) { if result == nil { result = [] @@ -69,7 +69,7 @@ extension Api.MessageMedia { result!.append(contentsOf: photoResult) } } - if let file = content.document { + if let file = document { if let fileResult = collectPreCachedResources(for: file) { if result == nil { result = [] @@ -90,8 +90,8 @@ extension Api.MessageMedia { extension Api.Message { var rawId: Int32 { switch self { - case let .message(message): - return message.id + case let .message(_, id, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _): + return id case let .messageEmpty(_, id, _): return id case let .messageService(_, id, _, _, _, _, _, _): @@ -101,12 +101,8 @@ extension Api.Message { func id(namespace: MessageId.Namespace = Namespaces.Message.Cloud) -> MessageId? { switch self { - case let .message(message): - let flags = message.flags - let id = message.id - let fromId = message.fromId - - let peerId: PeerId = message.peerId.peerId + case let .message(_, id, _, messagePeerId, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _): + let peerId: PeerId = messagePeerId.peerId return MessageId(peerId: peerId, namespace: namespace, id: id) case let .messageEmpty(_, id, peerId): if let peerId = peerId { @@ -114,7 +110,7 @@ extension Api.Message { } else { return nil } - case let .messageService(flags, id, fromId, chatPeerId, _, _, _, _): + case let .messageService(_, id, _, chatPeerId, _, _, _, _): let peerId: PeerId = chatPeerId.peerId return MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: id) } @@ -122,10 +118,10 @@ extension Api.Message { var timestamp: Int32? { switch self { - case let .message(message): - return message.date - case let .messageService(messageService): - return messageService.date + case let .message(_, _, _, _, _, _, _, date, _, _, _, _, _, _, _, _, _, _, _, _): + return date + case let .messageService(_, _, _, _, _, date, _, _): + return date case .messageEmpty: return nil } @@ -133,8 +129,8 @@ extension Api.Message { var preCachedResources: [(MediaResource, Data)]? { switch self { - case let .message(message): - return message.media?.preCachedResources + case let .message(_, _, _, _, _, _, _, _, _, media, _, _, _, _, _, _, _, _, _, _): + return media?.preCachedResources default: return nil } @@ -144,14 +140,14 @@ extension Api.Message { extension Api.Chat { var peerId: PeerId { switch self { - case let .chat(chat): - return PeerId(namespace: Namespaces.Peer.CloudGroup, id: PeerId.Id._internalFromInt64Value(chat.id)) + case let .chat(_, id, _, _, _, _, _, _, _, _): + return PeerId(namespace: Namespaces.Peer.CloudGroup, id: PeerId.Id._internalFromInt64Value(id)) case let .chatEmpty(id): return PeerId(namespace: Namespaces.Peer.CloudGroup, id: PeerId.Id._internalFromInt64Value(id)) case let .chatForbidden(id, _): return PeerId(namespace: Namespaces.Peer.CloudGroup, id: PeerId.Id._internalFromInt64Value(id)) - case let .channel(channel): - return PeerId(namespace: Namespaces.Peer.CloudChannel, id: PeerId.Id._internalFromInt64Value(channel.id)) + case let .channel(_, id, _, _, _, _, _, _, _, _, _, _): + return PeerId(namespace: Namespaces.Peer.CloudChannel, id: PeerId.Id._internalFromInt64Value(id)) case let .channelForbidden(_, id, _, _, _): return PeerId(namespace: Namespaces.Peer.CloudChannel, id: PeerId.Id._internalFromInt64Value(id)) } diff --git a/submodules/TelegramCore/Sources/Suggestions.swift b/submodules/TelegramCore/Sources/Suggestions.swift index 36906c406f..e8e81c25e4 100644 --- a/submodules/TelegramCore/Sources/Suggestions.swift +++ b/submodules/TelegramCore/Sources/Suggestions.swift @@ -25,7 +25,7 @@ public func getServerProvidedSuggestions(account: Account) -> Signal<[ServerProv guard let view = views.views[key] as? PreferencesView else { return [] } - guard let appConfiguration = view.values[PreferencesKeys.appConfiguration] as? AppConfiguration else { + guard let appConfiguration = view.values[PreferencesKeys.appConfiguration]?.get(AppConfiguration.self) else { return [] } guard let data = appConfiguration.data, let list = data["pending_suggestions"] as? [String] else { diff --git a/submodules/TelegramCore/Sources/SyncCore/SyncCore_AppConfiguration.swift b/submodules/TelegramCore/Sources/SyncCore/SyncCore_AppConfiguration.swift index 99595e9d22..40586d30fe 100644 --- a/submodules/TelegramCore/Sources/SyncCore/SyncCore_AppConfiguration.swift +++ b/submodules/TelegramCore/Sources/SyncCore/SyncCore_AppConfiguration.swift @@ -12,15 +12,15 @@ public struct AppConfiguration: Codable, Equatable { self.data = data } - public init(decoder: PostboxDecoder) { - self.data = decoder.decodeObjectForKey("data", decoder: { JSON(decoder: $0) }) as? JSON + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: StringCodingKey.self) + + self.data = try container.decodeIfPresent(JSON.self, forKey: "data") } - public func encode(_ encoder: PostboxEncoder) { - if let data = self.data { - encoder.encodeObject(data, forKey: "data") - } else { - encoder.encodeNil(forKey: "data") - } + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: StringCodingKey.self) + + try container.encodeIfPresent(self.data, forKey: "data") } } diff --git a/submodules/TelegramCore/Sources/SyncCore/SyncCore_CachedResolvedByNamePeer.swift b/submodules/TelegramCore/Sources/SyncCore/SyncCore_CachedResolvedByNamePeer.swift index cc358b3c1e..10d47173cb 100644 --- a/submodules/TelegramCore/Sources/SyncCore/SyncCore_CachedResolvedByNamePeer.swift +++ b/submodules/TelegramCore/Sources/SyncCore/SyncCore_CachedResolvedByNamePeer.swift @@ -9,7 +9,9 @@ public final class CachedResolvedByNamePeer: PostboxCoding { let key: ValueBoxKey if let nameData = name.data(using: .utf8) { key = ValueBoxKey(length: nameData.count) - nameData.withUnsafeBytes { (bytes: UnsafePointer) -> Void in + nameData.withUnsafeBytes { rawBytes -> Void in + let bytes = rawBytes.baseAddress!.assumingMemoryBound(to: Int8.self) + memcpy(key.memory, bytes, nameData.count) } } else { diff --git a/submodules/TelegramCore/Sources/SyncCore/SyncCore_CloudFileMediaResource.swift b/submodules/TelegramCore/Sources/SyncCore/SyncCore_CloudFileMediaResource.swift index fa65be62e9..e83573796a 100644 --- a/submodules/TelegramCore/Sources/SyncCore/SyncCore_CloudFileMediaResource.swift +++ b/submodules/TelegramCore/Sources/SyncCore/SyncCore_CloudFileMediaResource.swift @@ -520,7 +520,7 @@ public struct LocalFileMediaResourceId: MediaResourceId, Hashable, Equatable { } } -public class LocalFileMediaResource: TelegramMediaResource { +public class LocalFileMediaResource: TelegramMediaResource, Codable { public let fileId: Int64 public let size: Int? @@ -541,6 +541,14 @@ public class LocalFileMediaResource: TelegramMediaResource { self.size = nil } } + + public required init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: StringCodingKey.self) + + self.fileId = try container.decode(Int64.self, forKey: "f") + self.isSecretRelated = try container.decodeIfPresent(Bool.self, forKey: "sr") ?? false + self.size = (try container.decodeIfPresent(Int32.self, forKey: "s")).flatMap(Int.init) + } public func encode(_ encoder: PostboxEncoder) { encoder.encodeInt64(self.fileId, forKey: "f") @@ -551,6 +559,14 @@ public class LocalFileMediaResource: TelegramMediaResource { encoder.encodeNil(forKey: "s") } } + + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: StringCodingKey.self) + + try container.encode(self.fileId, forKey: "f") + try container.encode(self.isSecretRelated, forKey: "sr") + try container.encodeIfPresent(self.size.flatMap(Int32.init), forKey: "s") + } public var id: MediaResourceId { return LocalFileMediaResourceId(fileId: self.fileId) diff --git a/submodules/TelegramCore/Sources/SyncCore/SyncCore_GlobalNotificationSettings.swift b/submodules/TelegramCore/Sources/SyncCore/SyncCore_GlobalNotificationSettings.swift index 71b1b3138d..3b641ceddb 100644 --- a/submodules/TelegramCore/Sources/SyncCore/SyncCore_GlobalNotificationSettings.swift +++ b/submodules/TelegramCore/Sources/SyncCore/SyncCore_GlobalNotificationSettings.swift @@ -1,6 +1,6 @@ import Postbox -public struct MessageNotificationSettings: Codable { +public struct MessageNotificationSettings: Codable, Equatable { public var enabled: Bool public var displayPreviews: Bool public var sound: PeerMessageSound @@ -21,14 +21,15 @@ public struct MessageNotificationSettings: Codable { self.enabled = ((try? container.decode(Int32.self, forKey: "e")) ?? 0) != 0 self.displayPreviews = ((try? container.decode(Int32.self, forKey: "p")) ?? 0) != 0 - self.sound = PeerMessageSound.decodeInline(container) + self.sound = try PeerMessageSound.decodeInline(container) } public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: StringCodingKey.self) - encoder.encodeInt32(self.enabled ? 1 : 0, forKey: "e") - encoder.encodeInt32(self.displayPreviews ? 1 : 0, forKey: "p") - self.sound.encodeInline(encoder) + try container.encode((self.enabled ? 1 : 0) as Int32, forKey: "e") + try container.encode((self.displayPreviews ? 1 : 0) as Int32, forKey: "p") + try self.sound.encodeInline(&container) } } @@ -52,18 +53,20 @@ public struct GlobalNotificationSettingsSet: Codable, Equatable { public init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: StringCodingKey.self) - self.privateChats = decoder.decodeObjectForKey("p", decoder: { MessageNotificationSettings(decoder: $0) }) as! MessageNotificationSettings - self.groupChats = decoder.decodeObjectForKey("g", decoder: { MessageNotificationSettings(decoder: $0) }) as! MessageNotificationSettings - self.channels = (decoder.decodeObjectForKey("c", decoder: { MessageNotificationSettings(decoder: $0) }) as? MessageNotificationSettings) ?? MessageNotificationSettings.defaultSettings - self.contactsJoined = decoder.decodeInt32ForKey("contactsJoined", orElse: 1) != 0 + self.privateChats = try container.decode(MessageNotificationSettings.self, forKey: "p") + self.groupChats = try container.decode(MessageNotificationSettings.self, forKey: "g") + self.channels = try container.decode(MessageNotificationSettings.self, forKey: "c") + + self.contactsJoined = (try container.decode(Int32.self, forKey: "contactsJoined")) != 0 } public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: StringCodingKey.self) - encoder.encodeObject(self.privateChats, forKey: "p") - encoder.encodeObject(self.groupChats, forKey: "g") - encoder.encodeObject(self.channels, forKey: "c") - encoder.encodeInt32(self.contactsJoined ? 1 : 0, forKey: "contactsJoined") + try container.encode(self.privateChats, forKey: "p") + try container.encode(self.groupChats, forKey: "g") + try container.encode(self.channels, forKey: "c") + try container.encode((self.contactsJoined ? 1 : 0) as Int32, forKey: "contactsJoined") } } @@ -89,7 +92,7 @@ public struct GlobalNotificationSettings: Codable { ) } - private func defaultIncludePeer(peer: Peer) -> Bool { + func defaultIncludePeer(peer: Peer) -> Bool { let settings = self.effective if peer is TelegramUser || peer is TelegramSecretChat { return settings.privateChats.enabled @@ -135,16 +138,14 @@ public struct GlobalNotificationSettings: Codable { public init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: StringCodingKey.self) - self.toBeSynchronized = decoder.decodeObjectForKey("s", decoder: { GlobalNotificationSettingsSet(decoder: $0) }) as? GlobalNotificationSettingsSet - self.remote = decoder.decodeObjectForKey("r", decoder: { GlobalNotificationSettingsSet(decoder: $0) }) as! GlobalNotificationSettingsSet + self.toBeSynchronized = try container.decodeIfPresent(GlobalNotificationSettingsSet.self, forKey: "s") + self.remote = try container.decode(GlobalNotificationSettingsSet.self, forKey: "r") } public func encode(to encoder: Encoder) throws { - if let toBeSynchronized = self.toBeSynchronized { - encoder.encodeObject(toBeSynchronized, forKey: "s") - } else { - encoder.encodeNil(forKey: "s") - } - encoder.encodeObject(self.remote, forKey: "r") + var container = encoder.container(keyedBy: StringCodingKey.self) + + try container.encodeIfPresent(self.toBeSynchronized, forKey: "s") + try container.encode(self.remote, forKey: "r") } } diff --git a/submodules/TelegramCore/Sources/SyncCore/SyncCore_JSON.swift b/submodules/TelegramCore/Sources/SyncCore/SyncCore_JSON.swift index ef51457723..d656439ec7 100644 --- a/submodules/TelegramCore/Sources/SyncCore/SyncCore_JSON.swift +++ b/submodules/TelegramCore/Sources/SyncCore/SyncCore_JSON.swift @@ -1,6 +1,26 @@ import Postbox -public indirect enum JSON: PostboxCoding, Equatable { +public indirect enum JSON: Codable, Equatable { + private struct DictionaryKey: Codable, Hashable { + var key: String + + init(_ key: String) { + self.key = key + } + + init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: StringCodingKey.self) + + self.key = try container.decode(String.self, forKey: "k") + } + + func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: StringCodingKey.self) + + try container.encode(self.key, forKey: "k") + } + } + case null case number(Double) case string(String) @@ -17,47 +37,57 @@ public indirect enum JSON: PostboxCoding, Equatable { case dictionary = 5 } - public init(decoder: PostboxDecoder) { - switch decoder.decodeInt32ForKey("r", orElse: 0) { + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: StringCodingKey.self) + + switch try container.decode(Int32.self, forKey: "r") { case ValueType.null.rawValue: self = .null case ValueType.number.rawValue: - self = .number(decoder.decodeDoubleForKey("v", orElse: 0.0)) + self = .number(try container.decode(Double.self, forKey: "v")) case ValueType.string.rawValue: - self = .string(decoder.decodeStringForKey("v", orElse: "")) + self = .string(try container.decode(String.self, forKey: "v")) case ValueType.bool.rawValue: - self = .bool(decoder.decodeBoolForKey("v", orElse: false)) + self = .bool(try container.decode(Bool.self, forKey: "v")) case ValueType.array.rawValue: - self = .array(decoder.decodeObjectArrayForKey("v")) + self = .array(try container.decode([JSON].self, forKey: "v")) case ValueType.dictionary.rawValue: - self = .dictionary(decoder.decodeObjectDictionaryForKey("v", keyDecoder: { $0.decodeStringForKey("k", orElse: "") - }, valueDecoder: { JSON(decoder: $0) })) + let dict = try container.decode([DictionaryKey: JSON].self, forKey: "v") + var mappedDict: [String: JSON] = [:] + for (key, value) in dict { + mappedDict[key.key] = value + } + self = .dictionary(mappedDict) default: self = .null } } - public func encode(_ encoder: PostboxEncoder) { + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: StringCodingKey.self) + switch self { case .null: - encoder.encodeInt32(ValueType.null.rawValue, forKey: "r") + try container.encode(ValueType.null.rawValue, forKey: "r") case let .number(value): - encoder.encodeInt32(ValueType.number.rawValue, forKey: "r") - encoder.encodeDouble(value, forKey: "v") + try container.encode(ValueType.number.rawValue, forKey: "r") + try container.encode(value, forKey: "v") case let .string(value): - encoder.encodeInt32(ValueType.string.rawValue, forKey: "r") - encoder.encodeString(value, forKey: "v") + try container.encode(ValueType.string.rawValue, forKey: "r") + try container.encode(value, forKey: "v") case let .bool(value): - encoder.encodeInt32(ValueType.bool.rawValue, forKey: "r") - encoder.encodeBool(value, forKey: "v") + try container.encode(ValueType.bool.rawValue, forKey: "r") + try container.encode(value, forKey: "v") case let .array(value): - encoder.encodeInt32(ValueType.array.rawValue, forKey: "r") - encoder.encodeObjectArray(value, forKey: "v") + try container.encode(ValueType.array.rawValue, forKey: "r") + try container.encode(value, forKey: "v") case let .dictionary(value): - encoder.encodeInt32(ValueType.dictionary.rawValue, forKey: "r") - encoder.encodeObjectDictionary(value, forKey: "v") { key, encoder in - encoder.encodeString(key, forKey: "k") + try container.encode(ValueType.dictionary.rawValue, forKey: "r") + var mappedDict: [DictionaryKey: JSON] = [:] + for (k, v) in value { + mappedDict[DictionaryKey(k)] = v } + try container.encode(mappedDict, forKey: "v") } } diff --git a/submodules/TelegramCore/Sources/SyncCore/SyncCore_LimitsConfiguration.swift b/submodules/TelegramCore/Sources/SyncCore/SyncCore_LimitsConfiguration.swift index 82b78a4fbd..dc4533c506 100644 --- a/submodules/TelegramCore/Sources/SyncCore/SyncCore_LimitsConfiguration.swift +++ b/submodules/TelegramCore/Sources/SyncCore/SyncCore_LimitsConfiguration.swift @@ -64,7 +64,7 @@ public struct LimitsConfiguration: Codable, Equatable { try container.encode(self.maxRecentStickerCount, forKey: "maxRecentStickerCount") try container.encode(self.maxMessageEditingInterval, forKey: "maxMessageEditingInterval") try container.encode(self.maxMediaCaptionLength, forKey: "maxMediaCaptionLength") - try container.encode(self.canRemoveIncomingMessagesInPrivateChats ? 1 : 0, forKey: "canRemoveIncomingMessagesInPrivateChats") + try container.encode((self.canRemoveIncomingMessagesInPrivateChats ? 1 : 0) as Int32, forKey: "canRemoveIncomingMessagesInPrivateChats") try container.encode(self.maxMessageRevokeInterval, forKey: "maxMessageRevokeInterval") try container.encode(self.maxMessageRevokeIntervalInPrivateChats, forKey: "maxMessageRevokeIntervalInPrivateChats") } diff --git a/submodules/TelegramCore/Sources/SyncCore/SyncCore_MediaReference.swift b/submodules/TelegramCore/Sources/SyncCore/SyncCore_MediaReference.swift index 089f3a275b..29fa4cf791 100644 --- a/submodules/TelegramCore/Sources/SyncCore/SyncCore_MediaReference.swift +++ b/submodules/TelegramCore/Sources/SyncCore/SyncCore_MediaReference.swift @@ -269,7 +269,7 @@ public enum AnyMediaReference: Equatable { return .stickerPack(stickerPack: stickerPack) case .savedGif: return .savedGif - case let .avatarList(peer, media): + case .avatarList: return nil } } diff --git a/submodules/TelegramCore/Sources/SyncCore/SyncCore_SecretChatState.swift b/submodules/TelegramCore/Sources/SyncCore/SyncCore_SecretChatState.swift index 48be226cf4..88a5006690 100644 --- a/submodules/TelegramCore/Sources/SyncCore/SyncCore_SecretChatState.swift +++ b/submodules/TelegramCore/Sources/SyncCore/SyncCore_SecretChatState.swift @@ -23,11 +23,15 @@ public struct SecretChatKeySha1Fingerprint: PostboxCoding, Equatable { var k0: Int64 = 0 var k1: Int64 = 0 var k2: Int32 = 0 - digest.withUnsafeBytes { (bytes: UnsafePointer) -> Void in + digest.withUnsafeBytes { rawBytes -> Void in + let bytes = rawBytes.baseAddress!.assumingMemoryBound(to: Int64.self) + k0 = bytes.pointee k1 = bytes.advanced(by: 1).pointee } - digest.withUnsafeBytes { (bytes: UnsafePointer) -> Void in + digest.withUnsafeBytes { rawBytes -> Void in + let bytes = rawBytes.baseAddress!.assumingMemoryBound(to: Int32.self) + k2 = bytes.advanced(by: 4).pointee } self.k0 = k0 @@ -56,11 +60,15 @@ public struct SecretChatKeySha1Fingerprint: PostboxCoding, Equatable { public func data() -> Data { var data = Data() data.count = 20 - data.withUnsafeMutableBytes { (bytes: UnsafeMutablePointer) -> Void in + data.withUnsafeMutableBytes { rawBytes -> Void in + let bytes = rawBytes.baseAddress!.assumingMemoryBound(to: Int64.self) + bytes.pointee = self.k0 bytes.advanced(by: 1).pointee = self.k1 } - data.withUnsafeMutableBytes { (bytes: UnsafeMutablePointer) -> Void in + data.withUnsafeMutableBytes { rawBytes -> Void in + let bytes = rawBytes.baseAddress!.assumingMemoryBound(to: Int32.self) + bytes.advanced(by: 4).pointee = self.k2 } return data @@ -92,7 +100,9 @@ public struct SecretChatKeySha256Fingerprint: PostboxCoding, Equatable { var k1: Int64 = 0 var k2: Int64 = 0 var k3: Int64 = 0 - digest.withUnsafeBytes { (bytes: UnsafePointer) -> Void in + digest.withUnsafeBytes { rawBytes -> Void in + let bytes = rawBytes.baseAddress!.assumingMemoryBound(to: Int64.self) + k0 = bytes.pointee k1 = bytes.advanced(by: 1).pointee k2 = bytes.advanced(by: 2).pointee @@ -128,7 +138,9 @@ public struct SecretChatKeySha256Fingerprint: PostboxCoding, Equatable { public func data() -> Data { var data = Data() data.count = 32 - data.withUnsafeMutableBytes { (bytes: UnsafeMutablePointer) -> Void in + data.withUnsafeMutableBytes { rawBytes -> Void in + let bytes = rawBytes.baseAddress!.assumingMemoryBound(to: Int64.self) + bytes.pointee = self.k0 bytes.advanced(by: 1).pointee = self.k1 bytes.advanced(by: 2).pointee = self.k2 diff --git a/submodules/TelegramCore/Sources/SyncCore/SyncCore_StandaloneAccountTransaction.swift b/submodules/TelegramCore/Sources/SyncCore/SyncCore_StandaloneAccountTransaction.swift index 2d16cfdff6..6127a574fd 100644 --- a/submodules/TelegramCore/Sources/SyncCore/SyncCore_StandaloneAccountTransaction.swift +++ b/submodules/TelegramCore/Sources/SyncCore/SyncCore_StandaloneAccountTransaction.swift @@ -34,37 +34,63 @@ public let telegramPostboxSeedConfiguration: SeedConfiguration = { globalMessageIdsPeerIdNamespaces.insert(GlobalMessageIdsNamespace(peerIdNamespace: peerIdNamespace, messageIdNamespace: Namespaces.Message.Cloud)) } - return SeedConfiguration(globalMessageIdsPeerIdNamespaces: globalMessageIdsPeerIdNamespaces, initializeChatListWithHole: (topLevel: ChatListHole(index: MessageIndex(id: MessageId(peerId: PeerId(namespace: Namespaces.Peer.Empty, id: PeerId.Id._internalFromInt64Value(0)), namespace: Namespaces.Message.Cloud, id: 1), timestamp: Int32.max - 1)), groups: ChatListHole(index: MessageIndex(id: MessageId(peerId: PeerId(namespace: Namespaces.Peer.Empty, id: PeerId.Id._internalFromInt64Value(0)), namespace: Namespaces.Message.Cloud, id: 1), timestamp: Int32.max - 1))), messageHoles: messageHoles, upgradedMessageHoles: upgradedMessageHoles, messageThreadHoles: messageThreadHoles, existingMessageTags: MessageTags.all, messageTagsWithSummary: [.unseenPersonalMessage, .pinned], existingGlobalMessageTags: GlobalMessageTags.all, peerNamespacesRequiringMessageTextIndex: [Namespaces.Peer.SecretChat], peerSummaryCounterTags: { peer, isContact in - if let peer = peer as? TelegramUser { - if peer.botInfo != nil { - return .bot - } else if isContact { - return .contact + return SeedConfiguration( + globalMessageIdsPeerIdNamespaces: globalMessageIdsPeerIdNamespaces, + initializeChatListWithHole: ( + topLevel: ChatListHole(index: MessageIndex(id: MessageId(peerId: PeerId(namespace: Namespaces.Peer.Empty, id: PeerId.Id._internalFromInt64Value(0)), namespace: Namespaces.Message.Cloud, id: 1), timestamp: Int32.max - 1)), + groups: ChatListHole(index: MessageIndex(id: MessageId(peerId: PeerId(namespace: Namespaces.Peer.Empty, id: PeerId.Id._internalFromInt64Value(0)), namespace: Namespaces.Message.Cloud, id: 1), timestamp: Int32.max - 1)) + ), + messageHoles: messageHoles, + upgradedMessageHoles: upgradedMessageHoles, + messageThreadHoles: messageThreadHoles, + existingMessageTags: MessageTags.all, + messageTagsWithSummary: [.unseenPersonalMessage, .pinned], + existingGlobalMessageTags: GlobalMessageTags.all, + peerNamespacesRequiringMessageTextIndex: [Namespaces.Peer.SecretChat], + peerSummaryCounterTags: { peer, isContact in + if let peer = peer as? TelegramUser { + if peer.botInfo != nil { + return .bot + } else if isContact { + return .contact + } else { + return .nonContact + } + } else if let _ = peer as? TelegramGroup { + return .group + } else if let _ = peer as? TelegramSecretChat { + return .nonContact + } else if let channel = peer as? TelegramChannel { + switch channel.info { + case .broadcast: + return .channel + case .group: + if channel.username != nil { + return .group + } else { + return .group + } + } } else { + assertionFailure() return .nonContact } - } else if let _ = peer as? TelegramGroup { - return .group - } else if let _ = peer as? TelegramSecretChat { - return .nonContact - } else if let channel = peer as? TelegramChannel { - switch channel.info { - case .broadcast: - return .channel - case .group: - if channel.username != nil { - return .group - } else { - return .group - } + }, + additionalChatListIndexNamespace: Namespaces.Message.Cloud, + messageNamespacesRequiringGroupStatsValidation: [Namespaces.Message.Cloud], + defaultMessageNamespaceReadStates: [Namespaces.Message.Local: .idBased(maxIncomingReadId: 0, maxOutgoingReadId: 0, maxKnownId: 0, count: 0, markedUnread: false)], + chatMessagesNamespaces: Set([Namespaces.Message.Cloud, Namespaces.Message.Local, Namespaces.Message.SecretIncoming]), + getGlobalNotificationSettings: { transaction -> PostboxGlobalNotificationSettings? in + (transaction.getPreferencesEntry(key: PreferencesKeys.globalNotifications)?.get(GlobalNotificationSettings.self)).flatMap { settings in + return PostboxGlobalNotificationSettings(defaultIncludePeer: { peer in + return settings.defaultIncludePeer(peer: peer) + }) } - } else { - assertionFailure() - return .nonContact - } - }, additionalChatListIndexNamespace: Namespaces.Message.Cloud, messageNamespacesRequiringGroupStatsValidation: [Namespaces.Message.Cloud], defaultMessageNamespaceReadStates: [Namespaces.Message.Local: .idBased(maxIncomingReadId: 0, maxOutgoingReadId: 0, maxKnownId: 0, count: 0, markedUnread: false)], chatMessagesNamespaces: Set([Namespaces.Message.Cloud, Namespaces.Message.Local, Namespaces.Message.SecretIncoming]), globalNotificationSettingsPreferencesKey: { transaction in - return transaction.getPreferencesEntry(PreferencesKeys.globalNotifications)?.get(GlobalNotificationSettings.self) - }, defaultGlobalNotificationSettings: GlobalNotificationSettings.defaultSettings) + }, + defaultGlobalNotificationSettings: PostboxGlobalNotificationSettings(defaultIncludePeer: { peer in + return GlobalNotificationSettings.defaultSettings.defaultIncludePeer(peer: peer) + }) + ) }() public enum AccountTransactionError { diff --git a/submodules/TelegramCore/Sources/SyncCore/SyncCore_SynchronizeAppLogEventsOperation.swift b/submodules/TelegramCore/Sources/SyncCore/SyncCore_SynchronizeAppLogEventsOperation.swift index de56774577..3970b41e43 100644 --- a/submodules/TelegramCore/Sources/SyncCore/SyncCore_SynchronizeAppLogEventsOperation.swift +++ b/submodules/TelegramCore/Sources/SyncCore/SyncCore_SynchronizeAppLogEventsOperation.swift @@ -5,18 +5,25 @@ private enum SynchronizeAppLogEventsOperationContentType: Int32 { case sync } -public enum SynchronizeAppLogEventsOperationContent: PostboxCoding { +public enum SynchronizeAppLogEventsOperationContent: Codable { case add(time: Double, type: String, peerId: PeerId?, data: JSON) case sync - public init(decoder: PostboxDecoder) { - switch decoder.decodeInt32ForKey("r", orElse: 0) { + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: StringCodingKey.self) + + switch try container.decode(Int32.self, forKey: "r") { case SynchronizeAppLogEventsOperationContentType.add.rawValue: var peerId: PeerId? - if let id = decoder.decodeOptionalInt64ForKey("p") { + if let id = try? container.decodeIfPresent(Int64.self, forKey: "p") { peerId = PeerId(id) } - self = .add(time: decoder.decodeDoubleForKey("tm", orElse: 0.0), type: decoder.decodeStringForKey("t", orElse: ""), peerId: peerId, data: decoder.decodeObjectForKey("d", decoder: { JSON(decoder: $0) }) as! JSON) + self = .add( + time: try container.decode(Double.self, forKey: "tm"), + type: try container.decode(String.self, forKey: "t"), + peerId: peerId, + data: try container.decode(JSON.self, forKey: "d") + ) case SynchronizeAppLogEventsOperationContentType.sync.rawValue: self = .sync default: @@ -24,37 +31,47 @@ public enum SynchronizeAppLogEventsOperationContent: PostboxCoding { self = .sync } } - - public func encode(_ encoder: PostboxEncoder) { + + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: StringCodingKey.self) + switch self { case let .add(time, type, peerId, data): - encoder.encodeInt32(SynchronizeAppLogEventsOperationContentType.add.rawValue, forKey: "r") - encoder.encodeDouble(time, forKey: "tm") - encoder.encodeString(type, forKey: "t") - if let peerId = peerId { - encoder.encodeInt64(peerId.toInt64(), forKey: "p") - } else { - encoder.encodeNil(forKey: "p") - } - encoder.encodeObject(data, forKey: "d") + try container.encode(SynchronizeAppLogEventsOperationContentType.add.rawValue, forKey: "r") + try container.encode(time, forKey: "tm") + try container.encode(type, forKey: "t") + try container.encodeIfPresent(peerId?.toInt64(), forKey: "p") + try container.encode(data, forKey: "d") case .sync: - encoder.encodeInt32(SynchronizeAppLogEventsOperationContentType.sync.rawValue, forKey: "r") + try container.encode(SynchronizeAppLogEventsOperationContentType.sync.rawValue, forKey: "r") } } } -public final class SynchronizeAppLogEventsOperation: PostboxCoding { +public final class SynchronizeAppLogEventsOperation: Codable, PostboxCoding { public let content: SynchronizeAppLogEventsOperationContent public init(content: SynchronizeAppLogEventsOperationContent) { self.content = content } - public init(decoder: PostboxDecoder) { - self.content = decoder.decodeObjectForKey("c", decoder: { SynchronizeAppLogEventsOperationContent(decoder: $0) }) as! SynchronizeAppLogEventsOperationContent + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: StringCodingKey.self) + + self.content = try container.decode(SynchronizeAppLogEventsOperationContent.self, forKey: "c") } + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: StringCodingKey.self) + + try container.encode(self.content, forKey: "c") + } + + public init(decoder: PostboxDecoder) { + self.content = decoder.decode(SynchronizeAppLogEventsOperationContent.self, forKey: "c")! + } + public func encode(_ encoder: PostboxEncoder) { - encoder.encodeObject(self.content, forKey: "c") + encoder.encode(self.content, forKey: "c") } } diff --git a/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramPeerNotificationSettings.swift b/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramPeerNotificationSettings.swift index 529efd76d7..afac21e3ea 100644 --- a/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramPeerNotificationSettings.swift +++ b/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramPeerNotificationSettings.swift @@ -59,6 +59,37 @@ public enum PeerMessageSound: Equatable { return .bundledModern(id: 0) } } + + static func decodeInline(_ container: PostboxDecoder) -> PeerMessageSound { + switch container.decodeInt32ForKey("s.v", orElse: 0) { + case PeerMessageSoundValue.none.rawValue: + return .none + case PeerMessageSoundValue.bundledModern.rawValue: + return .bundledModern(id: container.decodeInt32ForKey("s.i", orElse: 0)) + case PeerMessageSoundValue.bundledClassic.rawValue: + return .bundledClassic(id: container.decodeInt32ForKey("s.i", orElse: 0)) + case PeerMessageSoundValue.default.rawValue: + return .default + default: + assertionFailure() + return .bundledModern(id: 0) + } + } + + func encodeInline(_ container: inout KeyedEncodingContainer) throws { + switch self { + case .none: + try container.encode(PeerMessageSoundValue.none.rawValue, forKey: "s.v") + case let .bundledModern(id): + try container.encode(PeerMessageSoundValue.bundledModern.rawValue, forKey: "s.v") + try container.encode(id, forKey: "s.i") + case let .bundledClassic(id): + try container.encode(PeerMessageSoundValue.bundledClassic.rawValue, forKey: "s.v") + try container.encode(id, forKey: "s.i") + case .default: + try container.encode(PeerMessageSoundValue.default.rawValue, forKey: "s.v") + } + } func encodeInline(_ encoder: PostboxEncoder) { switch self { diff --git a/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramTheme.swift b/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramTheme.swift index 3a7c4d34f4..5253f971e7 100644 --- a/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramTheme.swift +++ b/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramTheme.swift @@ -14,7 +14,7 @@ public extension UInt32 { } } -public final class TelegramThemeSettings: PostboxCoding, Codable, Equatable { +public final class TelegramThemeSettings: PostboxCoding, Equatable { public static func == (lhs: TelegramThemeSettings, rhs: TelegramThemeSettings) -> Bool { if lhs.baseTheme != rhs.baseTheme { return false @@ -110,7 +110,7 @@ public final class TelegramThemeSettings: PostboxCoding, Codable, Equatable { } } -public final class TelegramTheme: Codable, OrderedItemListEntryContents, Equatable { +public final class TelegramTheme: OrderedItemListEntryContents, Equatable { public let id: Int64 public let accessHash: Int64 public let slug: String @@ -144,27 +144,6 @@ public final class TelegramTheme: Codable, OrderedItemListEntryContents, Equatab self.isDefault = decoder.decodeInt32ForKey("isDefault", orElse: 0) != 0 self.installCount = decoder.decodeOptionalInt32ForKey("installCount") } - - public init(from decoder: Decoder) throws { - let container = try decoder.container(keyedBy: StringCodingKey.self) - - self.id = try container.decode(Int64.self, forKey: "id") - self.accessHash = try container.decode(Int64.self, forKey: "accessHash") - self.slug = try container.decode(String.self, forKey: "slug") - self.title = try container.decode(String.self, forKey: "title") - - if let fileData = try container.decodeIfPresent(Data.self, forKey: "file") { - self.file = TelegramMediaFile(decoder: PostboxDecoder(buffer: MemoryBuffer(data: fileData))) - } else { - self.file = nil - } - - self.settings = try container.decodeIfPresent(TelegramThemeSettings.self, forKey: "settings") - - self.isCreator = (try container.decode(Int32.self, forKey: "isCreator")) != 0 - self.isDefault = (try container.decode(Int32.self, forKey: "isDefault")) != 0 - self.installCount = try container.decodeIfPresent(Int32.self, forKey: "installCount") - } public func encode(_ encoder: PostboxEncoder) { encoder.encodeInt64(self.id, forKey: "id") @@ -189,26 +168,6 @@ public final class TelegramTheme: Codable, OrderedItemListEntryContents, Equatab encoder.encodeNil(forKey: "installCount") } } - - public func encode(to encoder: Encoder) throws { - var container = encoder.container(keyedBy: StringCodingKey.self) - - try container.encode(self.id, forKey: "id") - try container.encode(self.accessHash, forKey: "accessHash") - try container.encode(self.slug, forKey: "slug") - try container.encode(self.title, forKey: "title") - if let file = self.file { - let innerEncoder = PostboxEncoder() - file.encode(innerEncoder) - try container.encode(innerEncoder.makeData(), forKey: "file") - } else { - try container.encodeNil(forKey: "file") - } - try container.encodeIfPresent(self.settings, forKey: "settings") - try container.encode((self.isCreator ? 1 : 0) as Int32, forKey: "isCreator") - try container.encode((self.isDefault ? 1 : 0) as Int32, forKey: "isDefault") - try container.encodeIfPresent(self.installCount, forKey: "installCount") - } public static func ==(lhs: TelegramTheme, rhs: TelegramTheme) -> Bool { if lhs.id != rhs.id { diff --git a/submodules/TelegramCore/Sources/SyncCore/SyncCore_ThemeSettings.swift b/submodules/TelegramCore/Sources/SyncCore/SyncCore_ThemeSettings.swift index 64191262a0..9a28cee8bd 100644 --- a/submodules/TelegramCore/Sources/SyncCore/SyncCore_ThemeSettings.swift +++ b/submodules/TelegramCore/Sources/SyncCore/SyncCore_ThemeSettings.swift @@ -10,13 +10,22 @@ public final class ThemeSettings: Codable, Equatable { public init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: StringCodingKey.self) - self.currentTheme = try container.decodeIfPresent(TelegramTheme.self, forKey: "t") + if let currentThemeData = try container.decodeIfPresent(AdaptedPostboxDecoder.RawObjectData.self, forKey: "t") { + self.currentTheme = TelegramTheme(decoder: PostboxDecoder(buffer: MemoryBuffer(data: currentThemeData.data))) + } else { + self.currentTheme = nil + } } public func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: StringCodingKey.self) - try container.encodeIfPresent(self.currentTheme, forKey: "t") + if let currentTheme = self.currentTheme { + let currentThemeData = PostboxEncoder().encodeObjectToRawData(currentTheme) + try container.encode(currentThemeData, forKey: "t") + } else { + try container.encodeNil(forKey: "t") + } } public static func ==(lhs: ThemeSettings, rhs: ThemeSettings) -> Bool { diff --git a/submodules/TelegramCore/Sources/TelegramEngine/AccountData/ChangeAccountPhoneNumber.swift b/submodules/TelegramCore/Sources/TelegramEngine/AccountData/ChangeAccountPhoneNumber.swift index da7e7916af..6364b4514a 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/AccountData/ChangeAccountPhoneNumber.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/AccountData/ChangeAccountPhoneNumber.swift @@ -114,6 +114,6 @@ func _internal_requestChangeAccountPhoneNumber(account: Account, phoneNumber: St updatePeers(transaction: transaction, peers: [user], update: { _, updated in return updated }) - } |> mapError { _ -> ChangeAccountPhoneNumberError in return .generic } + } |> mapError { _ -> ChangeAccountPhoneNumberError in } } } diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Auth/AuthTransfer.swift b/submodules/TelegramCore/Sources/TelegramEngine/Auth/AuthTransfer.swift index 21ceaf85e8..f12c3b4d16 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Auth/AuthTransfer.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Auth/AuthTransfer.swift @@ -35,9 +35,9 @@ func _internal_exportAuthTransferToken(accountManager: AccountManager mapToSignal { result -> Signal in switch result { - case let .password(password): + case let .password(_, _, _, _, hint, _, _, _, _, _): return account.postbox.transaction { transaction -> Api.auth.LoginToken? in - transaction.setState(UnauthorizedAccountState(isTestingEnvironment: account.testingEnvironment, masterDatacenterId: account.masterDatacenterId, contents: .passwordEntry(hint: password.hint ?? "", number: nil, code: nil, suggestReset: false, syncContacts: syncContacts))) + transaction.setState(UnauthorizedAccountState(isTestingEnvironment: account.testingEnvironment, masterDatacenterId: account.masterDatacenterId, contents: .passwordEntry(hint: hint ?? "", number: nil, code: nil, suggestReset: false, syncContacts: syncContacts))) return nil } |> castError(ExportAuthTransferTokenError.self) @@ -73,9 +73,9 @@ func _internal_exportAuthTransferToken(accountManager: AccountManager mapToSignal { result -> Signal in switch result { - case let .password(password): + case let .password(_, _, _, _, hint, _, _, _, _, _): return updatedAccount.postbox.transaction { transaction -> Api.auth.LoginToken? in - transaction.setState(UnauthorizedAccountState(isTestingEnvironment: updatedAccount.testingEnvironment, masterDatacenterId: updatedAccount.masterDatacenterId, contents: .passwordEntry(hint: password.hint ?? "", number: nil, code: nil, suggestReset: false, syncContacts: syncContacts))) + transaction.setState(UnauthorizedAccountState(isTestingEnvironment: updatedAccount.testingEnvironment, masterDatacenterId: updatedAccount.masterDatacenterId, contents: .passwordEntry(hint: hint ?? "", number: nil, code: nil, suggestReset: false, syncContacts: syncContacts))) return nil } |> castError(ExportAuthTransferTokenError.self) @@ -130,7 +130,7 @@ func _internal_exportAuthTransferToken(accountManager: AccountManager castError(ExportAuthTransferTokenError.self) |> switchToLatest - case let .authorizationSignUpRequired: + case .authorizationSignUpRequired: return .fail(.generic) } } diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Auth/TwoStepVerification.swift b/submodules/TelegramCore/Sources/TelegramEngine/Auth/TwoStepVerification.swift index ff04a4c1c0..c87dd353b5 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Auth/TwoStepVerification.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Auth/TwoStepVerification.swift @@ -15,11 +15,11 @@ func _internal_twoStepVerificationConfiguration(account: Account) -> Signal retryRequest |> map { result -> TwoStepVerificationConfiguration in switch result { - case let .password(password): - if password.currentAlgo != nil { - return .set(hint: password.hint ?? "", hasRecoveryEmail: (password.flags & (1 << 0)) != 0, pendingEmail: password.emailUnconfirmedPattern.flatMap({ TwoStepVerificationPendingEmail(pattern: $0, codeLength: nil) }), hasSecureValues: (password.flags & (1 << 1)) != 0, pendingResetTimestamp: password.pendingResetDate) + case let .password(flags, currentAlgo, _, _, hint, emailUnconfirmedPattern, _, _, _, pendingResetDate): + if currentAlgo != nil { + return .set(hint: hint ?? "", hasRecoveryEmail: (flags & (1 << 0)) != 0, pendingEmail: emailUnconfirmedPattern.flatMap({ TwoStepVerificationPendingEmail(pattern: $0, codeLength: nil) }), hasSecureValues: (flags & (1 << 1)) != 0, pendingResetTimestamp: pendingResetDate) } else { - return .notSet(pendingEmail: password.emailUnconfirmedPattern.flatMap({ TwoStepVerificationPendingEmail(pattern: $0, codeLength: nil) })) + return .notSet(pendingEmail: emailUnconfirmedPattern.flatMap({ TwoStepVerificationPendingEmail(pattern: $0, codeLength: nil) })) } } } diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Contacts/ContactManagement.swift b/submodules/TelegramCore/Sources/TelegramEngine/Contacts/ContactManagement.swift index 74ab3af05c..98a2b5f991 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Contacts/ContactManagement.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Contacts/ContactManagement.swift @@ -5,7 +5,9 @@ import SwiftSignalKit import CryptoUtils private func md5(_ data: Data) -> Data { - return data.withUnsafeBytes { bytes -> Data in + return data.withUnsafeBytes { rawBytes -> Data in + let bytes = rawBytes.baseAddress! + return CryptoMD5(bytes, Int32(data.count)) } } diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Contacts/UpdateContactName.swift b/submodules/TelegramCore/Sources/TelegramEngine/Contacts/UpdateContactName.swift index 471faaa5ba..6daaab4baa 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Contacts/UpdateContactName.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Contacts/UpdateContactName.swift @@ -24,6 +24,6 @@ func _internal_updateContactName(account: Account, peerId: PeerId, firstName: St return .fail(.generic) } } - |> mapError { _ -> UpdateContactNameError in return .generic } + |> mapError { _ -> UpdateContactNameError in } |> switchToLatest } diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Data/Configuration.swift b/submodules/TelegramCore/Sources/TelegramEngine/Data/Configuration.swift index 48f702ccad..d196aa0f54 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Data/Configuration.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Data/Configuration.swift @@ -83,7 +83,7 @@ public extension TelegramEngine.EngineData.Item { guard let view = view as? PreferencesView else { preconditionFailure() } - guard let limitsConfiguration = view.values[PreferencesKeys.limitsConfiguration] as? LimitsConfiguration else { + guard let limitsConfiguration = view.values[PreferencesKeys.limitsConfiguration]?.get(LimitsConfiguration.self) else { return EngineConfiguration.Limits(LimitsConfiguration.defaultValue) } return EngineConfiguration.Limits(limitsConfiguration) diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Localization/LocalizationInfo.swift b/submodules/TelegramCore/Sources/TelegramEngine/Localization/LocalizationInfo.swift index cc0332797b..838c889580 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Localization/LocalizationInfo.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Localization/LocalizationInfo.swift @@ -6,8 +6,8 @@ import TelegramApi extension LocalizationInfo { init(apiLanguage: Api.LangPackLanguage) { switch apiLanguage { - case let .langPackLanguage(language): - self.init(languageCode: language.langCode, baseLanguageCode: language.baseLangCode, customPluralizationCode: language.pluralCode, title: language.name, localizedTitle: language.nativeName, isOfficial: (language.flags & (1 << 0)) != 0, totalStringCount: language.stringsCount, translatedStringCount: language.translatedCount, platformUrl: language.translationsUrl) + case let .langPackLanguage(flags, name, nativeName, langCode, baseLangCode, pluralCode, stringsCount, translatedCount, translationsUrl): + self.init(languageCode: langCode, baseLanguageCode: baseLangCode, customPluralizationCode: pluralCode, title: name, localizedTitle: nativeName, isOfficial: (flags & (1 << 0)) != 0, totalStringCount: stringsCount, translatedStringCount: translatedCount, platformUrl: translationsUrl) } } } diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Localization/Localizations.swift b/submodules/TelegramCore/Sources/TelegramEngine/Localization/Localizations.swift index 172f3e09f0..a2533fb7c7 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Localization/Localizations.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Localization/Localizations.swift @@ -9,8 +9,8 @@ func _internal_currentlySuggestedLocalization(network: Network, extractKeys: [St |> retryRequest |> mapToSignal { result -> Signal in switch result { - case let .config(config): - if let suggestedLangCode = config.suggestedLangCode { + case let .config(_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, suggestedLangCode, _, _): + if let suggestedLangCode = suggestedLangCode { return _internal_suggestedLocalizationInfo(network: network, languageCode: suggestedLangCode, extractKeys: extractKeys) |> map(Optional.init) } else { return .single(nil) diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Messages/ChatList.swift b/submodules/TelegramCore/Sources/TelegramEngine/Messages/ChatList.swift index bf2a88a5e6..5023bcdef8 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Messages/ChatList.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Messages/ChatList.swift @@ -116,7 +116,7 @@ public extension EngineChatList.Group { extension EngineChatList.Item { convenience init?(_ entry: ChatListEntry) { switch entry { - case let .MessageEntry(index, messages, readState, isRemovedFromTotalUnreadCount, embeddedInterfaceState, renderedPeer, presence, summaryInfo, hasFailed, isContact): + case let .MessageEntry(index, messages, readState, isRemovedFromTotalUnreadCount, _, renderedPeer, presence, summaryInfo, hasFailed, isContact): self.init( index: index, messages: messages.map(EngineMessage.init), diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Messages/ExportMessageLink.swift b/submodules/TelegramCore/Sources/TelegramEngine/Messages/ExportMessageLink.swift index 66c64fce1e..2be0e7f592 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Messages/ExportMessageLink.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Messages/ExportMessageLink.swift @@ -5,7 +5,7 @@ import SwiftSignalKit func _internal_exportMessageLink(account: Account, peerId: PeerId, messageId: MessageId, isThread: Bool = false) -> Signal { return account.postbox.transaction { transaction -> (Peer, MessageId)? in - var peer: Peer? = transaction.getPeer(messageId.peerId) + let peer: Peer? = transaction.getPeer(messageId.peerId) if let peer = peer { return (peer, messageId) } else { diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Messages/OutgoingMessageWithChatContextResult.swift b/submodules/TelegramCore/Sources/TelegramEngine/Messages/OutgoingMessageWithChatContextResult.swift index 983c0ecc2e..16ab23533f 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Messages/OutgoingMessageWithChatContextResult.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Messages/OutgoingMessageWithChatContextResult.swift @@ -132,7 +132,7 @@ private func outgoingMessageWithChatContextResult(to peerId: PeerId, results: Ch return .message(text: caption, attributes: attributes, mediaReference: nil, replyToMessageId: replyToMessageId, localGroupingKey: nil, correlationId: correlationId) } } - case let .text(text, entities, disableUrlPreview, replyMarkup): + case let .text(text, entities, _, replyMarkup): if let entities = entities { attributes.append(entities) } diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Messages/Polls.swift b/submodules/TelegramCore/Sources/TelegramEngine/Messages/Polls.swift index e8edd1a520..2f95cd54c3 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Messages/Polls.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Messages/Polls.swift @@ -31,7 +31,7 @@ func _internal_requestMessageSelectPollOption(account: Account, messageId: Messa resultPoll = transaction.getMedia(pollId) as? TelegramMediaPoll if let poll = poll { switch poll { - case let .poll(id, flags, question, answers, closePeriod, _): + case let .poll(_, flags, question, answers, closePeriod, _): let publicity: TelegramMediaPollPublicity if (flags & (1 << 1)) != 0 { publicity = .public @@ -45,15 +45,13 @@ func _internal_requestMessageSelectPollOption(account: Account, messageId: Messa kind = .poll(multipleAnswers: (flags & (1 << 2)) != 0) } resultPoll = TelegramMediaPoll(pollId: pollId, publicity: publicity, kind: kind, text: question, options: answers.map(TelegramMediaPollOption.init(apiOption:)), correctAnswers: nil, results: TelegramMediaPollResults(apiResults: results), isClosed: (flags & (1 << 0)) != 0, deadlineTimeout: closePeriod) - default: - break } } let resultsMin: Bool switch results { - case let .pollResults(pollResults): - resultsMin = (pollResults.flags & (1 << 0)) != 0 + case let .pollResults(flags, _, _, _, _, _): + resultsMin = (flags & (1 << 0)) != 0 } resultPoll = resultPoll?.withUpdatedResults(TelegramMediaPollResults(apiResults: results), min: resultsMin) diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Messages/RequestChatContextResults.swift b/submodules/TelegramCore/Sources/TelegramEngine/Messages/RequestChatContextResults.swift index 477ccd8f14..14f865ad8f 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Messages/RequestChatContextResults.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Messages/RequestChatContextResults.swift @@ -115,7 +115,7 @@ func _internal_requestChatContextResults(account: Account, botId: PeerId, peerId } if let (latitude, longitude) = location { flags |= (1 << 0) - var geoPointFlags: Int32 = 0 + let geoPointFlags: Int32 = 0 geoPoint = Api.InputGeoPoint.inputGeoPoint(flags: geoPointFlags, lat: latitude, long: longitude, accuracyRadius: nil) } diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Messages/RequestStartBot.swift b/submodules/TelegramCore/Sources/TelegramEngine/Messages/RequestStartBot.swift index 82f3cf7ae4..e26a6025b3 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Messages/RequestStartBot.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Messages/RequestStartBot.swift @@ -44,7 +44,7 @@ func _internal_requestStartBotInGroup(account: Account, botPeerId: PeerId, group return account.postbox.transaction { transaction -> (Peer?, Peer?) in return (transaction.getPeer(botPeerId), transaction.getPeer(groupPeerId)) } - |> mapError { _ -> RequestStartBotInGroupError in return .generic } + |> mapError { _ -> RequestStartBotInGroupError in } |> mapToSignal { botPeer, groupPeer -> Signal in if let botPeer = botPeer, let inputUser = apiInputUser(botPeer), let groupPeer = groupPeer, let inputGroup = apiInputPeer(groupPeer) { let request = account.network.request(Api.functions.messages.startBot(bot: inputUser, peer: inputGroup, randomId: Int64.random(in: Int64.min ... Int64.max), startParam: payload ?? "")) @@ -55,8 +55,7 @@ func _internal_requestStartBotInGroup(account: Account, botPeerId: PeerId, group account.stateManager.addUpdates(result) if groupPeerId.namespace == Namespaces.Peer.CloudChannel { return _internal_fetchChannelParticipant(account: account, peerId: groupPeerId, participantId: botPeerId) - |> mapError { _ -> RequestStartBotInGroupError in return .generic - } + |> mapError { _ -> RequestStartBotInGroupError in } |> mapToSignal { participant -> Signal in return account.postbox.transaction { transaction -> StartBotInGroupResult in if let participant = participant, let peer = transaction.getPeer(participant.peerId) { @@ -69,8 +68,7 @@ func _internal_requestStartBotInGroup(account: Account, botPeerId: PeerId, group return .none } } - |> mapError { _ -> RequestStartBotInGroupError in return .generic - } + |> mapError { _ -> RequestStartBotInGroupError in } } } else { return .single(.none) diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Messages/SearchMessages.swift b/submodules/TelegramCore/Sources/TelegramEngine/Messages/SearchMessages.swift index 282b3f5686..8e9b879f1f 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Messages/SearchMessages.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Messages/SearchMessages.swift @@ -458,7 +458,6 @@ func _internal_downloadMessage(postbox: Postbox, network: Network, messageId: Me } } |> `catch` { _ -> Signal in - return .single(nil) } } } @@ -557,7 +556,6 @@ func fetchRemoteMessage(postbox: Postbox, source: FetchMessageHistoryHoleSource, } } |> `catch` { _ -> Signal in - return .single(nil) } } diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Messages/UpdatePinnedMessage.swift b/submodules/TelegramCore/Sources/TelegramEngine/Messages/UpdatePinnedMessage.swift index 621263a476..d50898bcd2 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Messages/UpdatePinnedMessage.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Messages/UpdatePinnedMessage.swift @@ -19,7 +19,6 @@ func _internal_requestUpdatePinnedMessage(account: Account, peerId: PeerId, upda return (transaction.getPeer(peerId), transaction.getPeerCachedData(peerId: peerId)) } |> mapError { _ -> UpdatePinnedMessageError in - return .generic } |> mapToSignal { peer, cachedPeerData -> Signal in guard let peer = peer, let inputPeer = apiInputPeer(peer) else { @@ -105,7 +104,6 @@ func _internal_requestUpdatePinnedMessage(account: Account, peerId: PeerId, upda } } |> mapError { _ -> UpdatePinnedMessageError in - return .generic } } } @@ -116,7 +114,6 @@ func _internal_requestUnpinAllMessages(account: Account, peerId: PeerId) -> Sign return (transaction.getPeer(peerId), transaction.getPeerCachedData(peerId: peerId)) } |> mapError { _ -> UpdatePinnedMessageError in - return .generic } |> mapToSignal { peer, cachedPeerData -> Signal in guard let peer = peer, let inputPeer = apiInputPeer(peer) else { diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Payments/BotPaymentForm.swift b/submodules/TelegramCore/Sources/TelegramEngine/Payments/BotPaymentForm.swift index 8c50af3d59..2ec581e49c 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Payments/BotPaymentForm.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Payments/BotPaymentForm.swift @@ -477,7 +477,7 @@ func _internal_requestBotPaymentReceipt(account: Account, messageId: MessageId) |> mapToSignal { result -> Signal in return account.postbox.transaction { transaction -> BotPaymentReceipt in switch result { - case let .paymentReceipt(flags, date, botId, providerId, title, description, photo, invoice, info, shipping, tipAmount, currency, totalAmount, credentialsTitle, users): + case let .paymentReceipt(_, _, botId, _, title, description, photo, invoice, info, shipping, tipAmount, currency, totalAmount, credentialsTitle, users): var peers: [Peer] = [] for user in users { peers.append(TelegramUser(user: user)) diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Peers/ChannelOwnershipTransfer.swift b/submodules/TelegramCore/Sources/TelegramEngine/Peers/ChannelOwnershipTransfer.swift index 9df47f95f4..1e5cdb1a5e 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Peers/ChannelOwnershipTransfer.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Peers/ChannelOwnershipTransfer.swift @@ -77,8 +77,7 @@ func _internal_updateChannelOwnership(account: Account, accountStateManager: Acc } return combineLatest(_internal_fetchChannelParticipant(account: account, peerId: channelId, participantId: account.peerId), _internal_fetchChannelParticipant(account: account, peerId: channelId, participantId: memberId)) - |> mapError { error -> ChannelOwnershipTransferError in - return .generic + |> mapError { _ -> ChannelOwnershipTransferError in } |> mapToSignal { currentCreator, currentParticipant -> Signal<[(ChannelParticipant?, RenderedChannelParticipant)], ChannelOwnershipTransferError> in return account.postbox.transaction { transaction -> Signal<[(ChannelParticipant?, RenderedChannelParticipant)], ChannelOwnershipTransferError> in @@ -185,14 +184,14 @@ func _internal_updateChannelOwnership(account: Account, accountStateManager: Acc } return [(currentCreator, RenderedChannelParticipant(participant: updatedPreviousCreator, peer: accountUser, peers: peers, presences: presences)), (currentParticipant, RenderedChannelParticipant(participant: updatedParticipant, peer: user, peers: peers, presences: presences))] } - |> mapError { _ -> ChannelOwnershipTransferError in return .generic } + |> mapError { _ -> ChannelOwnershipTransferError in } } } } else { return .fail(.generic) } } - |> mapError { _ -> ChannelOwnershipTransferError in return .generic } + |> mapError { _ -> ChannelOwnershipTransferError in } |> switchToLatest } } diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Peers/ChatListFiltering.swift b/submodules/TelegramCore/Sources/TelegramEngine/Peers/ChatListFiltering.swift index ad610f577f..729ee284da 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Peers/ChatListFiltering.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Peers/ChatListFiltering.swift @@ -277,9 +277,9 @@ public struct ChatListFilter: Codable, Equatable { try container.encodeIfPresent(self.emoticon, forKey: "emoticon") try container.encode(self.data.categories.rawValue, forKey: "categories") - try container.encode(self.data.excludeMuted ? 1 : 0, forKey: "excludeMuted") - try container.encode(self.data.excludeRead ? 1 : 0, forKey: "excludeRead") - try container.encode(self.data.excludeArchived ? 1 : 0, forKey: "excludeArchived") + try container.encode((self.data.excludeMuted ? 1 : 0) as Int32, forKey: "excludeMuted") + try container.encode((self.data.excludeRead ? 1 : 0) as Int32, forKey: "excludeRead") + try container.encode((self.data.excludeArchived ? 1 : 0) as Int32, forKey: "excludeArchived") try container.encode(self.data.includePeers.peers.map { $0.toInt64() }, forKey: "includePeers") try container.encode(self.data.includePeers.pinnedPeers.map { $0.toInt64() }, forKey: "pinnedPeers") try container.encode(self.data.excludePeers.map { $0.toInt64() }, forKey: "excludePeers") diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Peers/ConvertGroupToSupergroup.swift b/submodules/TelegramCore/Sources/TelegramEngine/Peers/ConvertGroupToSupergroup.swift index 26f89f9310..f126fde254 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Peers/ConvertGroupToSupergroup.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Peers/ConvertGroupToSupergroup.swift @@ -39,7 +39,6 @@ func _internal_convertGroupToSupergroup(account: Account, peerId: PeerId) -> Sig return createdPeerId } |> mapError { _ -> ConvertGroupToSupergroupError in - return .generic } |> timeout(5.0, queue: Queue.concurrentDefaultQueue(), alternate: .fail(.generic)) } @@ -64,6 +63,6 @@ public func convertGroupToGigagroup(account: Account, peerId: PeerId) -> Signal< return .complete() } } - |> mapError { _ -> ConvertGroupToGigagroupError in return .generic } + |> mapError { _ -> ConvertGroupToGigagroupError in } |> switchToLatest } diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Peers/CreateSecretChat.swift b/submodules/TelegramCore/Sources/TelegramEngine/Peers/CreateSecretChat.swift index 7d57209fb7..5a909d36b8 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Peers/CreateSecretChat.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Peers/CreateSecretChat.swift @@ -13,7 +13,7 @@ func _internal_createSecretChat(account: Account, peerId: PeerId) -> Signal Signal in if let peer = transaction.getPeer(peerId), let inputUser = apiInputUser(peer) { return validatedEncryptionConfig(postbox: account.postbox, network: account.network) - |> mapError { _ -> CreateSecretChatError in return .generic } + |> mapError { _ -> CreateSecretChatError in } |> mapToSignal { config -> Signal in let aBytes = malloc(256)! let _ = SecRandomCopyBytes(nil, 256, aBytes.assumingMemoryBound(to: UInt8.self)) @@ -43,11 +43,11 @@ func _internal_createSecretChat(account: Account, peerId: PeerId) -> Signal mapError { _ -> CreateSecretChatError in return .generic } + } |> mapError { _ -> CreateSecretChatError in } } } } else { return .fail(.generic) } - } |> mapError { _ -> CreateSecretChatError in return .generic } |> switchToLatest + } |> mapError { _ -> CreateSecretChatError in } |> switchToLatest } diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Peers/InactiveChannels.swift b/submodules/TelegramCore/Sources/TelegramEngine/Peers/InactiveChannels.swift index 718fd44925..da0d646349 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Peers/InactiveChannels.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Peers/InactiveChannels.swift @@ -24,16 +24,16 @@ func _internal_inactiveChannelList(network: Network) -> Signal<[InactiveChannel] |> retryRequest |> map { result in switch result { - case let .inactiveChats(dates, chats, users): + case let .inactiveChats(dates, chats, _): let channels = chats.compactMap { parseTelegramGroupOrChannel(chat: $0) } var participantsCounts: [PeerId: Int32] = [:] for chat in chats { switch chat { - case let .channel(channel): - if let participantsCountValue = channel.participantsCount { - participantsCounts[chat.peerId] = channel.participantsCount + case let .channel(_, _, _, _, _, _, _, _, _, _, _, participantsCountValue): + if let participantsCountValue = participantsCountValue { + participantsCounts[chat.peerId] = participantsCountValue } default: break diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Peers/InvitationLinks.swift b/submodules/TelegramCore/Sources/TelegramEngine/Peers/InvitationLinks.swift index e7ce8e3463..115e641426 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Peers/InvitationLinks.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Peers/InvitationLinks.swift @@ -109,7 +109,7 @@ func _internal_editPeerExportedInvitation(account: Account, peerId: PeerId, link } else { return nil } - } |> mapError { _ in .generic } + } |> mapError { _ -> EditPeerExportedInvitationError in } } } else { return .complete() @@ -179,7 +179,7 @@ func _internal_revokePeerExportedInvitation(account: Account, peerId: PeerId, li } else { return nil } - } |> mapError { _ in .generic } + } |> mapError { _ -> RevokePeerExportedInvitationError in } } } else { return .complete() diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Peers/JoinLink.swift b/submodules/TelegramCore/Sources/TelegramEngine/Peers/JoinLink.swift index deb87d78ed..2f20cf0c0c 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Peers/JoinLink.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Peers/JoinLink.swift @@ -67,9 +67,9 @@ func _internal_joinLinkInformation(_ hash: String, account: Account) -> Signal mapToSignal { (result) -> Signal in if let result = result { switch result { - case let .chatInvite(invite): - let photo = telegramMediaImageFromApiPhoto(invite.photo).flatMap({ smallestImageRepresentation($0.representations) }) - return .single(.invite(title: invite.title, photoRepresentation: photo, participantsCount: invite.participantsCount, participants: invite.participants?.map({TelegramUser(user: $0)}))) + case let .chatInvite(_, title, invitePhoto, participantsCount, participants): + let photo = telegramMediaImageFromApiPhoto(invitePhoto).flatMap({ smallestImageRepresentation($0.representations) }) + return .single(.invite(title: title, photoRepresentation: photo, participantsCount: participantsCount, participants: participants?.map({TelegramUser(user: $0)}))) case let .chatInviteAlready(chat): if let peer = parseTelegramGroupOrChannel(chat: chat) { return account.postbox.transaction({ (transaction) -> ExternalJoiningChatState in diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Peers/ManageChannelDiscussionGroup.swift b/submodules/TelegramCore/Sources/TelegramEngine/Peers/ManageChannelDiscussionGroup.swift index f905aae793..8f6a35ba9e 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Peers/ManageChannelDiscussionGroup.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Peers/ManageChannelDiscussionGroup.swift @@ -42,7 +42,7 @@ func _internal_updateGroupDiscussionForChannel(network: Network, postbox: Postbo return postbox.transaction { transaction -> (channel: Peer?, group: Peer?) in return (channel: channelId.flatMap(transaction.getPeer), group: groupId.flatMap(transaction.getPeer)) } - |> mapError { _ in ChannelDiscussionGroupError.generic } + |> mapError { _ -> ChannelDiscussionGroupError in } |> mapToSignal { channel, group -> Signal in let apiChannel = channel.flatMap(apiInputChannel) ?? Api.InputChannel.inputChannelEmpty let apiGroup = group.flatMap(apiInputChannel) ?? Api.InputChannel.inputChannelEmpty diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Peers/PeerPhotoUpdater.swift b/submodules/TelegramCore/Sources/TelegramEngine/Peers/PeerPhotoUpdater.swift index f5888f1e09..9e5d775178 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Peers/PeerPhotoUpdater.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Peers/PeerPhotoUpdater.swift @@ -72,7 +72,7 @@ func _internal_updatePeerPhoto(postbox: Postbox, network: Network, stateManager: func _internal_updatePeerPhotoInternal(postbox: Postbox, network: Network, stateManager: AccountStateManager?, accountPeerId: PeerId, peer: Signal, photo: Signal?, video: Signal?, videoStartTimestamp: Double?, mapResourceToAvatarSizes: @escaping (MediaResource, [TelegramMediaImageRepresentation]) -> Signal<[Int: Data], NoError>) -> Signal { return peer - |> mapError { _ in return .generic } + |> mapError { _ -> UploadPeerPhotoError in } |> mapToSignal { peer -> Signal in if let photo = photo { let mappedPhoto = photo @@ -99,7 +99,7 @@ func _internal_updatePeerPhotoInternal(postbox: Postbox, network: Network, state } return combineLatest(mappedPhoto, mappedVideo) - |> mapError { _ -> UploadPeerPhotoError in return .generic } + |> mapError { _ -> UploadPeerPhotoError in } |> mapToSignal { photoResult, videoResult -> Signal<(UpdatePeerPhotoStatus, MediaResource?, MediaResource?), UploadPeerPhotoError> in switch photoResult.content { case .error: @@ -200,7 +200,7 @@ func _internal_updatePeerPhotoInternal(postbox: Postbox, network: Network, state }) } return (.complete(representations), photoResult.resource, videoResult?.resource) - } |> mapError {_ in return UploadPeerPhotoError.generic} + } |> mapError { _ -> UploadPeerPhotoError in } } } else { var flags: Int32 = (1 << 0) @@ -248,7 +248,7 @@ func _internal_updatePeerPhotoInternal(postbox: Postbox, network: Network, state }) return (.complete(groupOrChannel.profileImageRepresentations), photoResult.resource, videoResult?.resource) } - |> mapError { _ in return .generic } + |> mapError { _ -> UploadPeerPhotoError in } } } } @@ -322,7 +322,7 @@ func _internal_updatePeerPhotoInternal(postbox: Postbox, network: Network, state }) return .complete(groupOrChannel.profileImageRepresentations) } - |> mapError { _ in return .generic } + |> mapError { _ -> UploadPeerPhotoError in } } } } diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Peers/RequestUserPhotos.swift b/submodules/TelegramCore/Sources/TelegramEngine/Peers/RequestUserPhotos.swift index 0463c673b2..4e430287c1 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Peers/RequestUserPhotos.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Peers/RequestUserPhotos.swift @@ -40,12 +40,12 @@ func _internal_requestPeerPhotos(postbox: Postbox, network: Network, peerId: Pee let totalCount:Int let photos: [Api.Photo] switch result { - case let .photos(data): - photos = data.photos + case let .photos(photosValue, _): + photos = photosValue totalCount = photos.count - case let .photosSlice(data): - photos = data.photos - totalCount = Int(data.count) + case let .photosSlice(count, photosValue, _): + photos = photosValue + totalCount = Int(count) } var images: [TelegramPeerPhoto] = [] diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Peers/SearchPeers.swift b/submodules/TelegramCore/Sources/TelegramEngine/Peers/SearchPeers.swift index d01b5d46fc..c6bc6cd994 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Peers/SearchPeers.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Peers/SearchPeers.swift @@ -44,8 +44,8 @@ func _internal_searchPeers(account: Account, query: String) -> Signal<([FoundPee peers[groupOrChannel.id] = groupOrChannel switch chat { /*feed*/ - case let .channel(channel): - if let participantsCount = channel.participantsCount { + case let .channel(_, _, _, _, _, _, _, _, _, _, _, participantsCount): + if let participantsCount = participantsCount { subscribers[groupOrChannel.id] = participantsCount } default: diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Peers/TogglePeerChatPinned.swift b/submodules/TelegramCore/Sources/TelegramEngine/Peers/TogglePeerChatPinned.swift index b9fb6232b4..46cb72da73 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Peers/TogglePeerChatPinned.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Peers/TogglePeerChatPinned.swift @@ -37,7 +37,7 @@ func _internal_toggleItemPinned(postbox: Postbox, location: TogglePeerChatPinned additionalCount = 1 } - let limitsConfiguration = transaction.getPreferencesEntry(key: PreferencesKeys.limitsConfiguration) as? LimitsConfiguration ?? LimitsConfiguration.defaultValue + let limitsConfiguration = transaction.getPreferencesEntry(key: PreferencesKeys.limitsConfiguration)?.get(LimitsConfiguration.self) ?? LimitsConfiguration.defaultValue let limitCount: Int if case .root = groupId { limitCount = Int(limitsConfiguration.maxPinnedChatCount) diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Peers/UpdateCachedPeerData.swift b/submodules/TelegramCore/Sources/TelegramEngine/Peers/UpdateCachedPeerData.swift index a2bfc8fc3c..5a0c0c34a7 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Peers/UpdateCachedPeerData.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Peers/UpdateCachedPeerData.swift @@ -171,15 +171,15 @@ func _internal_fetchAndUpdateCachedPeerData(accountPeerId: PeerId, peerId rawPee |> mapToSignal { result -> Signal in return postbox.transaction { transaction -> Bool in switch result { - case let .userFull(userFull): - if let telegramUser = TelegramUser.merge(transaction.getPeer(userFull.user.peerId) as? TelegramUser, rhs: userFull.user) { + case let .userFull(_, userFullUser, _, _, _, userFullNotifySettings, _, _, _, _, _, _): + if let telegramUser = TelegramUser.merge(transaction.getPeer(userFullUser.peerId) as? TelegramUser, rhs: userFullUser) { updatePeers(transaction: transaction, peers: [telegramUser], update: { _, updated -> Peer in return updated }) } - transaction.updateCurrentPeerNotificationSettings([peerId: TelegramPeerNotificationSettings(apiSettings: userFull.notifySettings)]) - if let presence = TelegramUserPresence(apiUser: userFull.user) { - updatePeerPresences(transaction: transaction, accountPeerId: accountPeerId, peerPresences: [userFull.user.peerId: presence]) + transaction.updateCurrentPeerNotificationSettings([peerId: TelegramPeerNotificationSettings(apiSettings: userFullNotifySettings)]) + if let presence = TelegramUserPresence(apiUser: userFullUser) { + updatePeerPresences(transaction: transaction, accountPeerId: accountPeerId, peerPresences: [userFullUser.peerId: presence]) } } transaction.updatePeerCachedData(peerIds: [peerId], update: { peerId, current in @@ -190,27 +190,25 @@ func _internal_fetchAndUpdateCachedPeerData(accountPeerId: PeerId, peerId rawPee previous = CachedUserData() } switch result { - case let .userFull(userFull): - let botInfo = userFull.botInfo.flatMap(BotInfo.init(apiBotInfo:)) - let isBlocked = (userFull.flags & (1 << 0)) != 0 - let voiceCallsAvailable = (userFull.flags & (1 << 4)) != 0 - var videoCallsAvailable = (userFull.flags & (1 << 13)) != 0 - #if DEBUG - videoCallsAvailable = true - #endif - let callsPrivate = (userFull.flags & (1 << 5)) != 0 - let canPinMessages = (userFull.flags & (1 << 7)) != 0 - let pinnedMessageId = userFull.pinnedMsgId.flatMap({ MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: $0) }) + case let .userFull(userFullFlags, _, userFullAbout, userFullSettings, _, _, userFullBotInfo, userFullPinnedMsgId, userFullCommonChatsCount, _, userFullTtlPeriod, userFullThemeEmoticon): + let botInfo = userFullBotInfo.flatMap(BotInfo.init(apiBotInfo:)) + let isBlocked = (userFullFlags & (1 << 0)) != 0 + let voiceCallsAvailable = (userFullFlags & (1 << 4)) != 0 + let videoCallsAvailable = (userFullFlags & (1 << 13)) != 0 + + let callsPrivate = (userFullFlags & (1 << 5)) != 0 + let canPinMessages = (userFullFlags & (1 << 7)) != 0 + let pinnedMessageId = userFullPinnedMsgId.flatMap({ MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: $0) }) - let peerStatusSettings = PeerStatusSettings(apiSettings: userFull.settings) + let peerStatusSettings = PeerStatusSettings(apiSettings: userFullSettings) - let hasScheduledMessages = (userFull.flags & 1 << 12) != 0 + let hasScheduledMessages = (userFullFlags & 1 << 12) != 0 - let autoremoveTimeout: CachedPeerAutoremoveTimeout = .known(CachedPeerAutoremoveTimeout.Value(userFull.ttlPeriod)) + let autoremoveTimeout: CachedPeerAutoremoveTimeout = .known(CachedPeerAutoremoveTimeout.Value(userFullTtlPeriod)) - return previous.withUpdatedAbout(userFull.about).withUpdatedBotInfo(botInfo).withUpdatedCommonGroupCount(userFull.commonChatsCount).withUpdatedIsBlocked(isBlocked).withUpdatedVoiceCallsAvailable(voiceCallsAvailable).withUpdatedVideoCallsAvailable(videoCallsAvailable).withUpdatedCallsPrivate(callsPrivate).withUpdatedCanPinMessages(canPinMessages).withUpdatedPeerStatusSettings(peerStatusSettings).withUpdatedPinnedMessageId(pinnedMessageId).withUpdatedHasScheduledMessages(hasScheduledMessages) + return previous.withUpdatedAbout(userFullAbout).withUpdatedBotInfo(botInfo).withUpdatedCommonGroupCount(userFullCommonChatsCount).withUpdatedIsBlocked(isBlocked).withUpdatedVoiceCallsAvailable(voiceCallsAvailable).withUpdatedVideoCallsAvailable(videoCallsAvailable).withUpdatedCallsPrivate(callsPrivate).withUpdatedCanPinMessages(canPinMessages).withUpdatedPeerStatusSettings(peerStatusSettings).withUpdatedPinnedMessageId(pinnedMessageId).withUpdatedHasScheduledMessages(hasScheduledMessages) .withUpdatedAutoremoveTimeout(autoremoveTimeout) - .withUpdatedThemeEmoticon(userFull.themeEmoticon) + .withUpdatedThemeEmoticon(userFullThemeEmoticon) } }) return true @@ -224,16 +222,16 @@ func _internal_fetchAndUpdateCachedPeerData(accountPeerId: PeerId, peerId rawPee switch result { case let .chatFull(fullChat, chats, users): switch fullChat { - case let .chatFull(chatFull): - transaction.updateCurrentPeerNotificationSettings([peerId: TelegramPeerNotificationSettings(apiSettings: chatFull.notifySettings)]) + case let .chatFull(_, _, _, _, _, notifySettings, _, _, _, _, _, _, _, _): + transaction.updateCurrentPeerNotificationSettings([peerId: TelegramPeerNotificationSettings(apiSettings: notifySettings)]) case .channelFull: break } switch fullChat { - case let .chatFull(chatFull): + case let .chatFull(chatFullFlags, _, chatFullAbout, chatFullParticipants, chatFullChatPhoto, _, chatFullExportedInvite, chatFullBotInfo, chatFullPinnedMsgId, _, chatFullCall, _, chatFullGroupcallDefaultJoinAs, chatFullThemeEmoticon): var botInfos: [CachedPeerBotInfo] = [] - for botInfo in chatFull.botInfo ?? [] { + for botInfo in chatFullBotInfo ?? [] { switch botInfo { case let .botInfo(userId, _, _): let peerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(userId)) @@ -241,7 +239,7 @@ func _internal_fetchAndUpdateCachedPeerData(accountPeerId: PeerId, peerId rawPee botInfos.append(CachedPeerBotInfo(peerId: peerId, botInfo: parsedBotInfo)) } } - let participants = CachedGroupParticipants(apiParticipants: chatFull.participants) + let participants = CachedGroupParticipants(apiParticipants: chatFullParticipants) var invitedBy: PeerId? if let participants = participants { @@ -255,10 +253,10 @@ func _internal_fetchAndUpdateCachedPeerData(accountPeerId: PeerId, peerId rawPee } } - let photo: TelegramMediaImage? = chatFull.chatPhoto.flatMap(telegramMediaImageFromApiPhoto) + let photo: TelegramMediaImage? = chatFullChatPhoto.flatMap(telegramMediaImageFromApiPhoto) - let exportedInvitation = chatFull.exportedInvite.flatMap { ExportedInvitation(apiExportedInvite: $0) } - let pinnedMessageId = chatFull.pinnedMsgId.flatMap({ MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: $0) }) + let exportedInvitation = chatFullExportedInvite.flatMap { ExportedInvitation(apiExportedInvite: $0) } + let pinnedMessageId = chatFullPinnedMsgId.flatMap({ MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: $0) }) var peers: [Peer] = [] var peerPresences: [PeerId: PeerPresence] = [:] @@ -283,16 +281,16 @@ func _internal_fetchAndUpdateCachedPeerData(accountPeerId: PeerId, peerId rawPee updatePeerPresences(transaction: transaction, accountPeerId: accountPeerId, peerPresences: peerPresences) var flags = CachedGroupFlags() - if (chatFull.flags & 1 << 7) != 0 { + if (chatFullFlags & 1 << 7) != 0 { flags.insert(.canChangeUsername) } var hasScheduledMessages = false - if (chatFull.flags & 1 << 8) != 0 { + if (chatFullFlags & 1 << 8) != 0 { hasScheduledMessages = true } - let groupCallDefaultJoinAs = chatFull.groupcallDefaultJoinAs + let groupCallDefaultJoinAs = chatFullGroupcallDefaultJoinAs transaction.updatePeerCachedData(peerIds: [peerId], update: { _, current in let previous: CachedGroupData @@ -303,7 +301,7 @@ func _internal_fetchAndUpdateCachedPeerData(accountPeerId: PeerId, peerId rawPee } var updatedActiveCall: CachedChannelData.ActiveCall? - if let inputCall = chatFull.call { + if let inputCall = chatFullCall { switch inputCall { case let .inputGroupCall(id, accessHash): updatedActiveCall = CachedChannelData.ActiveCall(id: id, accessHash: accessHash, title: previous.activeCall?.title, scheduleTimestamp: previous.activeCall?.scheduleTimestamp, subscribedToScheduled: previous.activeCall?.subscribedToScheduled ?? false) @@ -314,14 +312,14 @@ func _internal_fetchAndUpdateCachedPeerData(accountPeerId: PeerId, peerId rawPee .withUpdatedExportedInvitation(exportedInvitation) .withUpdatedBotInfos(botInfos) .withUpdatedPinnedMessageId(pinnedMessageId) - .withUpdatedAbout(chatFull.about) + .withUpdatedAbout(chatFullAbout) .withUpdatedFlags(flags) .withUpdatedHasScheduledMessages(hasScheduledMessages) .withUpdatedInvitedBy(invitedBy) .withUpdatedPhoto(photo) .withUpdatedActiveCall(updatedActiveCall) .withUpdatedCallJoinPeerId(groupCallDefaultJoinAs?.peerId) - .withUpdatedThemeEmoticon(chatFull.themeEmoticon) + .withUpdatedThemeEmoticon(chatFullThemeEmoticon) }) case .channelFull: break @@ -352,14 +350,14 @@ func _internal_fetchAndUpdateCachedPeerData(accountPeerId: PeerId, peerId rawPee switch result { case let .chatFull(fullChat, chats, users): switch fullChat { - case let .channelFull(channelFull): - transaction.updateCurrentPeerNotificationSettings([peerId: TelegramPeerNotificationSettings(apiSettings: channelFull.notifySettings)]) + case let .channelFull(_, _, _, _, _, _, _, _, _, _, _, _, notifySettings, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _): + transaction.updateCurrentPeerNotificationSettings([peerId: TelegramPeerNotificationSettings(apiSettings: notifySettings)]) case .chatFull: break } switch fullChat { - case let .channelFull(flags, _, about, participantsCount, adminsCount, kickedCount, bannedCount, _, _, _, _, chatPhoto, _, apiExportedInvite, apiBotInfos, migratedFromChatId, migratedFromMaxId, pinnedMsgId, stickerSet, minAvailableMsgId, folderId, linkedChatId, location, slowmodeSeconds, slowmodeNextSendDate, statsDc, pts, inputCall, ttl, pendingSuggestions, groupcallDefaultJoinAs, themeEmoticon): + case let .channelFull(flags, _, about, participantsCount, adminsCount, kickedCount, bannedCount, _, _, _, _, chatPhoto, _, apiExportedInvite, apiBotInfos, migratedFromChatId, migratedFromMaxId, pinnedMsgId, stickerSet, minAvailableMsgId, _, linkedChatId, location, slowmodeSeconds, slowmodeNextSendDate, statsDc, _, inputCall, ttl, pendingSuggestions, groupcallDefaultJoinAs, themeEmoticon): var channelFlags = CachedChannelFlags() if (flags & (1 << 3)) != 0 { channelFlags.insert(.canDisplayParticipants) diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Peers/UpdatePeerInfo.swift b/submodules/TelegramCore/Sources/TelegramEngine/Peers/UpdatePeerInfo.swift index 27bacc080f..47935d495e 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Peers/UpdatePeerInfo.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Peers/UpdatePeerInfo.swift @@ -42,7 +42,7 @@ func _internal_updatePeerTitle(account: Account, peerId: PeerId, title: String) return updated }) } - } |> mapError { _ -> UpdatePeerTitleError in return .generic } + } |> mapError { _ -> UpdatePeerTitleError in } } } else { return .fail(.generic) @@ -50,7 +50,7 @@ func _internal_updatePeerTitle(account: Account, peerId: PeerId, title: String) } else { return .fail(.generic) } - } |> mapError { _ -> UpdatePeerTitleError in return .generic } |> switchToLatest + } |> mapError { _ -> UpdatePeerTitleError in } |> switchToLatest } public enum UpdatePeerDescriptionError { @@ -79,7 +79,7 @@ func _internal_updatePeerDescription(account: Account, peerId: PeerId, descripti }) } } - |> mapError { _ -> UpdatePeerDescriptionError in return .generic } + |> mapError { _ -> UpdatePeerDescriptionError in } } } else { return .fail(.generic) @@ -87,5 +87,5 @@ func _internal_updatePeerDescription(account: Account, peerId: PeerId, descripti } else { return .fail(.generic) } - } |> mapError { _ -> UpdatePeerDescriptionError in return .generic } |> switchToLatest + } |> mapError { _ -> UpdatePeerDescriptionError in } |> switchToLatest } diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Privacy/UpdatedAccountPrivacySettings.swift b/submodules/TelegramCore/Sources/TelegramEngine/Privacy/UpdatedAccountPrivacySettings.swift index b9ec6fbb66..5fc712fd8c 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Privacy/UpdatedAccountPrivacySettings.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Privacy/UpdatedAccountPrivacySettings.swift @@ -106,8 +106,8 @@ func _internal_requestAccountPrivacySettings(account: Account) -> Signal Signal { - var initialState = CacheUsageStatsState() + let initialState = CacheUsageStatsState() if let peerId = peerId { initialState.lowerBound = MessageIndex.lowerBound(peerId: peerId) initialState.upperBound = MessageIndex.upperBound(peerId: peerId) @@ -75,7 +75,7 @@ func _internal_collectCacheUsageStats(account: Account, peerId: PeerId? = nil, a let fetch = account.postbox.transaction { transaction -> ([PeerId : Set], [MediaId : Media], MessageIndex?) in return transaction.enumerateMedia(lowerBound: state.with { $0.lowerBound }, upperBound: state.with { $0.upperBound }, limit: 1000) } - |> mapError { _ -> CollectCacheUsageStatsError in preconditionFailure() } + |> mapError { _ -> CollectCacheUsageStatsError in } let process: ([PeerId : Set], [MediaId : Media], MessageIndex?) -> Signal = { mediaByPeer, mediaRefs, updatedLowerBound in var mediaIdToPeerId: [MediaId: PeerId] = [:] @@ -141,7 +141,7 @@ func _internal_collectCacheUsageStats(account: Account, peerId: PeerId? = nil, a } } return account.postbox.mediaBox.collectResourceCacheUsage(resourceIds) - |> mapError { _ -> CollectCacheUsageStatsError in preconditionFailure() } + |> mapError { _ -> CollectCacheUsageStatsError in } |> mapToSignal { result -> Signal in state.with { state -> Void in state.lowerBound = updatedLowerBound @@ -171,7 +171,7 @@ func _internal_collectCacheUsageStats(account: Account, peerId: PeerId? = nil, a } if updatedLowerBound == nil { if peerId != nil { - let (finalMedia, finalMediaResourceIds, allResourceIds) = state.with { state -> ([PeerId: [PeerCacheUsageCategory: [MediaId: Int64]]], [MediaId: [MediaResourceId]], Set) in + let (finalMedia, finalMediaResourceIds, _) = state.with { state -> ([PeerId: [PeerCacheUsageCategory: [MediaId: Int64]]], [MediaId: [MediaResourceId]], Set) in return (state.media, state.mediaResourceIds, state.allResourceIds) } return account.postbox.transaction { transaction -> CacheUsageStats in @@ -185,7 +185,7 @@ func _internal_collectCacheUsageStats(account: Account, peerId: PeerId? = nil, a } } return CacheUsageStats(media: finalMedia, mediaResourceIds: finalMediaResourceIds, peers: peers, otherSize: 0, otherPaths: [], cacheSize: 0, tempPaths: [], tempSize: 0, immutableSize: 0) - } |> mapError { _ -> CollectCacheUsageStatsError in preconditionFailure() } + } |> mapError { _ -> CollectCacheUsageStatsError in } |> mapToSignal { stats -> Signal in return .fail(.done(stats)) } @@ -196,7 +196,7 @@ func _internal_collectCacheUsageStats(account: Account, peerId: PeerId? = nil, a } return account.postbox.mediaBox.collectOtherResourceUsage(excludeIds: excludeResourceIds, combinedExcludeIds: allResourceIds.union(excludeResourceIds)) - |> mapError { _ in return CollectCacheUsageStatsError.generic } + |> mapError { _ -> CollectCacheUsageStatsError in } |> mapToSignal { otherSize, otherPaths, cacheSize in var tempPaths: [String] = [] var tempSize: Int64 = 0 @@ -264,7 +264,7 @@ func _internal_collectCacheUsageStats(account: Account, peerId: PeerId? = nil, a } } return CacheUsageStats(media: finalMedia, mediaResourceIds: finalMediaResourceIds, peers: peers, otherSize: otherSize, otherPaths: otherPaths, cacheSize: cacheSize, tempPaths: tempPaths, tempSize: tempSize, immutableSize: immutableSize) - } |> mapError { _ -> CollectCacheUsageStatsError in preconditionFailure() } + } |> mapError { _ -> CollectCacheUsageStatsError in } |> mapToSignal { stats -> Signal in return .fail(.done(stats)) } diff --git a/submodules/TelegramCore/Sources/TelegramEngine/SecureId/AccessSecureId.swift b/submodules/TelegramCore/Sources/TelegramEngine/SecureId/AccessSecureId.swift index 96e678f46e..c59f6e35da 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/SecureId/AccessSecureId.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/SecureId/AccessSecureId.swift @@ -17,7 +17,9 @@ func encryptSecureData(key: Data, iv: Data, data: Data, decrypt: Bool) -> Data? } func verifySecureSecret(_ data: Data) -> Bool { - guard data.withUnsafeBytes({ (bytes: UnsafePointer) -> Bool in + guard data.withUnsafeBytes({ rawBytes -> Bool in + let bytes = rawBytes.baseAddress!.assumingMemoryBound(to: UInt8.self) + var checksum: UInt32 = 0 for i in 0 ..< data.count { checksum += UInt32(bytes.advanced(by: i).pointee) @@ -52,7 +54,9 @@ func decryptedSecureSecret(encryptedSecretData: Data, password: String, derivati let secretHashData = sha256Digest(decryptedSecret) var secretId: Int64 = 0 - secretHashData.withUnsafeBytes { (bytes: UnsafePointer) -> Void in + secretHashData.withUnsafeBytes { rawBytes -> Void in + let bytes = rawBytes.baseAddress!.assumingMemoryBound(to: Int8.self) + memcpy(&secretId, bytes, 8) } @@ -66,7 +70,9 @@ func decryptedSecureSecret(encryptedSecretData: Data, password: String, derivati func encryptedSecureSecret(secretData: Data, password: String, inputDerivation: TwoStepSecurePasswordDerivation) -> (data: Data, salt: TwoStepSecurePasswordDerivation, id: Int64)? { let secretHashData = sha256Digest(secretData) var secretId: Int64 = 0 - secretHashData.withUnsafeBytes { (bytes: UnsafePointer) -> Void in + secretHashData.withUnsafeBytes { rawBytes -> Void in + let bytes = rawBytes.baseAddress!.assumingMemoryBound(to: Int8.self) + memcpy(&secretId, bytes, 8) } @@ -92,14 +98,18 @@ func generateSecureSecretData() -> Data? { var secretData = Data(count: 32) let secretDataCount = secretData.count - guard secretData.withUnsafeMutableBytes({ (bytes: UnsafeMutablePointer) -> Bool in + guard secretData.withUnsafeMutableBytes({ rawBytes -> Bool in + let bytes = rawBytes.baseAddress!.assumingMemoryBound(to: Int8.self) + let copyResult = SecRandomCopyBytes(nil, 32, bytes) return copyResult == errSecSuccess }) else { return nil } - secretData.withUnsafeMutableBytes({ (bytes: UnsafeMutablePointer) in + secretData.withUnsafeMutableBytes({ rawBytes -> Void in + let bytes = rawBytes.baseAddress!.assumingMemoryBound(to: UInt8.self) + while true { var checksum: UInt32 = 0 for i in 0 ..< secretDataCount { @@ -173,7 +183,9 @@ func _internal_accessSecureId(network: Network, password: String) -> Signal<(con |> map { decryptedSecret in let secretHashData = sha256Digest(decryptedSecret) var secretId: Int64 = 0 - secretHashData.withUnsafeBytes { (bytes: UnsafePointer) -> Void in + secretHashData.withUnsafeBytes { rawBytes -> Void in + let bytes = rawBytes.baseAddress!.assumingMemoryBound(to: Int8.self) + memcpy(&secretId, bytes, 8) } return (SecureIdAccessContext(secret: decryptedSecret, id: secretId), settings) diff --git a/submodules/TelegramCore/Sources/TelegramEngine/SecureId/RequestSecureIdForm.swift b/submodules/TelegramCore/Sources/TelegramEngine/SecureId/RequestSecureIdForm.swift index 9bea496571..a979781b54 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/SecureId/RequestSecureIdForm.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/SecureId/RequestSecureIdForm.swift @@ -289,7 +289,7 @@ public func requestSecureIdForm(postbox: Postbox, network: Network, peerId: Peer } }, termsUrl: termsUrl, encryptedValues: values, errors: errors) } - } |> mapError { _ in return RequestSecureIdFormError.generic } + } |> mapError { _ -> RequestSecureIdFormError in } } } diff --git a/submodules/TelegramCore/Sources/TelegramEngine/SecureId/SaveSecureIdValue.swift b/submodules/TelegramCore/Sources/TelegramEngine/SecureId/SaveSecureIdValue.swift index f581816a7f..dc8d6bcb9a 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/SecureId/SaveSecureIdValue.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/SecureId/SaveSecureIdValue.swift @@ -55,7 +55,9 @@ func decryptedSecureValueAccessContext(context: SecureIdAccessContext, encrypted let valueSecretHash = sha512Digest(valueSecret) var valueSecretIdValue: Int64 = 0 - valueSecretHash.withUnsafeBytes { (bytes: UnsafePointer) -> Void in + valueSecretHash.withUnsafeBytes { rawBytes -> Void in + let bytes = rawBytes.baseAddress!.assumingMemoryBound(to: Int8.self) + memcpy(&valueSecretIdValue, bytes.advanced(by: valueSecretHash.count - 8), 8) } diff --git a/submodules/TelegramCore/Sources/TelegramEngine/SecureId/SecureIdPadding.swift b/submodules/TelegramCore/Sources/TelegramEngine/SecureId/SecureIdPadding.swift index 9d738ff468..e6188bfe09 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/SecureId/SecureIdPadding.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/SecureId/SecureIdPadding.swift @@ -4,10 +4,14 @@ func paddedSecureIdData(_ data: Data) -> Data { var paddingCount = Int(47 + arc4random_uniform(255 - 47)) paddingCount -= ((data.count + paddingCount) % 16) var result = Data(count: paddingCount + data.count) - result.withUnsafeMutableBytes { (bytes: UnsafeMutablePointer) -> Void in + result.withUnsafeMutableBytes { rawBytes -> Void in + let bytes = rawBytes.baseAddress!.assumingMemoryBound(to: UInt8.self) + bytes.advanced(by: 0).pointee = UInt8(paddingCount) arc4random_buf(bytes.advanced(by: 1), paddingCount - 1) - data.withUnsafeBytes { (source: UnsafePointer) -> Void in + data.withUnsafeBytes { rawSource -> Void in + let source = rawSource.baseAddress!.assumingMemoryBound(to: UInt8.self) + memcpy(bytes.advanced(by: paddingCount), source, data.count) } } diff --git a/submodules/TelegramCore/Sources/TelegramEngine/SecureId/SecureIdValueAccessContext.swift b/submodules/TelegramCore/Sources/TelegramEngine/SecureId/SecureIdValueAccessContext.swift index 9bfc8befa6..88bc31d1ff 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/SecureId/SecureIdValueAccessContext.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/SecureId/SecureIdValueAccessContext.swift @@ -25,7 +25,9 @@ public func generateSecureIdValueAccessContext() -> SecureIdValueAccessContext? } let secretHashData = sha512Digest(secret) var secretHash: Int64 = 0 - secretHashData.withUnsafeBytes { (bytes: UnsafePointer) -> Void in + secretHashData.withUnsafeBytes { rawBytes -> Void in + let bytes = rawBytes.baseAddress!.assumingMemoryBound(to: Int8.self) + memcpy(&secretHash, bytes.advanced(by: secretHashData.count - 8), 8) } return SecureIdValueAccessContext(secret: secret, id: secretHash) diff --git a/submodules/TelegramCore/Sources/TelegramEngine/SecureId/UploadSecureIdFile.swift b/submodules/TelegramCore/Sources/TelegramEngine/SecureId/UploadSecureIdFile.swift index de72484f17..59bc00b993 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/SecureId/UploadSecureIdFile.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/SecureId/UploadSecureIdFile.swift @@ -90,7 +90,6 @@ func decryptedSecureIdFile(context: SecureIdAccessContext, encryptedData: Data, public func uploadSecureIdFile(context: SecureIdAccessContext, postbox: Postbox, network: Network, resource: MediaResource) -> Signal { return postbox.mediaBox.resourceData(resource) |> mapError { _ -> UploadSecureIdFileError in - return .generic } |> mapToSignal { next -> Signal in if !next.complete { diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Stickers/ImportStickers.swift b/submodules/TelegramCore/Sources/TelegramEngine/Stickers/ImportStickers.swift index 8b50cb3cd7..11c4e64391 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Stickers/ImportStickers.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Stickers/ImportStickers.swift @@ -38,7 +38,7 @@ func _internal_uploadSticker(account: Account, peer: Peer, resource: MediaResour return .fail(.generic) } return uploadedSticker(postbox: account.postbox, network: account.network, resource: resource) - |> mapError { _ -> UploadStickerError in return .generic } + |> mapError { _ -> UploadStickerError in } |> mapToSignal { result -> Signal in switch result.content { case .error: diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Stickers/SearchStickers.swift b/submodules/TelegramCore/Sources/TelegramEngine/Stickers/SearchStickers.swift index 34a3670355..b94dbe42dc 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Stickers/SearchStickers.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Stickers/SearchStickers.swift @@ -175,7 +175,7 @@ func _internal_searchStickers(account: Account, query: String, scope: SearchStic var cached = transaction.retrieveItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedStickerQueryResults, key: CachedStickerQueryResult.cacheKey(query))) as? CachedStickerQueryResult let currentTime = Int32(CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970) - let appConfiguration: AppConfiguration = transaction.getPreferencesEntry(key: PreferencesKeys.appConfiguration) as? AppConfiguration ?? AppConfiguration.defaultValue + let appConfiguration: AppConfiguration = transaction.getPreferencesEntry(key: PreferencesKeys.appConfiguration)?.get(AppConfiguration.self) ?? AppConfiguration.defaultValue let searchStickersConfiguration = SearchStickersConfiguration.with(appConfiguration: appConfiguration) if let currentCached = cached, currentTime > currentCached.timestamp + searchStickersConfiguration.cacheTimeout { diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Stickers/StickerSetInstallation.swift b/submodules/TelegramCore/Sources/TelegramEngine/Stickers/StickerSetInstallation.swift index d7c71c93d4..2ef5a55c64 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Stickers/StickerSetInstallation.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Stickers/StickerSetInstallation.swift @@ -61,8 +61,8 @@ func _internal_requestStickerSet(postbox: Postbox, network: Network, reference: info = StickerPackCollectionInfo(apiSet: set, namespace: Namespaces.ItemCollection.CloudStickerPacks) switch set { - case let .stickerSet(data): - installed = (data.flags & (1 << 0) != 0) + case let .stickerSet(flags, _, _, _, _, _, _, _, _, _, _): + installed = (flags & (1 << 0) != 0) } var indexKeysByFile: [MediaId: [MemoryBuffer]] = [:] @@ -98,7 +98,7 @@ func _internal_requestStickerSet(postbox: Postbox, network: Network, reference: } if let collectionId = collectionId { - return localSignal(collectionId) |> mapError {_ in return .generic} |> mapToSignal { result -> Signal in + return localSignal(collectionId) |> mapError { _ -> RequestStickerSetError in } |> mapToSignal { result -> Signal in if let result = result { return .single(.local(info: result.0, items: result.1)) } else { @@ -192,7 +192,7 @@ func _internal_installStickerSetInteractively(account: Account, info: StickerPac collections.insert((info.id, info, items), at: 0) transaction.replaceItemCollections(namespace: info.id.namespace, itemCollections: collections) - } |> map { _ in return addResult} |> mapError {_ in return .generic} + } |> map { _ in return addResult} |> mapError { _ -> InstallStickerSetError in } } } diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Themes/ChatThemes.swift b/submodules/TelegramCore/Sources/TelegramEngine/Themes/ChatThemes.swift index 518dba5b1d..713f294bb2 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Themes/ChatThemes.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Themes/ChatThemes.swift @@ -22,16 +22,20 @@ public struct ChatTheme: Codable, Equatable { let container = try decoder.container(keyedBy: StringCodingKey.self) self.emoji = try container.decode(String.self, forKey: "e") - self.theme = try container.decode(TelegramTheme.self, forKey: "t") - self.darkTheme = try container.decode(TelegramTheme.self, forKey: "dt") + + let themeData = try container.decode(AdaptedPostboxDecoder.RawObjectData.self, forKey: "t") + self.theme = TelegramTheme(decoder: PostboxDecoder(buffer: MemoryBuffer(data: themeData.data))) + + let darkThemeData = try container.decode(AdaptedPostboxDecoder.RawObjectData.self, forKey: "dt") + self.darkTheme = TelegramTheme(decoder: PostboxDecoder(buffer: MemoryBuffer(data: darkThemeData.data))) } public func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: StringCodingKey.self) try container.encode(self.emoji, forKey: "e") - try container.encode(self.theme, forKey: "t") - try container.encode(self.darkTheme, forKey: "dt") + try container.encode(PostboxEncoder().encodeObjectToRawData(self.theme), forKey: "t") + try container.encode(PostboxEncoder().encodeObjectToRawData(self.darkTheme), forKey: "dt") } } diff --git a/submodules/TelegramCore/Sources/UpdatePeers.swift b/submodules/TelegramCore/Sources/UpdatePeers.swift index b221cfe80d..c97e0d8a12 100644 --- a/submodules/TelegramCore/Sources/UpdatePeers.swift +++ b/submodules/TelegramCore/Sources/UpdatePeers.swift @@ -152,9 +152,9 @@ func updateContacts(transaction: Transaction, apiUsers: [Api.User]) { for user in apiUsers { var isContact: Bool? switch user { - case let .user(user): - if (user.flags & (1 << 20)) == 0 { - isContact = (user.flags & (1 << 11)) != 0 + case let .user(flags, _, _, _, _, _, _, _, _, _, _, _, _): + if (flags & (1 << 20)) == 0 { + isContact = (flags & (1 << 11)) != 0 } case .userEmpty: isContact = false diff --git a/submodules/TelegramCore/Sources/Utils/Log.swift b/submodules/TelegramCore/Sources/Utils/Log.swift index 11ad4da33c..c12f70b4f0 100644 --- a/submodules/TelegramCore/Sources/Utils/Log.swift +++ b/submodules/TelegramCore/Sources/Utils/Log.swift @@ -198,7 +198,9 @@ public final class Logger { var fileEvents: [(Double, String)] = [] if let data = try? Data(contentsOf: URL(fileURLWithPath: filePath), options: .mappedRead) { let dataLength = data.count - data.withUnsafeBytes { (bytes: UnsafePointer) -> Void in + data.withUnsafeBytes { rawBytes -> Void in + let bytes = rawBytes.baseAddress!.assumingMemoryBound(to: Int8.self) + var offset = 0 while offset < dataLength { let remainingLength = dataLength - offset @@ -341,7 +343,9 @@ public final class Logger { if let currentFile = currentFile { if let data = content.data(using: .utf8) { - data.withUnsafeBytes { (bytes: UnsafePointer) -> Void in + data.withUnsafeBytes { rawBytes -> Void in + let bytes = rawBytes.baseAddress!.assumingMemoryBound(to: UInt8.self) + let _ = currentFile.write(bytes, count: data.count) } var newline: UInt8 = 0x0a @@ -448,7 +452,9 @@ public final class Logger { if let currentFile = currentFile { let contentDataCount = contentData.count - contentData.withUnsafeBytes { (bytes: UnsafePointer) -> Void in + contentData.withUnsafeBytes { rawBytes -> Void in + let bytes = rawBytes.baseAddress!.assumingMemoryBound(to: UInt8.self) + let _ = currentFile.write(bytes, count: contentDataCount) } if let shortFile = self.shortFile { diff --git a/submodules/TelegramCore/Sources/Utils/PeerUtils.swift b/submodules/TelegramCore/Sources/Utils/PeerUtils.swift index 70f32297a1..5efc7e35d6 100644 --- a/submodules/TelegramCore/Sources/Utils/PeerUtils.swift +++ b/submodules/TelegramCore/Sources/Utils/PeerUtils.swift @@ -57,23 +57,34 @@ public extension Peer { switch self { case let user as TelegramUser: if let firstName = user.firstName, let lastName = user.lastName, !firstName.isEmpty && !lastName.isEmpty { - return [firstName.substring(to: firstName.index(after: firstName.startIndex)).uppercased(), lastName.substring(to: lastName.index(after: lastName.startIndex)).uppercased()] + return [ + String(firstName[.. Signal { return uploadedWallpaper(postbox: account.postbox, network: account.network, resource: resource) - |> mapError { _ -> UploadWallpaperError in return .generic } + |> mapError { _ -> UploadWallpaperError in } |> mapToSignal { result -> Signal<(UploadWallpaperStatus, MediaResource?), UploadWallpaperError> in switch result.content { case .error: diff --git a/submodules/TelegramIntents/Sources/TelegramIntents.swift b/submodules/TelegramIntents/Sources/TelegramIntents.swift index dcf9261f8a..64378d8a68 100644 --- a/submodules/TelegramIntents/Sources/TelegramIntents.swift +++ b/submodules/TelegramIntents/Sources/TelegramIntents.swift @@ -69,7 +69,7 @@ public func donateSendMessageIntent(account: Account, sharedContext: SharedAccou return sharedContext.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.intentsSettings]) |> take(1) |> mapToSignal { sharedData -> Signal<[(Peer, SendMessageIntentSubject)], NoError> in - let settings = (sharedData.entries[ApplicationSpecificSharedDataKeys.intentsSettings] as? IntentsSettings) ?? IntentsSettings.defaultSettings + let settings = sharedData.entries[ApplicationSpecificSharedDataKeys.intentsSettings]?.get(IntentsSettings.self) ?? IntentsSettings.defaultSettings if let accountId = settings.account, accountId != account.peerId { return .single([]) } diff --git a/submodules/TelegramPermissionsUI/Sources/PermissionSplitTest.swift b/submodules/TelegramPermissionsUI/Sources/PermissionSplitTest.swift index 19cb69e699..a64a7227b3 100644 --- a/submodules/TelegramPermissionsUI/Sources/PermissionSplitTest.swift +++ b/submodules/TelegramPermissionsUI/Sources/PermissionSplitTest.swift @@ -99,7 +99,7 @@ public struct PermissionUISplitTest: SplitTest { public func permissionUISplitTest(postbox: Postbox) -> Signal { return postbox.preferencesView(keys: [PreferencesKeys.appConfiguration]) |> mapToSignal { view -> Signal in - if let appConfiguration = view.values[PreferencesKeys.appConfiguration] as? AppConfiguration, appConfiguration.data != nil { + if let appConfiguration = view.values[PreferencesKeys.appConfiguration]?.get(AppConfiguration.self), appConfiguration.data != nil { let (config, bucket) = PermissionUISplitTest.Configuration.with(appConfiguration: appConfiguration) return .single(PermissionUISplitTest(postbox: postbox, bucket: bucket, configuration: config)) } else { diff --git a/submodules/TelegramPresentationData/Sources/PresentationData.swift b/submodules/TelegramPresentationData/Sources/PresentationData.swift index a54199e3d7..f4049c15d5 100644 --- a/submodules/TelegramPresentationData/Sources/PresentationData.swift +++ b/submodules/TelegramPresentationData/Sources/PresentationData.swift @@ -232,57 +232,57 @@ public final class InitialPresentationDataAndSettings { public func currentPresentationDataAndSettings(accountManager: AccountManager, systemUserInterfaceStyle: WindowUserInterfaceStyle) -> Signal { return accountManager.transaction { transaction -> InitialPresentationDataAndSettings in let localizationSettings: LocalizationSettings? - if let current = transaction.getSharedData(SharedDataKeys.localizationSettings) as? LocalizationSettings { + if let current = transaction.getSharedData(SharedDataKeys.localizationSettings)?.get(LocalizationSettings.self) { localizationSettings = current } else { localizationSettings = nil } let themeSettings: PresentationThemeSettings - if let current = transaction.getSharedData(ApplicationSpecificSharedDataKeys.presentationThemeSettings) as? PresentationThemeSettings { + if let current = transaction.getSharedData(ApplicationSpecificSharedDataKeys.presentationThemeSettings)?.get(PresentationThemeSettings.self) { themeSettings = current } else { themeSettings = PresentationThemeSettings.defaultSettings } let automaticMediaDownloadSettings: MediaAutoDownloadSettings - if let value = transaction.getSharedData(ApplicationSpecificSharedDataKeys.automaticMediaDownloadSettings) as? MediaAutoDownloadSettings { + if let value = transaction.getSharedData(ApplicationSpecificSharedDataKeys.automaticMediaDownloadSettings)?.get(MediaAutoDownloadSettings.self) { automaticMediaDownloadSettings = value } else { automaticMediaDownloadSettings = MediaAutoDownloadSettings.defaultSettings } let autodownloadSettings: AutodownloadSettings - if let value = transaction.getSharedData(SharedDataKeys.autodownloadSettings) as? AutodownloadSettings { + if let value = transaction.getSharedData(SharedDataKeys.autodownloadSettings)?.get(AutodownloadSettings.self) { autodownloadSettings = value } else { autodownloadSettings = .defaultSettings } let callListSettings: CallListSettings - if let value = transaction.getSharedData(ApplicationSpecificSharedDataKeys.callListSettings) as? CallListSettings { + if let value = transaction.getSharedData(ApplicationSpecificSharedDataKeys.callListSettings)?.get(CallListSettings.self) { callListSettings = value } else { callListSettings = CallListSettings.defaultSettings } let inAppNotificationSettings: InAppNotificationSettings - if let value = transaction.getSharedData(ApplicationSpecificSharedDataKeys.inAppNotificationSettings) as? InAppNotificationSettings { + if let value = transaction.getSharedData(ApplicationSpecificSharedDataKeys.inAppNotificationSettings)?.get(InAppNotificationSettings.self) { inAppNotificationSettings = value } else { inAppNotificationSettings = InAppNotificationSettings.defaultSettings } let mediaInputSettings: MediaInputSettings - if let value = transaction.getSharedData(ApplicationSpecificSharedDataKeys.mediaInputSettings) as? MediaInputSettings { + if let value = transaction.getSharedData(ApplicationSpecificSharedDataKeys.mediaInputSettings)?.get(MediaInputSettings.self) { mediaInputSettings = value } else { mediaInputSettings = MediaInputSettings.defaultSettings } - let experimentalUISettings: ExperimentalUISettings = (transaction.getSharedData(ApplicationSpecificSharedDataKeys.experimentalUISettings) as? ExperimentalUISettings) ?? ExperimentalUISettings.defaultSettings + let experimentalUISettings: ExperimentalUISettings = transaction.getSharedData(ApplicationSpecificSharedDataKeys.experimentalUISettings)?.get(ExperimentalUISettings.self) ?? ExperimentalUISettings.defaultSettings - let contactSettings: ContactSynchronizationSettings = (transaction.getSharedData(ApplicationSpecificSharedDataKeys.contactSynchronizationSettings) as? ContactSynchronizationSettings) ?? ContactSynchronizationSettings.defaultSettings + let contactSettings: ContactSynchronizationSettings = transaction.getSharedData(ApplicationSpecificSharedDataKeys.contactSynchronizationSettings)?.get(ContactSynchronizationSettings.self) ?? ContactSynchronizationSettings.defaultSettings let effectiveTheme: PresentationThemeReference let parameters = AutomaticThemeSwitchParameters(settings: themeSettings.automaticThemeSwitchSetting) @@ -569,13 +569,13 @@ public func updatedPresentationData(accountManager: AccountManager mapToSignal { sharedData, systemUserInterfaceStyle -> Signal in let themeSettings: PresentationThemeSettings - if let current = sharedData.entries[ApplicationSpecificSharedDataKeys.presentationThemeSettings] as? PresentationThemeSettings { + if let current = sharedData.entries[ApplicationSpecificSharedDataKeys.presentationThemeSettings]?.get(PresentationThemeSettings.self) { themeSettings = current } else { themeSettings = PresentationThemeSettings.defaultSettings } - let contactSettings: ContactSynchronizationSettings = sharedData.entries[ApplicationSpecificSharedDataKeys.contactSynchronizationSettings] as? ContactSynchronizationSettings ?? ContactSynchronizationSettings.defaultSettings + let contactSettings: ContactSynchronizationSettings = sharedData.entries[ApplicationSpecificSharedDataKeys.contactSynchronizationSettings]?.get(ContactSynchronizationSettings.self) ?? ContactSynchronizationSettings.defaultSettings var currentColors = themeSettings.themeSpecificAccentColors[themeSettings.theme.index] if let colors = currentColors, colors.baseColor == .theme { @@ -639,7 +639,7 @@ public func updatedPresentationData(accountManager: AccountManager map { preferences -> LimitsConfiguration in - return preferences.values[PreferencesKeys.limitsConfiguration] as? LimitsConfiguration ?? LimitsConfiguration.defaultValue + return preferences.values[PreferencesKeys.limitsConfiguration]?.get(LimitsConfiguration.self) ?? LimitsConfiguration.defaultValue } self.currentLimitsConfiguration = Atomic(value: limitsConfiguration) @@ -462,14 +462,14 @@ private final class ChatLocationContextHolderImpl: ChatLocationContextHolder { } func getAppConfiguration(transaction: Transaction) -> AppConfiguration { - let appConfiguration: AppConfiguration = transaction.getPreferencesEntry(key: PreferencesKeys.appConfiguration) as? AppConfiguration ?? AppConfiguration.defaultValue + let appConfiguration: AppConfiguration = transaction.getPreferencesEntry(key: PreferencesKeys.appConfiguration)?.get(AppConfiguration.self) ?? AppConfiguration.defaultValue return appConfiguration } func getAppConfiguration(postbox: Postbox) -> Signal { return postbox.preferencesView(keys: [PreferencesKeys.appConfiguration]) |> map { view -> AppConfiguration in - let appConfiguration: AppConfiguration = view.values[PreferencesKeys.appConfiguration] as? AppConfiguration ?? AppConfiguration.defaultValue + let appConfiguration: AppConfiguration = view.values[PreferencesKeys.appConfiguration]?.get(AppConfiguration.self) ?? AppConfiguration.defaultValue return appConfiguration } |> distinctUntilChanged diff --git a/submodules/TelegramUI/Sources/AppDelegate.swift b/submodules/TelegramUI/Sources/AppDelegate.swift index 5483fabe3b..e4e14c547f 100644 --- a/submodules/TelegramUI/Sources/AppDelegate.swift +++ b/submodules/TelegramUI/Sources/AppDelegate.swift @@ -34,6 +34,7 @@ import LightweightAccountData import TelegramAudio import DebugSettingsUI import BackgroundTasks +import UIKitRuntimeUtils #if canImport(AppCenter) import AppCenter @@ -99,14 +100,14 @@ private class ApplicationStatusBarHost: StatusBarHost { func setStatusBarStyle(_ style: UIStatusBarStyle, animated: Bool) { if self.shouldChangeStatusBarStyle?(style) ?? true { - self.application.setStatusBarStyle(style, animated: animated) + self.application.internalSetStatusBarStyle(style, animated: animated) } } var shouldChangeStatusBarStyle: ((UIStatusBarStyle) -> Bool)? func setStatusBarHidden(_ value: Bool, animated: Bool) { - self.application.setStatusBarHidden(value, with: animated ? .fade : .none) + self.application.internalSetStatusBarHidden(value, animation: animated ? .fade : .none) } var keyboardWindow: UIWindow? { @@ -175,7 +176,7 @@ final class SharedApplicationContext { } } -@objc(AppDelegate) class AppDelegate: UIResponder, UIApplicationDelegate, PKPushRegistryDelegate, UNUserNotificationCenterDelegate, UIAlertViewDelegate { +@objc(AppDelegate) class AppDelegate: UIResponder, UIApplicationDelegate, PKPushRegistryDelegate, UNUserNotificationCenterDelegate { @objc var window: UIWindow? var nativeWindow: (UIWindow & WindowHost)? var mainWindow: Window1! @@ -236,14 +237,6 @@ final class SharedApplicationContext { private var alertActions: (primary: (() -> Void)?, other: (() -> Void)?)? - func alertView(_ alertView: UIAlertView, clickedButtonAt buttonIndex: Int) { - if buttonIndex == alertView.firstOtherButtonIndex { - self.alertActions?.other?() - } else { - self.alertActions?.primary?() - } - } - private let deviceToken = Promise(nil) func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool { @@ -421,7 +414,7 @@ final class SharedApplicationContext { }, autolockDeadine: autolockDeadine, encryptionProvider: OpenSSLEncryptionProvider()) guard let appGroupUrl = maybeAppGroupUrl else { - UIAlertView(title: nil, message: "Error 2", delegate: nil, cancelButtonTitle: "OK").show() + self.mainWindow?.presentNative(UIAlertController(title: nil, message: "Error 2", preferredStyle: .alert)) return true } @@ -929,7 +922,7 @@ final class SharedApplicationContext { sharedApplicationContext.sharedContext.mediaManager.overlayMediaManager.attachOverlayMediaController(sharedApplicationContext.overlayMediaController) return accountManager.transaction { transaction -> (SharedApplicationContext, LoggingSettings) in - return (sharedApplicationContext, transaction.getSharedData(SharedDataKeys.loggingSettings) as? LoggingSettings ?? LoggingSettings.defaultSettings) + return (sharedApplicationContext, transaction.getSharedData(SharedDataKeys.loggingSettings)?.get(LoggingSettings.self) ?? LoggingSettings.defaultSettings) } } self.sharedContextPromise.set(sharedContextSignal @@ -958,7 +951,7 @@ final class SharedApplicationContext { }) |> mapToSignal { context -> Signal<(AccountContext, CallListSettings)?, NoError> in return sharedApplicationContext.sharedContext.accountManager.transaction { transaction -> CallListSettings? in - return transaction.getSharedData(ApplicationSpecificSharedDataKeys.callListSettings) as? CallListSettings + return transaction.getSharedData(ApplicationSpecificSharedDataKeys.callListSettings)?.get(CallListSettings.self) } |> reduceLeft(value: nil) { current, updated -> CallListSettings? in var result: CallListSettings? @@ -1040,12 +1033,12 @@ final class SharedApplicationContext { } |> mapToSignal { accountAndOtherAccountPhoneNumbers -> Signal<(UnauthorizedAccount, LimitsConfiguration, CallListSettings, ((String, AccountRecordId, Bool)?, [(String, AccountRecordId, Bool)]))?, NoError> in return sharedApplicationContext.sharedContext.accountManager.transaction { transaction -> CallListSettings in - return transaction.getSharedData(ApplicationSpecificSharedDataKeys.callListSettings) as? CallListSettings ?? CallListSettings.defaultSettings + return transaction.getSharedData(ApplicationSpecificSharedDataKeys.callListSettings)?.get(CallListSettings.self) ?? CallListSettings.defaultSettings } |> mapToSignal { callListSettings -> Signal<(UnauthorizedAccount, LimitsConfiguration, CallListSettings, ((String, AccountRecordId, Bool)?, [(String, AccountRecordId, Bool)]))?, NoError> in if let (account, otherAccountPhoneNumbers) = accountAndOtherAccountPhoneNumbers { return account.postbox.transaction { transaction -> (UnauthorizedAccount, LimitsConfiguration, CallListSettings, ((String, AccountRecordId, Bool)?, [(String, AccountRecordId, Bool)]))? in - let limitsConfiguration = transaction.getPreferencesEntry(key: PreferencesKeys.limitsConfiguration) as? LimitsConfiguration ?? LimitsConfiguration.defaultValue + let limitsConfiguration = transaction.getPreferencesEntry(key: PreferencesKeys.limitsConfiguration)?.get(LimitsConfiguration.self) ?? LimitsConfiguration.defaultValue return (account, limitsConfiguration, callListSettings, otherAccountPhoneNumbers) } } else { @@ -1313,7 +1306,7 @@ final class SharedApplicationContext { } if UIApplication.shared.isStatusBarHidden { - UIApplication.shared.setStatusBarHidden(false, with: .none) + UIApplication.shared.internalSetStatusBarHidden(false, animation: .none) } /*if #available(iOS 13.0, *) { @@ -2032,7 +2025,7 @@ final class SharedApplicationContext { private func registerForNotifications(context: AccountContextImpl, authorize: Bool = true, completion: @escaping (Bool) -> Void = { _ in }) { let presentationData = context.sharedContext.currentPresentationData.with { $0 } let _ = (context.sharedContext.accountManager.transaction { transaction -> Bool in - let settings = transaction.getSharedData(ApplicationSpecificSharedDataKeys.inAppNotificationSettings) as? InAppNotificationSettings ?? InAppNotificationSettings.defaultSettings + let settings = transaction.getSharedData(ApplicationSpecificSharedDataKeys.inAppNotificationSettings)?.get(InAppNotificationSettings.self) ?? InAppNotificationSettings.defaultSettings return settings.displayNameOnLockscreen } |> deliverOnMainQueue).start(next: { displayNames in @@ -2257,7 +2250,7 @@ final class SharedApplicationContext { private func resetIntentsIfNeeded(context: AccountContextImpl) { let _ = (context.sharedContext.accountManager.transaction { transaction in - let settings = transaction.getSharedData(ApplicationSpecificSharedDataKeys.intentsSettings) as? IntentsSettings ?? IntentsSettings.defaultSettings + let settings = transaction.getSharedData(ApplicationSpecificSharedDataKeys.intentsSettings)?.get(IntentsSettings.self) ?? IntentsSettings.defaultSettings if !settings.initiallyReset || settings.account == nil { if #available(iOS 10.0, *) { Queue.mainQueue().async { @@ -2265,7 +2258,7 @@ final class SharedApplicationContext { } } transaction.updateSharedData(ApplicationSpecificSharedDataKeys.intentsSettings, { _ in - return IntentsSettings(initiallyReset: true, account: context.account.peerId, contacts: settings.contacts, privateChats: settings.privateChats, savedMessages: settings.savedMessages, groups: settings.groups, onlyShared: settings.onlyShared) + return PreferencesEntry(IntentsSettings(initiallyReset: true, account: context.account.peerId, contacts: settings.contacts, privateChats: settings.privateChats, savedMessages: settings.savedMessages, groups: settings.groups, onlyShared: settings.onlyShared)) }) } }).start() diff --git a/submodules/TelegramUI/Sources/ApplicationContext.swift b/submodules/TelegramUI/Sources/ApplicationContext.swift index 8b53fab81c..5fe82ef45e 100644 --- a/submodules/TelegramUI/Sources/ApplicationContext.swift +++ b/submodules/TelegramUI/Sources/ApplicationContext.swift @@ -264,7 +264,7 @@ final class AuthorizedApplicationContext { self.inAppNotificationSettingsDisposable.set(((context.sharedContext.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.inAppNotificationSettings])) |> deliverOnMainQueue).start(next: { [weak self] sharedData in if let strongSelf = self { - if let settings = sharedData.entries[ApplicationSpecificSharedDataKeys.inAppNotificationSettings] as? InAppNotificationSettings { + if let settings = sharedData.entries[ApplicationSpecificSharedDataKeys.inAppNotificationSettings]?.get(InAppNotificationSettings.self) { let previousSettings = strongSelf.inAppNotificationSettings strongSelf.inAppNotificationSettings = settings if let previousSettings = previousSettings, previousSettings.displayNameOnLockscreen != settings.displayNameOnLockscreen { @@ -696,7 +696,7 @@ final class AuthorizedApplicationContext { let importableContacts = self.context.sharedContext.contactDataManager?.importable() ?? .single([:]) self.context.account.importableContacts.set(self.context.account.postbox.preferencesView(keys: [PreferencesKeys.contactsSettings]) |> mapToSignal { preferences -> Signal<[DeviceContactNormalizedPhoneNumber: ImportableDeviceContactData], NoError> in - let settings: ContactsSettings = (preferences.values[PreferencesKeys.contactsSettings] as? ContactsSettings) ?? .defaultSettings + let settings: ContactsSettings = preferences.values[PreferencesKeys.contactsSettings]?.get(ContactsSettings.self) ?? .defaultSettings if settings.synchronizeContacts { return importableContacts } else { @@ -720,7 +720,7 @@ final class AuthorizedApplicationContext { let showCallsTabSignal = context.sharedContext.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.callListSettings]) |> map { sharedData -> Bool in var value = CallListSettings.defaultSettings.showTab - if let settings = sharedData.entries[ApplicationSpecificSharedDataKeys.callListSettings] as? CallListSettings { + if let settings = sharedData.entries[ApplicationSpecificSharedDataKeys.callListSettings]?.get(CallListSettings.self) { value = settings.showTab } return value diff --git a/submodules/TelegramUI/Sources/AudioWaveform.swift b/submodules/TelegramUI/Sources/AudioWaveform.swift index 01515cbead..954f810ae4 100644 --- a/submodules/TelegramUI/Sources/AudioWaveform.swift +++ b/submodules/TelegramUI/Sources/AudioWaveform.swift @@ -39,11 +39,11 @@ final class AudioWaveform: Equatable { var result = Data() result.count = numSamples * 2 - bitstream.withUnsafeBytes { (bytes: UnsafePointer) -> Void in - result.withUnsafeMutableBytes { (samples: UnsafeMutablePointer) -> Void in + bitstream.withUnsafeBytes { bytes -> Void in + result.withUnsafeMutableBytes { samples -> Void in let norm = Int64((1 << bitsPerSample) - 1) for i in 0 ..< numSamples { - samples[i] = Int16(Int64(getBits(data: bytes, length: bitstream.count, bitOffset: i * 5, numBits: 5)) * norm / norm) + samples.baseAddress!.assumingMemoryBound(to: Int16.self)[i] = Int16(Int64(getBits(data: bytes.baseAddress!.assumingMemoryBound(to: Int8.self), length: bitstream.count, bitOffset: i * 5, numBits: 5)) * norm / norm) } } } @@ -59,8 +59,12 @@ final class AudioWaveform: Equatable { let maxSample: Int32 = self.peak - self.samples.withUnsafeBytes { (samples: UnsafePointer) -> Void in - result.withUnsafeMutableBytes { (bytes: UnsafeMutablePointer) -> Void in + self.samples.withUnsafeBytes { rawSamples -> Void in + let samples = rawSamples.baseAddress!.assumingMemoryBound(to: Int16.self) + + result.withUnsafeMutableBytes { rawBytes -> Void in + let bytes = rawBytes.baseAddress!.assumingMemoryBound(to: Int16.self) + for i in 0 ..< numSamples { let value: Int32 = min(Int32(31), abs(Int32(samples[i])) * 31 / maxSample) if i == 99 { diff --git a/submodules/TelegramUI/Sources/AudioWaveformNode.swift b/submodules/TelegramUI/Sources/AudioWaveformNode.swift index 691bab2228..174c957ad0 100644 --- a/submodules/TelegramUI/Sources/AudioWaveformNode.swift +++ b/submodules/TelegramUI/Sources/AudioWaveformNode.swift @@ -90,7 +90,9 @@ final class AudioWaveformNode: ASDisplayNode { } if let waveform = parameters.waveform { - waveform.samples.withUnsafeBytes { (samples: UnsafePointer) -> Void in + waveform.samples.withUnsafeBytes { rawSamples -> Void in + let samples = rawSamples.baseAddress!.assumingMemoryBound(to: UInt16.self) + let peakHeight: CGFloat = 12.0 let maxReadSamples = waveform.samples.count / 2 diff --git a/submodules/TelegramUI/Sources/AuthorizationSequenceSplashController.swift b/submodules/TelegramUI/Sources/AuthorizationSequenceSplashController.swift index cd59666642..70640ea1a9 100644 --- a/submodules/TelegramUI/Sources/AuthorizationSequenceSplashController.swift +++ b/submodules/TelegramUI/Sources/AuthorizationSequenceSplashController.swift @@ -154,7 +154,7 @@ final class AuthorizationSequenceSplashController: ViewController { private func activateLocalization(_ code: String) { let currentCode = self.accountManager.transaction { transaction -> String in - if let current = transaction.getSharedData(SharedDataKeys.localizationSettings) as? LocalizationSettings { + if let current = transaction.getSharedData(SharedDataKeys.localizationSettings)?.get(LocalizationSettings.self) { return current.primaryComponent.languageCode } else { return "en" @@ -187,7 +187,7 @@ final class AuthorizationSequenceSplashController: ViewController { strongSelf.activateLocalizationDisposable.set(TelegramEngineUnauthorized(account: strongSelf.account).localization.downloadAndApplyLocalization(accountManager: accountManager, languageCode: code).start(completed: { let _ = (accountManager.transaction { transaction -> PresentationStrings? in let localizationSettings: LocalizationSettings? - if let current = transaction.getSharedData(SharedDataKeys.localizationSettings) as? LocalizationSettings { + if let current = transaction.getSharedData(SharedDataKeys.localizationSettings)?.get(LocalizationSettings.self) { localizationSettings = current } else { localizationSettings = nil diff --git a/submodules/TelegramUI/Sources/ChatController.swift b/submodules/TelegramUI/Sources/ChatController.swift index bba2c26553..262b6816e5 100644 --- a/submodules/TelegramUI/Sources/ChatController.swift +++ b/submodules/TelegramUI/Sources/ChatController.swift @@ -3889,7 +3889,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G let themeSettings = context.sharedContext.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.presentationThemeSettings]) |> map { sharedData -> PresentationThemeSettings in let themeSettings: PresentationThemeSettings - if let current = sharedData.entries[ApplicationSpecificSharedDataKeys.presentationThemeSettings] as? PresentationThemeSettings { + if let current = sharedData.entries[ApplicationSpecificSharedDataKeys.presentationThemeSettings]?.get(PresentationThemeSettings.self) { themeSettings = current } else { themeSettings = PresentationThemeSettings.defaultSettings @@ -4012,7 +4012,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G self.stickerSettingsDisposable = combineLatest(queue: Queue.mainQueue(), context.sharedContext.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.stickerSettings]), self.disableStickerAnimationsPromise.get()).start(next: { [weak self] sharedData, disableStickerAnimations in var stickerSettings = StickerSettings.defaultSettings - if let value = sharedData.entries[ApplicationSpecificSharedDataKeys.stickerSettings] as? StickerSettings { + if let value = sharedData.entries[ApplicationSpecificSharedDataKeys.stickerSettings]?.get(StickerSettings.self) { stickerSettings = value } @@ -9169,7 +9169,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G private func presentAttachmentMenu(editMediaOptions: MessageMediaEditingOptions?, editMediaReference: AnyMediaReference?) { let _ = (self.context.sharedContext.accountManager.transaction { transaction -> GeneratedMediaStoreSettings in - let entry = transaction.getSharedData(ApplicationSpecificSharedDataKeys.generatedMediaStoreSettings) as? GeneratedMediaStoreSettings + let entry = transaction.getSharedData(ApplicationSpecificSharedDataKeys.generatedMediaStoreSettings)?.get(GeneratedMediaStoreSettings.self) return entry ?? GeneratedMediaStoreSettings.defaultSettings } |> deliverOnMainQueue).start(next: { [weak self] settings in @@ -9546,7 +9546,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G private func presentMediaPicker(fileMode: Bool, editingMedia: Bool, completion: @escaping ([Any], Bool, Int32) -> Void) { let postbox = self.context.account.postbox let _ = (self.context.sharedContext.accountManager.transaction { transaction -> Signal<(GeneratedMediaStoreSettings, SearchBotsConfiguration), NoError> in - let entry = transaction.getSharedData(ApplicationSpecificSharedDataKeys.generatedMediaStoreSettings) as? GeneratedMediaStoreSettings + let entry = transaction.getSharedData(ApplicationSpecificSharedDataKeys.generatedMediaStoreSettings)?.get(GeneratedMediaStoreSettings.self) return postbox.transaction { transaction -> (GeneratedMediaStoreSettings, SearchBotsConfiguration) in let configuration = currentSearchBotsConfiguration(transaction: transaction) return (entry ?? GeneratedMediaStoreSettings.defaultSettings, configuration) @@ -9679,7 +9679,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G } let _ = (self.context.account.postbox.transaction { transaction -> SearchBotsConfiguration in - if let entry = transaction.getPreferencesEntry(key: PreferencesKeys.searchBotsConfiguration) as? SearchBotsConfiguration { + if let entry = transaction.getPreferencesEntry(key: PreferencesKeys.searchBotsConfiguration)?.get(SearchBotsConfiguration.self) { return entry } else { return SearchBotsConfiguration.defaultValue @@ -10381,7 +10381,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G private func displayPasteMenu(_ images: [UIImage]) { let _ = (self.context.sharedContext.accountManager.transaction { transaction -> GeneratedMediaStoreSettings in - let entry = transaction.getSharedData(ApplicationSpecificSharedDataKeys.generatedMediaStoreSettings) as? GeneratedMediaStoreSettings + let entry = transaction.getSharedData(ApplicationSpecificSharedDataKeys.generatedMediaStoreSettings)?.get(GeneratedMediaStoreSettings.self) return entry ?? GeneratedMediaStoreSettings.defaultSettings } |> deliverOnMainQueue).start(next: { [weak self] settings in @@ -12419,7 +12419,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G var parsedUrlValue: URL? if let parsed = URL(string: string) { parsedUrlValue = parsed - } else if let encoded = (string as NSString).addingPercentEscapes(using: String.Encoding.utf8.rawValue), let parsed = URL(string: encoded) { + } else if let encoded = (string as NSString).addingPercentEncoding(withAllowedCharacters: .urlQueryValueAllowed), let parsed = URL(string: encoded) { parsedUrlValue = parsed } diff --git a/submodules/TelegramUI/Sources/ChatControllerNode.swift b/submodules/TelegramUI/Sources/ChatControllerNode.swift index 7c0af628ab..a7ef4bd03c 100644 --- a/submodules/TelegramUI/Sources/ChatControllerNode.swift +++ b/submodules/TelegramUI/Sources/ChatControllerNode.swift @@ -438,7 +438,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate { self.interactiveEmojisDisposable = (self.context.account.postbox.preferencesView(keys: [PreferencesKeys.appConfiguration]) |> map { preferencesView -> InteractiveEmojiConfiguration in - let appConfiguration: AppConfiguration = preferencesView.values[PreferencesKeys.appConfiguration] as? AppConfiguration ?? .defaultValue + let appConfiguration: AppConfiguration = preferencesView.values[PreferencesKeys.appConfiguration]?.get(AppConfiguration.self) ?? .defaultValue return InteractiveEmojiConfiguration.with(appConfiguration: appConfiguration) } |> deliverOnMainQueue).start(next: { [weak self] emojis in diff --git a/submodules/TelegramUI/Sources/ChatHistoryListNode.swift b/submodules/TelegramUI/Sources/ChatHistoryListNode.swift index 31209b19ff..cc3ab17307 100644 --- a/submodules/TelegramUI/Sources/ChatHistoryListNode.swift +++ b/submodules/TelegramUI/Sources/ChatHistoryListNode.swift @@ -1166,7 +1166,7 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode { let appConfiguration = context.account.postbox.preferencesView(keys: [PreferencesKeys.appConfiguration]) |> take(1) |> map { view in - return view.values[PreferencesKeys.appConfiguration] as? AppConfiguration ?? .defaultValue + return view.values[PreferencesKeys.appConfiguration]?.get(AppConfiguration.self) ?? .defaultValue } var didSetPresentationData = false diff --git a/submodules/TelegramUI/Sources/ChatHistoryViewForLocation.swift b/submodules/TelegramUI/Sources/ChatHistoryViewForLocation.swift index 5e35e755f6..91ee4348bd 100644 --- a/submodules/TelegramUI/Sources/ChatHistoryViewForLocation.swift +++ b/submodules/TelegramUI/Sources/ChatHistoryViewForLocation.swift @@ -22,12 +22,12 @@ func preloadedChatHistoryViewForLocation(_ location: ChatHistoryLocationInput, c |> castError(Bool.self) |> mapToSignal { update -> Signal in switch update { - case let .Loading(value): - if case .Generic(.FillHole) = value.type { + case let .Loading(_, type): + if case .Generic(.FillHole) = type { return .fail(true) } - case let .HistoryView(value): - if case .Generic(.FillHole) = value.type { + case let .HistoryView(_, type, _, _, _, _, _): + if case .Generic(.FillHole) = type { return .fail(true) } } diff --git a/submodules/TelegramUI/Sources/ChatInterfaceStateContextMenus.swift b/submodules/TelegramUI/Sources/ChatInterfaceStateContextMenus.swift index 7a48c4c9dd..2a09397f6f 100644 --- a/submodules/TelegramUI/Sources/ChatInterfaceStateContextMenus.swift +++ b/submodules/TelegramUI/Sources/ChatInterfaceStateContextMenus.swift @@ -229,14 +229,14 @@ func messageMediaEditingOptions(message: Message) -> MessageMediaEditingOptions return [] case .Animated: return [] - case let .Video(video): - if video.flags.contains(.instantRoundVideo) { + case let .Video(_, _, flags): + if flags.contains(.instantRoundVideo) { return [] } else { options.formUnion([.imageOrVideo, .file]) } - case let .Audio(audio): - if audio.isVoice { + case let .Audio(isVoice, _, _, _, _): + if isVoice { return [] } else { if let _ = message.groupingKey { @@ -464,7 +464,7 @@ func contextMenuForChatPresentationInterfaceState(chatPresentationInterfaceState } let loadLimits = context.account.postbox.transaction { transaction -> LimitsConfiguration in - return transaction.getPreferencesEntry(key: PreferencesKeys.limitsConfiguration) as? LimitsConfiguration ?? LimitsConfiguration.defaultValue + return transaction.getPreferencesEntry(key: PreferencesKeys.limitsConfiguration)?.get(LimitsConfiguration.self) ?? LimitsConfiguration.defaultValue } let cachedData = context.account.postbox.transaction { transaction -> CachedPeerData? in @@ -1131,7 +1131,7 @@ private func canPerformDeleteActions(limits: LimitsConfiguration, accountPeerId: func chatAvailableMessageActionsImpl(postbox: Postbox, accountPeerId: PeerId, messageIds: Set, messages: [MessageId: Message] = [:], peers: [PeerId: Peer] = [:]) -> Signal { return postbox.transaction { transaction -> ChatAvailableMessageActions in - let limitsConfiguration: LimitsConfiguration = transaction.getPreferencesEntry(key: PreferencesKeys.limitsConfiguration) as? LimitsConfiguration ?? LimitsConfiguration.defaultValue + let limitsConfiguration: LimitsConfiguration = transaction.getPreferencesEntry(key: PreferencesKeys.limitsConfiguration)?.get(LimitsConfiguration.self) ?? LimitsConfiguration.defaultValue var optionsMap: [MessageId: ChatAvailableMessageActionOptions] = [:] var banPeer: Peer? var hadPersonalIncoming = false @@ -1166,8 +1166,8 @@ func chatAvailableMessageActionsImpl(postbox: Postbox, accountPeerId: PeerId, me if let message = getMessage(id) { for media in message.media { if let file = media as? TelegramMediaFile, file.isSticker { - for case let .Sticker(sticker) in file.attributes { - if let _ = sticker.packReference { + for case let .Sticker(_, packReference, _) in file.attributes { + if let _ = packReference { optionsMap[id]!.insert(.viewStickerPack) } break diff --git a/submodules/TelegramUI/Sources/ChatInterfaceStateContextQueries.swift b/submodules/TelegramUI/Sources/ChatInterfaceStateContextQueries.swift index ee8fa435d0..a57dba33ed 100644 --- a/submodules/TelegramUI/Sources/ChatInterfaceStateContextQueries.swift +++ b/submodules/TelegramUI/Sources/ChatInterfaceStateContextQueries.swift @@ -102,11 +102,11 @@ private func updatedContextQueryResultStateForQuery(context: AccountContext, pee let stickerConfiguration = context.account.postbox.preferencesView(keys: [PreferencesKeys.appConfiguration]) |> map { preferencesView -> StickersSearchConfiguration in - let appConfiguration: AppConfiguration = preferencesView.values[PreferencesKeys.appConfiguration] as? AppConfiguration ?? .defaultValue + let appConfiguration: AppConfiguration = preferencesView.values[PreferencesKeys.appConfiguration]?.get(AppConfiguration.self) ?? .defaultValue return StickersSearchConfiguration.with(appConfiguration: appConfiguration) } let stickerSettings = context.sharedContext.accountManager.transaction { transaction -> StickerSettings in - let stickerSettings: StickerSettings = (transaction.getSharedData(ApplicationSpecificSharedDataKeys.stickerSettings) as? StickerSettings) ?? .defaultSettings + let stickerSettings: StickerSettings = transaction.getSharedData(ApplicationSpecificSharedDataKeys.stickerSettings)?.get(StickerSettings.self) ?? .defaultSettings return stickerSettings } diff --git a/submodules/TelegramUI/Sources/ChatMediaInputNode.swift b/submodules/TelegramUI/Sources/ChatMediaInputNode.swift index 819b35c16f..05ccded636 100644 --- a/submodules/TelegramUI/Sources/ChatMediaInputNode.swift +++ b/submodules/TelegramUI/Sources/ChatMediaInputNode.swift @@ -1077,7 +1077,7 @@ final class ChatMediaInputNode: ChatInputNode { guard let view = views.views[preferencesViewKey] as? PreferencesView else { return defaultReactions } - guard let appConfiguration = view.values[PreferencesKeys.appConfiguration] as? AppConfiguration else { + guard let appConfiguration = view.values[PreferencesKeys.appConfiguration]?.get(AppConfiguration.self) else { return defaultReactions } guard let data = appConfiguration.data, let emojis = data["gif_search_emojies"] as? [String] else { diff --git a/submodules/TelegramUI/Sources/ChatMessageAnimatedStickerItemNode.swift b/submodules/TelegramUI/Sources/ChatMessageAnimatedStickerItemNode.swift index 9050165f81..292d5a5b60 100644 --- a/submodules/TelegramUI/Sources/ChatMessageAnimatedStickerItemNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageAnimatedStickerItemNode.swift @@ -1388,7 +1388,7 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView { let appConfiguration = item.context.account.postbox.preferencesView(keys: [PreferencesKeys.appConfiguration]) |> take(1) |> map { view in - return view.values[PreferencesKeys.appConfiguration] as? AppConfiguration ?? .defaultValue + return view.values[PreferencesKeys.appConfiguration]?.get(AppConfiguration.self) ?? .defaultValue } if let text = self.item?.message.text, var firstScalar = text.unicodeScalars.first { diff --git a/submodules/TelegramUI/Sources/ChatMessageAvatarAccessoryItem.swift b/submodules/TelegramUI/Sources/ChatMessageAvatarAccessoryItem.swift index bf81f9ace3..eb86e97f8f 100644 --- a/submodules/TelegramUI/Sources/ChatMessageAvatarAccessoryItem.swift +++ b/submodules/TelegramUI/Sources/ChatMessageAvatarAccessoryItem.swift @@ -168,8 +168,8 @@ final class ChatMessageAvatarAccessoryItemNode: ListViewAccessoryItemNode { func setPeer(context: AccountContext, theme: PresentationTheme, synchronousLoad: Bool, peer: Peer, authorOfMessage: MessageReference?, emptyColor: UIColor, controllerInteraction: ChatControllerInteraction) { self.controllerInteraction = controllerInteraction self.peer = peer - if let messageReference = authorOfMessage, case let .message(m) = messageReference.content { - self.messageId = m.id + if let messageReference = authorOfMessage, case let .message(_, id, _, _, _) = messageReference.content { + self.messageId = id } self.contextActionIsEnabled = peer.smallProfileImage != nil diff --git a/submodules/TelegramUI/Sources/ChatMessageBackground.swift b/submodules/TelegramUI/Sources/ChatMessageBackground.swift index e8acf53139..c618c7d7b9 100644 --- a/submodules/TelegramUI/Sources/ChatMessageBackground.swift +++ b/submodules/TelegramUI/Sources/ChatMessageBackground.swift @@ -101,7 +101,6 @@ class ChatMessageBackground: ASDisplayNode { func setType(type: ChatMessageBackgroundType, highlighted: Bool, graphics: PrincipalThemeEssentialGraphics, maskMode: Bool, hasWallpaper: Bool, transition: ContainedViewLayoutTransition, backgroundNode: WallpaperBackgroundNode?) { let previousType = self.type - let previousHighlighted = self.currentHighlighted if let currentType = previousType, currentType == type, self.currentHighlighted == highlighted, self.graphics === graphics, backgroundNode === self.backgroundNode, self.maskMode == maskMode, self.hasWallpaper == hasWallpaper { return } diff --git a/submodules/TelegramUI/Sources/ChatMessageBubbleItemNode.swift b/submodules/TelegramUI/Sources/ChatMessageBubbleItemNode.swift index 84e05988ae..7355ccd1f0 100644 --- a/submodules/TelegramUI/Sources/ChatMessageBubbleItemNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageBubbleItemNode.swift @@ -1335,22 +1335,26 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode var addedContentNodes: [(Message, Bool, ChatMessageBubbleContentNode)]? let (contentNodeMessagesAndClasses, needSeparateContainers) = contentNodeMessagesAndClassesForItem(item) - for (contentNodeMessage, contentNodeClass, attributes, bubbleAttributes) in contentNodeMessagesAndClasses { + for contentNodeItemValue in contentNodeMessagesAndClasses { + let contentNodeItem = contentNodeItemValue as (message: Message, type: AnyClass, attributes: ChatMessageEntryAttributes, bubbleAttributes: BubbleItemAttributes) + var found = false - for (currentMessage, currentClass, supportsMosaic, currentLayout) in currentContentClassesPropertiesAndLayouts { - if currentClass == contentNodeClass && currentMessage.stableId == contentNodeMessage.stableId { - contentPropertiesAndPrepareLayouts.append((contentNodeMessage, supportsMosaic, attributes, bubbleAttributes, currentLayout)) + for currentNodeItemValue in currentContentClassesPropertiesAndLayouts { + let currentNodeItem = currentNodeItemValue as (message: Message, type: AnyClass, supportsMosaic: Bool, currentLayout: (ChatMessageBubbleContentItem, ChatMessageItemLayoutConstants, ChatMessageBubblePreparePosition, Bool?, CGSize) -> (ChatMessageBubbleContentProperties, CGSize?, CGFloat, (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool) -> Void)))) + + if currentNodeItem.type == contentNodeItem.type && currentNodeItem.message.stableId == contentNodeItem.message.stableId { + contentPropertiesAndPrepareLayouts.append((contentNodeItem.message, currentNodeItem.supportsMosaic, contentNodeItem.attributes, contentNodeItem.bubbleAttributes, currentNodeItem.currentLayout)) found = true break } } if !found { - let contentNode = (contentNodeClass as! ChatMessageBubbleContentNode.Type).init() - contentPropertiesAndPrepareLayouts.append((contentNodeMessage, contentNode.supportsMosaic, attributes, bubbleAttributes, contentNode.asyncLayoutContent())) + let contentNode = (contentNodeItem.type as! ChatMessageBubbleContentNode.Type).init() + contentPropertiesAndPrepareLayouts.append((contentNodeItem.message, contentNode.supportsMosaic, contentNodeItem.attributes, contentNodeItem.bubbleAttributes, contentNode.asyncLayoutContent())) if addedContentNodes == nil { addedContentNodes = [] } - addedContentNodes!.append((contentNodeMessage, bubbleAttributes.isAttachment, contentNode)) + addedContentNodes!.append((contentNodeItem.message, contentNodeItem.bubbleAttributes.isAttachment, contentNode)) } } @@ -1862,8 +1866,10 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode findRemoved: for i in 0 ..< currentContentClassesPropertiesAndLayouts.count { let currentMessage = currentContentClassesPropertiesAndLayouts[i].0 let currentClass: AnyClass = currentContentClassesPropertiesAndLayouts[i].1 - for (contentNodeMessage, contentNodeClass, _, _) in contentNodeMessagesAndClasses { - if currentClass == contentNodeClass && currentMessage.stableId == contentNodeMessage.stableId { + for contentItemValue in contentNodeMessagesAndClasses { + let contentItem = contentItemValue as (message: Message, type: AnyClass, ChatMessageEntryAttributes, BubbleItemAttributes) + + if currentClass == contentItem.type && currentMessage.stableId == contentItem.message.stableId { continue findRemoved } } @@ -1944,7 +1950,12 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode bottomLeft = .merged bottomRight = .merged } else { - switch lastNodeTopPosition { + var switchValue = lastNodeTopPosition + if !"".isEmpty { + switchValue = .BubbleNeighbour + } + + switch switchValue { case .Neighbour: bottomLeft = .merged bottomRight = .merged @@ -2685,17 +2696,19 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode } var sortedContentNodes: [ChatMessageBubbleContentNode] = [] - outer: for (message, nodeClass, _, _) in contentNodeMessagesAndClasses { + outer: for contentItemValue in contentNodeMessagesAndClasses { + let contentItem = contentItemValue as (message: Message, type: AnyClass, ChatMessageEntryAttributes, BubbleItemAttributes) + if let addedContentNodes = addedContentNodes { for (contentNodeMessage, _, contentNode) in addedContentNodes { - if type(of: contentNode) == nodeClass && contentNodeMessage.stableId == message.stableId { + if type(of: contentNode) == contentItem.type && contentNodeMessage.stableId == contentItem.message.stableId { sortedContentNodes.append(contentNode) continue outer } } } for contentNode in updatedContentNodes { - if type(of: contentNode) == nodeClass && contentNode.item?.message.stableId == message.stableId { + if type(of: contentNode) == contentItem.type && contentNode.item?.message.stableId == contentItem.message.stableId { sortedContentNodes.append(contentNode) continue outer } diff --git a/submodules/TelegramUI/Sources/ChatMessageDateHeader.swift b/submodules/TelegramUI/Sources/ChatMessageDateHeader.swift index ec201e8fa3..f1a3477e78 100644 --- a/submodules/TelegramUI/Sources/ChatMessageDateHeader.swift +++ b/submodules/TelegramUI/Sources/ChatMessageDateHeader.swift @@ -415,8 +415,8 @@ final class ChatMessageAvatarHeaderNode: ListViewItemHeaderNode { return } var messageId: MessageId? - if let messageReference = messageReference, case let .message(m) = messageReference.content { - messageId = m.id + if let messageReference = messageReference, case let .message(_, id, _, _, _) = messageReference.content { + messageId = id } strongSelf.controllerInteraction.openPeerContextMenu(peer, messageId, strongSelf.containerNode, strongSelf.containerNode.bounds, gesture) } diff --git a/submodules/TelegramUI/Sources/ChatMessageInteractiveMediaNode.swift b/submodules/TelegramUI/Sources/ChatMessageInteractiveMediaNode.swift index 4ee254e260..5b7b0e5f30 100644 --- a/submodules/TelegramUI/Sources/ChatMessageInteractiveMediaNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageInteractiveMediaNode.swift @@ -1103,12 +1103,12 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTransitio return } - let automaticDownload: Bool + /*let automaticDownload: Bool if let autoDownload = self.automaticDownload, case .full = autoDownload { automaticDownload = true } else { automaticDownload = false - } + }*/ var secretBeginTimeAndTimeout: (Double?, Double)? let isSecretMedia = message.containsSecretMedia @@ -1391,10 +1391,7 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTransitio case .Remote: state = .download(messageTheme.mediaOverlayControlColors.foregroundColor) if let file = self.media as? TelegramMediaFile { - if false, file.isAnimated && (!automaticDownload || !automaticPlayback) { - let string = "\(gifTitle) " + dataSizeString(file.size ?? 0, formatting: formatting) - badgeContent = .mediaDownload(backgroundColor: messageTheme.mediaDateAndStatusFillColor, foregroundColor: messageTheme.mediaDateAndStatusTextColor, duration: string, size: nil, muted: false, active: false) - } else { + do { let durationString = file.isAnimated ? gifTitle : stringForDuration(playerDuration > 0 ? playerDuration : (file.duration ?? 0), position: playerPosition) if wideLayout { if isMediaStreamable(message: message, media: file) { diff --git a/submodules/TelegramUI/Sources/ChatMessageItem.swift b/submodules/TelegramUI/Sources/ChatMessageItem.swift index 02c67b230a..2fd6411bc5 100644 --- a/submodules/TelegramUI/Sources/ChatMessageItem.swift +++ b/submodules/TelegramUI/Sources/ChatMessageItem.swift @@ -47,8 +47,8 @@ public enum ChatMessageItemContent: Sequence { var firstMessageAttributes: ChatMessageEntryAttributes { switch self { - case let .message(message): - return message.attributes + case let .message(_, _, _, attributes): + return attributes case let .group(messages): return messages[0].3 } @@ -58,10 +58,10 @@ public enum ChatMessageItemContent: Sequence { var index = 0 return AnyIterator { () -> (Message, ChatMessageEntryAttributes)? in switch self { - case let .message(message): + case let .message(message, _, _, attributes): if index == 0 { index += 1 - return (message.message, message.attributes) + return (message, attributes) } else { index += 1 return nil diff --git a/submodules/TelegramUI/Sources/ChatMessageItemView.swift b/submodules/TelegramUI/Sources/ChatMessageItemView.swift index 614713e13d..1595531c00 100644 --- a/submodules/TelegramUI/Sources/ChatMessageItemView.swift +++ b/submodules/TelegramUI/Sources/ChatMessageItemView.swift @@ -255,14 +255,14 @@ final class ChatMessageAccessibilityData { label = item.presentationData.strings.VoiceOver_Chat_YourSticker } } - case let .Audio(audio): + case let .Audio(isVoice, duration, title, performer, _): isSpecialFile = true if isSelected == nil { hint = item.presentationData.strings.VoiceOver_Chat_PlayHint } traits.insert(.startsMediaSession) - if audio.isVoice { - let durationString = voiceMessageDurationFormatter.string(from: Double(audio.duration)) ?? "" + if isVoice { + let durationString = voiceMessageDurationFormatter.string(from: Double(duration)) ?? "" if isIncoming { if announceIncomingAuthors, let authorName = authorName { label = item.presentationData.strings.VoiceOver_Chat_VoiceMessageFrom(authorName).string @@ -274,7 +274,7 @@ final class ChatMessageAccessibilityData { } text = item.presentationData.strings.VoiceOver_Chat_Duration(durationString).string } else { - let durationString = musicDurationFormatter.string(from: Double(audio.duration)) ?? "" + let durationString = musicDurationFormatter.string(from: Double(duration)) ?? "" if isIncoming { if announceIncomingAuthors, let authorName = authorName { label = item.presentationData.strings.VoiceOver_Chat_MusicFrom(authorName).string @@ -284,20 +284,20 @@ final class ChatMessageAccessibilityData { } else { label = item.presentationData.strings.VoiceOver_Chat_YourMusic } - let performer = audio.performer ?? "Unknown" - let title = audio.title ?? "Unknown" + let performer = performer ?? "Unknown" + let title = title ?? "Unknown" text = item.presentationData.strings.VoiceOver_Chat_MusicTitle(title, performer).string text.append(item.presentationData.strings.VoiceOver_Chat_Duration(durationString).string) } - case let .Video(video): + case let .Video(duration, _, flags): isSpecialFile = true if isSelected == nil { hint = item.presentationData.strings.VoiceOver_Chat_PlayHint } traits.insert(.startsMediaSession) - let durationString = voiceMessageDurationFormatter.string(from: Double(video.duration)) ?? "" - if video.flags.contains(.instantRoundVideo) { + let durationString = voiceMessageDurationFormatter.string(from: Double(duration)) ?? "" + if flags.contains(.instantRoundVideo) { if isIncoming { if announceIncomingAuthors, let authorName = authorName { label = item.presentationData.strings.VoiceOver_Chat_VideoMessageFrom(authorName).string @@ -895,10 +895,6 @@ public class ChatMessageItemView: ListViewItemNode { } override public var preferredAnimationCurve: (CGFloat) -> CGFloat { - if false, let item = self.item, let subject = item.associatedData.subject, case .forwardedMessages = subject { - return listViewAnimationCurveEaseInOut - } else { - return listViewAnimationCurveSystem - } + return listViewAnimationCurveSystem } } diff --git a/submodules/TelegramUI/Sources/ChatMessageWebpageBubbleContentNode.swift b/submodules/TelegramUI/Sources/ChatMessageWebpageBubbleContentNode.swift index d851547ee1..59f20e8060 100644 --- a/submodules/TelegramUI/Sources/ChatMessageWebpageBubbleContentNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageWebpageBubbleContentNode.swift @@ -290,7 +290,7 @@ final class ChatMessageWebpageBubbleContentNode: ChatMessageBubbleContentNode { case "telegram_message": actionTitle = item.presentationData.strings.Conversation_ViewMessage case "telegram_voicechat": - if let channel = item.message.peers[item.message.id.peerId] as? TelegramChannel, case let .broadcast = channel.info { + if let channel = item.message.peers[item.message.id.peerId] as? TelegramChannel, case .broadcast = channel.info { title = item.presentationData.strings.Conversation_LiveStream } else { title = item.presentationData.strings.Conversation_VoiceChat diff --git a/submodules/TelegramUI/Sources/ChatSearchResultsContollerNode.swift b/submodules/TelegramUI/Sources/ChatSearchResultsContollerNode.swift index 901788194a..1756c19d0d 100644 --- a/submodules/TelegramUI/Sources/ChatSearchResultsContollerNode.swift +++ b/submodules/TelegramUI/Sources/ChatSearchResultsContollerNode.swift @@ -203,9 +203,9 @@ class ChatSearchResultsControllerNode: ViewControllerTracingNode, UIScrollViewDe return } switch item.content { - case let .peer(peer): - if let message = peer.messages.first { - let chatController = strongSelf.context.sharedContext.makeChatController(context: strongSelf.context, chatLocation: .peer(peer.peer.peerId), subject: .message(id: message.id, highlight: true, timecode: nil), botStart: nil, mode: .standard(previewing: true)) + case let .peer(messages, peer, _, _, _, _, _, _, _, _, _, _): + if let message = messages.first { + let chatController = strongSelf.context.sharedContext.makeChatController(context: strongSelf.context, chatLocation: .peer(peer.peerId), subject: .message(id: message.id, highlight: true, timecode: nil), botStart: nil, mode: .standard(previewing: true)) chatController.canReadHistory.set(false) let contextController = ContextController(account: strongSelf.context.account, presentationData: strongSelf.presentationData, source: .controller(ContextControllerContentSourceImpl(controller: chatController, sourceNode: node)), items: .single([]), reactionItems: [], gesture: gesture) presentInGlobalOverlay(contextController) diff --git a/submodules/TelegramUI/Sources/ChatTextInputAudioRecordingOverlayButton.swift b/submodules/TelegramUI/Sources/ChatTextInputAudioRecordingOverlayButton.swift index a4940fff0f..c527609339 100644 --- a/submodules/TelegramUI/Sources/ChatTextInputAudioRecordingOverlayButton.swift +++ b/submodules/TelegramUI/Sources/ChatTextInputAudioRecordingOverlayButton.swift @@ -3,6 +3,7 @@ import UIKit import Display import AsyncDisplayKit import AppBundle +import ObjCRuntimeUtils private let innerCircleDiameter: CGFloat = 110.0 private let outerCircleDiameter = innerCircleDiameter + 50.0 @@ -138,7 +139,7 @@ final class ChatTextInputAudioRecordingOverlay { }) var currentScaleValue: CGFloat = outerCircleMinScale - if let currentScale = self.outerCircleNode.layer.value(forKeyPath: "transform.scale") as? AnyObject, currentScale.responds(to: Selector("floatValue")) { + if let currentScale = self.outerCircleNode.layer.floatValue(forKeyPath: "transform.scale") { currentScaleValue = CGFloat(currentScale.floatValue) } diff --git a/submodules/TelegramUI/Sources/ChatTextInputPanelNode.swift b/submodules/TelegramUI/Sources/ChatTextInputPanelNode.swift index 499549bcae..3443208630 100644 --- a/submodules/TelegramUI/Sources/ChatTextInputPanelNode.swift +++ b/submodules/TelegramUI/Sources/ChatTextInputPanelNode.swift @@ -14,6 +14,7 @@ import ImageTransparency import ActivityIndicator import AnimationUI import Speak +import ObjCRuntimeUtils private let accessoryButtonFont = Font.medium(14.0) private let counterFont = Font.with(size: 14.0, design: .regular, traits: [.monospacedNumbers]) @@ -1969,7 +1970,7 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate { } func editableTextNodeTarget(forAction action: Selector) -> ASEditableTextNodeTargetForAction? { - if action == Selector(("_accessibilitySpeak:")) { + if action == makeSelectorFromString("_accessibilitySpeak:") { if case .format = self.inputMenu.state { return ASEditableTextNodeTargetForAction(target: nil) } else if let textInputNode = self.textInputNode, textInputNode.selectedRange.length > 0 { @@ -1977,7 +1978,7 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate { } else { return ASEditableTextNodeTargetForAction(target: nil) } - } else if action == Selector(("_accessibilitySpeakSpellOut:")) { + } else if action == makeSelectorFromString("_accessibilitySpeakSpellOut:") { if case .format = self.inputMenu.state { return ASEditableTextNodeTargetForAction(target: nil) } else if let textInputNode = self.textInputNode, textInputNode.selectedRange.length > 0 { @@ -1986,9 +1987,9 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate { return ASEditableTextNodeTargetForAction(target: nil) } } - else if action == Selector("_accessibilitySpeakLanguageSelection:") || action == Selector("_accessibilityPauseSpeaking:") || action == Selector("_accessibilitySpeakSentence:") { + else if action == makeSelectorFromString("_accessibilitySpeakLanguageSelection:") || action == makeSelectorFromString("_accessibilityPauseSpeaking:") || action == makeSelectorFromString("_accessibilitySpeakSentence:") { return ASEditableTextNodeTargetForAction(target: nil) - } else if action == Selector(("_showTextStyleOptions:")) { + } else if action == makeSelectorFromString("_showTextStyleOptions:") { if case .general = self.inputMenu.state { if let textInputNode = self.textInputNode, textInputNode.attributedText == nil || textInputNode.attributedText!.length == 0 || textInputNode.selectedRange.length == 0 { return ASEditableTextNodeTargetForAction(target: nil) diff --git a/submodules/TelegramUI/Sources/ContactMultiselectionController.swift b/submodules/TelegramUI/Sources/ContactMultiselectionController.swift index 26ffc272b3..a16b3d5bbc 100644 --- a/submodules/TelegramUI/Sources/ContactMultiselectionController.swift +++ b/submodules/TelegramUI/Sources/ContactMultiselectionController.swift @@ -204,8 +204,8 @@ class ContactMultiselectionControllerImpl: ViewController, ContactMultiselection self.navigationItem.leftBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.Common_Cancel, style: .plain, target: self, action: #selector(cancelPressed)) self.navigationItem.rightBarButtonItem = self.rightNavigationButton rightNavigationButton.isEnabled = false - case let .chatSelection(chatSelection): - self.titleView.title = CounterContollerTitle(title: chatSelection.title, counter: "") + case let .chatSelection(title, _, _, _): + self.titleView.title = CounterContollerTitle(title: title, counter: "") let rightNavigationButton = UIBarButtonItem(title: self.presentationData.strings.Common_Done, style: .done, target: self, action: #selector(self.rightNavigationButtonPressed)) self.rightNavigationButton = rightNavigationButton self.navigationItem.leftBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.Common_Cancel, style: .plain, target: self, action: #selector(cancelPressed)) diff --git a/submodules/TelegramUI/Sources/CreateGroupController.swift b/submodules/TelegramUI/Sources/CreateGroupController.swift index 0df811dd31..d0f04d282b 100644 --- a/submodules/TelegramUI/Sources/CreateGroupController.swift +++ b/submodules/TelegramUI/Sources/CreateGroupController.swift @@ -488,7 +488,6 @@ public func createGroupControllerImpl(context: AccountContext, peerIds: [PeerId] return .complete() } |> mapToSignal { _ -> Signal in - return .complete() } |> then(.single(peerId)) } else { diff --git a/submodules/TelegramUI/Sources/DeclareEncodables.swift b/submodules/TelegramUI/Sources/DeclareEncodables.swift index 444cfa1312..05d4689baa 100644 --- a/submodules/TelegramUI/Sources/DeclareEncodables.swift +++ b/submodules/TelegramUI/Sources/DeclareEncodables.swift @@ -14,49 +14,49 @@ import LocationUI import ChatInterfaceState private var telegramUIDeclaredEncodables: Void = { - declareEncodable(InAppNotificationSettings.self, f: { InAppNotificationSettings(decoder: $0) }) + //declareEncodable(InAppNotificationSettings.self, f: { InAppNotificationSettings(decoder: $0) }) declareEncodable(VideoLibraryMediaResource.self, f: { VideoLibraryMediaResource(decoder: $0) }) declareEncodable(LocalFileVideoMediaResource.self, f: { LocalFileVideoMediaResource(decoder: $0) }) declareEncodable(LocalFileGifMediaResource.self, f: { LocalFileGifMediaResource(decoder: $0) }) declareEncodable(PhotoLibraryMediaResource.self, f: { PhotoLibraryMediaResource(decoder: $0) }) - declareEncodable(PresentationPasscodeSettings.self, f: { PresentationPasscodeSettings(decoder: $0) }) - declareEncodable(MediaAutoDownloadSettings.self, f: { MediaAutoDownloadSettings(decoder: $0) }) - declareEncodable(AutomaticMediaDownloadSettings.self, f: { AutomaticMediaDownloadSettings(decoder: $0) }) - declareEncodable(GeneratedMediaStoreSettings.self, f: { GeneratedMediaStoreSettings(decoder: $0) }) - declareEncodable(PresentationThemeSettings.self, f: { PresentationThemeSettings(decoder: $0) }) + //declareEncodable(PresentationPasscodeSettings.self, f: { PresentationPasscodeSettings(decoder: $0) }) + //declareEncodable(MediaAutoDownloadSettings.self, f: { MediaAutoDownloadSettings(decoder: $0) }) + //declareEncodable(AutomaticMediaDownloadSettings.self, f: { AutomaticMediaDownloadSettings(decoder: $0) }) + //declareEncodable(GeneratedMediaStoreSettings.self, f: { GeneratedMediaStoreSettings(decoder: $0) }) + //declareEncodable(PresentationThemeSettings.self, f: { PresentationThemeSettings(decoder: $0) }) declareEncodable(ApplicationSpecificBoolNotice.self, f: { ApplicationSpecificBoolNotice(decoder: $0) }) declareEncodable(ApplicationSpecificVariantNotice.self, f: { ApplicationSpecificVariantNotice(decoder: $0) }) declareEncodable(ApplicationSpecificCounterNotice.self, f: { ApplicationSpecificCounterNotice(decoder: $0) }) declareEncodable(ApplicationSpecificTimestampNotice.self, f: { ApplicationSpecificTimestampNotice(decoder: $0) }) declareEncodable(ApplicationSpecificInt64ArrayNotice.self, f: { ApplicationSpecificInt64ArrayNotice(decoder: $0) }) - declareEncodable(CallListSettings.self, f: { CallListSettings(decoder: $0) }) - declareEncodable(VoiceCallSettings.self, f: { VoiceCallSettings(decoder: $0) }) - declareEncodable(ExperimentalSettings.self, f: { ExperimentalSettings(decoder: $0) }) - declareEncodable(ExperimentalUISettings.self, f: { ExperimentalUISettings(decoder: $0) }) - declareEncodable(MusicPlaybackSettings.self, f: { MusicPlaybackSettings(decoder: $0) }) + //declareEncodable(CallListSettings.self, f: { CallListSettings(decoder: $0) }) + //declareEncodable(VoiceCallSettings.self, f: { VoiceCallSettings(decoder: $0) }) + //declareEncodable(ExperimentalSettings.self, f: { ExperimentalSettings(decoder: $0) }) + //declareEncodable(ExperimentalUISettings.self, f: { ExperimentalUISettings(decoder: $0) }) + //declareEncodable(MusicPlaybackSettings.self, f: { MusicPlaybackSettings(decoder: $0) }) declareEncodable(ICloudFileResource.self, f: { ICloudFileResource(decoder: $0) }) - declareEncodable(MediaInputSettings.self, f: { MediaInputSettings(decoder: $0) }) - declareEncodable(ContactSynchronizationSettings.self, f: { ContactSynchronizationSettings(decoder: $0) }) + //declareEncodable(MediaInputSettings.self, f: { MediaInputSettings(decoder: $0) }) + //declareEncodable(ContactSynchronizationSettings.self, f: { ContactSynchronizationSettings(decoder: $0) }) declareEncodable(CachedChannelAdminRanks.self, f: { CachedChannelAdminRanks(decoder: $0) }) - declareEncodable(StickerSettings.self, f: { StickerSettings(decoder: $0) }) - declareEncodable(InstantPagePresentationSettings.self, f: { InstantPagePresentationSettings(decoder: $0) }) + //declareEncodable(StickerSettings.self, f: { StickerSettings(decoder: $0) }) + //declareEncodable(InstantPagePresentationSettings.self, f: { InstantPagePresentationSettings(decoder: $0) }) declareEncodable(InstantPageStoredState.self, f: { InstantPageStoredState(decoder: $0) }) declareEncodable(InstantPageStoredDetailsState.self, f: { InstantPageStoredDetailsState(decoder: $0) }) declareEncodable(CachedInstantPage.self, f: { CachedInstantPage(decoder: $0) }) declareEncodable(CachedWallpaper.self, f: { CachedWallpaper(decoder: $0) }) - declareEncodable(WatchPresetSettings.self, f: { WatchPresetSettings(decoder: $0) }) - declareEncodable(WebSearchSettings.self, f: { WebSearchSettings(decoder: $0) }) + //declareEncodable(WatchPresetSettings.self, f: { WatchPresetSettings(decoder: $0) }) + //declareEncodable(WebSearchSettings.self, f: { WebSearchSettings(decoder: $0) }) declareEncodable(RecentWebSearchQueryItem.self, f: { RecentWebSearchQueryItem(decoder: $0) }) declareEncodable(RecentWallpaperSearchQueryItem.self, f: { RecentWallpaperSearchQueryItem(decoder: $0) }) declareEncodable(RecentSettingsSearchQueryItem.self, f: { RecentSettingsSearchQueryItem(decoder: $0) }) - declareEncodable(VoipDerivedState.self, f: { VoipDerivedState(decoder: $0) }) - declareEncodable(ChatArchiveSettings.self, f: { ChatArchiveSettings(decoder: $0) }) + //declareEncodable(VoipDerivedState.self, f: { VoipDerivedState(decoder: $0) }) + //declareEncodable(ChatArchiveSettings.self, f: { ChatArchiveSettings(decoder: $0) }) declareEncodable(MediaPlaybackStoredState.self, f: { MediaPlaybackStoredState(decoder: $0) }) - declareEncodable(WebBrowserSettings.self, f: { WebBrowserSettings(decoder: $0) }) - declareEncodable(IntentsSettings.self, f: { IntentsSettings(decoder: $0) }) + //declareEncodable(WebBrowserSettings.self, f: { WebBrowserSettings(decoder: $0) }) + //declareEncodable(IntentsSettings.self, f: { IntentsSettings(decoder: $0) }) declareEncodable(CachedGeocode.self, f: { CachedGeocode(decoder: $0) }) - declareEncodable(ChatListFilterSettings.self, f: { ChatListFilterSettings(decoder: $0) }) - declareEncodable(WidgetSettings.self, f: { WidgetSettings(decoder: $0) }) + //declareEncodable(ChatListFilterSettings.self, f: { ChatListFilterSettings(decoder: $0) }) + //declareEncodable(WidgetSettings.self, f: { WidgetSettings(decoder: $0) }) return }() diff --git a/submodules/TelegramUI/Sources/DrawingStickersScreen.swift b/submodules/TelegramUI/Sources/DrawingStickersScreen.swift index 3dbcb071f0..4216d2b477 100644 --- a/submodules/TelegramUI/Sources/DrawingStickersScreen.swift +++ b/submodules/TelegramUI/Sources/DrawingStickersScreen.swift @@ -954,7 +954,7 @@ private final class DrawingStickersScreenNode: ViewControllerTracingNode { func updateLayout(width: CGFloat, topInset: CGFloat, leftInset: CGFloat, rightInset: CGFloat, bottomInset: CGFloat, standardInputHeight: CGFloat, inputHeight: CGFloat, maximumHeight: CGFloat, inputPanelHeight: CGFloat, transition: ContainedViewLayoutTransition, deviceMetrics: DeviceMetrics, isVisible: Bool) -> (CGFloat, CGFloat) { let searchMode: ChatMediaInputSearchMode? = nil - let displaySearch = false + let displaySearch = !"".isEmpty //silence warning let separatorHeight = max(UIScreenPixel, 1.0 - UIScreenPixel) let topPanelHeight: CGFloat = 56.0 let panelHeight: CGFloat diff --git a/submodules/TelegramUI/Sources/EmojiResources.swift b/submodules/TelegramUI/Sources/EmojiResources.swift index 849c21353f..a16daab35d 100644 --- a/submodules/TelegramUI/Sources/EmojiResources.swift +++ b/submodules/TelegramUI/Sources/EmojiResources.swift @@ -334,7 +334,9 @@ func fetchEmojiSpriteResource(account: Account, resource: EmojiSpriteResource) - if buffer.data.count < range.count { buffer.data.count = range.count } - buffer.data.withUnsafeMutableBytes { (bytes: UnsafeMutablePointer) -> Void in + buffer.data.withUnsafeMutableBytes { rawBytes -> Void in + let bytes = rawBytes.baseAddress!.assumingMemoryBound(to: UInt8.self) + data.copyBytes(to: bytes, from: range) } } @@ -343,7 +345,9 @@ func fetchEmojiSpriteResource(account: Account, resource: EmojiSpriteResource) - if buffer.data.count < resourceOffset + range.count { buffer.data.count = resourceOffset + range.count } - buffer.data.withUnsafeMutableBytes { (bytes: UnsafeMutablePointer) -> Void in + buffer.data.withUnsafeMutableBytes { rawBytes -> Void in + let bytes = rawBytes.baseAddress!.assumingMemoryBound(to: UInt8.self) + data.copyBytes(to: bytes.advanced(by: resourceOffset), from: range) } } diff --git a/submodules/TelegramUI/Sources/FetchManager.swift b/submodules/TelegramUI/Sources/FetchManager.swift index 9647c451b7..028bf0d04f 100644 --- a/submodules/TelegramUI/Sources/FetchManager.swift +++ b/submodules/TelegramUI/Sources/FetchManager.swift @@ -24,9 +24,10 @@ private struct FetchManagerLocationEntryId: Hashable { } return true } - - var hashValue: Int { - return self.resourceId.hashValue &* 31 &+ self.locationKey.hashValue + + func hash(into hasher: inout Hasher) { + hasher.combine(self.resourceId.hashValue) + hasher.combine(self.locationKey) } } @@ -221,7 +222,6 @@ private final class FetchManagerCategoryContext { return storeDownloadedMedia(storeManager: storeManager, media: mediaReference, peerType: peerType) |> castError(FetchResourceError.self) |> mapToSignal { _ -> Signal in - return .complete() } |> then(.single(type)) } @@ -349,7 +349,7 @@ private final class FetchManagerCategoryContext { if isVideoPreload { activeContext.disposable = (preloadVideoResource(postbox: self.postbox, resourceReference: entry.resourceReference, duration: 4.0) |> castError(FetchResourceError.self) - |> map { _ -> FetchResourceSourceType in return .local } + |> map { _ -> FetchResourceSourceType in } |> then(.single(.local)) |> deliverOnMainQueue).start(next: { _ in entryCompleted(topEntryId) @@ -362,7 +362,6 @@ private final class FetchManagerCategoryContext { return storeDownloadedMedia(storeManager: storeManager, media: mediaReference, peerType: peerType) |> castError(FetchResourceError.self) |> mapToSignal { _ -> Signal in - return .complete() } |> then(.single(type)) } diff --git a/submodules/TelegramUI/Sources/FetchVideoMediaResource.swift b/submodules/TelegramUI/Sources/FetchVideoMediaResource.swift index 99d89c1a8e..3478ce8392 100644 --- a/submodules/TelegramUI/Sources/FetchVideoMediaResource.swift +++ b/submodules/TelegramUI/Sources/FetchVideoMediaResource.swift @@ -210,7 +210,7 @@ public func fetchVideoLibraryMediaResource(account: Account, resource: VideoLibr return account.postbox.preferencesView(keys: [PreferencesKeys.appConfiguration]) |> take(1) |> map { view in - return view.values[PreferencesKeys.appConfiguration] as? AppConfiguration ?? .defaultValue + return view.values[PreferencesKeys.appConfiguration]?.get(AppConfiguration.self) ?? .defaultValue } |> castError(MediaResourceDataFetchError.self) |> mapToSignal { appConfiguration -> Signal in @@ -323,7 +323,7 @@ func fetchLocalFileVideoMediaResource(account: Account, resource: LocalFileVideo return account.postbox.preferencesView(keys: [PreferencesKeys.appConfiguration]) |> take(1) |> map { view in - return view.values[PreferencesKeys.appConfiguration] as? AppConfiguration ?? .defaultValue + return view.values[PreferencesKeys.appConfiguration]?.get(AppConfiguration.self) ?? .defaultValue } |> castError(MediaResourceDataFetchError.self) |> mapToSignal { appConfiguration -> Signal in diff --git a/submodules/TelegramUI/Sources/HorizontalListContextResultsChatInputContextPanelNode.swift b/submodules/TelegramUI/Sources/HorizontalListContextResultsChatInputContextPanelNode.swift index 14f0660861..169d75d239 100644 --- a/submodules/TelegramUI/Sources/HorizontalListContextResultsChatInputContextPanelNode.swift +++ b/submodules/TelegramUI/Sources/HorizontalListContextResultsChatInputContextPanelNode.swift @@ -14,9 +14,9 @@ import ContextUI private struct ChatContextResultStableId: Hashable { let result: ChatContextResult - - var hashValue: Int { - return result.id.hashValue + + func hash(into hasher: inout Hasher) { + hasher.combine(result.id.hashValue) } static func ==(lhs: ChatContextResultStableId, rhs: ChatContextResultStableId) -> Bool { diff --git a/submodules/TelegramUI/Sources/HorizontalStickerGridItem.swift b/submodules/TelegramUI/Sources/HorizontalStickerGridItem.swift index 1da6c74a9c..4e7f9e15d7 100755 --- a/submodules/TelegramUI/Sources/HorizontalStickerGridItem.swift +++ b/submodules/TelegramUI/Sources/HorizontalStickerGridItem.swift @@ -229,17 +229,10 @@ final class HorizontalStickerGridItemNode: GridItemNode { if self.currentIsPreviewing != isPreviewing { self.currentIsPreviewing = isPreviewing - - if isPreviewing { - self.layer.sublayerTransform = CATransform3DMakeScale(0.8, 0.8, 1.0) - if animated { - self.layer.animateSpring(from: 1.0 as NSNumber, to: 0.8 as NSNumber, keyPath: "sublayerTransform.scale", duration: 0.4) - } - } else { - self.layer.sublayerTransform = CATransform3DIdentity - if animated { - self.layer.animateSpring(from: 0.8 as NSNumber, to: 1.0 as NSNumber, keyPath: "sublayerTransform.scale", duration: 0.5) - } + + self.layer.sublayerTransform = CATransform3DIdentity + if animated { + self.layer.animateSpring(from: 0.8 as NSNumber, to: 1.0 as NSNumber, keyPath: "sublayerTransform.scale", duration: 0.5) } } } diff --git a/submodules/TelegramUI/Sources/ID3ArtworkReader.swift b/submodules/TelegramUI/Sources/ID3ArtworkReader.swift index 24f0f9f214..0fdc8aef04 100644 --- a/submodules/TelegramUI/Sources/ID3ArtworkReader.swift +++ b/submodules/TelegramUI/Sources/ID3ArtworkReader.swift @@ -99,8 +99,8 @@ private class DataStream { guard self.position + count <= self.data.count else { return nil } - let value = self.data.subdata(in: self.position ..< self.position + count).withUnsafeBytes { (pointer: UnsafePointer) -> T in - return pointer.pointee + let value = self.data.subdata(in: self.position ..< self.position + count).withUnsafeBytes { (pointer: UnsafeRawBufferPointer) -> T in + return pointer.baseAddress!.assumingMemoryBound(to: T.self).pointee } self.position += count return value diff --git a/submodules/TelegramUI/Sources/ManageSharedAccountInfo.swift b/submodules/TelegramUI/Sources/ManageSharedAccountInfo.swift index b6863bb552..543a1e6089 100644 --- a/submodules/TelegramUI/Sources/ManageSharedAccountInfo.swift +++ b/submodules/TelegramUI/Sources/ManageSharedAccountInfo.swift @@ -68,7 +68,7 @@ func sharedAccountInfos(accountManager: AccountManager take(1) |> mapToSignal { sharedData, accounts -> Signal in - let proxySettings = sharedData.entries[SharedDataKeys.proxySettings] as? ProxySettings + let proxySettings = sharedData.entries[SharedDataKeys.proxySettings]?.get(ProxySettings.self) let proxy = proxySettings?.effectiveActiveServer.flatMap { proxyServer -> AccountProxyConnection? in var username: String? var password: String? diff --git a/submodules/TelegramUI/Sources/ManagedAudioRecorder.swift b/submodules/TelegramUI/Sources/ManagedAudioRecorder.swift index 8e806c494d..62c84ba93a 100644 --- a/submodules/TelegramUI/Sources/ManagedAudioRecorder.swift +++ b/submodules/TelegramUI/Sources/ManagedAudioRecorder.swift @@ -234,7 +234,9 @@ final class ManagedAudioRecorderContext { var blockBuffer: CMBlockBuffer? let bytes = malloc(takeRange.count)! - toneData.withUnsafeBytes { (dataBytes: UnsafePointer) -> Void in + toneData.withUnsafeBytes { rawDataBytes -> Void in + let dataBytes = rawDataBytes.baseAddress!.assumingMemoryBound(to: UInt8.self) + memcpy(bytes, dataBytes.advanced(by: takeRange.lowerBound), takeRange.count) } let status = CMBlockBufferCreateWithMemoryBlock(allocator: nil, memoryBlock: bytes, blockLength: takeRange.count, blockAllocator: nil, customBlockSource: nil, offsetToData: 0, dataLength: takeRange.count, flags: 0, blockBufferOut: &blockBuffer) @@ -502,7 +504,9 @@ final class ManagedAudioRecorderContext { if audioBuffer.count != 0 { let takenBytes = min(self.audioBuffer.count, encoderPacketSizeInBytes - currentEncoderPacketSize) if takenBytes != 0 { - self.audioBuffer.withUnsafeBytes { (bytes: UnsafePointer) -> Void in + self.audioBuffer.withUnsafeBytes { rawBytes -> Void in + let bytes = rawBytes.baseAddress!.assumingMemoryBound(to: Int8.self) + memcpy(currentEncoderPacket.advanced(by: currentEncoderPacketSize), bytes, takenBytes) } self.audioBuffer.replaceSubrange(0 ..< takenBytes, with: Data()) @@ -511,9 +515,8 @@ final class ManagedAudioRecorderContext { } else if bufferOffset < Int(buffer.mDataByteSize) { let takenBytes = min(Int(buffer.mDataByteSize) - bufferOffset, encoderPacketSizeInBytes - currentEncoderPacketSize) if takenBytes != 0 { - self.audioBuffer.withUnsafeBytes { (bytes: UnsafePointer) -> Void in - memcpy(currentEncoderPacket.advanced(by: currentEncoderPacketSize), buffer.mData?.advanced(by: bufferOffset), takenBytes) - } + memcpy(currentEncoderPacket.advanced(by: currentEncoderPacketSize), buffer.mData?.advanced(by: bufferOffset), takenBytes) + bufferOffset += takenBytes currentEncoderPacketSize += takenBytes } @@ -562,7 +565,9 @@ final class ManagedAudioRecorderContext { let compressedSampleCount = self.compressedWaveformSamples.count / 2 if compressedSampleCount == 200 { - self.compressedWaveformSamples.withUnsafeMutableBytes { (compressedSamples: UnsafeMutablePointer) -> Void in + self.compressedWaveformSamples.withUnsafeMutableBytes { rawCompressedSamples -> Void in + let compressedSamples = rawCompressedSamples.baseAddress!.assumingMemoryBound(to: Int16.self) + for i in 0 ..< 100 { let maxSample = Int64(max(compressedSamples[i * 2 + 0], compressedSamples[i * 2 + 1])) compressedSamples[i] = Int16(maxSample) @@ -604,7 +609,9 @@ final class ManagedAudioRecorderContext { var waveform: Data? let count = self.compressedWaveformSamples.count / 2 - self.compressedWaveformSamples.withUnsafeMutableBytes { (samples: UnsafeMutablePointer) -> Void in + self.compressedWaveformSamples.withUnsafeMutableBytes { rawSamples -> Void in + let samples = rawSamples.baseAddress!.assumingMemoryBound(to: Int16.self) + for i in 0 ..< count { let sample = samples[i] let index = i * 100 / count diff --git a/submodules/TelegramUI/Sources/ManagedDiceAnimationNode.swift b/submodules/TelegramUI/Sources/ManagedDiceAnimationNode.swift index 0a5a2cdb37..ceaef5094e 100644 --- a/submodules/TelegramUI/Sources/ManagedDiceAnimationNode.swift +++ b/submodules/TelegramUI/Sources/ManagedDiceAnimationNode.swift @@ -133,7 +133,7 @@ final class ManagedDiceAnimationNode: ManagedAnimationNode, GenericAnimatedStick self.configuration.set(self.context.account.postbox.preferencesView(keys: [PreferencesKeys.appConfiguration]) |> map { preferencesView -> InteractiveEmojiConfiguration? in - let appConfiguration: AppConfiguration = preferencesView.values[PreferencesKeys.appConfiguration] as? AppConfiguration ?? .defaultValue + let appConfiguration: AppConfiguration = preferencesView.values[PreferencesKeys.appConfiguration]?.get(AppConfiguration.self) ?? .defaultValue return InteractiveEmojiConfiguration.with(appConfiguration: appConfiguration) }) self.emojis.set(context.engine.stickers.loadedStickerPack(reference: .dice(emoji), forceActualized: false) diff --git a/submodules/TelegramUI/Sources/MediaManager.swift b/submodules/TelegramUI/Sources/MediaManager.swift index 0b94cf60fd..f4abb6e120 100644 --- a/submodules/TelegramUI/Sources/MediaManager.swift +++ b/submodules/TelegramUI/Sources/MediaManager.swift @@ -479,7 +479,7 @@ public final class MediaManagerImpl: NSObject, MediaManager { inputData = self.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.musicPlaybackSettings]) |> take(1) |> mapToSignal { sharedData -> Signal<(Account, SharedMediaPlaylist, MusicPlaybackSettings, MediaPlaybackStoredState?)?, NoError> in - let settings = (sharedData.entries[ApplicationSpecificSharedDataKeys.musicPlaybackSettings] as? MusicPlaybackSettings) ?? MusicPlaybackSettings.defaultSettings + let settings = sharedData.entries[ApplicationSpecificSharedDataKeys.musicPlaybackSettings]?.get(MusicPlaybackSettings.self) ?? MusicPlaybackSettings.defaultSettings if let location = playlist.location as? PeerMessagesPlaylistLocation, let messageId = location.messageId { return mediaPlaybackStoredState(postbox: account.postbox, messageId: messageId) diff --git a/submodules/TelegramUI/Sources/OpenResolvedUrl.swift b/submodules/TelegramUI/Sources/OpenResolvedUrl.swift index 84c8380770..e8dc04e5a3 100644 --- a/submodules/TelegramUI/Sources/OpenResolvedUrl.swift +++ b/submodules/TelegramUI/Sources/OpenResolvedUrl.swift @@ -106,7 +106,7 @@ func openResolvedUrlImpl(_ resolvedUrl: ResolvedUrl, context: AccountContext, ur } case let .stickerPack(name): dismissInput() - if false { + /*if false { var mainStickerPack: StickerPackReference? var stickerPacks: [StickerPackReference] = [] if let message = contentContext as? Message { @@ -140,10 +140,10 @@ func openResolvedUrlImpl(_ resolvedUrl: ResolvedUrl, context: AccountContext, ur let controller = StickerPackScreen(context: context, mainStickerPack: mainStickerPack, stickerPacks: stickerPacks, parentNavigationController: navigationController, sendSticker: sendSticker) present(controller, nil) } - } else { + } else {*/ let controller = StickerPackScreen(context: context, mainStickerPack: .name(name), stickerPacks: [.name(name)], parentNavigationController: navigationController, sendSticker: sendSticker) present(controller, nil) - } + //} case let .instantView(webpage, anchor): navigationController?.pushViewController(InstantPageController(context: context, webPage: webpage, sourcePeerType: .channel, anchor: anchor)) case let .join(link): diff --git a/submodules/TelegramUI/Sources/OpenUrl.swift b/submodules/TelegramUI/Sources/OpenUrl.swift index 5114643757..a53cf2e052 100644 --- a/submodules/TelegramUI/Sources/OpenUrl.swift +++ b/submodules/TelegramUI/Sources/OpenUrl.swift @@ -149,7 +149,7 @@ func openExternalUrlImpl(context: AccountContext, urlContext: OpenURLContext, ur } if let parsed = URL(string: urlWithScheme) { parsedUrlValue = parsed - } else if let encoded = (urlWithScheme as NSString).addingPercentEscapes(using: String.Encoding.utf8.rawValue), let parsed = URL(string: encoded) { + } else if let encoded = (urlWithScheme as NSString).addingPercentEncoding(withAllowedCharacters: .urlQueryValueAllowed), let parsed = URL(string: encoded) { parsedUrlValue = parsed } @@ -710,14 +710,14 @@ func openExternalUrlImpl(context: AccountContext, urlContext: OpenURLContext, ur let settings = combineLatest(context.sharedContext.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.webBrowserSettings, ApplicationSpecificSharedDataKeys.presentationPasscodeSettings]), context.sharedContext.accountManager.accessChallengeData()) |> take(1) |> map { sharedData, accessChallengeData -> WebBrowserSettings in - let passcodeSettings = sharedData.entries[ApplicationSpecificSharedDataKeys.presentationPasscodeSettings] as? PresentationPasscodeSettings ?? PresentationPasscodeSettings.defaultSettings + let passcodeSettings = sharedData.entries[ApplicationSpecificSharedDataKeys.presentationPasscodeSettings]?.get(PresentationPasscodeSettings.self) ?? PresentationPasscodeSettings.defaultSettings if accessChallengeData.data.isLockable { if passcodeSettings.autolockTimeout != nil { return WebBrowserSettings(defaultWebBrowser: "Safari") } } - if let current = sharedData.entries[ApplicationSpecificSharedDataKeys.webBrowserSettings] as? WebBrowserSettings { + if let current = sharedData.entries[ApplicationSpecificSharedDataKeys.webBrowserSettings]?.get(WebBrowserSettings.self) { return current } else { return WebBrowserSettings.defaultSettings diff --git a/submodules/TelegramUI/Sources/PeerInfo/Panes/PeerInfoListPaneNode.swift b/submodules/TelegramUI/Sources/PeerInfo/Panes/PeerInfoListPaneNode.swift index 5b7ecb4ce0..347c63d61a 100644 --- a/submodules/TelegramUI/Sources/PeerInfo/Panes/PeerInfoListPaneNode.swift +++ b/submodules/TelegramUI/Sources/PeerInfo/Panes/PeerInfoListPaneNode.swift @@ -223,10 +223,10 @@ final class PeerInfoListPaneNode: ASDisplayNode, PeerInfoPaneNode { return } let _ = (strongSelf.context.sharedContext.accountManager.transaction { transaction -> AudioPlaybackRate in - let settings = transaction.getSharedData(ApplicationSpecificSharedDataKeys.musicPlaybackSettings) as? MusicPlaybackSettings ?? MusicPlaybackSettings.defaultSettings + let settings = transaction.getSharedData(ApplicationSpecificSharedDataKeys.musicPlaybackSettings)?.get(MusicPlaybackSettings.self) ?? MusicPlaybackSettings.defaultSettings transaction.updateSharedData(ApplicationSpecificSharedDataKeys.musicPlaybackSettings, { _ in - return settings.withUpdatedVoicePlaybackRate(rate) + return PreferencesEntry(settings.withUpdatedVoicePlaybackRate(rate)) }) return rate } diff --git a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoData.swift b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoData.swift index bfe3e5513e..668a68aba0 100644 --- a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoData.swift +++ b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoData.swift @@ -406,15 +406,15 @@ func peerInfoScreenSettingsData(context: AccountContext, peerId: PeerId, account let (notificationExceptions, notificationsAuthorizationStatus, notificationsWarningSuppressed) = notifications let (featuredStickerPacks, archivedStickerPacks) = stickerPacks - let proxySettings: ProxySettings = sharedPreferences.entries[SharedDataKeys.proxySettings] as? ProxySettings ?? ProxySettings.defaultSettings - let inAppNotificationSettings: InAppNotificationSettings = sharedPreferences.entries[ApplicationSpecificSharedDataKeys.inAppNotificationSettings] as? InAppNotificationSettings ?? InAppNotificationSettings.defaultSettings + let proxySettings: ProxySettings = sharedPreferences.entries[SharedDataKeys.proxySettings]?.get(ProxySettings.self) ?? ProxySettings.defaultSettings + let inAppNotificationSettings: InAppNotificationSettings = sharedPreferences.entries[ApplicationSpecificSharedDataKeys.inAppNotificationSettings]?.get(InAppNotificationSettings.self) ?? InAppNotificationSettings.defaultSettings let unreadTrendingStickerPacks = featuredStickerPacks.reduce(0, { count, item -> Int in return item.unread ? count + 1 : count }) var enableQRLogin = false - if let appConfiguration = accountPreferences.values[PreferencesKeys.appConfiguration] as? AppConfiguration, let data = appConfiguration.data, let enableQR = data["qr_login_camera"] as? Bool, enableQR { + if let appConfiguration = accountPreferences.values[PreferencesKeys.appConfiguration]?.get(AppConfiguration.self), let data = appConfiguration.data, let enableQR = data["qr_login_camera"] as? Bool, enableQR { enableQRLogin = true } @@ -564,7 +564,7 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen |> map { peerView, availablePanes, combinedView, status -> PeerInfoScreenData in var globalNotificationSettings: GlobalNotificationSettings = .defaultSettings if let preferencesView = combinedView.views[globalNotificationsKey] as? PreferencesView { - if let settings = preferencesView.values[PreferencesKeys.globalNotifications] as? GlobalNotificationSettings { + if let settings = preferencesView.values[PreferencesKeys.globalNotifications]?.get(GlobalNotificationSettings.self) { globalNotificationSettings = settings } } @@ -631,7 +631,7 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen |> map { peerView, availablePanes, combinedView, status, currentInvitationsContext, invitations -> PeerInfoScreenData in var globalNotificationSettings: GlobalNotificationSettings = .defaultSettings if let preferencesView = combinedView.views[globalNotificationsKey] as? PreferencesView { - if let settings = preferencesView.values[PreferencesKeys.globalNotifications] as? GlobalNotificationSettings { + if let settings = preferencesView.values[PreferencesKeys.globalNotifications]?.get(GlobalNotificationSettings.self) { globalNotificationSettings = settings } } @@ -779,7 +779,7 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen |> map { peerView, availablePanes, combinedView, status, membersData, currentInvitationsContext, invitations -> PeerInfoScreenData in var globalNotificationSettings: GlobalNotificationSettings = .defaultSettings if let preferencesView = combinedView.views[globalNotificationsKey] as? PreferencesView { - if let settings = preferencesView.values[PreferencesKeys.globalNotifications] as? GlobalNotificationSettings { + if let settings = preferencesView.values[PreferencesKeys.globalNotifications]?.get(GlobalNotificationSettings.self) { globalNotificationSettings = settings } } @@ -888,8 +888,8 @@ func availableActionsForMemberOfPeer(accountPeerId: PeerId, peer: Peer?, member: switch channelMember.participant { case .creator: break - case let .member(member): - if let adminInfo = member.adminInfo { + case let .member(_, _, adminInfo, _, _): + if let adminInfo = adminInfo { if adminInfo.promotedBy == accountPeerId { if !channel.flags.contains(.isGigagroup) { result.insert(.restrict) @@ -920,8 +920,8 @@ func availableActionsForMemberOfPeer(accountPeerId: PeerId, peer: Peer?, member: result.insert(.promote) case .admin: switch member { - case let .legacyGroupMember(legacyGroupMember): - if legacyGroupMember.invitedBy == accountPeerId { + case let .legacyGroupMember(_, _, invitedBy, _): + if invitedBy == accountPeerId { result.insert(.restrict) result.insert(.promote) } @@ -932,8 +932,8 @@ func availableActionsForMemberOfPeer(accountPeerId: PeerId, peer: Peer?, member: } case .member: switch member { - case let .legacyGroupMember(legacyGroupMember): - if legacyGroupMember.invitedBy == accountPeerId { + case let .legacyGroupMember(_, _, invitedBy, _): + if invitedBy == accountPeerId { result.insert(.restrict) } case .channelMember: diff --git a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoHeaderNode.swift b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoHeaderNode.swift index 758a112568..12f4218ebb 100644 --- a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoHeaderNode.swift +++ b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoHeaderNode.swift @@ -374,7 +374,7 @@ final class PeerInfoAvatarTransformContainerNode: ASDisplayNode { if peer.isDeleted { overrideImage = .deletedIcon } else if let previousItem = previousItem, item == nil { - if case let .image(image) = previousItem, let rep = image.1.last { + if case let .image(_, representations, _, _) = previousItem, let rep = representations.last { self.removedPhotoResourceIds.insert(rep.representation.resource.id.uniqueId) } overrideImage = AvatarNodeImageOverride.none @@ -596,9 +596,9 @@ final class PeerInfoEditingAvatarOverlayNode: ASDisplayNode { } } - transition.updateAlpha(node: self.updatingAvatarOverlay, alpha: overlayHidden ? 0.0 : 1.0) + transition.updateAlpha(node: self.updatingAvatarOverlay, alpha: 1.0) } else { - let targetOverlayAlpha: CGFloat = overlayHidden ? 0.0 : 1.0 + let targetOverlayAlpha: CGFloat = 0.0 if self.updatingAvatarOverlay.alpha != targetOverlayAlpha { let update = { self.statusNode.transitionToState(.none) @@ -679,7 +679,7 @@ final class PeerInfoEditingAvatarNode: ASDisplayNode { if canEditPeerInfo(context: self.context, peer: peer), peer.profileImageRepresentations.isEmpty { overrideImage = .editAvatarIcon } else if let previousItem = previousItem, item == nil { - if case let .image(image) = previousItem, let rep = image.1.last { + if case let .image(_, representations, _, _) = previousItem, let rep = representations.last { self.removedPhotoResourceIds.insert(rep.representation.resource.id.uniqueId) } overrideImage = AvatarNodeImageOverride.none diff --git a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoMembers.swift b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoMembers.swift index f6cc4942c8..5a870b205c 100644 --- a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoMembers.swift +++ b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoMembers.swift @@ -20,8 +20,8 @@ enum PeerInfoMember: Equatable { switch self { case let .channelMember(channelMember): return channelMember.peer.id - case let .legacyGroupMember(legacyGroupMember): - return legacyGroupMember.peer.peerId + case let .legacyGroupMember(peer, _, _, _): + return peer.peerId case let .account(peer): return peer.peerId } @@ -31,8 +31,8 @@ enum PeerInfoMember: Equatable { switch self { case let .channelMember(channelMember): return channelMember.peer - case let .legacyGroupMember(legacyGroupMember): - return legacyGroupMember.peer.peers[legacyGroupMember.peer.peerId]! + case let .legacyGroupMember(peer, _, _, _): + return peer.peers[peer.peerId]! case let .account(peer): return peer.peers[peer.peerId]! } @@ -42,8 +42,8 @@ enum PeerInfoMember: Equatable { switch self { case let .channelMember(channelMember): return channelMember.presences[channelMember.peer.id] as? TelegramUserPresence - case let .legacyGroupMember(legacyGroupMember): - return legacyGroupMember.presence + case let .legacyGroupMember(_, _, _, presence): + return presence case .account: return nil } @@ -55,15 +55,15 @@ enum PeerInfoMember: Equatable { switch channelMember.participant { case .creator: return .creator - case let .member(member): - if member.adminInfo != nil { + case let .member(_, _, adminInfo, _, _): + if adminInfo != nil { return .admin } else { return .member } } - case let .legacyGroupMember(legacyGroupMember): - return legacyGroupMember.role + case let .legacyGroupMember(_, role, _, _): + return role case .account: return .member } @@ -73,10 +73,10 @@ enum PeerInfoMember: Equatable { switch self { case let .channelMember(channelMember): switch channelMember.participant { - case let .creator(creator): - return creator.rank - case let .member(member): - return member.rank + case let .creator(_, _, rank): + return rank + case let .member(_, _, _, _, rank): + return rank } case .legacyGroupMember: return nil @@ -185,12 +185,12 @@ private final class PeerInfoMembersContextImpl { case .creator: role = .creator invitedBy = nil - case let .admin(admin): + case let .admin(_, invitedByValue, _): role = .admin - invitedBy = admin.invitedBy - case let .member(member): + invitedBy = invitedByValue + case let .member(_, invitedByValue, _): role = .member - invitedBy = member.invitedBy + invitedBy = invitedByValue } unsortedMembers.append(.legacyGroupMember(peer: RenderedPeer(peer: peer), role: role, invitedBy: invitedBy, presence: view.peerPresences[participant.peerId] as? TelegramUserPresence)) } @@ -249,9 +249,7 @@ private final class PeerInfoMembersContextImpl { self.pushState() disposable.set((signal - |> deliverOn(self.queue)).start(error: { _ in - completed() - }, completed: { + |> deliverOn(self.queue)).start(completed: { completed() })) } diff --git a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift index a155558446..f3d1768e8c 100644 --- a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift +++ b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift @@ -2505,14 +2505,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD strongSelf.controller?.present(statusController, in: .window(.root)) } strongSelf.activeActionDisposable.set((combineLatest(updateNameSignal, updateBioSignal) |> deliverOnMainQueue - |> deliverOnMainQueue).start(error: { _ in - dismissStatus?() - - guard let strongSelf = self else { - return - } - strongSelf.headerNode.navigationButtonContainer.performAction?(.cancel) - }, completed: { + |> deliverOnMainQueue).start(completed: { dismissStatus?() guard let strongSelf = self else { @@ -2812,8 +2805,8 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD var currentIsVideo = false let item = strongSelf.headerNode.avatarListNode.listContainerNode.currentItemNode?.item - if let item = item, case let .image(image) = item { - currentIsVideo = !image.2.isEmpty + if let item = item, case let .image(_, _, videoRepresentations, _) = item { + currentIsVideo = !videoRepresentations.isEmpty } let items: [ContextMenuItem] = [ @@ -4114,7 +4107,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD let peerId = self.peerId let _ = (self.context.account.postbox.transaction { transaction -> (TelegramPeerNotificationSettings, GlobalNotificationSettings) in let peerSettings: TelegramPeerNotificationSettings = (transaction.getPeerNotificationSettings(peerId) as? TelegramPeerNotificationSettings) ?? TelegramPeerNotificationSettings.defaultSettings - let globalSettings: GlobalNotificationSettings = (transaction.getPreferencesEntry(key: PreferencesKeys.globalNotifications) as? GlobalNotificationSettings) ?? GlobalNotificationSettings.defaultSettings + let globalSettings: GlobalNotificationSettings = transaction.getPreferencesEntry(key: PreferencesKeys.globalNotifications)?.get(GlobalNotificationSettings.self) ?? GlobalNotificationSettings.defaultSettings return (peerSettings, globalSettings) } |> deliverOnMainQueue).start(next: { [weak self] peerSettings, globalSettings in @@ -4148,7 +4141,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD let peerId = self.peerId let _ = (self.context.account.postbox.transaction { transaction -> (TelegramPeerNotificationSettings, GlobalNotificationSettings) in let peerSettings: TelegramPeerNotificationSettings = (transaction.getPeerNotificationSettings(peerId) as? TelegramPeerNotificationSettings) ?? TelegramPeerNotificationSettings.defaultSettings - let globalSettings: GlobalNotificationSettings = (transaction.getPreferencesEntry(key: PreferencesKeys.globalNotifications) as? GlobalNotificationSettings) ?? GlobalNotificationSettings.defaultSettings + let globalSettings: GlobalNotificationSettings = transaction.getPreferencesEntry(key: PreferencesKeys.globalNotifications)?.get(GlobalNotificationSettings.self) ?? GlobalNotificationSettings.defaultSettings return (peerSettings, globalSettings) } |> deliverOnMainQueue).start(next: { [weak self] peerSettings, globalSettings in @@ -5232,8 +5225,8 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD var currentIsVideo = false let item = self.headerNode.avatarListNode.listContainerNode.currentItemNode?.item - if let item = item, case let .image(image) = item { - currentIsVideo = !image.2.isEmpty + if let item = item, case let .image(_, _, videoRepresentations, _) = item { + currentIsVideo = !videoRepresentations.isEmpty } let peerId = self.peerId @@ -6575,7 +6568,7 @@ public final class PeerInfoScreenImpl: ViewController, PeerInfoScreen { let notificationsFromAllAccounts = self.context.sharedContext.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.inAppNotificationSettings]) |> map { sharedData -> Bool in - let settings = sharedData.entries[ApplicationSpecificSharedDataKeys.inAppNotificationSettings] as? InAppNotificationSettings ?? InAppNotificationSettings.defaultSettings + let settings = sharedData.entries[ApplicationSpecificSharedDataKeys.inAppNotificationSettings]?.get(InAppNotificationSettings.self) ?? InAppNotificationSettings.defaultSettings return settings.displayNotificationsFromAllAccounts } |> distinctUntilChanged diff --git a/submodules/TelegramUI/Sources/PeerSelectionTextInputPanelNode.swift b/submodules/TelegramUI/Sources/PeerSelectionTextInputPanelNode.swift index cfd7f85ebd..fabb3f56d6 100644 --- a/submodules/TelegramUI/Sources/PeerSelectionTextInputPanelNode.swift +++ b/submodules/TelegramUI/Sources/PeerSelectionTextInputPanelNode.swift @@ -12,6 +12,7 @@ import AccountContext import TouchDownGesture import ActivityIndicator import Speak +import ObjCRuntimeUtils private let counterFont = Font.with(size: 14.0, design: .regular, traits: [.monospacedNumbers]) private let minInputFontSize = chatTextInputMinFontSize @@ -706,7 +707,7 @@ class PeerSelectionTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDel } func editableTextNodeTarget(forAction action: Selector) -> ASEditableTextNodeTargetForAction? { - if action == Selector(("_accessibilitySpeak:")) { + if action == makeSelectorFromString("_accessibilitySpeak:") { if case .format = self.inputMenu.state { return ASEditableTextNodeTargetForAction(target: nil) } else if let textInputNode = self.textInputNode, textInputNode.selectedRange.length > 0 { @@ -714,7 +715,7 @@ class PeerSelectionTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDel } else { return ASEditableTextNodeTargetForAction(target: nil) } - } else if action == Selector(("_accessibilitySpeakSpellOut:")) { + } else if action == makeSelectorFromString("_accessibilitySpeakSpellOut:") { if case .format = self.inputMenu.state { return ASEditableTextNodeTargetForAction(target: nil) } else if let textInputNode = self.textInputNode, textInputNode.selectedRange.length > 0 { @@ -723,9 +724,9 @@ class PeerSelectionTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDel return ASEditableTextNodeTargetForAction(target: nil) } } - else if action == Selector("_accessibilitySpeakLanguageSelection:") || action == Selector("_accessibilityPauseSpeaking:") || action == Selector("_accessibilitySpeakSentence:") { + else if action == makeSelectorFromString("_accessibilitySpeakLanguageSelection:") || action == makeSelectorFromString("_accessibilityPauseSpeaking:") || action == makeSelectorFromString("_accessibilitySpeakSentence:") { return ASEditableTextNodeTargetForAction(target: nil) - } else if action == Selector(("_showTextStyleOptions:")) { + } else if action == makeSelectorFromString("_showTextStyleOptions:") { if case .general = self.inputMenu.state { if let textInputNode = self.textInputNode, textInputNode.attributedText == nil || textInputNode.attributedText!.length == 0 || textInputNode.selectedRange.length == 0 { return ASEditableTextNodeTargetForAction(target: nil) diff --git a/submodules/TelegramUI/Sources/PeersNearbyManager.swift b/submodules/TelegramUI/Sources/PeersNearbyManager.swift index 300852bdb0..79f01e9cd8 100644 --- a/submodules/TelegramUI/Sources/PeersNearbyManager.swift +++ b/submodules/TelegramUI/Sources/PeersNearbyManager.swift @@ -32,7 +32,7 @@ final class PeersNearbyManagerImpl: PeersNearbyManager { self.preferencesDisposable = (account.postbox.preferencesView(keys: [PreferencesKeys.peersNearby]) |> map { view -> Int32? in - let state = view.values[PreferencesKeys.peersNearby] as? PeersNearbyState ?? .default + let state = view.values[PreferencesKeys.peersNearby]?.get(PeersNearbyState.self) ?? .default return state.visibilityExpires } |> deliverOnMainQueue @@ -97,12 +97,6 @@ final class PeersNearbyManagerImpl: PeersNearbyManager { } private func updateLocation(_ location: CLLocation) { - self.updateDisposable.set(self.engine.peersNearby.updatePeersNearbyVisibility(update: .location(latitude: location.coordinate.latitude, longitude: location.coordinate.longitude), background: true).start(error: { [weak self] _ in - if let strongSelf = self { - let _ = strongSelf.engine.peersNearby.updatePeersNearbyVisibility(update: .invisible, background: false).start() - strongSelf.locationDisposable.set(nil) - strongSelf.updateDisposable.set(nil) - } - })) + self.updateDisposable.set(self.engine.peersNearby.updatePeersNearbyVisibility(update: .location(latitude: location.coordinate.latitude, longitude: location.coordinate.longitude), background: true).start()) } } diff --git a/submodules/TelegramUI/Sources/PollResultsController.swift b/submodules/TelegramUI/Sources/PollResultsController.swift index a6e213ab76..b5f56ded9a 100644 --- a/submodules/TelegramUI/Sources/PollResultsController.swift +++ b/submodules/TelegramUI/Sources/PollResultsController.swift @@ -76,10 +76,10 @@ private enum PollResultsEntry: ItemListNodeEntry { switch self { case .text: return PollResultsSection.text.rawValue - case let .optionPeer(optionPeer): - return PollResultsSection.option(optionPeer.optionId).rawValue - case let .optionExpand(optionExpand): - return PollResultsSection.option(optionExpand.optionId).rawValue + case let .optionPeer(optionId, _, _, _, _, _, _, _, _, _): + return PollResultsSection.option(optionId).rawValue + case let .optionExpand(optionId, _, _, _): + return PollResultsSection.option(optionId).rawValue case .solutionHeader, .solutionText: return PollResultsSection.solution.rawValue } @@ -89,10 +89,10 @@ private enum PollResultsEntry: ItemListNodeEntry { switch self { case .text: return .text - case let .optionPeer(optionPeer): - return .optionPeer(optionPeer.optionId, optionPeer.index) - case let .optionExpand(optionExpand): - return .optionExpand(optionExpand.optionId) + case let .optionPeer(optionId, index, _, _, _, _, _, _, _, _): + return .optionPeer(optionId, index) + case let .optionExpand(optionId, _, _, _): + return .optionExpand(optionId) case .solutionHeader: return .solutionHeader case .solutionText: @@ -129,7 +129,7 @@ private enum PollResultsEntry: ItemListNodeEntry { default: return true } - case let .optionPeer(lhsOptionPeer): + case let .optionPeer(lhsOptionId, lhsIndex, _, _, _, _, _, _, _, _): switch rhs { case .text: return false @@ -137,20 +137,20 @@ private enum PollResultsEntry: ItemListNodeEntry { return false case .solutionText: return false - case let .optionPeer(rhsOptionPeer): - if lhsOptionPeer.optionId == rhsOptionPeer.optionId { - return lhsOptionPeer.index < rhsOptionPeer.index + case let .optionPeer(rhsOptionId, rhsIndex, _, _, _, _, _, _, _, _): + if lhsOptionId == rhsOptionId { + return lhsIndex < rhsIndex } else { - return lhsOptionPeer.optionId < rhsOptionPeer.optionId + return lhsOptionId < rhsOptionId } - case let .optionExpand(rhsOptionExpand): - if lhsOptionPeer.optionId == rhsOptionExpand.optionId { + case let .optionExpand(rhsOptionId, _, _, _): + if lhsOptionId == rhsOptionId { return true } else { - return lhsOptionPeer.optionId < rhsOptionExpand.optionId + return lhsOptionId < rhsOptionId } } - case let .optionExpand(lhsOptionExpand): + case let .optionExpand(lhsOptionId, _, _, _): switch rhs { case .text: return false @@ -158,17 +158,17 @@ private enum PollResultsEntry: ItemListNodeEntry { return false case .solutionText: return false - case let .optionPeer(rhsOptionPeer): - if lhsOptionExpand.optionId == rhsOptionPeer.optionId { + case let .optionPeer(rhsOptionId, _, _, _, _, _, _, _, _, _): + if lhsOptionId == rhsOptionId { return false } else { - return lhsOptionExpand.optionId < rhsOptionPeer.optionId + return lhsOptionId < rhsOptionId } - case let .optionExpand(rhsOptionExpand): - if lhsOptionExpand.optionId == rhsOptionExpand.optionId { + case let .optionExpand(rhsOptionId, _, _, _): + if lhsOptionId == rhsOptionId { return false } else { - return lhsOptionExpand.optionId < rhsOptionExpand.optionId + return lhsOptionId < rhsOptionId } } } @@ -391,8 +391,8 @@ public func pollResultsController(context: AccountContext, messageId: MessageId, var isFirstOption = true loop: for i in 0 ..< entries.count { switch entries[i] { - case let .optionPeer(optionPeer): - if optionPeer.opaqueIdentifier == focusOnOptionWithOpaqueIdentifier { + case let .optionPeer(_, _, _, _, _, _, _, opaqueIdentifier, _, _): + if opaqueIdentifier == focusOnOptionWithOpaqueIdentifier { if !isFirstOption { initialScrollToItem = ListViewScrollToItem(index: i, position: .top(0.0), animated: false, curve: .Default(duration: nil), directionHint: .Down) } diff --git a/submodules/TelegramUI/Sources/PrefetchManager.swift b/submodules/TelegramUI/Sources/PrefetchManager.swift index 08dcbcd4dd..f381a6a487 100644 --- a/submodules/TelegramUI/Sources/PrefetchManager.swift +++ b/submodules/TelegramUI/Sources/PrefetchManager.swift @@ -54,7 +54,7 @@ private final class PrefetchManagerInnerImpl { let appConfiguration = account.postbox.preferencesView(keys: [PreferencesKeys.appConfiguration]) |> take(1) |> map { view in - return view.values[PreferencesKeys.appConfiguration] as? AppConfiguration ?? .defaultValue + return view.values[PreferencesKeys.appConfiguration]?.get(AppConfiguration.self) ?? .defaultValue } let orderedPreloadMedia = combineLatest(account.viewTracker.orderedPreloadMedia, TelegramEngine(account: account).stickers.loadedStickerPack(reference: .animatedEmoji, forceActualized: false), appConfiguration) diff --git a/submodules/TelegramUI/Sources/ShareExtensionContext.swift b/submodules/TelegramUI/Sources/ShareExtensionContext.swift index 559013266f..c27a0ad02e 100644 --- a/submodules/TelegramUI/Sources/ShareExtensionContext.swift +++ b/submodules/TelegramUI/Sources/ShareExtensionContext.swift @@ -248,7 +248,7 @@ public class ShareRootControllerImpl { } let account: Signal<(SharedAccountContextImpl, Account, [AccountWithInfo]), ShareAuthorizationError> = internalContext.sharedContext.accountManager.transaction { transaction -> (SharedAccountContextImpl, LoggingSettings) in - return (internalContext.sharedContext, transaction.getSharedData(SharedDataKeys.loggingSettings) as? LoggingSettings ?? LoggingSettings.defaultSettings) + return (internalContext.sharedContext, transaction.getSharedData(SharedDataKeys.loggingSettings)?.get(LoggingSettings.self) ?? LoggingSettings.defaultSettings) } |> castError(ShareAuthorizationError.self) |> mapToSignal { sharedContext, loggingSettings -> Signal<(SharedAccountContextImpl, Account, [AccountWithInfo]), ShareAuthorizationError> in @@ -261,7 +261,7 @@ public class ShareRootControllerImpl { let accountRecords = Set(transaction.getRecords().map { record in return record.id }) - let intentsSettings = transaction.getSharedData(ApplicationSpecificSharedDataKeys.intentsSettings) as? IntentsSettings ?? IntentsSettings.defaultSettings + let intentsSettings = transaction.getSharedData(ApplicationSpecificSharedDataKeys.intentsSettings)?.get(IntentsSettings.self) ?? IntentsSettings.defaultSettings return (accountRecords, intentsSettings.account) }) |> castError(ShareAuthorizationError.self) @@ -300,7 +300,7 @@ public class ShareRootControllerImpl { |> mapToSignal { sharedContext, account, otherAccounts -> Signal<(AccountContext, PostboxAccessChallengeData, [AccountWithInfo]), ShareAuthorizationError> in let limitsConfigurationAndContentSettings = account.postbox.transaction { transaction -> (LimitsConfiguration, ContentSettings, AppConfiguration) in return ( - transaction.getPreferencesEntry(key: PreferencesKeys.limitsConfiguration) as? LimitsConfiguration ?? LimitsConfiguration.defaultValue, + transaction.getPreferencesEntry(key: PreferencesKeys.limitsConfiguration)?.get(LimitsConfiguration.self) ?? LimitsConfiguration.defaultValue, getContentSettings(transaction: transaction), getAppConfiguration(transaction: transaction) ) diff --git a/submodules/TelegramUI/Sources/SharedAccountContext.swift b/submodules/TelegramUI/Sources/SharedAccountContext.swift index 46928694bf..940c314436 100644 --- a/submodules/TelegramUI/Sources/SharedAccountContext.swift +++ b/submodules/TelegramUI/Sources/SharedAccountContext.swift @@ -205,8 +205,8 @@ public final class SharedAccountContextImpl: SharedAccountContext { self._automaticMediaDownloadSettings.set(.single(initialPresentationDataAndSettings.automaticMediaDownloadSettings) |> then(accountManager.sharedData(keys: [SharedDataKeys.autodownloadSettings, ApplicationSpecificSharedDataKeys.automaticMediaDownloadSettings]) |> map { sharedData in - let autodownloadSettings: AutodownloadSettings = sharedData.entries[SharedDataKeys.autodownloadSettings] as? AutodownloadSettings ?? .defaultSettings - let automaticDownloadSettings: MediaAutoDownloadSettings = sharedData.entries[ApplicationSpecificSharedDataKeys.automaticMediaDownloadSettings] as? MediaAutoDownloadSettings ?? .defaultSettings + let autodownloadSettings: AutodownloadSettings = sharedData.entries[SharedDataKeys.autodownloadSettings]?.get(AutodownloadSettings.self) ?? .defaultSettings + let automaticDownloadSettings: MediaAutoDownloadSettings = sharedData.entries[ApplicationSpecificSharedDataKeys.automaticMediaDownloadSettings]?.get(MediaAutoDownloadSettings.self) ?? .defaultSettings return automaticDownloadSettings.updatedWithAutodownloadSettings(autodownloadSettings) } )) @@ -253,7 +253,7 @@ public final class SharedAccountContextImpl: SharedAccountContext { self._autodownloadSettings.set(.single(initialPresentationDataAndSettings.autodownloadSettings) |> then(accountManager.sharedData(keys: [SharedDataKeys.autodownloadSettings]) |> map { sharedData in - let autodownloadSettings: AutodownloadSettings = sharedData.entries[SharedDataKeys.autodownloadSettings] as? AutodownloadSettings ?? .defaultSettings + let autodownloadSettings: AutodownloadSettings = sharedData.entries[SharedDataKeys.autodownloadSettings]?.get(AutodownloadSettings.self) ?? .defaultSettings return autodownloadSettings } )) @@ -291,7 +291,7 @@ public final class SharedAccountContextImpl: SharedAccountContext { self.inAppNotificationSettingsDisposable = (self.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.inAppNotificationSettings]) |> deliverOnMainQueue).start(next: { [weak self] sharedData in if let strongSelf = self { - if let settings = sharedData.entries[ApplicationSpecificSharedDataKeys.inAppNotificationSettings] as? InAppNotificationSettings { + if let settings = sharedData.entries[ApplicationSpecificSharedDataKeys.inAppNotificationSettings]?.get(InAppNotificationSettings.self) { let _ = strongSelf.currentInAppNotificationSettings.swap(settings) } } @@ -300,7 +300,7 @@ public final class SharedAccountContextImpl: SharedAccountContext { self.mediaInputSettingsDisposable = (self.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.mediaInputSettings]) |> deliverOnMainQueue).start(next: { [weak self] sharedData in if let strongSelf = self { - if let settings = sharedData.entries[ApplicationSpecificSharedDataKeys.mediaInputSettings] as? MediaInputSettings { + if let settings = sharedData.entries[ApplicationSpecificSharedDataKeys.mediaInputSettings]?.get(MediaInputSettings.self) { let _ = strongSelf.currentMediaInputSettings.swap(settings) } } @@ -310,7 +310,7 @@ public final class SharedAccountContextImpl: SharedAccountContext { let _ = immediateExperimentalUISettingsValue.swap(initialPresentationDataAndSettings.experimentalUISettings) self.experimentalUISettingsDisposable = (self.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.experimentalUISettings]) |> deliverOnMainQueue).start(next: { sharedData in - if let settings = sharedData.entries[ApplicationSpecificSharedDataKeys.experimentalUISettings] as? ExperimentalUISettings { + if let settings = sharedData.entries[ApplicationSpecificSharedDataKeys.experimentalUISettings]?.get(ExperimentalUISettings.self) { let _ = immediateExperimentalUISettingsValue.swap(settings) } }) @@ -412,7 +412,7 @@ public final class SharedAccountContextImpl: SharedAccountContext { return nil }) return account.postbox.transaction { transaction -> AddedAccountResult in - let limitsConfiguration = transaction.getPreferencesEntry(key: PreferencesKeys.limitsConfiguration) as? LimitsConfiguration ?? LimitsConfiguration.defaultValue + let limitsConfiguration = transaction.getPreferencesEntry(key: PreferencesKeys.limitsConfiguration)?.get(LimitsConfiguration.self) ?? LimitsConfiguration.defaultValue let contentSettings = getContentSettings(transaction: transaction) let appConfiguration = getAppConfiguration(transaction: transaction) return .ready(id, account, attributes.sortIndex, limitsConfiguration, contentSettings, appConfiguration) @@ -769,7 +769,7 @@ public final class SharedAccountContextImpl: SharedAccountContext { let enableSpotlight = accountManager.sharedData(keys: Set([ApplicationSpecificSharedDataKeys.intentsSettings])) |> map { sharedData -> Bool in - let intentsSettings: IntentsSettings = sharedData.entries[ApplicationSpecificSharedDataKeys.intentsSettings] as? IntentsSettings ?? .defaultSettings + let intentsSettings: IntentsSettings = sharedData.entries[ApplicationSpecificSharedDataKeys.intentsSettings]?.get(IntentsSettings.self) ?? .defaultSettings return intentsSettings.contacts } |> distinctUntilChanged @@ -837,7 +837,7 @@ public final class SharedAccountContextImpl: SharedAccountContext { let settings = self.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.inAppNotificationSettings]) |> map { sharedData -> (allAccounts: Bool, includeMuted: Bool) in - let settings = sharedData.entries[ApplicationSpecificSharedDataKeys.inAppNotificationSettings] as? InAppNotificationSettings ?? InAppNotificationSettings.defaultSettings + let settings = sharedData.entries[ApplicationSpecificSharedDataKeys.inAppNotificationSettings]?.get(InAppNotificationSettings.self) ?? InAppNotificationSettings.defaultSettings return (settings.displayNotificationsFromAllAccounts, false) } |> distinctUntilChanged(isEqual: { lhs, rhs in diff --git a/submodules/TelegramUI/Sources/StoreDownloadedMedia.swift b/submodules/TelegramUI/Sources/StoreDownloadedMedia.swift index 0023d3a103..9b0a70435a 100644 --- a/submodules/TelegramUI/Sources/StoreDownloadedMedia.swift +++ b/submodules/TelegramUI/Sources/StoreDownloadedMedia.swift @@ -156,7 +156,7 @@ private final class DownloadedMediaStoreManagerPrivateImpl { self.appSpecificAssetCollectionValue = Promise(initializeOnFirstAccess: appSpecificAssetCollection()) self.storeSettings.set(accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.automaticMediaDownloadSettings]) |> map { sharedData -> MediaAutoDownloadSettings in - if let settings = sharedData.entries[ApplicationSpecificSharedDataKeys.automaticMediaDownloadSettings] as? MediaAutoDownloadSettings { + if let settings = sharedData.entries[ApplicationSpecificSharedDataKeys.automaticMediaDownloadSettings]?.get(MediaAutoDownloadSettings.self) { return settings } else { return .defaultSettings diff --git a/submodules/TelegramUI/Sources/ThemeUpdateManager.swift b/submodules/TelegramUI/Sources/ThemeUpdateManager.swift index cc9014cef7..28752c2da3 100644 --- a/submodules/TelegramUI/Sources/ThemeUpdateManager.swift +++ b/submodules/TelegramUI/Sources/ThemeUpdateManager.swift @@ -40,7 +40,7 @@ final class ThemeUpdateManagerImpl: ThemeUpdateManager { self.disposable = (sharedContext.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.presentationThemeSettings]) |> map { sharedData -> PresentationThemeSettings in - return (sharedData.entries[ApplicationSpecificSharedDataKeys.presentationThemeSettings] as? PresentationThemeSettings) ?? PresentationThemeSettings.defaultSettings + return sharedData.entries[ApplicationSpecificSharedDataKeys.presentationThemeSettings]?.get(PresentationThemeSettings.self) ?? PresentationThemeSettings.defaultSettings } |> deliverOn(queue)).start(next: { [weak self] themeSettings in self?.presentationThemeSettingsUpdated(themeSettings) @@ -124,7 +124,7 @@ final class ThemeUpdateManagerImpl: ThemeUpdateManager { let _ = (accountManager.transaction { transaction -> Void in transaction.updateSharedData(ApplicationSpecificSharedDataKeys.presentationThemeSettings, { entry in let current: PresentationThemeSettings - if let entry = entry as? PresentationThemeSettings { + if let entry = entry?.get(PresentationThemeSettings.self) { current = entry } else { current = PresentationThemeSettings.defaultSettings @@ -138,7 +138,7 @@ final class ThemeUpdateManagerImpl: ThemeUpdateManager { theme = updatedTheme } - return PresentationThemeSettings(theme: theme, themeSpecificAccentColors: current.themeSpecificAccentColors, themeSpecificChatWallpapers: current.themeSpecificChatWallpapers, useSystemFont: current.useSystemFont, fontSize: current.fontSize, listsFontSize: current.listsFontSize, chatBubbleSettings: current.chatBubbleSettings, automaticThemeSwitchSetting: automaticThemeSwitchSetting, largeEmoji: current.largeEmoji, reduceMotion: current.reduceMotion) + return PreferencesEntry(PresentationThemeSettings(theme: theme, themeSpecificAccentColors: current.themeSpecificAccentColors, themeSpecificChatWallpapers: current.themeSpecificChatWallpapers, useSystemFont: current.useSystemFont, fontSize: current.fontSize, listsFontSize: current.listsFontSize, chatBubbleSettings: current.chatBubbleSettings, automaticThemeSwitchSetting: automaticThemeSwitchSetting, largeEmoji: current.largeEmoji, reduceMotion: current.reduceMotion)) }) }).start() } diff --git a/submodules/TelegramUI/Sources/UpgradedAccounts.swift b/submodules/TelegramUI/Sources/UpgradedAccounts.swift index a02625e868..8423358e4f 100644 --- a/submodules/TelegramUI/Sources/UpgradedAccounts.swift +++ b/submodules/TelegramUI/Sources/UpgradedAccounts.swift @@ -103,11 +103,7 @@ private let applicationSpecificPreferencesKeyMapping: [LegacyApplicationSpecific ] private func upgradedSharedDataValue(_ value: PreferencesEntry?) -> PreferencesEntry? { - if let settings = value as? AutomaticMediaDownloadSettings { - return MediaAutoDownloadSettings.upgradeLegacySettings(settings) - } else { - return value - } + return value } public func upgradedAccounts(accountManager: AccountManager, rootPath: String, encryptionParameters: ValueBoxEncryptionParameters) -> Signal { @@ -154,7 +150,7 @@ public func upgradedAccounts(accountManager: AccountManager (ContactSynchronizationSettings, [AccountRecordId]) in - return (transaction.getSharedData(ApplicationSpecificSharedDataKeys.contactSynchronizationSettings) as? ContactSynchronizationSettings ?? ContactSynchronizationSettings.defaultSettings, transaction.getRecords().map({ $0.id })) + return (transaction.getSharedData(ApplicationSpecificSharedDataKeys.contactSynchronizationSettings)?.get(ContactSynchronizationSettings.self) ?? ContactSynchronizationSettings.defaultSettings, transaction.getRecords().map({ $0.id })) } |> mapToSignal { globalSettings, ids -> Signal in var importSignal: Signal = .complete() for id in ids { let importInfoAccounttSignal = accountTransaction(rootPath: rootPath, id: id, encryptionParameters: encryptionParameters, isReadOnly: false, transaction: { _, transaction -> Void in transaction.updatePreferencesEntry(key: PreferencesKeys.contactsSettings, { current in - var settings = current as? ContactsSettings ?? ContactsSettings.defaultSettings + var settings = current?.get(ContactsSettings.self) ?? ContactsSettings.defaultSettings settings.synchronizeContacts = globalSettings._legacySynchronizeDeviceContacts - return settings + return PreferencesEntry(settings) }) }) |> ignoreValues @@ -310,7 +306,6 @@ public func upgradedAccounts(accountManager: AccountManager then( applyVersion )) |> mapToSignal { _ -> Signal in - return .complete() } ) } diff --git a/submodules/TelegramUI/Sources/VerticalListContextResultsChatInputContextPanelNode.swift b/submodules/TelegramUI/Sources/VerticalListContextResultsChatInputContextPanelNode.swift index fd8185623d..e3a3c8d718 100644 --- a/submodules/TelegramUI/Sources/VerticalListContextResultsChatInputContextPanelNode.swift +++ b/submodules/TelegramUI/Sources/VerticalListContextResultsChatInputContextPanelNode.swift @@ -14,12 +14,12 @@ private enum VerticalChatContextResultsEntryStableId: Hashable { case action case result(ChatContextResult) - var hashValue: Int { + func hash(into hasher: inout Hasher) { switch self { case .action: - return 0 + hasher.combine(0) case let .result(result): - return result.id.hashValue + hasher.combine(result.id.hashValue) } } diff --git a/submodules/TelegramUI/Sources/VerticalListContextResultsChatInputPanelItem.swift b/submodules/TelegramUI/Sources/VerticalListContextResultsChatInputPanelItem.swift index cbbfda0c29..7cc0ce5527 100644 --- a/submodules/TelegramUI/Sources/VerticalListContextResultsChatInputPanelItem.swift +++ b/submodules/TelegramUI/Sources/VerticalListContextResultsChatInputPanelItem.swift @@ -196,7 +196,7 @@ final class VerticalListContextResultsChatInputPanelItemNode: ListViewItemNode { } if let selectedUrl = selectedUrl, let parsedUrl = URL(string: selectedUrl) { if let host = parsedUrl.host, !host.isEmpty { - iconText = NSAttributedString(string: host.substring(to: host.index(after: host.startIndex)).uppercased(), font: iconFont, textColor: UIColor.white) + iconText = NSAttributedString(string: String(host[.. Bool { - if let to = to as? ExperimentalUISettings { - return self == to - } else { - return false - } + try container.encode((self.keepChatNavigationStack ? 1 : 0) as Int32, forKey: "keepChatNavigationStack") + try container.encode((self.skipReadHistory ? 1 : 0) as Int32, forKey: "skipReadHistory") + try container.encode((self.crashOnLongQueries ? 1 : 0) as Int32, forKey: "crashOnLongQueries") + try container.encode((self.chatListPhotos ? 1 : 0) as Int32, forKey: "chatListPhotos") + try container.encode((self.knockoutWallpaper ? 1 : 0) as Int32, forKey: "knockoutWallpaper") + try container.encode((self.foldersTabAtBottom ? 1 : 0) as Int32, forKey: "foldersTabAtBottom") + try container.encode((self.playerEmbedding ? 1 : 0) as Int32, forKey: "playerEmbedding") + try container.encode((self.playlistPlayback ? 1 : 0) as Int32, forKey: "playlistPlayback") + try container.encodeIfPresent(self.preferredVideoCodec, forKey: "preferredVideoCodec") + try container.encode((self.disableVideoAspectScaling ? 1 : 0) as Int32, forKey: "disableVideoAspectScaling") + try container.encode((self.enableVoipTcp ? 1 : 0) as Int32, forKey: "enableVoipTcp") + try container.encode((self.experimentalCompatibility ? 1 : 0) as Int32, forKey: "experimentalCompatibility") + try container.encode((self.enableDebugDataDisplay ? 1 : 0) as Int32, forKey: "enableDebugDataDisplay") } } @@ -122,12 +107,12 @@ public func updateExperimentalUISettingsInteractively(accountManager: AccountMan return accountManager.transaction { transaction -> Void in transaction.updateSharedData(ApplicationSpecificSharedDataKeys.experimentalUISettings, { entry in let currentSettings: ExperimentalUISettings - if let entry = entry as? ExperimentalUISettings { + if let entry = entry?.get(ExperimentalUISettings.self) { currentSettings = entry } else { currentSettings = .defaultSettings } - return f(currentSettings) + return PreferencesEntry(f(currentSettings)) }) } } diff --git a/submodules/TelegramUIPreferences/Sources/GeneratedMediaStoreSettings.swift b/submodules/TelegramUIPreferences/Sources/GeneratedMediaStoreSettings.swift index c8473ee338..5a895ba369 100644 --- a/submodules/TelegramUIPreferences/Sources/GeneratedMediaStoreSettings.swift +++ b/submodules/TelegramUIPreferences/Sources/GeneratedMediaStoreSettings.swift @@ -3,7 +3,7 @@ import Postbox import TelegramCore import SwiftSignalKit -public struct GeneratedMediaStoreSettings: PreferencesEntry, Equatable { +public struct GeneratedMediaStoreSettings: Codable, Equatable { public let storeEditedPhotos: Bool public let storeCapturedMedia: Bool @@ -16,22 +16,18 @@ public struct GeneratedMediaStoreSettings: PreferencesEntry, Equatable { self.storeCapturedMedia = storeCapturedMedia } - public init(decoder: PostboxDecoder) { - self.storeEditedPhotos = decoder.decodeInt32ForKey("eph", orElse: 0) != 0 - self.storeCapturedMedia = decoder.decodeInt32ForKey("cpm", orElse: 0) != 0 + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: StringCodingKey.self) + + self.storeEditedPhotos = (try container.decode(Int32.self, forKey: "eph")) != 0 + self.storeCapturedMedia = (try container.decode(Int32.self, forKey: "cpm")) != 0 } - public func encode(_ encoder: PostboxEncoder) { - encoder.encodeInt32(self.storeEditedPhotos ? 1 : 0, forKey: "eph") - encoder.encodeInt32(self.storeCapturedMedia ? 1 : 0, forKey: "cpm") - } - - public func isEqual(to: PreferencesEntry) -> Bool { - if let to = to as? GeneratedMediaStoreSettings { - return self == to - } else { - return false - } + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: StringCodingKey.self) + + try container.encode((self.storeEditedPhotos ? 1 : 0) as Int32, forKey: "eph") + try container.encode((self.storeCapturedMedia ? 1 : 0) as Int32, forKey: "cpm") } public static func ==(lhs: GeneratedMediaStoreSettings, rhs: GeneratedMediaStoreSettings) -> Bool { @@ -47,12 +43,12 @@ public func updateGeneratedMediaStoreSettingsInteractively(accountManager: Accou return accountManager.transaction { transaction -> Void in transaction.updateSharedData(ApplicationSpecificSharedDataKeys.generatedMediaStoreSettings, { entry in let currentSettings: GeneratedMediaStoreSettings - if let entry = entry as? GeneratedMediaStoreSettings { + if let entry = entry?.get(GeneratedMediaStoreSettings.self) { currentSettings = entry } else { currentSettings = GeneratedMediaStoreSettings.defaultSettings } - return f(currentSettings) + return PreferencesEntry(f(currentSettings)) }) } } diff --git a/submodules/TelegramUIPreferences/Sources/InAppNotificationSettings.swift b/submodules/TelegramUIPreferences/Sources/InAppNotificationSettings.swift index 458f92472e..aca5725d3b 100644 --- a/submodules/TelegramUIPreferences/Sources/InAppNotificationSettings.swift +++ b/submodules/TelegramUIPreferences/Sources/InAppNotificationSettings.swift @@ -28,7 +28,7 @@ public enum TotalUnreadCountDisplayCategory: Int32 { } } -public struct InAppNotificationSettings: PreferencesEntry, Equatable { +public struct InAppNotificationSettings: Codable, Equatable { public var playSounds: Bool public var vibrate: Bool public var displayPreviews: Bool @@ -53,15 +53,17 @@ public struct InAppNotificationSettings: PreferencesEntry, Equatable { self.displayNotificationsFromAllAccounts = displayNotificationsFromAllAccounts } - public init(decoder: PostboxDecoder) { - self.playSounds = decoder.decodeInt32ForKey("s", orElse: 0) != 0 - self.vibrate = decoder.decodeInt32ForKey("v", orElse: 0) != 0 - self.displayPreviews = decoder.decodeInt32ForKey("p", orElse: 0) != 0 - self.totalUnreadCountDisplayStyle = TotalUnreadCountDisplayStyle(rawValue: decoder.decodeInt32ForKey("cds", orElse: 0)) ?? .filtered - self.totalUnreadCountDisplayCategory = TotalUnreadCountDisplayCategory(rawValue: decoder.decodeInt32ForKey("totalUnreadCountDisplayCategory", orElse: 1)) ?? .messages - if let value = decoder.decodeOptionalInt32ForKey("totalUnreadCountIncludeTags_2") { + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: StringCodingKey.self) + + self.playSounds = (try container.decode(Int32.self, forKey: "s")) != 0 + self.vibrate = (try container.decode(Int32.self, forKey: "v")) != 0 + self.displayPreviews = (try container.decode(Int32.self, forKey: "p")) != 0 + self.totalUnreadCountDisplayStyle = TotalUnreadCountDisplayStyle(rawValue: try container.decode(Int32.self, forKey: "cds")) ?? .filtered + self.totalUnreadCountDisplayCategory = TotalUnreadCountDisplayCategory(rawValue: try container.decodeIfPresent(Int32.self, forKey: "totalUnreadCountDisplayCategory") ?? 1) ?? .messages + if let value = try container.decodeIfPresent(Int32.self, forKey: "totalUnreadCountIncludeTags_2") { self.totalUnreadCountIncludeTags = PeerSummaryCounterTags(rawValue: value) - } else if let value = decoder.decodeOptionalInt32ForKey("totalUnreadCountIncludeTags") { + } else if let value = try container.decodeIfPresent(Int32.self, forKey: "totalUnreadCountIncludeTags") { var resultTags: PeerSummaryCounterTags = [] for legacyTag in LegacyPeerSummaryCounterTags(rawValue: value) { if legacyTag == .regularChatsAndPrivateGroups { @@ -79,27 +81,21 @@ public struct InAppNotificationSettings: PreferencesEntry, Equatable { } else { self.totalUnreadCountIncludeTags = .all } - self.displayNameOnLockscreen = decoder.decodeInt32ForKey("displayNameOnLockscreen", orElse: 1) != 0 - self.displayNotificationsFromAllAccounts = decoder.decodeInt32ForKey("displayNotificationsFromAllAccounts", orElse: 1) != 0 + self.displayNameOnLockscreen = (try container.decodeIfPresent(Int32.self, forKey: "displayNameOnLockscreen") ?? 1) != 0 + self.displayNotificationsFromAllAccounts = (try container.decodeIfPresent(Int32.self, forKey: "displayNotificationsFromAllAccounts") ?? 1) != 0 } - public func encode(_ encoder: PostboxEncoder) { - encoder.encodeInt32(self.playSounds ? 1 : 0, forKey: "s") - encoder.encodeInt32(self.vibrate ? 1 : 0, forKey: "v") - encoder.encodeInt32(self.displayPreviews ? 1 : 0, forKey: "p") - encoder.encodeInt32(self.totalUnreadCountDisplayStyle.rawValue, forKey: "cds") - encoder.encodeInt32(self.totalUnreadCountDisplayCategory.rawValue, forKey: "totalUnreadCountDisplayCategory") - encoder.encodeInt32(self.totalUnreadCountIncludeTags.rawValue, forKey: "totalUnreadCountIncludeTags_2") - encoder.encodeInt32(self.displayNameOnLockscreen ? 1 : 0, forKey: "displayNameOnLockscreen") - encoder.encodeInt32(self.displayNotificationsFromAllAccounts ? 1 : 0, forKey: "displayNotificationsFromAllAccounts") - } - - public func isEqual(to: PreferencesEntry) -> Bool { - if let to = to as? InAppNotificationSettings { - return self == to - } else { - return false - } + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: StringCodingKey.self) + + try container.encode((self.playSounds ? 1 : 0) as Int32, forKey: "s") + try container.encode((self.vibrate ? 1 : 0) as Int32, forKey: "v") + try container.encode((self.displayPreviews ? 1 : 0) as Int32, forKey: "p") + try container.encode(self.totalUnreadCountDisplayStyle.rawValue, forKey: "cds") + try container.encode(self.totalUnreadCountDisplayCategory.rawValue, forKey: "totalUnreadCountDisplayCategory") + try container.encode(self.totalUnreadCountIncludeTags.rawValue, forKey: "totalUnreadCountIncludeTags_2") + try container.encode((self.displayNameOnLockscreen ? 1 : 0) as Int32, forKey: "displayNameOnLockscreen") + try container.encode((self.displayNotificationsFromAllAccounts ? 1 : 0) as Int32, forKey: "displayNotificationsFromAllAccounts") } } @@ -107,12 +103,12 @@ public func updateInAppNotificationSettingsInteractively(accountManager: Account return accountManager.transaction { transaction -> Void in transaction.updateSharedData(ApplicationSpecificSharedDataKeys.inAppNotificationSettings, { entry in let currentSettings: InAppNotificationSettings - if let entry = entry as? InAppNotificationSettings { + if let entry = entry?.get(InAppNotificationSettings.self) { currentSettings = entry } else { currentSettings = InAppNotificationSettings.defaultSettings } - return f(currentSettings) + return PreferencesEntry(f(currentSettings)) }) } } diff --git a/submodules/TelegramUIPreferences/Sources/InstantPagePresentationSettings.swift b/submodules/TelegramUIPreferences/Sources/InstantPagePresentationSettings.swift index 24196f6a02..26a1ddba44 100644 --- a/submodules/TelegramUIPreferences/Sources/InstantPagePresentationSettings.swift +++ b/submodules/TelegramUIPreferences/Sources/InstantPagePresentationSettings.swift @@ -18,7 +18,7 @@ public enum InstantPagePresentationFontSize: Int32 { case xxlarge = 4 } -public final class InstantPagePresentationSettings: PreferencesEntry, Equatable { +public final class InstantPagePresentationSettings: Codable, Equatable { public static var defaultSettings = InstantPagePresentationSettings(themeType: .light, fontSize: .standard, forceSerif: false, autoNightMode: true, ignoreAutoNightModeUntil: 0) public var themeType: InstantPageThemeType @@ -35,28 +35,24 @@ public final class InstantPagePresentationSettings: PreferencesEntry, Equatable self.ignoreAutoNightModeUntil = ignoreAutoNightModeUntil } - public init(decoder: PostboxDecoder) { - self.themeType = InstantPageThemeType(rawValue: decoder.decodeInt32ForKey("themeType", orElse: 0))! - self.fontSize = InstantPagePresentationFontSize(rawValue: decoder.decodeInt32ForKey("fontSize", orElse: 0))! - self.forceSerif = decoder.decodeInt32ForKey("forceSerif", orElse: 0) != 0 - self.autoNightMode = decoder.decodeInt32ForKey("autoNightMode", orElse: 0) != 0 - self.ignoreAutoNightModeUntil = decoder.decodeInt32ForKey("ignoreAutoNightModeUntil", orElse: 0) + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: StringCodingKey.self) + + self.themeType = InstantPageThemeType(rawValue: try container.decode(Int32.self, forKey: "themeType"))! + self.fontSize = InstantPagePresentationFontSize(rawValue: try container.decode(Int32.self, forKey: "fontSize"))! + self.forceSerif = try container.decode(Int32.self, forKey: "forceSerif") != 0 + self.autoNightMode = try container.decode(Int32.self, forKey: "autoNightMode") != 0 + self.ignoreAutoNightModeUntil = try container.decode(Int32.self, forKey: "ignoreAutoNightModeUntil") } - public func encode(_ encoder: PostboxEncoder) { - encoder.encodeInt32(self.themeType.rawValue, forKey: "themeType") - encoder.encodeInt32(self.fontSize.rawValue, forKey: "fontSize") - encoder.encodeInt32(self.forceSerif ? 1 : 0, forKey: "forceSerif") - encoder.encodeInt32(self.autoNightMode ? 1 : 0, forKey: "autoNightMode") - encoder.encodeInt32(self.ignoreAutoNightModeUntil, forKey: "ignoreAutoNightModeUntil") - } - - public func isEqual(to: PreferencesEntry) -> Bool { - if let to = to as? InstantPagePresentationSettings { - return self == to - } else { - return false - } + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: StringCodingKey.self) + + try container.encode(self.themeType.rawValue, forKey: "themeType") + try container.encode(self.fontSize.rawValue, forKey: "fontSize") + try container.encode((self.forceSerif ? 1 : 0) as Int32, forKey: "forceSerif") + try container.encode((self.autoNightMode ? 1 : 0) as Int32, forKey: "autoNightMode") + try container.encode(self.ignoreAutoNightModeUntil, forKey: "ignoreAutoNightModeUntil") } public static func ==(lhs: InstantPagePresentationSettings, rhs: InstantPagePresentationSettings) -> Bool { @@ -103,12 +99,12 @@ public func updateInstantPagePresentationSettingsInteractively(accountManager: A return accountManager.transaction { transaction -> Void in transaction.updateSharedData(ApplicationSpecificSharedDataKeys.instantPagePresentationSettings, { entry in let currentSettings: InstantPagePresentationSettings - if let entry = entry as? InstantPagePresentationSettings { + if let entry = entry?.get(InstantPagePresentationSettings.self) { currentSettings = entry } else { currentSettings = InstantPagePresentationSettings.defaultSettings } - return f(currentSettings) + return PreferencesEntry(f(currentSettings)) }) } } diff --git a/submodules/TelegramUIPreferences/Sources/IntentsSettings.swift b/submodules/TelegramUIPreferences/Sources/IntentsSettings.swift index 221f946fe0..19e0c85704 100644 --- a/submodules/TelegramUIPreferences/Sources/IntentsSettings.swift +++ b/submodules/TelegramUIPreferences/Sources/IntentsSettings.swift @@ -3,7 +3,7 @@ import Postbox import TelegramCore import SwiftSignalKit -public struct IntentsSettings: PreferencesEntry, Equatable { +public struct IntentsSettings: Codable, Equatable { public let initiallyReset: Bool public let account: PeerId? @@ -27,36 +27,28 @@ public struct IntentsSettings: PreferencesEntry, Equatable { self.onlyShared = onlyShared } - public init(decoder: PostboxDecoder) { - self.initiallyReset = decoder.decodeBoolForKey("initiallyReset_v2", orElse: false) - self.account = decoder.decodeOptionalInt64ForKey("account").flatMap { PeerId($0) } - self.contacts = decoder.decodeBoolForKey("contacts", orElse: true) - self.privateChats = decoder.decodeBoolForKey("privateChats", orElse: false) - self.savedMessages = decoder.decodeBoolForKey("savedMessages", orElse: true) - self.groups = decoder.decodeBoolForKey("groups", orElse: false) - self.onlyShared = decoder.decodeBoolForKey("onlyShared", orElse: false) + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: StringCodingKey.self) + + self.initiallyReset = try container.decodeIfPresent(Bool.self, forKey: "initiallyReset_v2") ?? false + self.account = (try container.decodeIfPresent(Int64.self, forKey: "account")).flatMap { PeerId($0) } + self.contacts = try container.decodeIfPresent(Bool.self, forKey: "contacts") ?? true + self.privateChats = try container.decodeIfPresent(Bool.self, forKey: "privateChats") ?? false + self.savedMessages = try container.decodeIfPresent(Bool.self, forKey: "savedMessages") ?? true + self.groups = try container.decodeIfPresent(Bool.self, forKey: "groups") ?? false + self.onlyShared = try container.decodeIfPresent(Bool.self, forKey: "onlyShared") ?? false } - public func encode(_ encoder: PostboxEncoder) { - encoder.encodeBool(self.initiallyReset, forKey: "initiallyReset_v2") - if let account = self.account { - encoder.encodeInt64(account.toInt64(), forKey: "account") - } else { - encoder.encodeNil(forKey: "account") - } - encoder.encodeBool(self.contacts, forKey: "contacts") - encoder.encodeBool(self.privateChats, forKey: "privateChats") - encoder.encodeBool(self.savedMessages, forKey: "savedMessages") - encoder.encodeBool(self.groups, forKey: "groups") - encoder.encodeBool(self.onlyShared, forKey: "onlyShared") - } - - public func isEqual(to: PreferencesEntry) -> Bool { - if let to = to as? IntentsSettings { - return self == to - } else { - return false - } + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: StringCodingKey.self) + + try container.encode(self.initiallyReset, forKey: "initiallyReset_v2") + try container.encodeIfPresent(self.account?.toInt64(), forKey: "account") + try container.encode(self.contacts, forKey: "contacts") + try container.encode(self.privateChats, forKey: "privateChats") + try container.encode(self.savedMessages, forKey: "savedMessages") + try container.encode(self.groups, forKey: "groups") + try container.encode(self.onlyShared, forKey: "onlyShared") } public static func ==(lhs: IntentsSettings, rhs: IntentsSettings) -> Bool { @@ -95,14 +87,14 @@ public func updateIntentsSettingsInteractively(accountManager: AccountManager Bool { - if let to = to as? AutomaticMediaDownloadSettings { - return self == to - } else { - return false - } - } -} diff --git a/submodules/TelegramUIPreferences/Sources/MediaAutoDownloadSettings.swift b/submodules/TelegramUIPreferences/Sources/MediaAutoDownloadSettings.swift index c6a262d0a7..75f9a8e7f5 100644 --- a/submodules/TelegramUIPreferences/Sources/MediaAutoDownloadSettings.swift +++ b/submodules/TelegramUIPreferences/Sources/MediaAutoDownloadSettings.swift @@ -27,7 +27,7 @@ public enum MediaAutoDownloadPreset: Int32 { case custom } -public struct MediaAutoDownloadPresets: PostboxCoding, Equatable { +public struct MediaAutoDownloadPresets: Codable, Equatable { public var low: MediaAutoDownloadCategories public var medium: MediaAutoDownloadCategories public var high: MediaAutoDownloadCategories @@ -38,20 +38,24 @@ public struct MediaAutoDownloadPresets: PostboxCoding, Equatable { self.high = high } - public init(decoder: PostboxDecoder) { - self.low = decoder.decodeObjectForKey("low", decoder: MediaAutoDownloadCategories.init(decoder:)) as! MediaAutoDownloadCategories - self.medium = decoder.decodeObjectForKey("medium", decoder: MediaAutoDownloadCategories.init(decoder:)) as! MediaAutoDownloadCategories - self.high = decoder.decodeObjectForKey("high", decoder: MediaAutoDownloadCategories.init(decoder:)) as! MediaAutoDownloadCategories + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: StringCodingKey.self) + + self.low = try container.decode(MediaAutoDownloadCategories.self, forKey: "low") + self.medium = try container.decode(MediaAutoDownloadCategories.self, forKey: "medium") + self.high = try container.decode(MediaAutoDownloadCategories.self, forKey: "high") } - public func encode(_ encoder: PostboxEncoder) { - encoder.encodeObject(self.low, forKey: "low") - encoder.encodeObject(self.medium, forKey: "medium") - encoder.encodeObject(self.high, forKey: "high") + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: StringCodingKey.self) + + try container.encode(self.low, forKey: "low") + try container.encode(self.medium, forKey: "medium") + try container.encode(self.high, forKey: "high") } } -public struct MediaAutoDownloadConnection: PostboxCoding, Equatable { +public struct MediaAutoDownloadConnection: Codable, Equatable { public var enabled: Bool public var preset: MediaAutoDownloadPreset public var custom: MediaAutoDownloadCategories? @@ -62,24 +66,24 @@ public struct MediaAutoDownloadConnection: PostboxCoding, Equatable { self.custom = custom } - public init(decoder: PostboxDecoder) { - self.enabled = decoder.decodeInt32ForKey("enabled", orElse: 0) != 0 - self.preset = MediaAutoDownloadPreset(rawValue: decoder.decodeInt32ForKey("preset", orElse: 0)) ?? .medium - self.custom = decoder.decodeObjectForKey("custom", decoder: MediaAutoDownloadCategories.init(decoder:)) as? MediaAutoDownloadCategories + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: StringCodingKey.self) + + self.enabled = try container.decode(Int32.self, forKey: "enabled") != 0 + self.preset = MediaAutoDownloadPreset(rawValue: try container.decode(Int32.self, forKey: "preset")) ?? .medium + self.custom = try container.decodeIfPresent(MediaAutoDownloadCategories.self, forKey: "custom") } - public func encode(_ encoder: PostboxEncoder) { - encoder.encodeInt32(self.enabled ? 1 : 0, forKey: "enabled") - encoder.encodeInt32(self.preset.rawValue, forKey: "preset") - if let custom = self.custom { - encoder.encodeObject(custom, forKey: "custom") - } else { - encoder.encodeNil(forKey: "custom") - } + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: StringCodingKey.self) + + try container.encode((self.enabled ? 1 : 0) as Int32, forKey: "enabled") + try container.encode(self.preset.rawValue, forKey: "preset") + try container.encodeIfPresent(self.custom, forKey: "custom") } } -public struct MediaAutoDownloadCategories: PostboxCoding, Equatable, Comparable { +public struct MediaAutoDownloadCategories: Codable, Equatable, Comparable { public var basePreset: MediaAutoDownloadPreset public var photo: MediaAutoDownloadCategory public var video: MediaAutoDownloadCategory @@ -92,18 +96,22 @@ public struct MediaAutoDownloadCategories: PostboxCoding, Equatable, Comparable self.file = file } - public init(decoder: PostboxDecoder) { - self.basePreset = MediaAutoDownloadPreset(rawValue: decoder.decodeInt32ForKey("preset", orElse: 0)) ?? .medium - self.photo = decoder.decodeObjectForKey("photo", decoder: MediaAutoDownloadCategory.init(decoder:)) as! MediaAutoDownloadCategory - self.video = decoder.decodeObjectForKey("video", decoder: MediaAutoDownloadCategory.init(decoder:)) as! MediaAutoDownloadCategory - self.file = decoder.decodeObjectForKey("file", decoder: MediaAutoDownloadCategory.init(decoder:)) as! MediaAutoDownloadCategory + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: StringCodingKey.self) + + self.basePreset = MediaAutoDownloadPreset(rawValue: try container.decode(Int32.self, forKey: "preset")) ?? .medium + self.photo = try container.decode(MediaAutoDownloadCategory.self, forKey: "photo") + self.video = try container.decode(MediaAutoDownloadCategory.self, forKey: "video") + self.file = try container.decode(MediaAutoDownloadCategory.self, forKey: "file") } - public func encode(_ encoder: PostboxEncoder) { - encoder.encodeInt32(self.basePreset.rawValue, forKey: "preset") - encoder.encodeObject(self.photo, forKey: "photo") - encoder.encodeObject(self.video, forKey: "video") - encoder.encodeObject(self.file, forKey: "file") + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: StringCodingKey.self) + + try container.encode(self.basePreset.rawValue, forKey: "preset") + try container.encode(self.photo, forKey: "photo") + try container.encode(self.video, forKey: "video") + try container.encode(self.file, forKey: "file") } public static func < (lhs: MediaAutoDownloadCategories, rhs: MediaAutoDownloadCategories) -> Bool { @@ -113,7 +121,7 @@ public struct MediaAutoDownloadCategories: PostboxCoding, Equatable, Comparable } } -public struct MediaAutoDownloadCategory: PostboxCoding, Equatable { +public struct MediaAutoDownloadCategory: Codable, Equatable { public var contacts: Bool public var otherPrivate: Bool public var groups: Bool @@ -130,26 +138,30 @@ public struct MediaAutoDownloadCategory: PostboxCoding, Equatable { self.predownload = predownload } - public init(decoder: PostboxDecoder) { - self.contacts = decoder.decodeInt32ForKey("contacts", orElse: 0) != 0 - self.otherPrivate = decoder.decodeInt32ForKey("otherPrivate", orElse: 0) != 0 - self.groups = decoder.decodeInt32ForKey("groups", orElse: 0) != 0 - self.channels = decoder.decodeInt32ForKey("channels", orElse: 0) != 0 - self.sizeLimit = decoder.decodeInt32ForKey("size", orElse: 0) - self.predownload = decoder.decodeInt32ForKey("predownload", orElse: 0) != 0 + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: StringCodingKey.self) + + self.contacts = try container.decode(Int32.self, forKey: "contacts") != 0 + self.otherPrivate = try container.decode(Int32.self, forKey: "otherPrivate") != 0 + self.groups = try container.decode(Int32.self, forKey: "groups") != 0 + self.channels = try container.decode(Int32.self, forKey: "channels") != 0 + self.sizeLimit = try container.decode(Int32.self, forKey: "size") + self.predownload = try container.decode(Int32.self, forKey: "predownload") != 0 } - public func encode(_ encoder: PostboxEncoder) { - encoder.encodeInt32(self.contacts ? 1 : 0, forKey: "contacts") - encoder.encodeInt32(self.otherPrivate ? 1 : 0, forKey: "otherPrivate") - encoder.encodeInt32(self.groups ? 1 : 0, forKey: "groups") - encoder.encodeInt32(self.channels ? 1 : 0, forKey: "channels") - encoder.encodeInt32(self.sizeLimit, forKey: "size") - encoder.encodeInt32(self.predownload ? 1 : 0, forKey: "predownload") + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: StringCodingKey.self) + + try container.encode((self.contacts ? 1 : 0) as Int32, forKey: "contacts") + try container.encode((self.otherPrivate ? 1 : 0) as Int32, forKey: "otherPrivate") + try container.encode((self.groups ? 1 : 0) as Int32, forKey: "groups") + try container.encode((self.channels ? 1 : 0) as Int32, forKey: "channels") + try container.encode(self.sizeLimit, forKey: "size") + try container.encode((self.predownload ? 1 : 0) as Int32, forKey: "predownload") } } -public struct MediaAutoDownloadSettings: PreferencesEntry, Equatable { +public struct MediaAutoDownloadSettings: Codable, Equatable { public var presets: MediaAutoDownloadPresets public var cellular: MediaAutoDownloadConnection public var wifi: MediaAutoDownloadConnection @@ -185,47 +197,32 @@ public struct MediaAutoDownloadSettings: PreferencesEntry, Equatable { self.downloadInBackground = downloadInBackground } - public static func upgradeLegacySettings(_ settings: AutomaticMediaDownloadSettings) -> MediaAutoDownloadSettings { - if settings == AutomaticMediaDownloadSettings.defaultSettings { - return MediaAutoDownloadSettings.defaultSettings - } - - let defaultSettings = MediaAutoDownloadSettings.defaultSettings - let saveDownloadedPhotos = MediaAutoDownloadCategory(contacts: settings.peers.contacts.saveDownloadedPhotos, otherPrivate: settings.peers.otherPrivate.saveDownloadedPhotos, groups: settings.peers.groups.saveDownloadedPhotos, channels: settings.peers.channels.saveDownloadedPhotos, sizeLimit: 0, predownload: false) - - let cellular = MediaAutoDownloadConnection(enabled: settings.masterEnabled, preset: .medium, custom: nil) - let wifi = MediaAutoDownloadConnection(enabled: settings.masterEnabled, preset: .high, custom: nil) - - return MediaAutoDownloadSettings(presets: defaultSettings.presets, cellular: cellular, wifi: wifi, saveDownloadedPhotos: saveDownloadedPhotos, autoplayGifs: settings.autoplayGifs, autoplayVideos: true, downloadInBackground: settings.downloadInBackground) - } - - public init(decoder: PostboxDecoder) { + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: StringCodingKey.self) + let defaultSettings = MediaAutoDownloadSettings.defaultSettings self.presets = defaultSettings.presets - self.cellular = decoder.decodeObjectForKey("cellular", decoder: MediaAutoDownloadConnection.init(decoder:)) as? MediaAutoDownloadConnection ?? defaultSettings.cellular - self.wifi = decoder.decodeObjectForKey("wifi", decoder: MediaAutoDownloadConnection.init(decoder:)) as? MediaAutoDownloadConnection ?? defaultSettings.wifi - self.saveDownloadedPhotos = decoder.decodeObjectForKey("saveDownloadedPhotos", decoder: MediaAutoDownloadCategory.init(decoder:)) as? MediaAutoDownloadCategory ?? defaultSettings.saveDownloadedPhotos - self.autoplayGifs = decoder.decodeInt32ForKey("autoplayGifs", orElse: 1) != 0 - self.autoplayVideos = decoder.decodeInt32ForKey("autoplayVideos", orElse: 1) != 0 - self.downloadInBackground = decoder.decodeInt32ForKey("downloadInBackground", orElse: 1) != 0 + + self.cellular = (try? container.decodeIfPresent(MediaAutoDownloadConnection.self, forKey: "cellular")) ?? defaultSettings.cellular + self.wifi = (try? container.decodeIfPresent(MediaAutoDownloadConnection.self, forKey: "wifi")) ?? defaultSettings.wifi + + self.saveDownloadedPhotos = (try? container.decodeIfPresent(MediaAutoDownloadCategory.self, forKey: "saveDownloadedPhotos")) ?? defaultSettings.saveDownloadedPhotos + + self.autoplayGifs = try container.decode(Int32.self, forKey: "autoplayGifs") != 0 + self.autoplayVideos = try container.decode(Int32.self, forKey: "autoplayVideos") != 0 + self.downloadInBackground = try container.decode(Int32.self, forKey: "downloadInBackground") != 0 } - public func encode(_ encoder: PostboxEncoder) { - encoder.encodeObject(self.cellular, forKey: "cellular") - encoder.encodeObject(self.wifi, forKey: "wifi") - encoder.encodeObject(self.saveDownloadedPhotos, forKey: "saveDownloadedPhotos") - encoder.encodeInt32(self.autoplayGifs ? 1 : 0, forKey: "autoplayGifs") - encoder.encodeInt32(self.autoplayVideos ? 1 : 0, forKey: "autoplayVideos") - encoder.encodeInt32(self.downloadInBackground ? 1 : 0, forKey: "downloadInBackground") - } - - public func isEqual(to: PreferencesEntry) -> Bool { - if let to = to as? MediaAutoDownloadSettings { - return self == to - } else { - return false - } + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: StringCodingKey.self) + + try container.encode(self.cellular, forKey: "cellular") + try container.encode(self.wifi, forKey: "wifi") + try container.encode(self.saveDownloadedPhotos, forKey: "saveDownloadedPhotos") + try container.encode((self.autoplayGifs ? 1 : 0) as Int32, forKey: "autoplayGifs") + try container.encode((self.autoplayVideos ? 1 : 0) as Int32, forKey: "autoplayVideos") + try container.encode((self.downloadInBackground ? 1 : 0) as Int32, forKey: "downloadInBackground") } public func connectionSettings(for networkType: MediaAutoDownloadNetworkType) -> MediaAutoDownloadConnection { @@ -261,13 +258,13 @@ public func updateMediaDownloadSettingsInteractively(accountManager: AccountMana return accountManager.transaction { transaction -> Void in transaction.updateSharedData(ApplicationSpecificSharedDataKeys.automaticMediaDownloadSettings, { entry in let currentSettings: MediaAutoDownloadSettings - if let entry = entry as? MediaAutoDownloadSettings { + if let entry = entry?.get(MediaAutoDownloadSettings.self) { currentSettings = entry } else { currentSettings = MediaAutoDownloadSettings.defaultSettings } let updated = f(currentSettings) - return updated + return PreferencesEntry(updated) }) } } diff --git a/submodules/TelegramUIPreferences/Sources/MediaInputSettings.swift b/submodules/TelegramUIPreferences/Sources/MediaInputSettings.swift index e1c5f49d42..df05ae0771 100644 --- a/submodules/TelegramUIPreferences/Sources/MediaInputSettings.swift +++ b/submodules/TelegramUIPreferences/Sources/MediaInputSettings.swift @@ -3,7 +3,7 @@ import Postbox import TelegramCore import SwiftSignalKit -public struct MediaInputSettings: PreferencesEntry, Equatable { +public struct MediaInputSettings: Codable, Equatable { public let enableRaiseToSpeak: Bool public static var defaultSettings: MediaInputSettings { @@ -14,20 +14,16 @@ public struct MediaInputSettings: PreferencesEntry, Equatable { self.enableRaiseToSpeak = enableRaiseToSpeak } - public init(decoder: PostboxDecoder) { - self.enableRaiseToSpeak = decoder.decodeInt32ForKey("enableRaiseToSpeak", orElse: 1) != 0 + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: StringCodingKey.self) + + self.enableRaiseToSpeak = (try container.decode(Int32.self, forKey: "enableRaiseToSpeak")) != 0 } - public func encode(_ encoder: PostboxEncoder) { - encoder.encodeInt32(self.enableRaiseToSpeak ? 1 : 0, forKey: "enableRaiseToSpeak") - } - - public func isEqual(to: PreferencesEntry) -> Bool { - if let to = to as? MediaInputSettings { - return self == to - } else { - return false - } + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: StringCodingKey.self) + + try container.encode((self.enableRaiseToSpeak ? 1 : 0) as Int32, forKey: "enableRaiseToSpeak") } public static func ==(lhs: MediaInputSettings, rhs: MediaInputSettings) -> Bool { @@ -43,12 +39,12 @@ public func updateMediaInputSettingsInteractively(accountManager: AccountManager return accountManager.transaction { transaction -> Void in transaction.updateSharedData(ApplicationSpecificSharedDataKeys.mediaInputSettings, { entry in let currentSettings: MediaInputSettings - if let entry = entry as? MediaInputSettings { + if let entry = entry?.get(MediaInputSettings.self) { currentSettings = entry } else { currentSettings = MediaInputSettings.defaultSettings } - return f(currentSettings) + return PreferencesEntry(f(currentSettings)) }) } } diff --git a/submodules/TelegramUIPreferences/Sources/MusicPlaybackSettings.swift b/submodules/TelegramUIPreferences/Sources/MusicPlaybackSettings.swift index 37d28f873f..f094a19775 100644 --- a/submodules/TelegramUIPreferences/Sources/MusicPlaybackSettings.swift +++ b/submodules/TelegramUIPreferences/Sources/MusicPlaybackSettings.swift @@ -37,7 +37,7 @@ public enum AudioPlaybackRate: Int32 { } } -public struct MusicPlaybackSettings: PreferencesEntry, Equatable { +public struct MusicPlaybackSettings: Codable, Equatable { public var order: MusicPlaybackSettingsOrder public var looping: MusicPlaybackSettingsLooping public var voicePlaybackRate: AudioPlaybackRate @@ -52,24 +52,20 @@ public struct MusicPlaybackSettings: PreferencesEntry, Equatable { self.voicePlaybackRate = voicePlaybackRate } - public init(decoder: PostboxDecoder) { - self.order = MusicPlaybackSettingsOrder(rawValue: decoder.decodeInt32ForKey("order", orElse: 0)) ?? .regular - self.looping = MusicPlaybackSettingsLooping(rawValue: decoder.decodeInt32ForKey("looping", orElse: 0)) ?? .none - self.voicePlaybackRate = AudioPlaybackRate(rawValue: decoder.decodeInt32ForKey("voicePlaybackRate", orElse: AudioPlaybackRate.x1.rawValue)) ?? .x1 + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: StringCodingKey.self) + + self.order = MusicPlaybackSettingsOrder(rawValue: try container.decode(Int32.self, forKey: "order")) ?? .regular + self.looping = MusicPlaybackSettingsLooping(rawValue: try container.decode(Int32.self, forKey: "looping")) ?? .none + self.voicePlaybackRate = AudioPlaybackRate(rawValue: try container.decodeIfPresent(Int32.self, forKey: "voicePlaybackRate") ?? AudioPlaybackRate.x1.rawValue) ?? .x1 } - public func encode(_ encoder: PostboxEncoder) { - encoder.encodeInt32(self.order.rawValue, forKey: "order") - encoder.encodeInt32(self.looping.rawValue, forKey: "looping") - encoder.encodeInt32(self.voicePlaybackRate.rawValue, forKey: "voicePlaybackRate") - } - - public func isEqual(to: PreferencesEntry) -> Bool { - if let to = to as? MusicPlaybackSettings { - return self == to - } else { - return false - } + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: StringCodingKey.self) + + try container.encode(self.order.rawValue, forKey: "order") + try container.encode(self.looping.rawValue, forKey: "looping") + try container.encode(self.voicePlaybackRate.rawValue, forKey: "voicePlaybackRate") } public static func ==(lhs: MusicPlaybackSettings, rhs: MusicPlaybackSettings) -> Bool { @@ -93,12 +89,12 @@ public func updateMusicPlaybackSettingsInteractively(accountManager: AccountMana return accountManager.transaction { transaction -> Void in transaction.updateSharedData(ApplicationSpecificSharedDataKeys.musicPlaybackSettings, { entry in let currentSettings: MusicPlaybackSettings - if let entry = entry as? MusicPlaybackSettings { + if let entry = entry?.get(MusicPlaybackSettings.self) { currentSettings = entry } else { currentSettings = MusicPlaybackSettings.defaultSettings } - return f(currentSettings) + return PreferencesEntry(f(currentSettings)) }) } } diff --git a/submodules/TelegramUIPreferences/Sources/PresentationPasscodeSettings.swift b/submodules/TelegramUIPreferences/Sources/PresentationPasscodeSettings.swift index 45c1b0dcec..957cf8227f 100644 --- a/submodules/TelegramUIPreferences/Sources/PresentationPasscodeSettings.swift +++ b/submodules/TelegramUIPreferences/Sources/PresentationPasscodeSettings.swift @@ -3,7 +3,7 @@ import Postbox import TelegramCore import SwiftSignalKit -public struct PresentationPasscodeSettings: PreferencesEntry, Equatable { +public struct PresentationPasscodeSettings: Codable, Equatable { public var enableBiometrics: Bool public var autolockTimeout: Int32? public var biometricsDomainState: Data? @@ -20,38 +20,22 @@ public struct PresentationPasscodeSettings: PreferencesEntry, Equatable { self.shareBiometricsDomainState = shareBiometricsDomainState } - public init(decoder: PostboxDecoder) { - self.enableBiometrics = decoder.decodeInt32ForKey("s", orElse: 0) != 0 - self.autolockTimeout = decoder.decodeOptionalInt32ForKey("al") - self.biometricsDomainState = decoder.decodeDataForKey("ds") - self.shareBiometricsDomainState = decoder.decodeDataForKey("sds") + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: StringCodingKey.self) + + self.enableBiometrics = (try container.decode(Int32.self, forKey: "s")) != 0 + self.autolockTimeout = try container.decodeIfPresent(Int32.self, forKey: "al") + self.biometricsDomainState = try container.decodeIfPresent(Data.self, forKey: "ds") + self.shareBiometricsDomainState = try container.decodeIfPresent(Data.self, forKey: "sds") } - public func encode(_ encoder: PostboxEncoder) { - encoder.encodeInt32(self.enableBiometrics ? 1 : 0, forKey: "s") - if let autolockTimeout = self.autolockTimeout { - encoder.encodeInt32(autolockTimeout, forKey: "al") - } else { - encoder.encodeNil(forKey: "al") - } - if let biometricsDomainState = self.biometricsDomainState { - encoder.encodeData(biometricsDomainState, forKey: "ds") - } else { - encoder.encodeNil(forKey: "ds") - } - if let shareBiometricsDomainState = self.shareBiometricsDomainState { - encoder.encodeData(shareBiometricsDomainState, forKey: "sds") - } else { - encoder.encodeNil(forKey: "sds") - } - } - - public func isEqual(to: PreferencesEntry) -> Bool { - if let to = to as? PresentationPasscodeSettings { - return self == to - } else { - return false - } + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: StringCodingKey.self) + + try container.encode((self.enableBiometrics ? 1 : 0) as Int32, forKey: "s") + try container.encodeIfPresent(self.autolockTimeout, forKey: "al") + try container.encodeIfPresent(self.biometricsDomainState, forKey: "ds") + try container.encodeIfPresent(self.shareBiometricsDomainState, forKey: "sds") } public static func ==(lhs: PresentationPasscodeSettings, rhs: PresentationPasscodeSettings) -> Bool { @@ -84,11 +68,11 @@ public func updatePresentationPasscodeSettingsInteractively(accountManager: Acco public func updatePresentationPasscodeSettingsInternal(transaction: AccountManagerModifier, _ f: @escaping (PresentationPasscodeSettings) -> PresentationPasscodeSettings) { transaction.updateSharedData(ApplicationSpecificSharedDataKeys.presentationPasscodeSettings, { entry in let currentSettings: PresentationPasscodeSettings - if let entry = entry as? PresentationPasscodeSettings { + if let entry = entry?.get(PresentationPasscodeSettings.self) { currentSettings = entry } else { currentSettings = PresentationPasscodeSettings.defaultSettings } - return f(currentSettings) + return PreferencesEntry(f(currentSettings)) }) } diff --git a/submodules/TelegramUIPreferences/Sources/PresentationThemeSettings.swift b/submodules/TelegramUIPreferences/Sources/PresentationThemeSettings.swift index fa7a55fe50..7800057498 100644 --- a/submodules/TelegramUIPreferences/Sources/PresentationThemeSettings.swift +++ b/submodules/TelegramUIPreferences/Sources/PresentationThemeSettings.swift @@ -262,51 +262,57 @@ public enum PresentationFontSize: Int32, CaseIterable { case medium = 6 } -public enum AutomaticThemeSwitchTimeBasedSetting: PostboxCoding, Equatable { +public enum AutomaticThemeSwitchTimeBasedSetting: Codable, Equatable { case manual(fromSeconds: Int32, toSeconds: Int32) case automatic(latitude: Double, longitude: Double, localizedName: String) - public init(decoder: PostboxDecoder) { - switch decoder.decodeInt32ForKey("_t", orElse: 0) { + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: StringCodingKey.self) + + switch try container.decode(Int32.self, forKey: "_t") { case 0: - self = .manual(fromSeconds: decoder.decodeInt32ForKey("fromSeconds", orElse: 0), toSeconds: decoder.decodeInt32ForKey("toSeconds", orElse: 0)) + self = .manual(fromSeconds: try container.decode(Int32.self, forKey: "fromSeconds"), toSeconds: try container.decode(Int32.self, forKey: "toSeconds")) case 1: - self = .automatic(latitude: decoder.decodeDoubleForKey("latitude", orElse: 0.0), longitude: decoder.decodeDoubleForKey("longitude", orElse: 0.0), localizedName: decoder.decodeStringForKey("localizedName", orElse: "")) + self = .automatic(latitude: try container.decode(Double.self, forKey: "latitude"), longitude: try container.decode(Double.self, forKey: "longitude"), localizedName: try container.decode(String.self, forKey: "localizedName")) default: assertionFailure() self = .manual(fromSeconds: 0, toSeconds: 1) } } - public func encode(_ encoder: PostboxEncoder) { + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: StringCodingKey.self) + switch self { case let .manual(fromSeconds, toSeconds): - encoder.encodeInt32(0, forKey: "_t") - encoder.encodeInt32(fromSeconds, forKey: "fromSeconds") - encoder.encodeInt32(toSeconds, forKey: "toSeconds") + try container.encode(0 as Int32, forKey: "_t") + try container.encode(fromSeconds, forKey: "fromSeconds") + try container.encode(toSeconds, forKey: "toSeconds") case let .automatic(latitude, longitude, localizedName): - encoder.encodeInt32(1, forKey: "_t") - encoder.encodeDouble(latitude, forKey: "latitude") - encoder.encodeDouble(longitude, forKey: "longitude") - encoder.encodeString(localizedName, forKey: "localizedName") + try container.encode(1 as Int32, forKey: "_t") + try container.encode(latitude, forKey: "latitude") + try container.encode(longitude, forKey: "longitude") + try container.encode(localizedName, forKey: "localizedName") } } } -public enum AutomaticThemeSwitchTrigger: PostboxCoding, Equatable { +public enum AutomaticThemeSwitchTrigger: Codable, Equatable { case system case explicitNone case timeBased(setting: AutomaticThemeSwitchTimeBasedSetting) case brightness(threshold: Double) - public init(decoder: PostboxDecoder) { - switch decoder.decodeInt32ForKey("_t", orElse: 0) { + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: StringCodingKey.self) + + switch try container.decode(Int32.self, forKey: "_t") { case 0: self = .system case 1: - self = .timeBased(setting: decoder.decodeObjectForKey("setting", decoder: { AutomaticThemeSwitchTimeBasedSetting(decoder: $0) }) as! AutomaticThemeSwitchTimeBasedSetting) + self = .timeBased(setting: try container.decode(AutomaticThemeSwitchTimeBasedSetting.self, forKey: "setting")) case 2: - self = .brightness(threshold: decoder.decodeDoubleForKey("threshold", orElse: 0.2)) + self = .brightness(threshold: try container.decode(Double.self, forKey: "threshold")) case 3: self = .explicitNone default: @@ -315,23 +321,25 @@ public enum AutomaticThemeSwitchTrigger: PostboxCoding, Equatable { } } - public func encode(_ encoder: PostboxEncoder) { + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: StringCodingKey.self) + switch self { case .system: - encoder.encodeInt32(0, forKey: "_t") + try container.encode(0 as Int32, forKey: "_t") case let .timeBased(setting): - encoder.encodeInt32(1, forKey: "_t") - encoder.encodeObject(setting, forKey: "setting") + try container.encode(1 as Int32, forKey: "_t") + try container.encode(setting, forKey: "setting") case let .brightness(threshold): - encoder.encodeInt32(2, forKey: "_t") - encoder.encodeDouble(threshold, forKey: "threshold") + try container.encode(2 as Int32, forKey: "_t") + try container.encode(threshold, forKey: "threshold") case .explicitNone: - encoder.encodeInt32(3, forKey: "_t") + try container.encode(3 as Int32, forKey: "_t") } } } -public struct AutomaticThemeSwitchSetting: PostboxCoding, Equatable { +public struct AutomaticThemeSwitchSetting: Codable, Equatable { public var trigger: AutomaticThemeSwitchTrigger public var theme: PresentationThemeReference @@ -340,20 +348,26 @@ public struct AutomaticThemeSwitchSetting: PostboxCoding, Equatable { self.theme = theme } - public init(decoder: PostboxDecoder) { - self.trigger = decoder.decodeObjectForKey("trigger", decoder: { AutomaticThemeSwitchTrigger(decoder: $0) }) as! AutomaticThemeSwitchTrigger - if let theme = decoder.decodeObjectForKey("theme_v2", decoder: { PresentationThemeReference(decoder: $0) }) as? PresentationThemeReference { - self.theme = theme - } else if let legacyValue = decoder.decodeOptionalInt32ForKey("theme") { + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: StringCodingKey.self) + + self.trigger = try container.decode(AutomaticThemeSwitchTrigger.self, forKey: "trigger") + if let themeData = try container.decodeIfPresent(AdaptedPostboxDecoder.RawObjectData.self, forKey: "theme_v2") { + self.theme = PresentationThemeReference(decoder: PostboxDecoder(buffer: MemoryBuffer(data: themeData.data))) + } else if let legacyValue = try container.decodeIfPresent(Int32.self, forKey: "theme") { self.theme = .builtin(PresentationBuiltinThemeReference(rawValue: legacyValue) ?? .nightAccent) } else { self.theme = .builtin(.nightAccent) } } - public func encode(_ encoder: PostboxEncoder) { - encoder.encodeObject(self.trigger, forKey: "trigger") - encoder.encodeObject(self.theme, forKey: "theme_v2") + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: StringCodingKey.self) + + try container.encode(self.trigger, forKey: "trigger") + + let themeData = PostboxEncoder().encodeObjectToRawData(self.theme) + try container.encode(themeData, forKey: "theme_v2") } } @@ -512,7 +526,7 @@ public struct PresentationThemeAccentColor: PostboxCoding, Equatable { } } -public struct PresentationChatBubbleSettings: PostboxCoding, Equatable { +public struct PresentationChatBubbleSettings: Codable, Equatable { public var mainRadius: Int32 public var auxiliaryRadius: Int32 public var mergeBubbleCorners: Bool @@ -525,20 +539,44 @@ public struct PresentationChatBubbleSettings: PostboxCoding, Equatable { self.mergeBubbleCorners = mergeBubbleCorners } - public init(decoder: PostboxDecoder) { - self.mainRadius = decoder.decodeInt32ForKey("mainRadius", orElse: 16) - self.auxiliaryRadius = decoder.decodeInt32ForKey("auxiliaryRadius", orElse: 8) - self.mergeBubbleCorners = decoder.decodeInt32ForKey("mergeBubbleCorners", orElse: 1) != 0 + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: StringCodingKey.self) + + self.mainRadius = try container.decodeIfPresent(Int32.self, forKey: "mainRadius") ?? 16 + self.auxiliaryRadius = try container.decodeIfPresent(Int32.self, forKey: "auxiliaryRadius") ?? 8 + self.mergeBubbleCorners = (try container.decodeIfPresent(Int32.self, forKey: "mergeBubbleCorners") ?? 1) != 0 } - public func encode(_ encoder: PostboxEncoder) { - encoder.encodeInt32(self.mainRadius, forKey: "mainRadius") - encoder.encodeInt32(self.auxiliaryRadius, forKey: "auxiliaryRadius") - encoder.encodeInt32(self.mergeBubbleCorners ? 1 : 0, forKey: "mergeBubbleCorners") + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: StringCodingKey.self) + + try container.encode(self.mainRadius, forKey: "mainRadius") + try container.encode(self.auxiliaryRadius, forKey: "auxiliaryRadius") + try container.encode((self.mergeBubbleCorners ? 1 : 0) as Int32, forKey: "mergeBubbleCorners") } } -public struct PresentationThemeSettings: PreferencesEntry { +public struct PresentationThemeSettings: Codable { + private struct DictionaryKey: Codable, Hashable { + var key: Int64 + + init(_ key: Int64) { + self.key = key + } + + init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: StringCodingKey.self) + + self.key = try container.decode(Int64.self, forKey: "k") + } + + func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: StringCodingKey.self) + + try container.encode(self.key, forKey: "k") + } + } + public var theme: PresentationThemeReference public var themeSpecificAccentColors: [Int64: PresentationThemeAccentColor] public var themeSpecificChatWallpapers: [Int64: TelegramWallpaper] @@ -602,54 +640,68 @@ public struct PresentationThemeSettings: PreferencesEntry { self.reduceMotion = reduceMotion } - public init(decoder: PostboxDecoder) { - self.theme = decoder.decodeObjectForKey("t", decoder: { PresentationThemeReference(decoder: $0) }) as? PresentationThemeReference ?? .builtin(.dayClassic) + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: StringCodingKey.self) - self.themeSpecificChatWallpapers = decoder.decodeObjectDictionaryForKey("themeSpecificChatWallpapers", keyDecoder: { decoder in - return decoder.decodeInt64ForKey("k", orElse: 0) - }, valueDecoder: { decoder in - return TelegramWallpaper(decoder: decoder) - }) - - self.themeSpecificAccentColors = decoder.decodeObjectDictionaryForKey("themeSpecificAccentColors", keyDecoder: { decoder in - return decoder.decodeInt64ForKey("k", orElse: 0) - }, valueDecoder: { decoder in - return PresentationThemeAccentColor(decoder: decoder) - }) - - self.useSystemFont = decoder.decodeInt32ForKey("useSystemFont", orElse: 1) != 0 - let fontSize = PresentationFontSize(rawValue: decoder.decodeInt32ForKey("f", orElse: PresentationFontSize.regular.rawValue)) ?? .regular - self.fontSize = fontSize - self.listsFontSize = PresentationFontSize(rawValue: decoder.decodeInt32ForKey("lf", orElse: PresentationFontSize.regular.rawValue)) ?? fontSize - self.chatBubbleSettings = decoder.decodeObjectForKey("chatBubbleSettings", decoder: { PresentationChatBubbleSettings(decoder: $0) }) as? PresentationChatBubbleSettings ?? PresentationChatBubbleSettings.default - self.automaticThemeSwitchSetting = (decoder.decodeObjectForKey("automaticThemeSwitchSetting", decoder: { AutomaticThemeSwitchSetting(decoder: $0) }) as? AutomaticThemeSwitchSetting) ?? AutomaticThemeSwitchSetting(trigger: .system, theme: .builtin(.night)) - self.largeEmoji = decoder.decodeBoolForKey("largeEmoji", orElse: true) - self.reduceMotion = decoder.decodeBoolForKey("reduceMotion", orElse: false) - } - - public func encode(_ encoder: PostboxEncoder) { - encoder.encodeObject(self.theme, forKey: "t") - encoder.encodeObjectDictionary(self.themeSpecificAccentColors, forKey: "themeSpecificAccentColors", keyEncoder: { key, encoder in - encoder.encodeInt64(key, forKey: "k") - }) - encoder.encodeObjectDictionary(self.themeSpecificChatWallpapers, forKey: "themeSpecificChatWallpapers", keyEncoder: { key, encoder in - encoder.encodeInt64(key, forKey: "k") - }) - encoder.encodeInt32(self.useSystemFont ? 1 : 0, forKey: "useSystemFont") - encoder.encodeInt32(self.fontSize.rawValue, forKey: "f") - encoder.encodeInt32(self.listsFontSize.rawValue, forKey: "lf") - encoder.encodeObject(self.chatBubbleSettings, forKey: "chatBubbleSettings") - encoder.encodeObject(self.automaticThemeSwitchSetting, forKey: "automaticThemeSwitchSetting") - encoder.encodeBool(self.largeEmoji, forKey: "largeEmoji") - encoder.encodeBool(self.reduceMotion, forKey: "reduceMotion") - } - - public func isEqual(to: PreferencesEntry) -> Bool { - if let to = to as? PresentationThemeSettings { - return self == to + if let themeData = try container.decodeIfPresent(AdaptedPostboxDecoder.RawObjectData.self, forKey: "t"), let theme = PostboxDecoder(buffer: MemoryBuffer(data: themeData.data)).decodeRootObjectWithHash(hash: themeData.typeHash) as? PresentationThemeReference { + self.theme = theme } else { - return false + self.theme = .builtin(.dayClassic) } + + let themeSpecificChatWallpapersDict = try container.decode([DictionaryKey: AdaptedPostboxDecoder.RawObjectData].self, forKey: "themeSpecificChatWallpapers") + var mappedThemeSpecificChatWallpapers: [Int64: TelegramWallpaper] = [:] + for (key, value) in themeSpecificChatWallpapersDict { + let innerDecoder = PostboxDecoder(buffer: MemoryBuffer(data: value.data)) + mappedThemeSpecificChatWallpapers[key.key] = TelegramWallpaper(decoder: innerDecoder) + } + self.themeSpecificChatWallpapers = mappedThemeSpecificChatWallpapers + + let themeSpecificAccentColorsDict = try container.decode([DictionaryKey: AdaptedPostboxDecoder.RawObjectData].self, forKey: "themeSpecificAccentColors") + var mappedThemeSpecificAccentColors: [Int64: PresentationThemeAccentColor] = [:] + for (key, value) in themeSpecificAccentColorsDict { + let innerDecoder = PostboxDecoder(buffer: MemoryBuffer(data: value.data)) + mappedThemeSpecificAccentColors[key.key] = PresentationThemeAccentColor(decoder: innerDecoder) + } + self.themeSpecificAccentColors = mappedThemeSpecificAccentColors + + self.useSystemFont = (try container.decodeIfPresent(Int32.self, forKey: "useSystemFont") ?? 1) != 0 + + let fontSize = PresentationFontSize(rawValue: try container.decodeIfPresent(Int32.self, forKey: "f") ?? PresentationFontSize.regular.rawValue) ?? .regular + self.fontSize = fontSize + self.listsFontSize = PresentationFontSize(rawValue: try container.decodeIfPresent(Int32.self, forKey: "lf") ?? PresentationFontSize.regular.rawValue) ?? fontSize + + self.chatBubbleSettings = try container.decodeIfPresent(PresentationChatBubbleSettings.self, forKey: "chatBubbleSettings") ?? PresentationChatBubbleSettings.default + self.automaticThemeSwitchSetting = try container.decodeIfPresent(AutomaticThemeSwitchSetting.self, forKey: "automaticThemeSwitchSetting") ?? AutomaticThemeSwitchSetting(trigger: .system, theme: .builtin(.night)) + + self.largeEmoji = try container.decodeIfPresent(Bool.self, forKey: "largeEmoji") ?? true + self.reduceMotion = try container.decodeIfPresent(Bool.self, forKey: "reduceMotion") ?? false + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: StringCodingKey.self) + + try container.encode(PostboxEncoder().encodeObjectToRawData(self.theme), forKey: "t") + + var mappedThemeSpecificAccentColors: [DictionaryKey: AdaptedPostboxEncoder.RawObjectData] = [:] + for (key, value) in self.themeSpecificAccentColors { + mappedThemeSpecificAccentColors[DictionaryKey(key)] = PostboxEncoder().encodeObjectToRawData(value) + } + try container.encode(mappedThemeSpecificAccentColors, forKey: "themeSpecificAccentColors") + + var mappedThemeSpecificChatWallpapers: [DictionaryKey: AdaptedPostboxEncoder.RawObjectData] = [:] + for (key, value) in self.themeSpecificChatWallpapers { + mappedThemeSpecificChatWallpapers[DictionaryKey(key)] = PostboxEncoder().encodeObjectToRawData(value) + } + try container.encode(mappedThemeSpecificChatWallpapers, forKey: "themeSpecificChatWallpapers") + + try container.encode((self.useSystemFont ? 1 : 0) as Int32, forKey: "useSystemFont") + try container.encode(self.fontSize.rawValue, forKey: "f") + try container.encode(self.listsFontSize.rawValue, forKey: "lf") + try container.encode(self.chatBubbleSettings, forKey: "chatBubbleSettings") + try container.encode(self.automaticThemeSwitchSetting, forKey: "automaticThemeSwitchSetting") + try container.encode(self.largeEmoji, forKey: "largeEmoji") + try container.encode(self.reduceMotion, forKey: "reduceMotion") } public static func ==(lhs: PresentationThemeSettings, rhs: PresentationThemeSettings) -> Bool { @@ -697,12 +749,12 @@ public func updatePresentationThemeSettingsInteractively(accountManager: Account return accountManager.transaction { transaction -> Void in transaction.updateSharedData(ApplicationSpecificSharedDataKeys.presentationThemeSettings, { entry in let currentSettings: PresentationThemeSettings - if let entry = entry as? PresentationThemeSettings { + if let entry = entry?.get(PresentationThemeSettings.self) { currentSettings = entry } else { currentSettings = PresentationThemeSettings.defaultSettings } - return f(currentSettings) + return PreferencesEntry(f(currentSettings)) }) } } diff --git a/submodules/TelegramUIPreferences/Sources/RenderedTotalUnreadCount.swift b/submodules/TelegramUIPreferences/Sources/RenderedTotalUnreadCount.swift index dff99b50bf..ea3a4a9b9a 100644 --- a/submodules/TelegramUIPreferences/Sources/RenderedTotalUnreadCount.swift +++ b/submodules/TelegramUIPreferences/Sources/RenderedTotalUnreadCount.swift @@ -34,7 +34,7 @@ public func renderedTotalUnreadCount(accountManager: AccountManager Bool { - if let to = to as? StickerSettings { - return self == to - } else { - return false - } + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: StringCodingKey.self) + + try container.encode(self.emojiStickerSuggestionMode.rawValue, forKey: "emojiStickerSuggestionMode") + try container.encode(self.loopAnimatedStickers, forKey: "loopAnimatedStickers") } public static func ==(lhs: StickerSettings, rhs: StickerSettings) -> Bool { @@ -57,12 +53,12 @@ public func updateStickerSettingsInteractively(accountManager: AccountManager Void in transaction.updateSharedData(ApplicationSpecificSharedDataKeys.stickerSettings, { entry in let currentSettings: StickerSettings - if let entry = entry as? StickerSettings { + if let entry = entry?.get(StickerSettings.self) { currentSettings = entry } else { currentSettings = StickerSettings.defaultSettings } - return f(currentSettings) + return PreferencesEntry(f(currentSettings)) }) } } diff --git a/submodules/TelegramUIPreferences/Sources/VoiceCallSettings.swift b/submodules/TelegramUIPreferences/Sources/VoiceCallSettings.swift index 3dc6a49852..fa6d5954a7 100644 --- a/submodules/TelegramUIPreferences/Sources/VoiceCallSettings.swift +++ b/submodules/TelegramUIPreferences/Sources/VoiceCallSettings.swift @@ -29,7 +29,7 @@ public enum VoiceCallDataSaving: Int32 { case `default` } -public struct VoiceCallSettings: PreferencesEntry, Equatable { +public struct VoiceCallSettings: Codable, Equatable { public var dataSaving: VoiceCallDataSaving public var enableSystemIntegration: Bool @@ -42,22 +42,18 @@ public struct VoiceCallSettings: PreferencesEntry, Equatable { self.enableSystemIntegration = enableSystemIntegration } - public init(decoder: PostboxDecoder) { - self.dataSaving = VoiceCallDataSaving(rawValue: decoder.decodeInt32ForKey("ds", orElse: 0))! - self.enableSystemIntegration = decoder.decodeInt32ForKey("enableSystemIntegration", orElse: 1) != 0 + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: StringCodingKey.self) + + self.dataSaving = VoiceCallDataSaving(rawValue: try container.decode(Int32.self, forKey: "ds")) ?? .default + self.enableSystemIntegration = (try container.decode(Int32.self, forKey: "enableSystemIntegration")) != 0 } - public func encode(_ encoder: PostboxEncoder) { - encoder.encodeInt32(self.dataSaving.rawValue, forKey: "ds") - encoder.encodeInt32(self.enableSystemIntegration ? 1 : 0, forKey: "enableSystemIntegration") - } - - public func isEqual(to: PreferencesEntry) -> Bool { - if let to = to as? VoiceCallSettings { - return self == to - } else { - return false - } + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: StringCodingKey.self) + + try container.encode(self.dataSaving.rawValue, forKey: "ds") + try container.encode((self.enableSystemIntegration ? 1 : 0) as Int32, forKey: "enableSystemIntegration") } public static func ==(lhs: VoiceCallSettings, rhs: VoiceCallSettings) -> Bool { @@ -75,12 +71,12 @@ public func updateVoiceCallSettingsSettingsInteractively(accountManager: Account return accountManager.transaction { transaction -> Void in transaction.updateSharedData(ApplicationSpecificSharedDataKeys.voiceCallSettings, { entry in let currentSettings: VoiceCallSettings - if let entry = entry as? VoiceCallSettings { + if let entry = entry?.get(VoiceCallSettings.self) { currentSettings = entry } else { currentSettings = VoiceCallSettings.defaultSettings } - return f(currentSettings) + return PreferencesEntry(f(currentSettings)) }) } } diff --git a/submodules/TelegramUIPreferences/Sources/VoipDerivedState.swift b/submodules/TelegramUIPreferences/Sources/VoipDerivedState.swift index eb11fd9455..cf75372566 100644 --- a/submodules/TelegramUIPreferences/Sources/VoipDerivedState.swift +++ b/submodules/TelegramUIPreferences/Sources/VoipDerivedState.swift @@ -1,8 +1,9 @@ import Foundation import Postbox +import TelegramCore import SwiftSignalKit -public struct VoipDerivedState: Equatable, PreferencesEntry { +public struct VoipDerivedState: Codable, Equatable { public var data: Data public static var `default`: VoipDerivedState { @@ -13,20 +14,16 @@ public struct VoipDerivedState: Equatable, PreferencesEntry { self.data = data } - public init(decoder: PostboxDecoder) { - self.data = decoder.decodeDataForKey("data") ?? Data() + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: StringCodingKey.self) + + self.data = try container.decode(Data.self, forKey: "data") } - public func encode(_ encoder: PostboxEncoder) { - encoder.encodeData(self.data, forKey: "data") - } - - public func isEqual(to: PreferencesEntry) -> Bool { - if let to = to as? VoipDerivedState { - return self == to - } else { - return false - } + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: StringCodingKey.self) + + try container.encode(self.data, forKey: "data") } } @@ -34,12 +31,12 @@ public func updateVoipDerivedStateInteractively(postbox: Postbox, _ f: @escaping return postbox.transaction { transaction -> Void in transaction.updatePreferencesEntry(key: ApplicationSpecificPreferencesKeys.voipDerivedState, { entry in let currentSettings: VoipDerivedState - if let entry = entry as? VoipDerivedState { + if let entry = entry?.get(VoipDerivedState.self) { currentSettings = entry } else { currentSettings = .default } - return f(currentSettings) + return PreferencesEntry(f(currentSettings)) }) } } diff --git a/submodules/TelegramUIPreferences/Sources/WatchPresetSettings.swift b/submodules/TelegramUIPreferences/Sources/WatchPresetSettings.swift index c73fa77c0e..99ff7f799e 100644 --- a/submodules/TelegramUIPreferences/Sources/WatchPresetSettings.swift +++ b/submodules/TelegramUIPreferences/Sources/WatchPresetSettings.swift @@ -3,7 +3,7 @@ import Postbox import TelegramCore import SwiftSignalKit -public struct WatchPresetSettings: PreferencesEntry, Equatable { +public struct WatchPresetSettings: Codable, Equatable { public var customPresets: [String : String] public static var defaultSettings: WatchPresetSettings { @@ -14,9 +14,11 @@ public struct WatchPresetSettings: PreferencesEntry, Equatable { self.customPresets = presets } - public init(decoder: PostboxDecoder) { - let keys = decoder.decodeStringArrayForKey("presetKeys") - let values = decoder.decodeStringArrayForKey("presetValues") + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: StringCodingKey.self) + + let keys = try container.decode([String].self, forKey: "presetKeys") + let values = try container.decode([String].self, forKey: "presetValues") if keys.count == values.count { var presets: [String : String] = [:] for i in 0 ..< keys.count { @@ -28,7 +30,9 @@ public struct WatchPresetSettings: PreferencesEntry, Equatable { } } - public func encode(_ encoder: PostboxEncoder) { + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: StringCodingKey.self) + let keys = self.customPresets.keys.sorted() let values = keys.reduce([String]()) { (values, index) in var values = values @@ -37,16 +41,8 @@ public struct WatchPresetSettings: PreferencesEntry, Equatable { } return values } - encoder.encodeStringArray(keys, forKey: "presetKeys") - encoder.encodeStringArray(values, forKey: "presetValues") - } - - public func isEqual(to: PreferencesEntry) -> Bool { - if let to = to as? WatchPresetSettings { - return self == to - } else { - return false - } + try container.encode(keys, forKey: "presetKeys") + try container.encode(values, forKey: "presetValues") } public static func ==(lhs: WatchPresetSettings, rhs: WatchPresetSettings) -> Bool { @@ -58,12 +54,12 @@ public func updateWatchPresetSettingsInteractively(accountManager: AccountManage return accountManager.transaction { transaction -> Void in transaction.updateSharedData(ApplicationSpecificSharedDataKeys.watchPresetSettings, { entry in let currentSettings: WatchPresetSettings - if let entry = entry as? WatchPresetSettings { + if let entry = entry?.get(WatchPresetSettings.self) { currentSettings = entry } else { currentSettings = WatchPresetSettings.defaultSettings } - return f(currentSettings) + return PreferencesEntry(f(currentSettings)) }) } } diff --git a/submodules/TelegramUIPreferences/Sources/WebBrowserSettings.swift b/submodules/TelegramUIPreferences/Sources/WebBrowserSettings.swift index d2b0082fef..0739d93e81 100644 --- a/submodules/TelegramUIPreferences/Sources/WebBrowserSettings.swift +++ b/submodules/TelegramUIPreferences/Sources/WebBrowserSettings.swift @@ -3,7 +3,7 @@ import Postbox import TelegramCore import SwiftSignalKit -public struct WebBrowserSettings: PreferencesEntry, Equatable { +public struct WebBrowserSettings: Codable, Equatable { public let defaultWebBrowser: String? public static var defaultSettings: WebBrowserSettings { @@ -14,24 +14,16 @@ public struct WebBrowserSettings: PreferencesEntry, Equatable { self.defaultWebBrowser = defaultWebBrowser } - public init(decoder: PostboxDecoder) { - self.defaultWebBrowser = decoder.decodeOptionalStringForKey("defaultWebBrowser") + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: StringCodingKey.self) + + self.defaultWebBrowser = try? container.decodeIfPresent(String.self, forKey: "defaultWebBrowser") } - public func encode(_ encoder: PostboxEncoder) { - if let defaultWebBrowser = self.defaultWebBrowser { - encoder.encodeString(defaultWebBrowser, forKey: "defaultWebBrowser") - } else { - encoder.encodeNil(forKey: "defaultWebBrowser") - } - } - - public func isEqual(to: PreferencesEntry) -> Bool { - if let to = to as? WebBrowserSettings { - return self == to - } else { - return false - } + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: StringCodingKey.self) + + try container.encodeIfPresent(self.defaultWebBrowser, forKey: "defaultWebBrowser") } public static func ==(lhs: WebBrowserSettings, rhs: WebBrowserSettings) -> Bool { @@ -47,12 +39,12 @@ public func updateWebBrowserSettingsInteractively(accountManager: AccountManager return accountManager.transaction { transaction -> Void in transaction.updateSharedData(ApplicationSpecificSharedDataKeys.webBrowserSettings, { entry in let currentSettings: WebBrowserSettings - if let entry = entry as? WebBrowserSettings { + if let entry = entry?.get(WebBrowserSettings.self) { currentSettings = entry } else { currentSettings = WebBrowserSettings.defaultSettings } - return f(currentSettings) + return PreferencesEntry(f(currentSettings)) }) } } diff --git a/submodules/TelegramUIPreferences/Sources/WebSearchSettings.swift b/submodules/TelegramUIPreferences/Sources/WebSearchSettings.swift index 99c3c2b35e..09debb4d1c 100644 --- a/submodules/TelegramUIPreferences/Sources/WebSearchSettings.swift +++ b/submodules/TelegramUIPreferences/Sources/WebSearchSettings.swift @@ -8,7 +8,7 @@ public enum WebSearchScope: Int32 { case gifs } -public struct WebSearchSettings: Equatable, PreferencesEntry { +public struct WebSearchSettings: Codable, Equatable { public var scope: WebSearchScope public static var defaultSettings: WebSearchSettings { @@ -19,20 +19,16 @@ public struct WebSearchSettings: Equatable, PreferencesEntry { self.scope = scope } - public init(decoder: PostboxDecoder) { - self.scope = WebSearchScope(rawValue: decoder.decodeInt32ForKey("scope", orElse: 0)) ?? .images + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: StringCodingKey.self) + + self.scope = WebSearchScope(rawValue: try container.decode(Int32.self, forKey: "scope")) ?? .images } - public func encode(_ encoder: PostboxEncoder) { - encoder.encodeInt32(self.scope.rawValue, forKey: "scope") - } - - public func isEqual(to: PreferencesEntry) -> Bool { - if let to = to as? WebSearchSettings { - return self == to - } else { - return false - } + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: StringCodingKey.self) + + try container.encode(self.scope.rawValue, forKey: "scope") } } @@ -40,12 +36,12 @@ public func updateWebSearchSettingsInteractively(accountManager: AccountManager< return accountManager.transaction { transaction -> Void in transaction.updateSharedData(ApplicationSpecificSharedDataKeys.webSearchSettings, { entry in let currentSettings: WebSearchSettings - if let entry = entry as? WebSearchSettings { + if let entry = entry?.get(WebSearchSettings.self) { currentSettings = entry } else { currentSettings = .defaultSettings } - return f(currentSettings) + return PreferencesEntry(f(currentSettings)) }) } } diff --git a/submodules/TelegramUIPreferences/Sources/WidgetSettings.swift b/submodules/TelegramUIPreferences/Sources/WidgetSettings.swift index c2965f2c42..f54174921d 100644 --- a/submodules/TelegramUIPreferences/Sources/WidgetSettings.swift +++ b/submodules/TelegramUIPreferences/Sources/WidgetSettings.swift @@ -1,9 +1,9 @@ - import Foundation import Postbox +import TelegramCore import SwiftSignalKit -public struct WidgetSettings: PreferencesEntry, Equatable { +public struct WidgetSettings: Codable, Equatable { public var useHints: Bool public var peers: [PeerId] @@ -22,22 +22,18 @@ public struct WidgetSettings: PreferencesEntry, Equatable { self.peers = peers } - public init(decoder: PostboxDecoder) { - self.useHints = decoder.decodeBoolForKey("useHints", orElse: true) - self.peers = decoder.decodeInt64ArrayForKey("peers").map { PeerId($0) } + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: StringCodingKey.self) + + self.useHints = try container.decode(Bool.self, forKey: "useHints") + self.peers = (try container.decode([Int64].self, forKey: "peers")).map { PeerId($0) } } - public func encode(_ encoder: PostboxEncoder) { - encoder.encodeBool(self.useHints, forKey: "useHints") - encoder.encodeInt64Array(self.peers.map { $0.toInt64() }, forKey: "peers") - } - - public func isEqual(to: PreferencesEntry) -> Bool { - if let to = to as? WidgetSettings { - return self == to - } else { - return false - } + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: StringCodingKey.self) + + try container.encode(self.useHints, forKey: "useHints") + try container.encode(self.peers.map { $0.toInt64() } as [Int64], forKey: "peers") } } @@ -51,11 +47,11 @@ public func updateWidgetSettingsInteractively(postbox: Postbox, _ f: @escaping ( public func updateWidgetSettingsInteractively(transaction: Transaction, _ f: @escaping (WidgetSettings) -> WidgetSettings) { transaction.updatePreferencesEntry(key: ApplicationSpecificPreferencesKeys.widgetSettings, { entry in let currentSettings: WidgetSettings - if let entry = entry as? WidgetSettings { + if let entry = entry?.get(WidgetSettings.self) { currentSettings = entry } else { currentSettings = .default } - return f(currentSettings) + return PreferencesEntry(f(currentSettings)) }) } diff --git a/submodules/UIKitRuntimeUtils/Source/UIKitRuntimeUtils/UIViewController+Navigation.h b/submodules/UIKitRuntimeUtils/Source/UIKitRuntimeUtils/UIViewController+Navigation.h index e34181f313..c592dfc1b2 100644 --- a/submodules/UIKitRuntimeUtils/Source/UIKitRuntimeUtils/UIViewController+Navigation.h +++ b/submodules/UIKitRuntimeUtils/Source/UIKitRuntimeUtils/UIViewController+Navigation.h @@ -18,6 +18,13 @@ typedef NS_OPTIONS(NSUInteger, UIResponderDisableAutomaticKeyboardHandling) { @end +@interface UIApplication (Additions) + +- (void)internalSetStatusBarStyle:(UIStatusBarStyle)style animated:(BOOL)animated; +- (void)internalSetStatusBarHidden:(BOOL)hidden animation:(UIStatusBarAnimation)animation; + +@end + @interface UIView (Navigation) @property (nonatomic) bool disablesInteractiveTransitionGestureRecognizer; diff --git a/submodules/UIKitRuntimeUtils/Source/UIKitRuntimeUtils/UIViewController+Navigation.m b/submodules/UIKitRuntimeUtils/Source/UIKitRuntimeUtils/UIViewController+Navigation.m index a59590d627..d5a8a31551 100644 --- a/submodules/UIKitRuntimeUtils/Source/UIKitRuntimeUtils/UIViewController+Navigation.m +++ b/submodules/UIKitRuntimeUtils/Source/UIKitRuntimeUtils/UIViewController+Navigation.m @@ -238,6 +238,24 @@ static bool notyfyingShiftState = false; @end +@implementation UIApplication (Additions) + +- (void)internalSetStatusBarStyle:(UIStatusBarStyle)style animated:(BOOL)animated { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + [self setStatusBarStyle:style animated:animated]; +#pragma clang diagnostic pop +} + +- (void)internalSetStatusBarHidden:(BOOL)hidden animation:(UIStatusBarAnimation)animation { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + [self setStatusBarHidden:hidden withAnimation:animation]; +#pragma clang diagnostic pop +} + +@end + @implementation UIView (Navigation) - (bool)disablesInteractiveTransitionGestureRecognizer { diff --git a/submodules/UrlHandling/Sources/UrlHandling.swift b/submodules/UrlHandling/Sources/UrlHandling.swift index bed77ec35c..17d07d9177 100644 --- a/submodules/UrlHandling/Sources/UrlHandling.swift +++ b/submodules/UrlHandling/Sources/UrlHandling.swift @@ -564,7 +564,7 @@ public func resolveUrlImpl(context: AccountContext, peerId: PeerId?, url: String return ApplicationSpecificNotice.getSecretChatLinkPreviews(accountManager: context.sharedContext.accountManager) |> mapToSignal { linkPreviews -> Signal in return context.account.postbox.transaction { transaction -> Signal in - let appConfiguration: AppConfiguration = transaction.getPreferencesEntry(key: PreferencesKeys.appConfiguration) as? AppConfiguration ?? AppConfiguration.defaultValue + let appConfiguration: AppConfiguration = transaction.getPreferencesEntry(key: PreferencesKeys.appConfiguration)?.get(AppConfiguration.self) ?? AppConfiguration.defaultValue let urlHandlingConfiguration = UrlHandlingConfiguration.with(appConfiguration: appConfiguration) var skipUrlAuth = skipUrlAuth diff --git a/submodules/WatchBridge/Sources/WatchCommunicationManager.swift b/submodules/WatchBridge/Sources/WatchCommunicationManager.swift index fdc6f30dfa..4672c1a99b 100644 --- a/submodules/WatchBridge/Sources/WatchCommunicationManager.swift +++ b/submodules/WatchBridge/Sources/WatchCommunicationManager.swift @@ -96,7 +96,7 @@ public final class WatchCommunicationManager { strongSelf.presets.set(context.context.sharedContext.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.watchPresetSettings]) |> map({ sharedData -> WatchPresetSettings in - return (sharedData.entries[ApplicationSpecificSharedDataKeys.watchPresetSettings] as? WatchPresetSettings) ?? WatchPresetSettings.defaultSettings + return sharedData.entries[ApplicationSpecificSharedDataKeys.watchPresetSettings]?.get(WatchPresetSettings.self) ?? WatchPresetSettings.defaultSettings })) } else { strongSelf.accountContext.set(.single(nil)) diff --git a/submodules/WebSearchUI/Sources/WebSearchController.swift b/submodules/WebSearchUI/Sources/WebSearchController.swift index 7652ef49a9..819cd31677 100644 --- a/submodules/WebSearchUI/Sources/WebSearchController.swift +++ b/submodules/WebSearchUI/Sources/WebSearchController.swift @@ -182,7 +182,7 @@ public final class WebSearchController: ViewController { let settings = self.context.sharedContext.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.webSearchSettings]) |> map { sharedData -> WebSearchSettings in - if let current = sharedData.entries[ApplicationSpecificSharedDataKeys.webSearchSettings] as? WebSearchSettings { + if let current = sharedData.entries[ApplicationSpecificSharedDataKeys.webSearchSettings]?.get(WebSearchSettings.self) { return current } else { return WebSearchSettings.defaultSettings @@ -191,7 +191,7 @@ public final class WebSearchController: ViewController { let gifProvider = self.context.account.postbox.preferencesView(keys: [PreferencesKeys.appConfiguration]) |> map { view -> String? in - guard let appConfiguration = view.values[PreferencesKeys.appConfiguration] as? AppConfiguration else { + guard let appConfiguration = view.values[PreferencesKeys.appConfiguration]?.get(AppConfiguration.self) else { return nil } let configuration = WebSearchConfiguration(appConfiguration: appConfiguration) diff --git a/submodules/WidgetSetupScreen/Sources/WidgetSetupScreen.swift b/submodules/WidgetSetupScreen/Sources/WidgetSetupScreen.swift index c358864c6a..ebe97ba61b 100644 --- a/submodules/WidgetSetupScreen/Sources/WidgetSetupScreen.swift +++ b/submodules/WidgetSetupScreen/Sources/WidgetSetupScreen.swift @@ -293,7 +293,7 @@ public func widgetSetupScreen(context: AccountContext) -> ViewController { ]) |> mapToSignal { views -> Signal in let widgetSettings: WidgetSettings - if let view = views.views[preferencesKey] as? PreferencesView, let value = view.values[ApplicationSpecificPreferencesKeys.widgetSettings] as? WidgetSettings { + if let view = views.views[preferencesKey] as? PreferencesView, let value = view.values[ApplicationSpecificPreferencesKeys.widgetSettings]?.get(WidgetSettings.self) { widgetSettings = value } else { widgetSettings = .default From 40736ca677353b6233fca87897d1a8f3eb28d97f Mon Sep 17 00:00:00 2001 From: Ali <> Date: Tue, 7 Sep 2021 15:09:12 +0400 Subject: [PATCH 03/30] Coding fixes --- Telegram/BUILD | 1 + Telegram/NotificationService/BUILD | 2 ++ .../NotificationService/Sources/NotificationService.swift | 5 ++--- submodules/Postbox/Sources/Coding.swift | 2 ++ .../Sources/Utils/Decoder/AdaptedPostboxDecoder.swift | 4 ++++ .../Sources/Utils/Encoder/AdaptedPostboxEncoder.swift | 4 ++++ 6 files changed, 15 insertions(+), 3 deletions(-) diff --git a/Telegram/BUILD b/Telegram/BUILD index 1e41387b9b..803f6deadc 100644 --- a/Telegram/BUILD +++ b/Telegram/BUILD @@ -1623,6 +1623,7 @@ ios_extension( ":MtProtoKitFramework", ":SwiftSignalKitFramework", ":PostboxFramework", + ":TelegramCoreFramework", ], ) diff --git a/Telegram/NotificationService/BUILD b/Telegram/NotificationService/BUILD index 4c124fb09d..25a2d700ca 100644 --- a/Telegram/NotificationService/BUILD +++ b/Telegram/NotificationService/BUILD @@ -7,6 +7,8 @@ swift_library( "Sources/*.swift", ]), deps = [ + "//submodules/Postbox:Postbox", + "//submodules/TelegramCore:TelegramCore", "//submodules/BuildConfig:BuildConfig", "//submodules/MtProtoKit:MtProtoKit", "//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit", diff --git a/Telegram/NotificationService/Sources/NotificationService.swift b/Telegram/NotificationService/Sources/NotificationService.swift index a00e09cf1b..c6311cfccb 100644 --- a/Telegram/NotificationService/Sources/NotificationService.swift +++ b/Telegram/NotificationService/Sources/NotificationService.swift @@ -2,6 +2,8 @@ import Foundation import UserNotifications import SwiftSignalKit import NotificationServiceObjC +import Postbox +import TelegramCore private let queue = Queue() @@ -18,9 +20,6 @@ final class NotificationService: UNNotificationServiceExtension { f() } }, countIncomingMessage: { rootPath, accountId, encryptionParameters, peerId, messageId in - /*SyncProviderImpl.addIncomingMessage(queue: queue, withRootPath: rootPath, accountId: accountId, encryptionParameters: encryptionParameters, peerId: peerId, messageId: messageId, completion: { count in - completion?(count) - })*/ completion?(0) }, isLocked: { rootPath in return SyncProviderImpl.isLocked(withRootPath: rootPath) diff --git a/submodules/Postbox/Sources/Coding.swift b/submodules/Postbox/Sources/Coding.swift index 8e1c769ddf..0aaa7d87bc 100644 --- a/submodules/Postbox/Sources/Coding.swift +++ b/submodules/Postbox/Sources/Coding.swift @@ -779,6 +779,8 @@ public final class PostboxDecoder { offset += 1 if keyLength != Int(readKeyLength) { + /*let keyString = String(data: Data(bytes: bytes + (offset - Int(readKeyLength) - 1), count: Int(readKeyLength)), encoding: .utf8) + print("\(String(describing: keyString))")*/ skipValue(bytes, offset: &offset, length: length, valueType: ValueType(rawValue: readValueType)!) continue } diff --git a/submodules/Postbox/Sources/Utils/Decoder/AdaptedPostboxDecoder.swift b/submodules/Postbox/Sources/Utils/Decoder/AdaptedPostboxDecoder.swift index 4f25acfd9c..3552f98c79 100644 --- a/submodules/Postbox/Sources/Utils/Decoder/AdaptedPostboxDecoder.swift +++ b/submodules/Postbox/Sources/Utils/Decoder/AdaptedPostboxDecoder.swift @@ -19,6 +19,10 @@ final public class AdaptedPostboxDecoder { self.data = data self.typeHash = typeHash } + + public init(from decoder: Decoder) throws { + preconditionFailure() + } } public init() { diff --git a/submodules/Postbox/Sources/Utils/Encoder/AdaptedPostboxEncoder.swift b/submodules/Postbox/Sources/Utils/Encoder/AdaptedPostboxEncoder.swift index 3851657b9e..2e0854f5d0 100644 --- a/submodules/Postbox/Sources/Utils/Encoder/AdaptedPostboxEncoder.swift +++ b/submodules/Postbox/Sources/Utils/Encoder/AdaptedPostboxEncoder.swift @@ -10,6 +10,10 @@ public class AdaptedPostboxEncoder { self.typeHash = typeHash self.data = data } + + public func encode(to encoder: Encoder) throws { + preconditionFailure() + } } public init() { From e6308196fe4c826f907f074e127443b645dc25d8 Mon Sep 17 00:00:00 2001 From: Ali <> Date: Tue, 7 Sep 2021 15:22:50 +0400 Subject: [PATCH 04/30] Coding fixes --- submodules/Postbox/Sources/Coding.swift | 14 ++++++++++++++ .../AdaptedPostboxKeyedEncodingContainer.swift | 7 +------ .../Sources/TelegramEngine/Themes/ChatThemes.swift | 2 +- 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/submodules/Postbox/Sources/Coding.swift b/submodules/Postbox/Sources/Coding.swift index 0aaa7d87bc..9128c80edd 100644 --- a/submodules/Postbox/Sources/Coding.swift +++ b/submodules/Postbox/Sources/Coding.swift @@ -671,6 +671,20 @@ public final class PostboxEncoder { self.buffer.write(value) } + func encodeInnerObjectDataWithHeader(typeHash: Int32, data: Data, valueType: ValueType, forKey key: String) { + self.encodeKey(key) + + var t: Int8 = valueType.rawValue + self.buffer.write(&t, offset: 0, length: 1) + + var typeHash = typeHash + self.buffer.write(&typeHash, offset: 0, length: 4) + + var length: Int32 = Int32(data.count) + self.buffer.write(&length, offset: 0, length: 4) + self.buffer.write(data) + } + public let sharedWriteBuffer = WriteBuffer() } diff --git a/submodules/Postbox/Sources/Utils/Encoder/AdaptedPostboxKeyedEncodingContainer.swift b/submodules/Postbox/Sources/Utils/Encoder/AdaptedPostboxKeyedEncodingContainer.swift index cd152c85e1..8ca346d42a 100644 --- a/submodules/Postbox/Sources/Utils/Encoder/AdaptedPostboxKeyedEncodingContainer.swift +++ b/submodules/Postbox/Sources/Utils/Encoder/AdaptedPostboxKeyedEncodingContainer.swift @@ -44,12 +44,7 @@ extension _AdaptedPostboxEncoder.KeyedContainer: KeyedEncodingContainerProtocol if let value = value as? Data { self.encoder.encodeData(value, forKey: key.stringValue) } else if let value = value as? AdaptedPostboxEncoder.RawObjectData { - let typeHash: Int32 = value.typeHash - let innerEncoder = _AdaptedPostboxEncoder(typeHash: typeHash) - try! value.encode(to: innerEncoder) - - let (data, valueType) = innerEncoder.makeData(addHeader: true, isDictionary: false) - self.encoder.encodeInnerObjectData(data, valueType: valueType, forKey: key.stringValue) + self.encoder.encodeInnerObjectDataWithHeader(typeHash: value.typeHash, data: value.data, valueType: .Object, forKey: key.stringValue) } else { let typeHash: Int32 = murMurHashString32("\(type(of: value))") let innerEncoder = _AdaptedPostboxEncoder(typeHash: typeHash) diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Themes/ChatThemes.swift b/submodules/TelegramCore/Sources/TelegramEngine/Themes/ChatThemes.swift index 713f294bb2..97f7bb021d 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Themes/ChatThemes.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Themes/ChatThemes.swift @@ -69,7 +69,7 @@ public final class ChatThemes: Codable, Equatable { func _internal_getChatThemes(accountManager: AccountManager, network: Network, forceUpdate: Bool = false, onlyCached: Bool = false) -> Signal<[ChatTheme], NoError> { let fetch: ([ChatTheme]?, Int32?) -> Signal<[ChatTheme], NoError> = { current, hash in - return network.request(Api.functions.account.getChatThemes(hash: hash ?? 0)) + return network.request(Api.functions.account.getChatThemes(hash: 0)) |> retryRequest |> mapToSignal { result -> Signal<[ChatTheme], NoError> in switch result { From 4412a8afc800b31047b6fad213fb6d0c706c7bf5 Mon Sep 17 00:00:00 2001 From: Ali <> Date: Mon, 13 Sep 2021 16:41:48 +0400 Subject: [PATCH 05/30] Fix synthetic user id hashes --- submodules/TelegramUI/Sources/ChatMessageBubbleItemNode.swift | 4 ++-- submodules/TelegramUI/Sources/ChatMessageItem.swift | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/submodules/TelegramUI/Sources/ChatMessageBubbleItemNode.swift b/submodules/TelegramUI/Sources/ChatMessageBubbleItemNode.swift index 7355ccd1f0..2a548b593f 100644 --- a/submodules/TelegramUI/Sources/ChatMessageBubbleItemNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageBubbleItemNode.swift @@ -1167,7 +1167,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode ignoreForward = true effectiveAuthor = forwardInfo.author if effectiveAuthor == nil, let authorSignature = forwardInfo.authorSignature { - effectiveAuthor = TelegramUser(id: PeerId(namespace: Namespaces.Peer.Empty, id: PeerId.Id._internalFromInt64Value(Int64(authorSignature.persistentHashValue))), accessHash: nil, firstName: authorSignature, lastName: nil, username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: UserInfoFlags()) + effectiveAuthor = TelegramUser(id: PeerId(namespace: Namespaces.Peer.Empty, id: PeerId.Id._internalFromInt64Value(Int64(authorSignature.persistentHashValue % 32))), accessHash: nil, firstName: authorSignature, lastName: nil, username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: UserInfoFlags()) } } displayAuthorInfo = !mergedTop.merged && incoming && effectiveAuthor != nil @@ -1183,7 +1183,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode displayAuthorInfo = !mergedTop.merged && incoming } else if let forwardInfo = item.content.firstMessage.forwardInfo, forwardInfo.flags.contains(.isImported), let authorSignature = forwardInfo.authorSignature { ignoreForward = true - effectiveAuthor = TelegramUser(id: PeerId(namespace: Namespaces.Peer.Empty, id: PeerId.Id._internalFromInt64Value(Int64(authorSignature.persistentHashValue))), accessHash: nil, firstName: authorSignature, lastName: nil, username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: UserInfoFlags()) + effectiveAuthor = TelegramUser(id: PeerId(namespace: Namespaces.Peer.Empty, id: PeerId.Id._internalFromInt64Value(Int64(authorSignature.persistentHashValue % 32))), accessHash: nil, firstName: authorSignature, lastName: nil, username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: UserInfoFlags()) displayAuthorInfo = !mergedTop.merged && incoming } else if let _ = item.content.firstMessage.adAttribute, let author = item.content.firstMessage.author { ignoreForward = true diff --git a/submodules/TelegramUI/Sources/ChatMessageItem.swift b/submodules/TelegramUI/Sources/ChatMessageItem.swift index 2fd6411bc5..9d392bbacc 100644 --- a/submodules/TelegramUI/Sources/ChatMessageItem.swift +++ b/submodules/TelegramUI/Sources/ChatMessageItem.swift @@ -305,7 +305,7 @@ public final class ChatMessageItem: ListViewItem, CustomStringConvertible { if let forwardInfo = content.firstMessage.forwardInfo { effectiveAuthor = forwardInfo.author if effectiveAuthor == nil, let authorSignature = forwardInfo.authorSignature { - effectiveAuthor = TelegramUser(id: PeerId(namespace: Namespaces.Peer.Empty, id: PeerId.Id._internalFromInt64Value(Int64(authorSignature.persistentHashValue))), accessHash: nil, firstName: authorSignature, lastName: nil, username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: UserInfoFlags()) + effectiveAuthor = TelegramUser(id: PeerId(namespace: Namespaces.Peer.Empty, id: PeerId.Id._internalFromInt64Value(Int64(authorSignature.persistentHashValue % 32))), accessHash: nil, firstName: authorSignature, lastName: nil, username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: UserInfoFlags()) } } displayAuthorInfo = incoming && effectiveAuthor != nil From 0553a14eb3409343ca7a8d5ed1e443425352d79f Mon Sep 17 00:00:00 2001 From: Ali <> Date: Mon, 13 Sep 2021 20:40:09 +0400 Subject: [PATCH 06/30] Update notification service --- Telegram/NotificationService/BUILD | 3 +- .../ApplicationSpecificSharedDataKeys.swift | 17 -- .../Sources/InAppNotificationSettings.swift | 1 - .../Sources/Namespaces.swift | 55 ---- .../Sources/NotificationService.swift | 277 ++++++++++++++++-- .../NotificationService/Sources/Sync.swift | 148 ---------- .../Sources/TelegramChannel.swift | 39 --- Telegram/SiriIntents/IntentHandler.swift | 2 +- submodules/MtProtoKit/Sources/MTContext.m | 4 +- .../Postbox/Sources/AccountManager.swift | 18 +- .../Postbox/Sources/CachedPeerDataTable.swift | 7 +- .../Postbox/Sources/ChatListIndexTable.swift | 8 +- .../Postbox/Sources/ChatListTable.swift | 4 +- submodules/Postbox/Sources/ContactTable.swift | 8 +- .../Sources/GlobalMessageIdsTable.swift | 4 +- .../Sources/ItemCollectionItemTable.swift | 4 +- .../MessageHistoryHoleIndexTable.swift | 4 +- .../Sources/MessageHistoryIndexTable.swift | 4 +- .../MessageHistoryReadStateTable.swift | 8 +- .../Postbox/Sources/MessageHistoryTable.swift | 4 +- .../MessageHistoryTagsSummaryTable.swift | 8 +- .../Sources/MessageHistoryTagsTable.swift | 4 +- .../MessageHistoryThreadHoleIndexTable.swift | 4 +- .../Sources/MessageHistoryThreadsTable.swift | 4 +- .../Postbox/Sources/MetadataTable.swift | 4 +- .../Sources/OrderedItemListTable.swift | 4 +- .../PeerMergedOperationLogIndexTable.swift | 4 +- .../Postbox/Sources/PeerNameIndexTable.swift | 4 +- ...eerNotificationSettingsBehaviorTable.swift | 4 +- .../PeerNotificationSettingsTable.swift | 8 +- .../Sources/PeerOperationLogTable.swift | 4 +- submodules/Postbox/Sources/PeerTable.swift | 7 +- .../Sources/PendingMessageActionsTable.swift | 4 +- submodules/Postbox/Sources/Postbox.swift | 134 ++++----- .../Sources/PostboxUpgrade_21to22.swift | 2 +- .../Postbox/Sources/SqliteValueBox.swift | 11 +- submodules/Postbox/Sources/Table.swift | 4 +- ...TimestampBasedMessageAttributesTable.swift | 4 +- .../Utils/Decoder/AdaptedPostboxDecoder.swift | 7 + .../Sources/Account/Account.swift | 236 +++++++++------ .../Sources/Account/AccountManager.swift | 30 -- .../Sources/Network/Network.swift | 28 +- .../Sources/State/AccountStateManager.swift | 35 ++- ...yncCore_StandaloneAccountTransaction.swift | 4 +- .../TelegramUI/Sources/AppDelegate.swift | 6 +- .../Sources/NotificationContentContext.swift | 2 +- submodules/TelegramUI/Sources/OpenUrl.swift | 4 +- .../Sources/ShareExtensionContext.swift | 2 +- .../TelegramUI/Sources/UpgradedAccounts.swift | 201 +------------ .../UrlHandling/Sources/UrlHandling.swift | 4 +- 50 files changed, 600 insertions(+), 796 deletions(-) delete mode 100644 Telegram/NotificationService/Sources/ApplicationSpecificSharedDataKeys.swift delete mode 100644 Telegram/NotificationService/Sources/InAppNotificationSettings.swift delete mode 100644 Telegram/NotificationService/Sources/Namespaces.swift delete mode 100644 Telegram/NotificationService/Sources/Sync.swift delete mode 100644 Telegram/NotificationService/Sources/TelegramChannel.swift diff --git a/Telegram/NotificationService/BUILD b/Telegram/NotificationService/BUILD index 25a2d700ca..cd676b58bd 100644 --- a/Telegram/NotificationService/BUILD +++ b/Telegram/NotificationService/BUILD @@ -15,7 +15,8 @@ swift_library( "//submodules/EncryptionProvider:EncryptionProvider", "//submodules/AppLockState:AppLockState", "//submodules/NotificationsPresentationData:NotificationsPresentationData", - "//Telegram/NotificationService/NotificationServiceObjC:NotificationServiceObjC", + "//submodules/TelegramUIPreferences:TelegramUIPreferences", + "//submodules/OpenSSLEncryptionProvider:OpenSSLEncryptionProvider" ], visibility = [ "//visibility:public", diff --git a/Telegram/NotificationService/Sources/ApplicationSpecificSharedDataKeys.swift b/Telegram/NotificationService/Sources/ApplicationSpecificSharedDataKeys.swift deleted file mode 100644 index a8099363a0..0000000000 --- a/Telegram/NotificationService/Sources/ApplicationSpecificSharedDataKeys.swift +++ /dev/null @@ -1,17 +0,0 @@ -import Foundation -/*import ValueBox - -private func applicationSpecificSharedDataKey(_ value: Int32) -> ValueBoxKey { - let key = ValueBoxKey(length: 4) - key.setInt32(0, value: value + 1000) - return key -} - -private enum ApplicationSpecificSharedDataKeyValues: Int32 { - case inAppNotificationSettings = 0 -} - -public struct ApplicationSpecificSharedDataKeys { - public static let inAppNotificationSettings = applicationSpecificSharedDataKey(ApplicationSpecificSharedDataKeyValues.inAppNotificationSettings.rawValue) -} -*/ diff --git a/Telegram/NotificationService/Sources/InAppNotificationSettings.swift b/Telegram/NotificationService/Sources/InAppNotificationSettings.swift deleted file mode 100644 index fecc4ab449..0000000000 --- a/Telegram/NotificationService/Sources/InAppNotificationSettings.swift +++ /dev/null @@ -1 +0,0 @@ -import Foundation diff --git a/Telegram/NotificationService/Sources/Namespaces.swift b/Telegram/NotificationService/Sources/Namespaces.swift deleted file mode 100644 index a8fa068454..0000000000 --- a/Telegram/NotificationService/Sources/Namespaces.swift +++ /dev/null @@ -1,55 +0,0 @@ -/*import PostboxDataTypes - -struct LegacyPeerSummaryCounterTags: OptionSet, Sequence, Hashable { - var rawValue: Int32 - - init(rawValue: Int32) { - self.rawValue = rawValue - } - - static let regularChatsAndPrivateGroups = LegacyPeerSummaryCounterTags(rawValue: 1 << 0) - static let publicGroups = LegacyPeerSummaryCounterTags(rawValue: 1 << 1) - static let channels = LegacyPeerSummaryCounterTags(rawValue: 1 << 2) - - public func makeIterator() -> AnyIterator { - var index = 0 - return AnyIterator { () -> LegacyPeerSummaryCounterTags? in - while index < 31 { - let currentTags = self.rawValue >> UInt32(index) - let tag = LegacyPeerSummaryCounterTags(rawValue: 1 << UInt32(index)) - index += 1 - if currentTags == 0 { - break - } - - if (currentTags & 1) != 0 { - return tag - } - } - return nil - } - } -} - -extension PeerSummaryCounterTags { - static let privateChat = PeerSummaryCounterTags(rawValue: 1 << 3) - static let secretChat = PeerSummaryCounterTags(rawValue: 1 << 4) - static let privateGroup = PeerSummaryCounterTags(rawValue: 1 << 5) - static let bot = PeerSummaryCounterTags(rawValue: 1 << 6) - static let channel = PeerSummaryCounterTags(rawValue: 1 << 7) - static let publicGroup = PeerSummaryCounterTags(rawValue: 1 << 8) -} - -struct Namespaces { - struct Message { - static let Cloud: Int32 = 0 - } - - struct Peer { - static let CloudUser: Int32 = 0 - static let CloudGroup: Int32 = 1 - static let CloudChannel: Int32 = 2 - static let SecretChat: Int32 = 3 - } -} -*/ diff --git a/Telegram/NotificationService/Sources/NotificationService.swift b/Telegram/NotificationService/Sources/NotificationService.swift index c6311cfccb..0b919542ea 100644 --- a/Telegram/NotificationService/Sources/NotificationService.swift +++ b/Telegram/NotificationService/Sources/NotificationService.swift @@ -1,53 +1,270 @@ import Foundation import UserNotifications import SwiftSignalKit -import NotificationServiceObjC import Postbox import TelegramCore +import BuildConfig +import OpenSSLEncryptionProvider +import TelegramUIPreferences private let queue = Queue() +private var installedSharedLogger = false + +private func setupSharedLogger(rootPath: String, path: String) { + if !installedSharedLogger { + installedSharedLogger = true + Logger.setSharedLogger(Logger(rootPath: rootPath, basePath: path)) + } +} + +private let accountAuxiliaryMethods = AccountAuxiliaryMethods(fetchResource: { account, resource, ranges, _ in + return nil +}, fetchResourceMediaReferenceHash: { resource in + return .single(nil) +}, prepareSecretThumbnailData: { _ in + return nil +}) + +private func rootPathForBasePath(_ appGroupPath: String) -> String { + return appGroupPath + "/telegram-data" +} + +@available(iOSApplicationExtension 10.0, iOS 10.0, *) +private struct NotificationContent { + var title: String? + var subtitle: String? + var body: String? + var badge: Int? + + func asNotificationContent() -> UNNotificationContent { + let content = UNMutableNotificationContent() + + content.title = self.title ?? "" + content.subtitle = self.subtitle ?? "" + content.body = self.body ?? "" + + if let badge = self.badge { + content.badge = badge as NSNumber + } + + return content + } +} + +@available(iOSApplicationExtension 10.0, iOS 10.0, *) +private final class NotificationServiceHandler { + private let queue: Queue + private let accountManager: AccountManager + private let encryptionParameters: ValueBoxEncryptionParameters + private var stateManager: AccountStateManager? + + private let notificationKeyDisposable = MetaDisposable() + private let pollDisposable = MetaDisposable() + + init?(queue: Queue, updateCurrentContent: @escaping (UNNotificationContent) -> Void, completed: @escaping () -> Void, payload: [AnyHashable: Any]) { + self.queue = queue + + guard let appBundleIdentifier = Bundle.main.bundleIdentifier, let lastDotRange = appBundleIdentifier.range(of: ".", options: [.backwards]) else { + return nil + } + + let baseAppBundleId = String(appBundleIdentifier[..(basePath: rootPath + "/accounts-metadata", isTemporary: true, isReadOnly: false, useCaches: false) + + let deviceSpecificEncryptionParameters = BuildConfig.deviceSpecificEncryptionParameters(rootPath, baseAppBundleId: baseAppBundleId) + self.encryptionParameters = ValueBoxEncryptionParameters(forceEncryptionIfNoSet: false, key: ValueBoxEncryptionParameters.Key(data: deviceSpecificEncryptionParameters.key)!, salt: ValueBoxEncryptionParameters.Salt(data: deviceSpecificEncryptionParameters.salt)!) + + let networkArguments = NetworkInitializationArguments(apiId: apiId, apiHash: apiHash, languagesCategory: languagesCategory, appVersion: appVersion, voipMaxLayer: 0, voipVersions: [], appData: .single(buildConfig.bundleData(withAppToken: nil, signatureDict: nil)), autolockDeadine: .single(nil), encryptionProvider: OpenSSLEncryptionProvider()) + + guard var encryptedPayload = payload["p"] as? String else { + return nil + } + encryptedPayload = encryptedPayload.replacingOccurrences(of: "-", with: "+") + encryptedPayload = encryptedPayload.replacingOccurrences(of: "_", with: "/") + while encryptedPayload.count % 4 != 0 { + encryptedPayload.append("=") + } + guard let payloadData = Data(base64Encoded: encryptedPayload) else { + return nil + } + + let _ = (self.accountManager.currentAccountRecord(allocateIfNotExists: false) + |> take(1) + |> deliverOn(self.queue)).start(next: { [weak self] records in + guard let strongSelf = self, let record = records else { + return + } + + let _ = (standaloneStateManager( + accountManager: strongSelf.accountManager, + networkArguments: networkArguments, + id: record.0, + encryptionParameters: strongSelf.encryptionParameters, + rootPath: rootPath, + auxiliaryMethods: accountAuxiliaryMethods + ) + |> deliverOn(strongSelf.queue)).start(next: { stateManager in + guard let strongSelf = self else { + return + } + guard let stateManager = stateManager else { + completed() + return + } + strongSelf.stateManager = stateManager + + strongSelf.notificationKeyDisposable.set((existingMasterNotificationsKey(postbox: stateManager.postbox) + |> deliverOn(strongSelf.queue)).start(next: { notificationsKey in + guard let strongSelf = self else { + return + } + guard let notificationsKey = notificationsKey else { + completed() + return + } + guard let decryptedPayload = decryptedNotificationPayload(key: notificationsKey, data: payloadData) else { + completed() + return + } + guard let payloadJson = try? JSONSerialization.jsonObject(with: decryptedPayload, options: []) as? [String: Any] else { + completed() + return + } + guard let aps = payloadJson["aps"] as? [String: Any] else { + completed() + return + } + + var content: NotificationContent = NotificationContent() + if let alert = aps["alert"] as? [String: Any] { + content.title = alert["title"] as? String + content.subtitle = alert["subtitle"] as? String + content.body = alert["body"] as? String + } else if let alert = aps["alert"] as? String { + content.body = alert + } else { + completed() + return + } + + updateCurrentContent(content.asNotificationContent()) + + if let stateManager = strongSelf.stateManager { + stateManager.network.shouldKeepConnection.set(.single(true)) + strongSelf.pollDisposable.set(stateManager.pollStateUpdateCompletion().start(completed: { + queue.async { + guard let strongSelf = self, let stateManager = strongSelf.stateManager else { + completed() + return + } + + let _ = (renderedTotalUnreadCount( + accountManager: strongSelf.accountManager, + postbox: stateManager.postbox + ) + |> deliverOn(strongSelf.queue)).start(next: { value in + content.badge = Int(value.0) + + updateCurrentContent(content.asNotificationContent()) + + completed() + }) + } + })) + stateManager.reset() + } else { + completed() + } + })) + }) + }) + } + + deinit { + self.pollDisposable.dispose() + self.stateManager?.network.shouldKeepConnection.set(.single(false)) + } +} + +@available(iOSApplicationExtension 10.0, iOS 10.0, *) +private final class BoxedNotificationServiceHandler { + let value: NotificationServiceHandler? + + init(value: NotificationServiceHandler?) { + self.value = value + } +} + @available(iOSApplicationExtension 10.0, iOS 10.0, *) @objc(NotificationService) final class NotificationService: UNNotificationServiceExtension { - private let impl: QueueLocalObject + private var impl: QueueLocalObject? + + private let content = Atomic(value: nil) + private var contentHandler: ((UNNotificationContent) -> Void)? override init() { - self.impl = QueueLocalObject(queue: queue, generate: { - var completion: ((Int32) -> Void)? - let impl = NotificationServiceImpl(serialDispatch: { f in - queue.async { - f() - } - }, countIncomingMessage: { rootPath, accountId, encryptionParameters, peerId, messageId in - completion?(0) - }, isLocked: { rootPath in - return SyncProviderImpl.isLocked(withRootPath: rootPath) - }, lockedMessageText: { rootPath in - return SyncProviderImpl.lockedMessageText(withRootPath: rootPath) - }) - - completion = { [weak impl] count in - queue.async { - impl?.updateUnreadCount(count) - } - } - - return impl - }) - super.init() } override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) { - self.impl.with { impl in - impl.didReceive(request, withContentHandler: contentHandler) - } + let _ = self.content.swap(request.content) + self.contentHandler = contentHandler + + self.impl = nil + + let content = self.content + + self.impl = QueueLocalObject(queue: queue, generate: { [weak self] in + return BoxedNotificationServiceHandler(value: NotificationServiceHandler( + queue: queue, + updateCurrentContent: { value in + let _ = content.swap(value) + }, + completed: { + guard let strongSelf = self else { + return + } + strongSelf.impl = nil + if let content = content.with({ $0 }), let contentHandler = strongSelf.contentHandler { + contentHandler(content) + } + }, + payload: request.content.userInfo + )) + }) } override func serviceExtensionTimeWillExpire() { - self.impl.with { impl in - impl.serviceExtensionTimeWillExpire() + if let content = self.content.with({ $0 }), let contentHandler = self.contentHandler { + contentHandler(content) } } } diff --git a/Telegram/NotificationService/Sources/Sync.swift b/Telegram/NotificationService/Sources/Sync.swift deleted file mode 100644 index cb2ed09a48..0000000000 --- a/Telegram/NotificationService/Sources/Sync.swift +++ /dev/null @@ -1,148 +0,0 @@ -import Foundation -import SwiftSignalKit -//import ValueBox -//import PostboxDataTypes -//import MessageHistoryReadStateTable -//import MessageHistoryMetadataTable -//import PreferencesTable -//import PeerTable -//import PostboxCoding -import AppLockState -import NotificationsPresentationData -import BuildConfig - -/*private let registeredTypes: Void = { - declareEncodable(InAppNotificationSettings.self, f: InAppNotificationSettings.init(decoder:)) - declareEncodable(TelegramChannel.self, f: TelegramChannel.init(decoder:)) -}()*/ - -private func accountRecordIdPathName(_ id: Int64) -> String { - return "account-\(UInt64(bitPattern: id))" -} - -/*private final class ValueBoxLoggerImpl: ValueBoxLogger { - func log(_ what: String) { - print("ValueBox: \(what)") - } -}*/ - -enum SyncProviderImpl { - static func isLocked(withRootPath rootPath: String) -> Bool { - if let data = try? Data(contentsOf: URL(fileURLWithPath: appLockStatePath(rootPath: rootPath))), let state = try? JSONDecoder().decode(LockState.self, from: data), isAppLocked(state: state) { - return true - } else { - return false - } - } - - static func lockedMessageText(withRootPath rootPath: String) -> String { - if let data = try? Data(contentsOf: URL(fileURLWithPath: notificationsPresentationDataPath(rootPath: rootPath))), let value = try? JSONDecoder().decode(NotificationsPresentationData.self, from: data) { - return value.applicationLockedMessageString - } else { - return "You have a new message" - } - } - - /*static func addIncomingMessage(queue: Queue, withRootPath rootPath: String, accountId: Int64, encryptionParameters: DeviceSpecificEncryptionParameters, peerId: Int64, messageId: Int32, completion: @escaping (Int32) -> Void) { - queue.async { - let _ = registeredTypes - - let sharedBasePath = rootPath + "/accounts-metadata" - let basePath = rootPath + "/" + accountRecordIdPathName(accountId) + "/postbox" - - let sharedValueBox = SqliteValueBox(basePath: sharedBasePath + "/db", queue: queue, logger: ValueBoxLoggerImpl(), encryptionParameters: nil, disableCache: true, upgradeProgress: { _ in - }) - - let valueBox = SqliteValueBox(basePath: basePath + "/db", queue: queue, logger: ValueBoxLoggerImpl(), encryptionParameters: ValueBoxEncryptionParameters(forceEncryptionIfNoSet: false, key: ValueBoxEncryptionParameters.Key(data: encryptionParameters.key)!, salt: ValueBoxEncryptionParameters.Salt(data: encryptionParameters.salt)!), disableCache: true, upgradeProgress: { _ in - }) - - let metadataTable = MessageHistoryMetadataTable(valueBox: valueBox, table: MessageHistoryMetadataTable.tableSpec(10)) - let readStateTable = MessageHistoryReadStateTable(valueBox: valueBox, table: MessageHistoryReadStateTable.tableSpec(14), defaultMessageNamespaceReadStates: [:]) - let peerTable = PeerTable(valueBox: valueBox, table: PeerTable.tableSpec(2), reverseAssociatedTable: nil) - - let preferencesTable = PreferencesTable(valueBox: sharedValueBox, table: PreferencesTable.tableSpec(2)) - - let peerId = PeerId(peerId) - - let initialCombinedState = readStateTable.getCombinedState(peerId) - - let combinedState = initialCombinedState.flatMap { state -> CombinedPeerReadState in - var state = state - for i in 0 ..< state.states.count { - if state.states[i].0 == Namespaces.Message.Cloud { - switch state.states[i].1 { - case .idBased(let maxIncomingReadId, let maxOutgoingReadId, var maxKnownId, var count, let markedUnread): - if messageId > maxIncomingReadId { - count += 1 - } - maxKnownId = max(maxKnownId, messageId) - state.states[i] = (state.states[i].0, .idBased(maxIncomingReadId: maxIncomingReadId, maxOutgoingReadId: maxOutgoingReadId, maxKnownId: maxKnownId, count: count, markedUnread: markedUnread)) - default: - break - } - } - } - return state - } - - if let combinedState = combinedState { - let initialCount = initialCombinedState?.count ?? 0 - let updatedCount = combinedState.count - let deltaCount = max(0, updatedCount - initialCount) - - let tag: PeerSummaryCounterTags - if peerId.namespace == Namespaces.Peer.CloudChannel { - if let channel = peerTable.get(peerId) as? TelegramChannel { - switch channel.info { - case .broadcast: - tag = .channel - case .group: - if channel.username != nil { - tag = .publicGroup - } else { - tag = .privateGroup - } - } - } else { - tag = .channel - } - } else if peerId.namespace == Namespaces.Peer.CloudGroup { - tag = .privateGroup - } else { - tag = .privateChat - } - - var totalCount: Int32 = -1 - - var totalUnreadState = metadataTable.getChatListTotalUnreadState() - if var counters = totalUnreadState.absoluteCounters[tag] { - if initialCount == 0 && updatedCount > 0 { - counters.chatCount += 1 - } - counters.messageCount += deltaCount - totalUnreadState.absoluteCounters[tag] = counters - } - if var counters = totalUnreadState.filteredCounters[tag] { - if initialCount == 0 && updatedCount > 0 { - counters.chatCount += 1 - } - counters.messageCount += deltaCount - totalUnreadState.filteredCounters[tag] = counters - } - - let inAppSettings = preferencesTable.get(key: ApplicationSpecificSharedDataKeys.inAppNotificationSettings) as? InAppNotificationSettings ?? InAppNotificationSettings.defaultSettings - - totalCount = totalUnreadState.count(for: inAppSettings.totalUnreadCountDisplayStyle.category, in: inAppSettings.totalUnreadCountDisplayCategory.statsType, with: inAppSettings.totalUnreadCountIncludeTags) - metadataTable.setChatListTotalUnreadState(totalUnreadState) - metadataTable.setShouldReindexUnreadCounts(value: true) - - metadataTable.beforeCommit() - readStateTable.beforeCommit() - - completion(totalCount) - } else { - completion(-1) - } - } - }*/ -} diff --git a/Telegram/NotificationService/Sources/TelegramChannel.swift b/Telegram/NotificationService/Sources/TelegramChannel.swift deleted file mode 100644 index 7f43eb20d6..0000000000 --- a/Telegram/NotificationService/Sources/TelegramChannel.swift +++ /dev/null @@ -1,39 +0,0 @@ -/*import PostboxDataTypes -import PostboxCoding - -public enum TelegramChannelInfo: Int32 { - case broadcast = 0 - case group = 1 -} - -public final class TelegramChannel: Peer { - public let id: PeerId - public let username: String? - public let info: TelegramChannelInfo - - public let associatedPeerId: PeerId? = nil - public let notificationSettingsPeerId: PeerId? = nil - - public init(decoder: PostboxDecoder) { - self.id = PeerId(decoder.decodeInt64ForKey("i", orElse: 0)) - self.username = decoder.decodeOptionalStringForKey("un") - self.info = TelegramChannelInfo(rawValue: decoder.decodeInt32ForKey("i.t", orElse: 0)) ?? .broadcast - } - - public func encode(_ encoder: PostboxEncoder) { - preconditionFailure() - } - - public func isEqual(_ other: Peer) -> Bool { - guard let other = other as? TelegramChannel else { - return false - } - - if self.username != other.username { - return false - } - - return true - } -} -*/ diff --git a/Telegram/SiriIntents/IntentHandler.swift b/Telegram/SiriIntents/IntentHandler.swift index 452362d86f..ed260d7bcb 100644 --- a/Telegram/SiriIntents/IntentHandler.swift +++ b/Telegram/SiriIntents/IntentHandler.swift @@ -121,7 +121,7 @@ class DefaultIntentHandler: INExtension, INSendMessageIntentHandling, INSearchFo let appVersion = (Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String) ?? "unknown" initializeAccountManagement() - let accountManager = AccountManager(basePath: rootPath + "/accounts-metadata", isTemporary: true, isReadOnly: false) + let accountManager = AccountManager(basePath: rootPath + "/accounts-metadata", isTemporary: true, isReadOnly: false, useCaches: false) self.accountManager = accountManager let deviceSpecificEncryptionParameters = BuildConfig.deviceSpecificEncryptionParameters(rootPath, baseAppBundleId: baseAppBundleId) diff --git a/submodules/MtProtoKit/Sources/MTContext.m b/submodules/MtProtoKit/Sources/MTContext.m index 08078e7ad2..c6d7103e6c 100644 --- a/submodules/MtProtoKit/Sources/MTContext.m +++ b/submodules/MtProtoKit/Sources/MTContext.m @@ -386,14 +386,14 @@ static int32_t fixedTimeDifferenceValue = 0; NSDictionary *datacenterAuthInfoById = [keychain objectForKey:@"datacenterAuthInfoById" group:@"persistent"]; if (datacenterAuthInfoById != nil) { _datacenterAuthInfoById = [[NSMutableDictionary alloc] initWithDictionary:datacenterAuthInfoById]; -#if DEBUG +/*#if DEBUG NSArray *keys = [_datacenterAuthInfoById allKeys]; for (NSNumber *key in keys) { if (parseAuthInfoMapKeyInteger(key).selector != MTDatacenterAuthInfoSelectorPersistent) { [_datacenterAuthInfoById removeObjectForKey:key]; } } -#endif +#endif*/ } NSDictionary *datacenterPublicKeysById = [keychain objectForKey:@"datacenterPublicKeysById" group:@"ephemeral"]; diff --git a/submodules/Postbox/Sources/AccountManager.swift b/submodules/Postbox/Sources/AccountManager.swift index b2a26e9d54..3cdd47d984 100644 --- a/submodules/Postbox/Sources/AccountManager.swift +++ b/submodules/Postbox/Sources/AccountManager.swift @@ -69,7 +69,7 @@ final class AccountManagerImpl { } } - fileprivate init?(queue: Queue, basePath: String, isTemporary: Bool, isReadOnly: Bool, temporarySessionId: Int64) { + fileprivate init?(queue: Queue, basePath: String, isTemporary: Bool, isReadOnly: Bool, useCaches: Bool, temporarySessionId: Int64) { let startTime = CFAbsoluteTimeGetCurrent() self.queue = queue @@ -77,19 +77,19 @@ final class AccountManagerImpl { self.atomicStatePath = "\(basePath)/atomic-state" self.temporarySessionId = temporarySessionId let _ = try? FileManager.default.createDirectory(atPath: basePath, withIntermediateDirectories: true, attributes: nil) - guard let guardValueBox = SqliteValueBox(basePath: basePath + "/guard_db", queue: queue, isTemporary: isTemporary, isReadOnly: false, encryptionParameters: nil, upgradeProgress: { _ in }) else { + guard let guardValueBox = SqliteValueBox(basePath: basePath + "/guard_db", queue: queue, isTemporary: isTemporary, isReadOnly: false, useCaches: useCaches, encryptionParameters: nil, upgradeProgress: { _ in }) else { return nil } self.guardValueBox = guardValueBox - guard let valueBox = SqliteValueBox(basePath: basePath + "/db", queue: queue, isTemporary: isTemporary, isReadOnly: isReadOnly, encryptionParameters: nil, upgradeProgress: { _ in }) else { + guard let valueBox = SqliteValueBox(basePath: basePath + "/db", queue: queue, isTemporary: isTemporary, isReadOnly: isReadOnly, useCaches: useCaches, encryptionParameters: nil, upgradeProgress: { _ in }) else { return nil } self.valueBox = valueBox - self.legacyMetadataTable = AccountManagerMetadataTable(valueBox: self.valueBox, table: AccountManagerMetadataTable.tableSpec(0)) - self.legacyRecordTable = AccountManagerRecordTable(valueBox: self.valueBox, table: AccountManagerRecordTable.tableSpec(1)) - self.sharedDataTable = AccountManagerSharedDataTable(valueBox: self.valueBox, table: AccountManagerSharedDataTable.tableSpec(2)) - self.noticeTable = NoticeTable(valueBox: self.valueBox, table: NoticeTable.tableSpec(3)) + self.legacyMetadataTable = AccountManagerMetadataTable(valueBox: self.valueBox, table: AccountManagerMetadataTable.tableSpec(0), useCaches: useCaches) + self.legacyRecordTable = AccountManagerRecordTable(valueBox: self.valueBox, table: AccountManagerRecordTable.tableSpec(1), useCaches: useCaches) + self.sharedDataTable = AccountManagerSharedDataTable(valueBox: self.valueBox, table: AccountManagerSharedDataTable.tableSpec(2), useCaches: useCaches) + self.noticeTable = NoticeTable(valueBox: self.valueBox, table: NoticeTable.tableSpec(3), useCaches: useCaches) do { let data = try Data(contentsOf: URL(fileURLWithPath: self.atomicStatePath)) @@ -472,7 +472,7 @@ public final class AccountManager { return AccountManagerImpl.getCurrentRecords(basePath: basePath) } - public init(basePath: String, isTemporary: Bool, isReadOnly: Bool) { + public init(basePath: String, isTemporary: Bool, isReadOnly: Bool, useCaches: Bool) { self.queue = sharedQueue self.basePath = basePath var temporarySessionId: Int64 = 0 @@ -480,7 +480,7 @@ public final class AccountManager { self.temporarySessionId = temporarySessionId let queue = self.queue self.impl = QueueLocalObject(queue: queue, generate: { - if let value = AccountManagerImpl(queue: queue, basePath: basePath, isTemporary: isTemporary, isReadOnly: isReadOnly, temporarySessionId: temporarySessionId) { + if let value = AccountManagerImpl(queue: queue, basePath: basePath, isTemporary: isTemporary, isReadOnly: isReadOnly, useCaches: useCaches, temporarySessionId: temporarySessionId) { return value } else { preconditionFailure() diff --git a/submodules/Postbox/Sources/CachedPeerDataTable.swift b/submodules/Postbox/Sources/CachedPeerDataTable.swift index 8e4a5dae7b..1d61516e9c 100644 --- a/submodules/Postbox/Sources/CachedPeerDataTable.swift +++ b/submodules/Postbox/Sources/CachedPeerDataTable.swift @@ -11,8 +11,8 @@ final class CachedPeerDataTable: Table { private var cachedDatas: [PeerId: CachedPeerData] = [:] private var updatedPeerIds = Set() - override init(valueBox: ValueBox, table: ValueBoxTable) { - super.init(valueBox: valueBox, table: table) + override init(valueBox: ValueBox, table: ValueBoxTable, useCaches: Bool) { + super.init(valueBox: valueBox, table: table, useCaches: useCaches) } private func key(_ id: PeerId) -> ValueBoxKey { @@ -54,5 +54,8 @@ final class CachedPeerDataTable: Table { } self.updatedPeerIds.removeAll() + if !self.useCaches { + self.cachedDatas.removeAll() + } } } diff --git a/submodules/Postbox/Sources/ChatListIndexTable.swift b/submodules/Postbox/Sources/ChatListIndexTable.swift index c55218901f..56e00e27c4 100644 --- a/submodules/Postbox/Sources/ChatListIndexTable.swift +++ b/submodules/Postbox/Sources/ChatListIndexTable.swift @@ -52,13 +52,13 @@ final class ChatListIndexTable: Table { private var updatedPreviousPeerCachedIndices: [PeerId: ChatListPeerInclusionIndex] = [:] - init(valueBox: ValueBox, table: ValueBoxTable, peerNameIndexTable: PeerNameIndexTable, metadataTable: MessageHistoryMetadataTable, readStateTable: MessageHistoryReadStateTable, notificationSettingsTable: PeerNotificationSettingsTable) { + init(valueBox: ValueBox, table: ValueBoxTable, useCaches: Bool, peerNameIndexTable: PeerNameIndexTable, metadataTable: MessageHistoryMetadataTable, readStateTable: MessageHistoryReadStateTable, notificationSettingsTable: PeerNotificationSettingsTable) { self.peerNameIndexTable = peerNameIndexTable self.metadataTable = metadataTable self.readStateTable = readStateTable self.notificationSettingsTable = notificationSettingsTable - super.init(valueBox: valueBox, table: table) + super.init(valueBox: valueBox, table: table, useCaches: useCaches) } private func key(_ peerId: PeerId) -> ValueBoxKey { @@ -554,6 +554,10 @@ final class ChatListIndexTable: Table { override func beforeCommit() { assert(self.updatedPreviousPeerCachedIndices.isEmpty) + + if !self.useCaches { + self.cachedPeerIndices.removeAll() + } } func debugReindexUnreadCounts(postbox: Postbox, currentTransaction: Transaction) -> ([PeerGroupId: ChatListTotalUnreadState], [PeerGroupId: PeerGroupUnreadCountersCombinedSummary]) { diff --git a/submodules/Postbox/Sources/ChatListTable.swift b/submodules/Postbox/Sources/ChatListTable.swift index 5c7428d278..84c355e13e 100644 --- a/submodules/Postbox/Sources/ChatListTable.swift +++ b/submodules/Postbox/Sources/ChatListTable.swift @@ -133,12 +133,12 @@ final class ChatListTable: Table { let metadataTable: MessageHistoryMetadataTable let seedConfiguration: SeedConfiguration - init(valueBox: ValueBox, table: ValueBoxTable, indexTable: ChatListIndexTable, metadataTable: MessageHistoryMetadataTable, seedConfiguration: SeedConfiguration) { + init(valueBox: ValueBox, table: ValueBoxTable, useCaches: Bool, indexTable: ChatListIndexTable, metadataTable: MessageHistoryMetadataTable, seedConfiguration: SeedConfiguration) { self.indexTable = indexTable self.metadataTable = metadataTable self.seedConfiguration = seedConfiguration - super.init(valueBox: valueBox, table: table) + super.init(valueBox: valueBox, table: table, useCaches: useCaches) } private func key(groupId: PeerGroupId, index: ChatListIndex, type: ChatListEntryType) -> ValueBoxKey { diff --git a/submodules/Postbox/Sources/ContactTable.swift b/submodules/Postbox/Sources/ContactTable.swift index e236a3879a..84ead561b2 100644 --- a/submodules/Postbox/Sources/ContactTable.swift +++ b/submodules/Postbox/Sources/ContactTable.swift @@ -10,10 +10,10 @@ final class ContactTable: Table { private var peerIdsBeforeModification: Set? private var peerIds: Set? - init(valueBox: ValueBox, table: ValueBoxTable, peerNameIndexTable: PeerNameIndexTable) { + init(valueBox: ValueBox, table: ValueBoxTable, useCaches: Bool, peerNameIndexTable: PeerNameIndexTable) { self.peerNameIndexTable = peerNameIndexTable - super.init(valueBox: valueBox, table: table) + super.init(valueBox: valueBox, table: table, useCaches: useCaches) } private func key(_ id: PeerId, sharedKey: ValueBoxKey = ValueBoxKey(length: 8)) -> ValueBoxKey { @@ -98,5 +98,9 @@ final class ContactTable: Table { self.peerIdsBeforeModification = nil } + + if !self.useCaches { + self.peerIds = nil + } } } diff --git a/submodules/Postbox/Sources/GlobalMessageIdsTable.swift b/submodules/Postbox/Sources/GlobalMessageIdsTable.swift index 800ddf9ffa..d013e32dea 100644 --- a/submodules/Postbox/Sources/GlobalMessageIdsTable.swift +++ b/submodules/Postbox/Sources/GlobalMessageIdsTable.swift @@ -10,10 +10,10 @@ final class GlobalMessageIdsTable: Table { private let sharedKey = ValueBoxKey(length: 8) private let sharedBuffer = WriteBuffer() - init(valueBox: ValueBox, table: ValueBoxTable, seedConfiguration: SeedConfiguration) { + init(valueBox: ValueBox, table: ValueBoxTable, useCaches: Bool, seedConfiguration: SeedConfiguration) { self.seedConfiguration = seedConfiguration - super.init(valueBox: valueBox, table: table) + super.init(valueBox: valueBox, table: table, useCaches: useCaches) } private func key(_ id: Int32) -> ValueBoxKey { diff --git a/submodules/Postbox/Sources/ItemCollectionItemTable.swift b/submodules/Postbox/Sources/ItemCollectionItemTable.swift index bd9852319c..44c00ffc0c 100644 --- a/submodules/Postbox/Sources/ItemCollectionItemTable.swift +++ b/submodules/Postbox/Sources/ItemCollectionItemTable.swift @@ -63,9 +63,9 @@ final class ItemCollectionItemTable: Table { private let sharedKey = ValueBoxKey(length: 4 + 8 + 4 + 8) - init(valueBox: ValueBox, table: ValueBoxTable, reverseIndexTable: ReverseIndexReferenceTable) { + init(valueBox: ValueBox, table: ValueBoxTable, useCaches: Bool, reverseIndexTable: ReverseIndexReferenceTable) { self.reverseIndexTable = reverseIndexTable - super.init(valueBox: valueBox, table: table) + super.init(valueBox: valueBox, table: table, useCaches: useCaches) } private func key(collectionId: ItemCollectionId, index: ItemCollectionItemIndex) -> ValueBoxKey { diff --git a/submodules/Postbox/Sources/MessageHistoryHoleIndexTable.swift b/submodules/Postbox/Sources/MessageHistoryHoleIndexTable.swift index 5f95fe4b65..233c6d12dd 100644 --- a/submodules/Postbox/Sources/MessageHistoryHoleIndexTable.swift +++ b/submodules/Postbox/Sources/MessageHistoryHoleIndexTable.swift @@ -49,11 +49,11 @@ final class MessageHistoryHoleIndexTable: Table { let metadataTable: MessageHistoryMetadataTable let seedConfiguration: SeedConfiguration - init(valueBox: ValueBox, table: ValueBoxTable, metadataTable: MessageHistoryMetadataTable, seedConfiguration: SeedConfiguration) { + init(valueBox: ValueBox, table: ValueBoxTable, useCaches: Bool, metadataTable: MessageHistoryMetadataTable, seedConfiguration: SeedConfiguration) { self.seedConfiguration = seedConfiguration self.metadataTable = metadataTable - super.init(valueBox: valueBox, table: table) + super.init(valueBox: valueBox, table: table, useCaches: useCaches) } private func key(id: MessageId, space: MessageHistoryHoleSpace) -> ValueBoxKey { diff --git a/submodules/Postbox/Sources/MessageHistoryIndexTable.swift b/submodules/Postbox/Sources/MessageHistoryIndexTable.swift index f7dc5bd9f3..8d3b262f66 100644 --- a/submodules/Postbox/Sources/MessageHistoryIndexTable.swift +++ b/submodules/Postbox/Sources/MessageHistoryIndexTable.swift @@ -47,13 +47,13 @@ final class MessageHistoryIndexTable: Table { private var cachedExistingNamespaces: [PeerId: Set] = [:] - init(valueBox: ValueBox, table: ValueBoxTable, messageHistoryHoleIndexTable: MessageHistoryHoleIndexTable, globalMessageIdsTable: GlobalMessageIdsTable, metadataTable: MessageHistoryMetadataTable, seedConfiguration: SeedConfiguration) { + init(valueBox: ValueBox, table: ValueBoxTable, useCaches: Bool, messageHistoryHoleIndexTable: MessageHistoryHoleIndexTable, globalMessageIdsTable: GlobalMessageIdsTable, metadataTable: MessageHistoryMetadataTable, seedConfiguration: SeedConfiguration) { self.messageHistoryHoleIndexTable = messageHistoryHoleIndexTable self.globalMessageIdsTable = globalMessageIdsTable self.seedConfiguration = seedConfiguration self.metadataTable = metadataTable - super.init(valueBox: valueBox, table: table) + super.init(valueBox: valueBox, table: table, useCaches: useCaches) } private func key(_ id: MessageId) -> ValueBoxKey { diff --git a/submodules/Postbox/Sources/MessageHistoryReadStateTable.swift b/submodules/Postbox/Sources/MessageHistoryReadStateTable.swift index 07f910245c..e138e975dd 100644 --- a/submodules/Postbox/Sources/MessageHistoryReadStateTable.swift +++ b/submodules/Postbox/Sources/MessageHistoryReadStateTable.swift @@ -32,10 +32,10 @@ final class MessageHistoryReadStateTable: Table { return self.sharedKey } - init(valueBox: ValueBox, table: ValueBoxTable, seedConfiguration: SeedConfiguration) { + init(valueBox: ValueBox, table: ValueBoxTable, useCaches: Bool, seedConfiguration: SeedConfiguration) { self.seedConfiguration = seedConfiguration - super.init(valueBox: valueBox, table: table) + super.init(valueBox: valueBox, table: table, useCaches: useCaches) } private func get(_ id: PeerId) -> InternalPeerReadStates? { @@ -567,6 +567,10 @@ final class MessageHistoryReadStateTable: Table { } } self.updatedInitialPeerReadStates.removeAll() + + if !self.useCaches { + self.cachedPeerReadStates.removeAll() + } } } } diff --git a/submodules/Postbox/Sources/MessageHistoryTable.swift b/submodules/Postbox/Sources/MessageHistoryTable.swift index 3c20cf3822..ade57e7bfc 100644 --- a/submodules/Postbox/Sources/MessageHistoryTable.swift +++ b/submodules/Postbox/Sources/MessageHistoryTable.swift @@ -90,7 +90,7 @@ final class MessageHistoryTable: Table { let summaryTable: MessageHistoryTagsSummaryTable let pendingActionsTable: PendingMessageActionsTable - init(valueBox: ValueBox, table: ValueBoxTable, seedConfiguration: SeedConfiguration, messageHistoryIndexTable: MessageHistoryIndexTable, messageHistoryHoleIndexTable: MessageHistoryHoleIndexTable, messageMediaTable: MessageMediaTable, historyMetadataTable: MessageHistoryMetadataTable, globallyUniqueMessageIdsTable: MessageGloballyUniqueIdTable, unsentTable: MessageHistoryUnsentTable, failedTable: MessageHistoryFailedTable, tagsTable: MessageHistoryTagsTable, threadsTable: MessageHistoryThreadsTable, globalTagsTable: GlobalMessageHistoryTagsTable, localTagsTable: LocalMessageHistoryTagsTable, timeBasedAttributesTable: TimestampBasedMessageAttributesTable, readStateTable: MessageHistoryReadStateTable, synchronizeReadStateTable: MessageHistorySynchronizeReadStateTable, textIndexTable: MessageHistoryTextIndexTable, summaryTable: MessageHistoryTagsSummaryTable, pendingActionsTable: PendingMessageActionsTable) { + init(valueBox: ValueBox, table: ValueBoxTable, useCaches: Bool, seedConfiguration: SeedConfiguration, messageHistoryIndexTable: MessageHistoryIndexTable, messageHistoryHoleIndexTable: MessageHistoryHoleIndexTable, messageMediaTable: MessageMediaTable, historyMetadataTable: MessageHistoryMetadataTable, globallyUniqueMessageIdsTable: MessageGloballyUniqueIdTable, unsentTable: MessageHistoryUnsentTable, failedTable: MessageHistoryFailedTable, tagsTable: MessageHistoryTagsTable, threadsTable: MessageHistoryThreadsTable, globalTagsTable: GlobalMessageHistoryTagsTable, localTagsTable: LocalMessageHistoryTagsTable, timeBasedAttributesTable: TimestampBasedMessageAttributesTable, readStateTable: MessageHistoryReadStateTable, synchronizeReadStateTable: MessageHistorySynchronizeReadStateTable, textIndexTable: MessageHistoryTextIndexTable, summaryTable: MessageHistoryTagsSummaryTable, pendingActionsTable: PendingMessageActionsTable) { self.seedConfiguration = seedConfiguration self.messageHistoryIndexTable = messageHistoryIndexTable self.messageHistoryHoleIndexTable = messageHistoryHoleIndexTable @@ -110,7 +110,7 @@ final class MessageHistoryTable: Table { self.summaryTable = summaryTable self.pendingActionsTable = pendingActionsTable - super.init(valueBox: valueBox, table: table) + super.init(valueBox: valueBox, table: table, useCaches: useCaches) } private func key(_ index: MessageIndex, key: ValueBoxKey = ValueBoxKey(length: 8 + 4 + 4 + 4)) -> ValueBoxKey { diff --git a/submodules/Postbox/Sources/MessageHistoryTagsSummaryTable.swift b/submodules/Postbox/Sources/MessageHistoryTagsSummaryTable.swift index 207d57e036..71bc63c674 100644 --- a/submodules/Postbox/Sources/MessageHistoryTagsSummaryTable.swift +++ b/submodules/Postbox/Sources/MessageHistoryTagsSummaryTable.swift @@ -82,10 +82,10 @@ class MessageHistoryTagsSummaryTable: Table { private let sharedKey = ValueBoxKey(length: 4 + 8 + 4) - init(valueBox: ValueBox, table: ValueBoxTable, invalidateTable: InvalidatedMessageHistoryTagsSummaryTable) { + init(valueBox: ValueBox, table: ValueBoxTable, useCaches: Bool, invalidateTable: InvalidatedMessageHistoryTagsSummaryTable) { self.invalidateTable = invalidateTable - super.init(valueBox: valueBox, table: table) + super.init(valueBox: valueBox, table: table, useCaches: useCaches) } private func key(key: MessageHistoryTagsSummaryKey, sharedKey: ValueBoxKey = ValueBoxKey(length: 4 + 8 + 4)) -> ValueBoxKey { @@ -172,5 +172,9 @@ class MessageHistoryTagsSummaryTable: Table { } self.updatedKeys.removeAll() } + + if !self.useCaches { + self.cachedSummaries.removeAll() + } } } diff --git a/submodules/Postbox/Sources/MessageHistoryTagsTable.swift b/submodules/Postbox/Sources/MessageHistoryTagsTable.swift index a8102d32de..afa6092684 100644 --- a/submodules/Postbox/Sources/MessageHistoryTagsTable.swift +++ b/submodules/Postbox/Sources/MessageHistoryTagsTable.swift @@ -14,11 +14,11 @@ class MessageHistoryTagsTable: Table { private let summaryTable: MessageHistoryTagsSummaryTable private let summaryTags: MessageTags - init(valueBox: ValueBox, table: ValueBoxTable, seedConfiguration: SeedConfiguration, summaryTable: MessageHistoryTagsSummaryTable) { + init(valueBox: ValueBox, table: ValueBoxTable, useCaches: Bool, seedConfiguration: SeedConfiguration, summaryTable: MessageHistoryTagsSummaryTable) { self.summaryTable = summaryTable self.summaryTags = seedConfiguration.messageTagsWithSummary - super.init(valueBox: valueBox, table: table) + super.init(valueBox: valueBox, table: table, useCaches: useCaches) } private func key(tag: MessageTags, index: MessageIndex, key: ValueBoxKey = ValueBoxKey(length: 8 + 4 + 4 + 4 + 4)) -> ValueBoxKey { diff --git a/submodules/Postbox/Sources/MessageHistoryThreadHoleIndexTable.swift b/submodules/Postbox/Sources/MessageHistoryThreadHoleIndexTable.swift index 00c2e0acfe..99d08ca410 100644 --- a/submodules/Postbox/Sources/MessageHistoryThreadHoleIndexTable.swift +++ b/submodules/Postbox/Sources/MessageHistoryThreadHoleIndexTable.swift @@ -25,11 +25,11 @@ final class MessageHistoryThreadHoleIndexTable: Table { let metadataTable: MessageHistoryMetadataTable let seedConfiguration: SeedConfiguration - init(valueBox: ValueBox, table: ValueBoxTable, metadataTable: MessageHistoryMetadataTable, seedConfiguration: SeedConfiguration) { + init(valueBox: ValueBox, table: ValueBoxTable, useCaches: Bool, metadataTable: MessageHistoryMetadataTable, seedConfiguration: SeedConfiguration) { self.seedConfiguration = seedConfiguration self.metadataTable = metadataTable - super.init(valueBox: valueBox, table: table) + super.init(valueBox: valueBox, table: table, useCaches: useCaches) } private func key(threadId: Int64, id: MessageId, space: MessageHistoryHoleSpace) -> ValueBoxKey { diff --git a/submodules/Postbox/Sources/MessageHistoryThreadsTable.swift b/submodules/Postbox/Sources/MessageHistoryThreadsTable.swift index a7f55d6576..6bf1a5b865 100644 --- a/submodules/Postbox/Sources/MessageHistoryThreadsTable.swift +++ b/submodules/Postbox/Sources/MessageHistoryThreadsTable.swift @@ -11,8 +11,8 @@ class MessageHistoryThreadsTable: Table { private let sharedKey = ValueBoxKey(length: 8 + 8 + 4 + 4 + 4) - override init(valueBox: ValueBox, table: ValueBoxTable) { - super.init(valueBox: valueBox, table: table) + override init(valueBox: ValueBox, table: ValueBoxTable, useCaches: Bool) { + super.init(valueBox: valueBox, table: table, useCaches: useCaches) } private func key(threadId: Int64, index: MessageIndex, key: ValueBoxKey = ValueBoxKey(length: 8 + 8 + 4 + 4 + 4)) -> ValueBoxKey { diff --git a/submodules/Postbox/Sources/MetadataTable.swift b/submodules/Postbox/Sources/MetadataTable.swift index 25e92291e5..5aafcdba4d 100644 --- a/submodules/Postbox/Sources/MetadataTable.swift +++ b/submodules/Postbox/Sources/MetadataTable.swift @@ -19,8 +19,8 @@ final class MetadataTable: Table { private let sharedBuffer = WriteBuffer() - override init(valueBox: ValueBox, table: ValueBoxTable) { - super.init(valueBox: valueBox, table: table) + override init(valueBox: ValueBox, table: ValueBoxTable, useCaches: Bool) { + super.init(valueBox: valueBox, table: table, useCaches: useCaches) } private func key(_ key: MetadataKey) -> ValueBoxKey { diff --git a/submodules/Postbox/Sources/OrderedItemListTable.swift b/submodules/Postbox/Sources/OrderedItemListTable.swift index 469316f141..6a7dfde6cb 100644 --- a/submodules/Postbox/Sources/OrderedItemListTable.swift +++ b/submodules/Postbox/Sources/OrderedItemListTable.swift @@ -19,10 +19,10 @@ final class OrderedItemListTable: Table { private let indexTable: OrderedItemListIndexTable - init(valueBox: ValueBox, table: ValueBoxTable, indexTable: OrderedItemListIndexTable) { + init(valueBox: ValueBox, table: ValueBoxTable, useCaches: Bool, indexTable: OrderedItemListIndexTable) { self.indexTable = indexTable - super.init(valueBox: valueBox, table: table) + super.init(valueBox: valueBox, table: table, useCaches: useCaches) } private func keyIndexToId(collectionId: Int32, itemIndex: UInt32) -> ValueBoxKey { diff --git a/submodules/Postbox/Sources/PeerMergedOperationLogIndexTable.swift b/submodules/Postbox/Sources/PeerMergedOperationLogIndexTable.swift index 07016e2b77..b04a4652c3 100644 --- a/submodules/Postbox/Sources/PeerMergedOperationLogIndexTable.swift +++ b/submodules/Postbox/Sources/PeerMergedOperationLogIndexTable.swift @@ -7,10 +7,10 @@ final class PeerMergedOperationLogIndexTable: Table { private let metadataTable: PeerOperationLogMetadataTable - init(valueBox: ValueBox, table: ValueBoxTable, metadataTable: PeerOperationLogMetadataTable) { + init(valueBox: ValueBox, table: ValueBoxTable, useCaches: Bool, metadataTable: PeerOperationLogMetadataTable) { self.metadataTable = metadataTable - super.init(valueBox: valueBox, table: table) + super.init(valueBox: valueBox, table: table, useCaches: useCaches) } private func key(tag: PeerOperationLogTag, index: Int32) -> ValueBoxKey { diff --git a/submodules/Postbox/Sources/PeerNameIndexTable.swift b/submodules/Postbox/Sources/PeerNameIndexTable.swift index 6212a1f713..c03b8cf8f9 100644 --- a/submodules/Postbox/Sources/PeerNameIndexTable.swift +++ b/submodules/Postbox/Sources/PeerNameIndexTable.swift @@ -140,11 +140,11 @@ final class PeerNameIndexTable: Table { private var entryUpdates: [PeerId: PeerNameIndexCategoriesEntryUpdate] = [:] - init(valueBox: ValueBox, table: ValueBoxTable, peerTable: PeerTable, peerNameTokenIndexTable: ReverseIndexReferenceTable) { + init(valueBox: ValueBox, table: ValueBoxTable, useCaches: Bool, peerTable: PeerTable, peerNameTokenIndexTable: ReverseIndexReferenceTable) { self.peerTable = peerTable self.peerNameTokenIndexTable = peerNameTokenIndexTable - super.init(valueBox: valueBox, table: table) + super.init(valueBox: valueBox, table: table, useCaches: useCaches) } private func key(_ peerId: PeerId) -> ValueBoxKey { diff --git a/submodules/Postbox/Sources/PeerNotificationSettingsBehaviorTable.swift b/submodules/Postbox/Sources/PeerNotificationSettingsBehaviorTable.swift index 77c7d21f6f..1483b36039 100644 --- a/submodules/Postbox/Sources/PeerNotificationSettingsBehaviorTable.swift +++ b/submodules/Postbox/Sources/PeerNotificationSettingsBehaviorTable.swift @@ -11,10 +11,10 @@ final class PeerNotificationSettingsBehaviorTable: Table { private let indexTable: PeerNotificationSettingsBehaviorIndexTable - init(valueBox: ValueBox, table: ValueBoxTable, indexTable: PeerNotificationSettingsBehaviorIndexTable) { + init(valueBox: ValueBox, table: ValueBoxTable, useCaches: Bool, indexTable: PeerNotificationSettingsBehaviorIndexTable) { self.indexTable = indexTable - super.init(valueBox: valueBox, table: table) + super.init(valueBox: valueBox, table: table, useCaches: useCaches) } private func key(peerId: PeerId, timestamp: Int32) -> ValueBoxKey { diff --git a/submodules/Postbox/Sources/PeerNotificationSettingsTable.swift b/submodules/Postbox/Sources/PeerNotificationSettingsTable.swift index 956d12bd8e..f9dcab6944 100644 --- a/submodules/Postbox/Sources/PeerNotificationSettingsTable.swift +++ b/submodules/Postbox/Sources/PeerNotificationSettingsTable.swift @@ -63,11 +63,11 @@ final class PeerNotificationSettingsTable: Table { private var cachedSettings: [PeerId: PeerNotificationSettingsTableEntry] = [:] private var updatedInitialSettings: [PeerId: PeerNotificationSettingsTableEntry] = [:] - init(valueBox: ValueBox, table: ValueBoxTable, pendingIndexTable: PendingPeerNotificationSettingsIndexTable, behaviorTable: PeerNotificationSettingsBehaviorTable) { + init(valueBox: ValueBox, table: ValueBoxTable, useCaches: Bool, pendingIndexTable: PendingPeerNotificationSettingsIndexTable, behaviorTable: PeerNotificationSettingsBehaviorTable) { self.pendingIndexTable = pendingIndexTable self.behaviorTable = behaviorTable - super.init(valueBox: valueBox, table: table) + super.init(valueBox: valueBox, table: table, useCaches: useCaches) } private func key(_ id: PeerId) -> ValueBoxKey { @@ -301,6 +301,10 @@ final class PeerNotificationSettingsTable: Table { } self.updatedInitialSettings.removeAll() + + if !self.useCaches { + self.cachedSettings.removeAll() + } } } } diff --git a/submodules/Postbox/Sources/PeerOperationLogTable.swift b/submodules/Postbox/Sources/PeerOperationLogTable.swift index eb3836958b..f3c3a9cc95 100644 --- a/submodules/Postbox/Sources/PeerOperationLogTable.swift +++ b/submodules/Postbox/Sources/PeerOperationLogTable.swift @@ -112,11 +112,11 @@ final class PeerOperationLogTable: Table { private let metadataTable: PeerOperationLogMetadataTable private let mergedIndexTable: PeerMergedOperationLogIndexTable - init(valueBox: ValueBox, table: ValueBoxTable, metadataTable: PeerOperationLogMetadataTable, mergedIndexTable: PeerMergedOperationLogIndexTable) { + init(valueBox: ValueBox, table: ValueBoxTable, useCaches: Bool, metadataTable: PeerOperationLogMetadataTable, mergedIndexTable: PeerMergedOperationLogIndexTable) { self.metadataTable = metadataTable self.mergedIndexTable = mergedIndexTable - super.init(valueBox: valueBox, table: table) + super.init(valueBox: valueBox, table: table, useCaches: useCaches) } private func key(peerId: PeerId, tag: PeerOperationLogTag, index: Int32) -> ValueBoxKey { diff --git a/submodules/Postbox/Sources/PeerTable.swift b/submodules/Postbox/Sources/PeerTable.swift index 0fb0aa67cc..6f40d870d3 100644 --- a/submodules/Postbox/Sources/PeerTable.swift +++ b/submodules/Postbox/Sources/PeerTable.swift @@ -13,10 +13,10 @@ final class PeerTable: Table { private var cachedPeers: [PeerId: Peer] = [:] private var updatedInitialPeers: [PeerId: Peer?] = [:] - init(valueBox: ValueBox, table: ValueBoxTable, reverseAssociatedTable: ReverseAssociatedPeerTable) { + init(valueBox: ValueBox, table: ValueBoxTable, useCaches: Bool, reverseAssociatedTable: ReverseAssociatedPeerTable) { self.reverseAssociatedTable = reverseAssociatedTable - super.init(valueBox: valueBox, table: table) + super.init(valueBox: valueBox, table: table, useCaches: useCaches) } private func key(_ id: PeerId) -> ValueBoxKey { @@ -87,6 +87,9 @@ final class PeerTable: Table { } self.updatedInitialPeers.removeAll() + if !self.useCaches { + self.cachedPeers.removeAll() + } } } } diff --git a/submodules/Postbox/Sources/PendingMessageActionsTable.swift b/submodules/Postbox/Sources/PendingMessageActionsTable.swift index 5a611987ec..edfe554f9e 100644 --- a/submodules/Postbox/Sources/PendingMessageActionsTable.swift +++ b/submodules/Postbox/Sources/PendingMessageActionsTable.swift @@ -53,10 +53,10 @@ final class PendingMessageActionsTable: Table { private let metadataTable: PendingMessageActionsMetadataTable - init(valueBox: ValueBox, table: ValueBoxTable, metadataTable: PendingMessageActionsMetadataTable) { + init(valueBox: ValueBox, table: ValueBoxTable, useCaches: Bool, metadataTable: PendingMessageActionsMetadataTable) { self.metadataTable = metadataTable - super.init(valueBox: valueBox, table: table) + super.init(valueBox: valueBox, table: table, useCaches: useCaches) } private func forwardKey(id: MessageId, actionType: PendingMessageActionType) -> ValueBoxKey { diff --git a/submodules/Postbox/Sources/Postbox.swift b/submodules/Postbox/Sources/Postbox.swift index a7d139facc..605c4a4fae 100644 --- a/submodules/Postbox/Sources/Postbox.swift +++ b/submodules/Postbox/Sources/Postbox.swift @@ -1165,7 +1165,7 @@ func debugRestoreState(basePath:String, name: String) { private let sharedQueue = Queue(name: "org.telegram.postbox.Postbox") -public func openPostbox(basePath: String, seedConfiguration: SeedConfiguration, encryptionParameters: ValueBoxEncryptionParameters, timestampForAbsoluteTimeBasedOperations: Int32, isTemporary: Bool, isReadOnly: Bool, useCopy: Bool) -> Signal { +public func openPostbox(basePath: String, seedConfiguration: SeedConfiguration, encryptionParameters: ValueBoxEncryptionParameters, timestampForAbsoluteTimeBasedOperations: Int32, isTemporary: Bool, isReadOnly: Bool, useCopy: Bool, useCaches: Bool) -> Signal { let queue = sharedQueue return Signal { subscriber in queue.async { @@ -1209,7 +1209,7 @@ public func openPostbox(basePath: String, seedConfiguration: SeedConfiguration, postboxLog("openPostbox, initialize SqliteValueBox") - guard var valueBox = SqliteValueBox(basePath: dbBasePath, queue: queue, isTemporary: isTemporary, isReadOnly: isReadOnly, encryptionParameters: encryptionParameters, upgradeProgress: { progress in + guard var valueBox = SqliteValueBox(basePath: dbBasePath, queue: queue, isTemporary: isTemporary, isReadOnly: isReadOnly, useCaches: useCaches, encryptionParameters: encryptionParameters, upgradeProgress: { progress in postboxLog("openPostbox, SqliteValueBox upgrading progress \(progress)") subscriber.putNext(.upgrading(progress)) }) else { @@ -1219,7 +1219,7 @@ public func openPostbox(basePath: String, seedConfiguration: SeedConfiguration, } loop: while true { - let metadataTable = MetadataTable(valueBox: valueBox, table: MetadataTable.tableSpec(0)) + let metadataTable = MetadataTable(valueBox: valueBox, table: MetadataTable.tableSpec(0), useCaches: useCaches) let userVersion: Int32? = metadataTable.userVersion() let currentUserVersion: Int32 = 25 @@ -1237,7 +1237,7 @@ public func openPostbox(basePath: String, seedConfiguration: SeedConfiguration, postboxLog("Version \(userVersion) is newer than supported") assertionFailure("Version \(userVersion) is newer than supported") valueBox.drop() - guard let updatedValueBox = SqliteValueBox(basePath: dbBasePath, queue: queue, isTemporary: isTemporary, isReadOnly: isReadOnly, encryptionParameters: encryptionParameters, upgradeProgress: { progress in + guard let updatedValueBox = SqliteValueBox(basePath: dbBasePath, queue: queue, isTemporary: isTemporary, isReadOnly: isReadOnly, useCaches: useCaches, encryptionParameters: encryptionParameters, upgradeProgress: { progress in subscriber.putNext(.upgrading(progress)) }) else { subscriber.putNext(.error) @@ -1261,7 +1261,7 @@ public func openPostbox(basePath: String, seedConfiguration: SeedConfiguration, valueBox.internalClose() let _ = try? FileManager.default.removeItem(atPath: dbBasePath) let _ = try? FileManager.default.moveItem(atPath: updatedPath, toPath: dbBasePath) - guard let updatedValueBox = SqliteValueBox(basePath: dbBasePath, queue: queue, isTemporary: isTemporary, isReadOnly: isReadOnly, encryptionParameters: encryptionParameters, upgradeProgress: { progress in + guard let updatedValueBox = SqliteValueBox(basePath: dbBasePath, queue: queue, isTemporary: isTemporary, isReadOnly: isReadOnly, useCaches: useCaches, encryptionParameters: encryptionParameters, upgradeProgress: { progress in subscriber.putNext(.upgrading(progress)) }) else { subscriber.putNext(.error) @@ -1275,7 +1275,7 @@ public func openPostbox(basePath: String, seedConfiguration: SeedConfiguration, assertionFailure("Couldn't find any upgrade for \(userVersion)") postboxLog("Couldn't find any upgrade for \(userVersion)") valueBox.drop() - guard let updatedValueBox = SqliteValueBox(basePath: dbBasePath, queue: queue, isTemporary: isTemporary, isReadOnly: isReadOnly, encryptionParameters: encryptionParameters, upgradeProgress: { progress in + guard let updatedValueBox = SqliteValueBox(basePath: dbBasePath, queue: queue, isTemporary: isTemporary, isReadOnly: isReadOnly, useCaches: useCaches, encryptionParameters: encryptionParameters, upgradeProgress: { progress in subscriber.putNext(.upgrading(progress)) }) else { subscriber.putNext(.error) @@ -1293,7 +1293,7 @@ public func openPostbox(basePath: String, seedConfiguration: SeedConfiguration, let endTime = CFAbsoluteTimeGetCurrent() postboxLog("Postbox load took \((endTime - startTime) * 1000.0) ms") - subscriber.putNext(.postbox(Postbox(queue: queue, basePath: basePath, seedConfiguration: seedConfiguration, valueBox: valueBox, timestampForAbsoluteTimeBasedOperations: timestampForAbsoluteTimeBasedOperations, isTemporary: isTemporary, tempDir: tempDir))) + subscriber.putNext(.postbox(Postbox(queue: queue, basePath: basePath, seedConfiguration: seedConfiguration, valueBox: valueBox, timestampForAbsoluteTimeBasedOperations: timestampForAbsoluteTimeBasedOperations, isTemporary: isTemporary, tempDir: tempDir, useCaches: useCaches))) postboxLog("openPostbox, putCompletion") @@ -1450,7 +1450,7 @@ public final class Postbox { var installedMessageActionsByPeerId: [PeerId: Bag<([StoreMessage], Transaction) -> Void>] = [:] - init(queue: Queue, basePath: String, seedConfiguration: SeedConfiguration, valueBox: SqliteValueBox, timestampForAbsoluteTimeBasedOperations: Int32, isTemporary: Bool, tempDir: TempBoxDirectory?) { + init(queue: Queue, basePath: String, seedConfiguration: SeedConfiguration, valueBox: SqliteValueBox, timestampForAbsoluteTimeBasedOperations: Int32, isTemporary: Bool, tempDir: TempBoxDirectory?, useCaches: Bool) { assert(queue.isCurrent()) let startTime = CFAbsoluteTimeGetCurrent() @@ -1465,67 +1465,67 @@ public final class Postbox { self.mediaBox = MediaBox(basePath: self.basePath + "/media") self.valueBox = valueBox - self.metadataTable = MetadataTable(valueBox: self.valueBox, table: MetadataTable.tableSpec(0)) + self.metadataTable = MetadataTable(valueBox: self.valueBox, table: MetadataTable.tableSpec(0), useCaches: useCaches) - self.keychainTable = KeychainTable(valueBox: self.valueBox, table: KeychainTable.tableSpec(1)) - self.reverseAssociatedPeerTable = ReverseAssociatedPeerTable(valueBox: self.valueBox, table:ReverseAssociatedPeerTable.tableSpec(40)) - self.peerTable = PeerTable(valueBox: self.valueBox, table: PeerTable.tableSpec(2), reverseAssociatedTable: self.reverseAssociatedPeerTable) - self.globalMessageIdsTable = GlobalMessageIdsTable(valueBox: self.valueBox, table: GlobalMessageIdsTable.tableSpec(3), seedConfiguration: seedConfiguration) - self.globallyUniqueMessageIdsTable = MessageGloballyUniqueIdTable(valueBox: self.valueBox, table: MessageGloballyUniqueIdTable.tableSpec(32)) - self.messageHistoryMetadataTable = MessageHistoryMetadataTable(valueBox: self.valueBox, table: MessageHistoryMetadataTable.tableSpec(10)) - self.messageHistoryHoleIndexTable = MessageHistoryHoleIndexTable(valueBox: self.valueBox, table: MessageHistoryHoleIndexTable.tableSpec(56), metadataTable: self.messageHistoryMetadataTable, seedConfiguration: self.seedConfiguration) - self.messageHistoryUnsentTable = MessageHistoryUnsentTable(valueBox: self.valueBox, table: MessageHistoryUnsentTable.tableSpec(11)) - self.messageHistoryFailedTable = MessageHistoryFailedTable(valueBox: self.valueBox, table: MessageHistoryFailedTable.tableSpec(49)) - self.invalidatedMessageHistoryTagsSummaryTable = InvalidatedMessageHistoryTagsSummaryTable(valueBox: self.valueBox, table: InvalidatedMessageHistoryTagsSummaryTable.tableSpec(47)) - self.messageHistoryTagsSummaryTable = MessageHistoryTagsSummaryTable(valueBox: self.valueBox, table: MessageHistoryTagsSummaryTable.tableSpec(44), invalidateTable: self.invalidatedMessageHistoryTagsSummaryTable) - self.pendingMessageActionsMetadataTable = PendingMessageActionsMetadataTable(valueBox: self.valueBox, table: PendingMessageActionsMetadataTable.tableSpec(45)) - self.pendingMessageActionsTable = PendingMessageActionsTable(valueBox: self.valueBox, table: PendingMessageActionsTable.tableSpec(46), metadataTable: self.pendingMessageActionsMetadataTable) - self.messageHistoryTagsTable = MessageHistoryTagsTable(valueBox: self.valueBox, table: MessageHistoryTagsTable.tableSpec(12), seedConfiguration: self.seedConfiguration, summaryTable: self.messageHistoryTagsSummaryTable) - self.messageHistoryThreadsTable = MessageHistoryThreadsTable(valueBox: self.valueBox, table: MessageHistoryThreadsTable.tableSpec(62)) - self.messageHistoryThreadHoleIndexTable = MessageHistoryThreadHoleIndexTable(valueBox: self.valueBox, table: MessageHistoryThreadHoleIndexTable.tableSpec(63), metadataTable: self.messageHistoryMetadataTable, seedConfiguration: self.seedConfiguration) - self.globalMessageHistoryTagsTable = GlobalMessageHistoryTagsTable(valueBox: self.valueBox, table: GlobalMessageHistoryTagsTable.tableSpec(39)) - self.localMessageHistoryTagsTable = LocalMessageHistoryTagsTable(valueBox: self.valueBox, table: GlobalMessageHistoryTagsTable.tableSpec(52)) - self.messageHistoryIndexTable = MessageHistoryIndexTable(valueBox: self.valueBox, table: MessageHistoryIndexTable.tableSpec(4), messageHistoryHoleIndexTable: self.messageHistoryHoleIndexTable, globalMessageIdsTable: self.globalMessageIdsTable, metadataTable: self.messageHistoryMetadataTable, seedConfiguration: self.seedConfiguration) - self.mediaTable = MessageMediaTable(valueBox: self.valueBox, table: MessageMediaTable.tableSpec(6)) - self.readStateTable = MessageHistoryReadStateTable(valueBox: self.valueBox, table: MessageHistoryReadStateTable.tableSpec(14), seedConfiguration: seedConfiguration) - self.synchronizeReadStateTable = MessageHistorySynchronizeReadStateTable(valueBox: self.valueBox, table: MessageHistorySynchronizeReadStateTable.tableSpec(15)) - self.synchronizeGroupMessageStatsTable = InvalidatedGroupMessageStatsTable(valueBox: self.valueBox, table: InvalidatedGroupMessageStatsTable.tableSpec(59)) - self.timestampBasedMessageAttributesIndexTable = TimestampBasedMessageAttributesIndexTable(valueBox: self.valueBox, table: TimestampBasedMessageAttributesTable.tableSpec(33)) - self.timestampBasedMessageAttributesTable = TimestampBasedMessageAttributesTable(valueBox: self.valueBox, table: TimestampBasedMessageAttributesTable.tableSpec(34), indexTable: self.timestampBasedMessageAttributesIndexTable) + self.keychainTable = KeychainTable(valueBox: self.valueBox, table: KeychainTable.tableSpec(1), useCaches: useCaches) + self.reverseAssociatedPeerTable = ReverseAssociatedPeerTable(valueBox: self.valueBox, table:ReverseAssociatedPeerTable.tableSpec(40), useCaches: useCaches) + self.peerTable = PeerTable(valueBox: self.valueBox, table: PeerTable.tableSpec(2), useCaches: useCaches, reverseAssociatedTable: self.reverseAssociatedPeerTable) + self.globalMessageIdsTable = GlobalMessageIdsTable(valueBox: self.valueBox, table: GlobalMessageIdsTable.tableSpec(3), useCaches: useCaches, seedConfiguration: seedConfiguration) + self.globallyUniqueMessageIdsTable = MessageGloballyUniqueIdTable(valueBox: self.valueBox, table: MessageGloballyUniqueIdTable.tableSpec(32), useCaches: useCaches) + self.messageHistoryMetadataTable = MessageHistoryMetadataTable(valueBox: self.valueBox, table: MessageHistoryMetadataTable.tableSpec(10), useCaches: useCaches) + self.messageHistoryHoleIndexTable = MessageHistoryHoleIndexTable(valueBox: self.valueBox, table: MessageHistoryHoleIndexTable.tableSpec(56), useCaches: useCaches, metadataTable: self.messageHistoryMetadataTable, seedConfiguration: self.seedConfiguration) + self.messageHistoryUnsentTable = MessageHistoryUnsentTable(valueBox: self.valueBox, table: MessageHistoryUnsentTable.tableSpec(11), useCaches: useCaches) + self.messageHistoryFailedTable = MessageHistoryFailedTable(valueBox: self.valueBox, table: MessageHistoryFailedTable.tableSpec(49), useCaches: useCaches) + self.invalidatedMessageHistoryTagsSummaryTable = InvalidatedMessageHistoryTagsSummaryTable(valueBox: self.valueBox, table: InvalidatedMessageHistoryTagsSummaryTable.tableSpec(47), useCaches: useCaches) + self.messageHistoryTagsSummaryTable = MessageHistoryTagsSummaryTable(valueBox: self.valueBox, table: MessageHistoryTagsSummaryTable.tableSpec(44), useCaches: useCaches, invalidateTable: self.invalidatedMessageHistoryTagsSummaryTable) + self.pendingMessageActionsMetadataTable = PendingMessageActionsMetadataTable(valueBox: self.valueBox, table: PendingMessageActionsMetadataTable.tableSpec(45), useCaches: useCaches) + self.pendingMessageActionsTable = PendingMessageActionsTable(valueBox: self.valueBox, table: PendingMessageActionsTable.tableSpec(46), useCaches: useCaches, metadataTable: self.pendingMessageActionsMetadataTable) + self.messageHistoryTagsTable = MessageHistoryTagsTable(valueBox: self.valueBox, table: MessageHistoryTagsTable.tableSpec(12), useCaches: useCaches, seedConfiguration: self.seedConfiguration, summaryTable: self.messageHistoryTagsSummaryTable) + self.messageHistoryThreadsTable = MessageHistoryThreadsTable(valueBox: self.valueBox, table: MessageHistoryThreadsTable.tableSpec(62), useCaches: useCaches) + self.messageHistoryThreadHoleIndexTable = MessageHistoryThreadHoleIndexTable(valueBox: self.valueBox, table: MessageHistoryThreadHoleIndexTable.tableSpec(63), useCaches: useCaches, metadataTable: self.messageHistoryMetadataTable, seedConfiguration: self.seedConfiguration) + self.globalMessageHistoryTagsTable = GlobalMessageHistoryTagsTable(valueBox: self.valueBox, table: GlobalMessageHistoryTagsTable.tableSpec(39), useCaches: useCaches) + self.localMessageHistoryTagsTable = LocalMessageHistoryTagsTable(valueBox: self.valueBox, table: GlobalMessageHistoryTagsTable.tableSpec(52), useCaches: useCaches) + self.messageHistoryIndexTable = MessageHistoryIndexTable(valueBox: self.valueBox, table: MessageHistoryIndexTable.tableSpec(4), useCaches: useCaches, messageHistoryHoleIndexTable: self.messageHistoryHoleIndexTable, globalMessageIdsTable: self.globalMessageIdsTable, metadataTable: self.messageHistoryMetadataTable, seedConfiguration: self.seedConfiguration) + self.mediaTable = MessageMediaTable(valueBox: self.valueBox, table: MessageMediaTable.tableSpec(6), useCaches: useCaches) + self.readStateTable = MessageHistoryReadStateTable(valueBox: self.valueBox, table: MessageHistoryReadStateTable.tableSpec(14), useCaches: useCaches, seedConfiguration: seedConfiguration) + self.synchronizeReadStateTable = MessageHistorySynchronizeReadStateTable(valueBox: self.valueBox, table: MessageHistorySynchronizeReadStateTable.tableSpec(15), useCaches: useCaches) + self.synchronizeGroupMessageStatsTable = InvalidatedGroupMessageStatsTable(valueBox: self.valueBox, table: InvalidatedGroupMessageStatsTable.tableSpec(59), useCaches: useCaches) + self.timestampBasedMessageAttributesIndexTable = TimestampBasedMessageAttributesIndexTable(valueBox: self.valueBox, table: TimestampBasedMessageAttributesTable.tableSpec(33), useCaches: useCaches) + self.timestampBasedMessageAttributesTable = TimestampBasedMessageAttributesTable(valueBox: self.valueBox, table: TimestampBasedMessageAttributesTable.tableSpec(34), useCaches: useCaches, indexTable: self.timestampBasedMessageAttributesIndexTable) self.textIndexTable = MessageHistoryTextIndexTable(valueBox: self.valueBox, table: MessageHistoryTextIndexTable.tableSpec(41)) - self.additionalChatListItemsTable = AdditionalChatListItemsTable(valueBox: self.valueBox, table: AdditionalChatListItemsTable.tableSpec(55)) - self.messageHistoryTable = MessageHistoryTable(valueBox: self.valueBox, table: MessageHistoryTable.tableSpec(7), seedConfiguration: seedConfiguration, messageHistoryIndexTable: self.messageHistoryIndexTable, messageHistoryHoleIndexTable: self.messageHistoryHoleIndexTable, messageMediaTable: self.mediaTable, historyMetadataTable: self.messageHistoryMetadataTable, globallyUniqueMessageIdsTable: self.globallyUniqueMessageIdsTable, unsentTable: self.messageHistoryUnsentTable, failedTable: self.messageHistoryFailedTable, tagsTable: self.messageHistoryTagsTable, threadsTable: self.messageHistoryThreadsTable, globalTagsTable: self.globalMessageHistoryTagsTable, localTagsTable: self.localMessageHistoryTagsTable, timeBasedAttributesTable: self.timestampBasedMessageAttributesTable, readStateTable: self.readStateTable, synchronizeReadStateTable: self.synchronizeReadStateTable, textIndexTable: self.textIndexTable, summaryTable: self.messageHistoryTagsSummaryTable, pendingActionsTable: self.pendingMessageActionsTable) - self.peerChatStateTable = PeerChatStateTable(valueBox: self.valueBox, table: PeerChatStateTable.tableSpec(13)) - self.peerNameTokenIndexTable = ReverseIndexReferenceTable(valueBox: self.valueBox, table: ReverseIndexReferenceTable.tableSpec(26)) - self.peerNameIndexTable = PeerNameIndexTable(valueBox: self.valueBox, table: PeerNameIndexTable.tableSpec(27), peerTable: self.peerTable, peerNameTokenIndexTable: self.peerNameTokenIndexTable) - self.contactsTable = ContactTable(valueBox: self.valueBox, table: ContactTable.tableSpec(16), peerNameIndexTable: self.peerNameIndexTable) - self.peerRatingTable = RatingTable(valueBox: self.valueBox, table: RatingTable.tableSpec(17)) - self.cachedPeerDataTable = CachedPeerDataTable(valueBox: self.valueBox, table: CachedPeerDataTable.tableSpec(18)) - self.pendingPeerNotificationSettingsIndexTable = PendingPeerNotificationSettingsIndexTable(valueBox: self.valueBox, table: PendingPeerNotificationSettingsIndexTable.tableSpec(48)) - self.peerNotificationSettingsBehaviorIndexTable = PeerNotificationSettingsBehaviorIndexTable(valueBox: self.valueBox, table: PeerNotificationSettingsBehaviorIndexTable.tableSpec(60)) - self.peerNotificationSettingsBehaviorTable = PeerNotificationSettingsBehaviorTable(valueBox: self.valueBox, table: PeerNotificationSettingsBehaviorTable.tableSpec(61), indexTable: self.peerNotificationSettingsBehaviorIndexTable) - self.peerNotificationSettingsTable = PeerNotificationSettingsTable(valueBox: self.valueBox, table: PeerNotificationSettingsTable.tableSpec(19), pendingIndexTable: self.pendingPeerNotificationSettingsIndexTable, behaviorTable: self.peerNotificationSettingsBehaviorTable) - self.peerPresenceTable = PeerPresenceTable(valueBox: self.valueBox, table: PeerPresenceTable.tableSpec(20)) - self.itemCollectionInfoTable = ItemCollectionInfoTable(valueBox: self.valueBox, table: ItemCollectionInfoTable.tableSpec(21)) - self.itemCollectionReverseIndexTable = ReverseIndexReferenceTable(valueBox: self.valueBox, table: ReverseIndexReferenceTable.tableSpec(36)) - self.itemCollectionItemTable = ItemCollectionItemTable(valueBox: self.valueBox, table: ItemCollectionItemTable.tableSpec(22), reverseIndexTable: self.itemCollectionReverseIndexTable) - self.peerChatInterfaceStateTable = PeerChatInterfaceStateTable(valueBox: self.valueBox, table: PeerChatInterfaceStateTable.tableSpec(67)) - self.peerChatThreadInterfaceStateTable = PeerChatThreadInterfaceStateTable(valueBox: self.valueBox, table: PeerChatThreadInterfaceStateTable.tableSpec(68)) - self.itemCacheMetaTable = ItemCacheMetaTable(valueBox: self.valueBox, table: ItemCacheMetaTable.tableSpec(24)) - self.itemCacheTable = ItemCacheTable(valueBox: self.valueBox, table: ItemCacheTable.tableSpec(25)) - self.chatListIndexTable = ChatListIndexTable(valueBox: self.valueBox, table: ChatListIndexTable.tableSpec(8), peerNameIndexTable: self.peerNameIndexTable, metadataTable: self.messageHistoryMetadataTable, readStateTable: self.readStateTable, notificationSettingsTable: self.peerNotificationSettingsTable) - self.chatListTable = ChatListTable(valueBox: self.valueBox, table: ChatListTable.tableSpec(9), indexTable: self.chatListIndexTable, metadataTable: self.messageHistoryMetadataTable, seedConfiguration: self.seedConfiguration) - self.peerChatTopTaggedMessageIdsTable = PeerChatTopTaggedMessageIdsTable(valueBox: self.valueBox, table: PeerChatTopTaggedMessageIdsTable.tableSpec(28)) - self.peerOperationLogMetadataTable = PeerOperationLogMetadataTable(valueBox: self.valueBox, table: PeerOperationLogMetadataTable.tableSpec(29)) - self.peerMergedOperationLogIndexTable = PeerMergedOperationLogIndexTable(valueBox: self.valueBox, table: PeerMergedOperationLogIndexTable.tableSpec(30), metadataTable: self.peerOperationLogMetadataTable) - self.peerOperationLogTable = PeerOperationLogTable(valueBox: self.valueBox, table: PeerOperationLogTable.tableSpec(31), metadataTable: self.peerOperationLogMetadataTable, mergedIndexTable: self.peerMergedOperationLogIndexTable) - 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)) - self.noticeTable = NoticeTable(valueBox: self.valueBox, table: NoticeTable.tableSpec(43)) - self.deviceContactImportInfoTable = DeviceContactImportInfoTable(valueBox: self.valueBox, table: DeviceContactImportInfoTable.tableSpec(54)) - self.groupMessageStatsTable = GroupMessageStatsTable(valueBox: self.valueBox, table: GroupMessageStatsTable.tableSpec(58)) + self.additionalChatListItemsTable = AdditionalChatListItemsTable(valueBox: self.valueBox, table: AdditionalChatListItemsTable.tableSpec(55), useCaches: useCaches) + self.messageHistoryTable = MessageHistoryTable(valueBox: self.valueBox, table: MessageHistoryTable.tableSpec(7), useCaches: useCaches, seedConfiguration: seedConfiguration, messageHistoryIndexTable: self.messageHistoryIndexTable, messageHistoryHoleIndexTable: self.messageHistoryHoleIndexTable, messageMediaTable: self.mediaTable, historyMetadataTable: self.messageHistoryMetadataTable, globallyUniqueMessageIdsTable: self.globallyUniqueMessageIdsTable, unsentTable: self.messageHistoryUnsentTable, failedTable: self.messageHistoryFailedTable, tagsTable: self.messageHistoryTagsTable, threadsTable: self.messageHistoryThreadsTable, globalTagsTable: self.globalMessageHistoryTagsTable, localTagsTable: self.localMessageHistoryTagsTable, timeBasedAttributesTable: self.timestampBasedMessageAttributesTable, readStateTable: self.readStateTable, synchronizeReadStateTable: self.synchronizeReadStateTable, textIndexTable: self.textIndexTable, summaryTable: self.messageHistoryTagsSummaryTable, pendingActionsTable: self.pendingMessageActionsTable) + self.peerChatStateTable = PeerChatStateTable(valueBox: self.valueBox, table: PeerChatStateTable.tableSpec(13), useCaches: useCaches) + self.peerNameTokenIndexTable = ReverseIndexReferenceTable(valueBox: self.valueBox, table: ReverseIndexReferenceTable.tableSpec(26), useCaches: useCaches) + self.peerNameIndexTable = PeerNameIndexTable(valueBox: self.valueBox, table: PeerNameIndexTable.tableSpec(27), useCaches: useCaches, peerTable: self.peerTable, peerNameTokenIndexTable: self.peerNameTokenIndexTable) + self.contactsTable = ContactTable(valueBox: self.valueBox, table: ContactTable.tableSpec(16), useCaches: useCaches, peerNameIndexTable: self.peerNameIndexTable) + self.peerRatingTable = RatingTable(valueBox: self.valueBox, table: RatingTable.tableSpec(17), useCaches: useCaches) + self.cachedPeerDataTable = CachedPeerDataTable(valueBox: self.valueBox, table: CachedPeerDataTable.tableSpec(18), useCaches: useCaches) + self.pendingPeerNotificationSettingsIndexTable = PendingPeerNotificationSettingsIndexTable(valueBox: self.valueBox, table: PendingPeerNotificationSettingsIndexTable.tableSpec(48), useCaches: useCaches) + self.peerNotificationSettingsBehaviorIndexTable = PeerNotificationSettingsBehaviorIndexTable(valueBox: self.valueBox, table: PeerNotificationSettingsBehaviorIndexTable.tableSpec(60), useCaches: useCaches) + self.peerNotificationSettingsBehaviorTable = PeerNotificationSettingsBehaviorTable(valueBox: self.valueBox, table: PeerNotificationSettingsBehaviorTable.tableSpec(61), useCaches: useCaches, indexTable: self.peerNotificationSettingsBehaviorIndexTable) + self.peerNotificationSettingsTable = PeerNotificationSettingsTable(valueBox: self.valueBox, table: PeerNotificationSettingsTable.tableSpec(19), useCaches: useCaches, pendingIndexTable: self.pendingPeerNotificationSettingsIndexTable, behaviorTable: self.peerNotificationSettingsBehaviorTable) + self.peerPresenceTable = PeerPresenceTable(valueBox: self.valueBox, table: PeerPresenceTable.tableSpec(20), useCaches: useCaches) + self.itemCollectionInfoTable = ItemCollectionInfoTable(valueBox: self.valueBox, table: ItemCollectionInfoTable.tableSpec(21), useCaches: useCaches) + self.itemCollectionReverseIndexTable = ReverseIndexReferenceTable(valueBox: self.valueBox, table: ReverseIndexReferenceTable.tableSpec(36), useCaches: useCaches) + self.itemCollectionItemTable = ItemCollectionItemTable(valueBox: self.valueBox, table: ItemCollectionItemTable.tableSpec(22), useCaches: useCaches, reverseIndexTable: self.itemCollectionReverseIndexTable) + self.peerChatInterfaceStateTable = PeerChatInterfaceStateTable(valueBox: self.valueBox, table: PeerChatInterfaceStateTable.tableSpec(67), useCaches: useCaches) + self.peerChatThreadInterfaceStateTable = PeerChatThreadInterfaceStateTable(valueBox: self.valueBox, table: PeerChatThreadInterfaceStateTable.tableSpec(68), useCaches: useCaches) + self.itemCacheMetaTable = ItemCacheMetaTable(valueBox: self.valueBox, table: ItemCacheMetaTable.tableSpec(24), useCaches: useCaches) + self.itemCacheTable = ItemCacheTable(valueBox: self.valueBox, table: ItemCacheTable.tableSpec(25), useCaches: useCaches) + self.chatListIndexTable = ChatListIndexTable(valueBox: self.valueBox, table: ChatListIndexTable.tableSpec(8), useCaches: useCaches, peerNameIndexTable: self.peerNameIndexTable, metadataTable: self.messageHistoryMetadataTable, readStateTable: self.readStateTable, notificationSettingsTable: self.peerNotificationSettingsTable) + self.chatListTable = ChatListTable(valueBox: self.valueBox, table: ChatListTable.tableSpec(9), useCaches: useCaches, indexTable: self.chatListIndexTable, metadataTable: self.messageHistoryMetadataTable, seedConfiguration: self.seedConfiguration) + self.peerChatTopTaggedMessageIdsTable = PeerChatTopTaggedMessageIdsTable(valueBox: self.valueBox, table: PeerChatTopTaggedMessageIdsTable.tableSpec(28), useCaches: useCaches) + self.peerOperationLogMetadataTable = PeerOperationLogMetadataTable(valueBox: self.valueBox, table: PeerOperationLogMetadataTable.tableSpec(29), useCaches: useCaches) + self.peerMergedOperationLogIndexTable = PeerMergedOperationLogIndexTable(valueBox: self.valueBox, table: PeerMergedOperationLogIndexTable.tableSpec(30), useCaches: useCaches, metadataTable: self.peerOperationLogMetadataTable) + self.peerOperationLogTable = PeerOperationLogTable(valueBox: self.valueBox, table: PeerOperationLogTable.tableSpec(31), useCaches: useCaches, metadataTable: self.peerOperationLogMetadataTable, mergedIndexTable: self.peerMergedOperationLogIndexTable) + self.preferencesTable = PreferencesTable(valueBox: self.valueBox, table: PreferencesTable.tableSpec(35), useCaches: useCaches) + self.orderedItemListIndexTable = OrderedItemListIndexTable(valueBox: self.valueBox, table: OrderedItemListIndexTable.tableSpec(37), useCaches: useCaches) + self.orderedItemListTable = OrderedItemListTable(valueBox: self.valueBox, table: OrderedItemListTable.tableSpec(38), useCaches: useCaches, indexTable: self.orderedItemListIndexTable) + self.unorderedItemListTable = UnorderedItemListTable(valueBox: self.valueBox, table: UnorderedItemListTable.tableSpec(42), useCaches: useCaches) + self.noticeTable = NoticeTable(valueBox: self.valueBox, table: NoticeTable.tableSpec(43), useCaches: useCaches) + self.deviceContactImportInfoTable = DeviceContactImportInfoTable(valueBox: self.valueBox, table: DeviceContactImportInfoTable.tableSpec(54), useCaches: useCaches) + self.groupMessageStatsTable = GroupMessageStatsTable(valueBox: self.valueBox, table: GroupMessageStatsTable.tableSpec(58), useCaches: useCaches) var tables: [Table] = [] tables.append(self.metadataTable) diff --git a/submodules/Postbox/Sources/PostboxUpgrade_21to22.swift b/submodules/Postbox/Sources/PostboxUpgrade_21to22.swift index 070ab8c6a0..6184ccd834 100644 --- a/submodules/Postbox/Sources/PostboxUpgrade_21to22.swift +++ b/submodules/Postbox/Sources/PostboxUpgrade_21to22.swift @@ -5,7 +5,7 @@ import SwiftSignalKit func postboxUpgrade_21to22(queue: Queue, basePath: String, valueBox: ValueBox, encryptionParameters: ValueBoxEncryptionParameters, progress: (Float) -> Void) -> String? { postboxLog("Upgrade 21->22 started") valueBox.begin() - let metadataTable = MetadataTable(valueBox: valueBox, table: MetadataTable.tableSpec(0)) + let metadataTable = MetadataTable(valueBox: valueBox, table: MetadataTable.tableSpec(0), useCaches: false) metadataTable.setUserVersion(22) valueBox.commit() return nil diff --git a/submodules/Postbox/Sources/SqliteValueBox.swift b/submodules/Postbox/Sources/SqliteValueBox.swift index de9169dac5..133996cc46 100644 --- a/submodules/Postbox/Sources/SqliteValueBox.swift +++ b/submodules/Postbox/Sources/SqliteValueBox.swift @@ -163,6 +163,7 @@ public final class SqliteValueBox: ValueBox { fileprivate let basePath: String private let isTemporary: Bool private let isReadOnly: Bool + private let useCaches: Bool private let inMemory: Bool private let encryptionParameters: ValueBoxEncryptionParameters? private let databasePath: String @@ -201,10 +202,11 @@ public final class SqliteValueBox: ValueBox { private let queue: Queue - public init?(basePath: String, queue: Queue, isTemporary: Bool, isReadOnly: Bool, encryptionParameters: ValueBoxEncryptionParameters?, upgradeProgress: (Float) -> Void, inMemory: Bool = false) { + public init?(basePath: String, queue: Queue, isTemporary: Bool, isReadOnly: Bool, useCaches: Bool, encryptionParameters: ValueBoxEncryptionParameters?, upgradeProgress: (Float) -> Void, inMemory: Bool = false) { self.basePath = basePath self.isTemporary = isTemporary self.isReadOnly = isReadOnly + self.useCaches = useCaches self.inMemory = inMemory self.encryptionParameters = encryptionParameters self.databasePath = basePath + "/db_sqlite" @@ -420,8 +422,11 @@ public final class SqliteValueBox: ValueBox { } postboxLog("Did set up encryption") - - //database.execute("PRAGMA cache_size=-2097152") + + if !self.useCaches { + resultCode = database.execute("PRAGMA cache_size=32") + assert(resultCode) + } resultCode = database.execute("PRAGMA mmap_size=0") assert(resultCode) resultCode = database.execute("PRAGMA synchronous=NORMAL") diff --git a/submodules/Postbox/Sources/Table.swift b/submodules/Postbox/Sources/Table.swift index a94415c3b5..ae3a385c04 100644 --- a/submodules/Postbox/Sources/Table.swift +++ b/submodules/Postbox/Sources/Table.swift @@ -3,10 +3,12 @@ import Foundation open class Table { public final let valueBox: ValueBox public final let table: ValueBoxTable + public final let useCaches: Bool - public init(valueBox: ValueBox, table: ValueBoxTable) { + public init(valueBox: ValueBox, table: ValueBoxTable, useCaches: Bool) { self.valueBox = valueBox self.table = table + self.useCaches = useCaches } open func clearMemoryCache() { diff --git a/submodules/Postbox/Sources/TimestampBasedMessageAttributesTable.swift b/submodules/Postbox/Sources/TimestampBasedMessageAttributesTable.swift index 541cf987e4..525e9c4425 100644 --- a/submodules/Postbox/Sources/TimestampBasedMessageAttributesTable.swift +++ b/submodules/Postbox/Sources/TimestampBasedMessageAttributesTable.swift @@ -26,10 +26,10 @@ final class TimestampBasedMessageAttributesTable: Table { private let indexTable: TimestampBasedMessageAttributesIndexTable - init(valueBox: ValueBox, table: ValueBoxTable, indexTable: TimestampBasedMessageAttributesIndexTable) { + init(valueBox: ValueBox, table: ValueBoxTable, useCaches: Bool, indexTable: TimestampBasedMessageAttributesIndexTable) { self.indexTable = indexTable - super.init(valueBox: valueBox, table: table) + super.init(valueBox: valueBox, table: table, useCaches: useCaches) } private func key(tag: UInt16, timestamp: Int32, id: MessageId) -> ValueBoxKey { diff --git a/submodules/Postbox/Sources/Utils/Decoder/AdaptedPostboxDecoder.swift b/submodules/Postbox/Sources/Utils/Decoder/AdaptedPostboxDecoder.swift index 3552f98c79..41f0f6f4cc 100644 --- a/submodules/Postbox/Sources/Utils/Decoder/AdaptedPostboxDecoder.swift +++ b/submodules/Postbox/Sources/Utils/Decoder/AdaptedPostboxDecoder.swift @@ -33,6 +33,13 @@ final public class AdaptedPostboxDecoder { } func decode(_ type: T.Type, from data: Data, contentType: ContentType) throws -> T where T : Decodable { + if type == AdaptedPostboxDecoder.RawObjectData.self { + if case .object = contentType { + return AdaptedPostboxDecoder.RawObjectData(data: data, typeHash: 0) as! T + } else { + preconditionFailure() + } + } let decoder = _AdaptedPostboxDecoder(data: data, contentType: contentType) return try T(from: decoder) } diff --git a/submodules/TelegramCore/Sources/Account/Account.swift b/submodules/TelegramCore/Sources/Account/Account.swift index 87b0cd6fcd..78fd20753c 100644 --- a/submodules/TelegramCore/Sources/Account/Account.swift +++ b/submodules/TelegramCore/Sources/Account/Account.swift @@ -21,30 +21,30 @@ private func makeExclusiveKeychain(id: AccountRecordId, postbox: Postbox) -> Key } return dict } - return Keychain(get: { key in + return Keychain(get: { [weak postbox] key in let enabled = accountRecordToActiveKeychainId.with { dict -> Bool in return dict[id] == keychainId } - if enabled { + if enabled, let postbox = postbox { return postbox.keychainEntryForKey(key) } else { Logger.shared.log("Keychain", "couldn't get \(key) — not current") return nil } - }, set: { (key, data) in + }, set: { [weak postbox] key, data in let enabled = accountRecordToActiveKeychainId.with { dict -> Bool in return dict[id] == keychainId } - if enabled { + if enabled, let postbox = postbox { postbox.setKeychainEntryForKey(key, value: data) } else { Logger.shared.log("Keychain", "couldn't set \(key) — not current") } - }, remove: { key in + }, remove: { [weak postbox] key in let enabled = accountRecordToActiveKeychainId.with { dict -> Bool in return dict[id] == keychainId } - if enabled { + if enabled, let postbox = postbox { postbox.removeKeychainEntryForKey(key) } else { Logger.shared.log("Keychain", "couldn't remove \(key) — not current") @@ -162,85 +162,19 @@ public enum AccountResult { case authorized(Account) } -public enum AccountPreferenceEntriesResult { - case progress(Float) - case result(String, [ValueBoxKey: PreferencesEntry]) -} - -public func accountPreferenceEntries(rootPath: String, id: AccountRecordId, keys: Set, encryptionParameters: ValueBoxEncryptionParameters) -> Signal { - let path = "\(rootPath)/\(accountRecordIdPathName(id))" - let postbox = openPostbox(basePath: path + "/postbox", seedConfiguration: telegramPostboxSeedConfiguration, encryptionParameters: encryptionParameters, timestampForAbsoluteTimeBasedOperations: Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970), isTemporary: true, isReadOnly: true, useCopy: false) - return postbox - |> mapToSignal { value -> Signal in - switch value { - case let .upgrading(progress): - return .single(.progress(progress)) - case let .postbox(postbox): - return postbox.transaction { transaction -> AccountPreferenceEntriesResult in - var result: [ValueBoxKey: PreferencesEntry] = [:] - for key in keys { - if let value = transaction.getPreferencesEntry(key: key) { - result[key] = value - } - } - return .result(path, result) - } - case .error: - return .single(.progress(0.0)) - } - } -} - -public enum AccountNoticeEntriesResult { - case progress(Float) - case result(String, [ValueBoxKey: NoticeEntry]) -} - -public func accountNoticeEntries(rootPath: String, id: AccountRecordId, encryptionParameters: ValueBoxEncryptionParameters) -> Signal { - let path = "\(rootPath)/\(accountRecordIdPathName(id))" - let postbox = openPostbox(basePath: path + "/postbox", seedConfiguration: telegramPostboxSeedConfiguration, encryptionParameters: encryptionParameters, timestampForAbsoluteTimeBasedOperations: Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970), isTemporary: true, isReadOnly: true, useCopy: false) - return postbox - |> mapToSignal { value -> Signal in - switch value { - case let .upgrading(progress): - return .single(.progress(progress)) - case let .postbox(postbox): - return postbox.transaction { transaction -> AccountNoticeEntriesResult in - return .result(path, transaction.getAllNoticeEntries()) - } - case .error: - return .single(.progress(0.0)) - } - } -} - -public enum LegacyAccessChallengeDataResult { - case progress(Float) - case result(PostboxAccessChallengeData) -} - -public func accountLegacyAccessChallengeData(rootPath: String, id: AccountRecordId, encryptionParameters: ValueBoxEncryptionParameters) -> Signal { - let path = "\(rootPath)/\(accountRecordIdPathName(id))" - let postbox = openPostbox(basePath: path + "/postbox", seedConfiguration: telegramPostboxSeedConfiguration, encryptionParameters: encryptionParameters, timestampForAbsoluteTimeBasedOperations: Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970), isTemporary: true, isReadOnly: true, useCopy: false) - return postbox - |> mapToSignal { value -> Signal in - switch value { - case let .upgrading(progress): - return .single(.progress(progress)) - case let .postbox(postbox): - return postbox.transaction { transaction -> LegacyAccessChallengeDataResult in - return .result(transaction.legacyGetAccessChallengeData()) - } - case .error: - return .single(.progress(0.0)) - } - } -} - public func accountWithId(accountManager: AccountManager, networkArguments: NetworkInitializationArguments, id: AccountRecordId, encryptionParameters: ValueBoxEncryptionParameters, supplementary: Bool, rootPath: String, beginWithTestingEnvironment: Bool, backupData: AccountBackupData?, auxiliaryMethods: AccountAuxiliaryMethods, shouldKeepAutoConnection: Bool = true) -> Signal { let path = "\(rootPath)/\(accountRecordIdPathName(id))" - let postbox = openPostbox(basePath: path + "/postbox", seedConfiguration: telegramPostboxSeedConfiguration, encryptionParameters: encryptionParameters, timestampForAbsoluteTimeBasedOperations: Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970), isTemporary: false, isReadOnly: false, useCopy: false) + let postbox = openPostbox( + basePath: path + "/postbox", + seedConfiguration: telegramPostboxSeedConfiguration, + encryptionParameters: encryptionParameters, + timestampForAbsoluteTimeBasedOperations: Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970), + isTemporary: false, + isReadOnly: false, + useCopy: false, + useCaches: !supplementary + ) return postbox |> mapToSignal { result -> Signal in @@ -251,7 +185,11 @@ public func accountWithId(accountManager: AccountManager (LocalizationSettings?, ProxySettings?) in - return (transaction.getSharedData(SharedDataKeys.localizationSettings)?.get(LocalizationSettings.self), transaction.getSharedData(SharedDataKeys.proxySettings)?.get(ProxySettings.self)) + var localizationSettings: LocalizationSettings? + if !supplementary { + localizationSettings = transaction.getSharedData(SharedDataKeys.localizationSettings)?.get(LocalizationSettings.self) + } + return (localizationSettings, transaction.getSharedData(SharedDataKeys.proxySettings)?.get(ProxySettings.self)) } |> mapToSignal { localizationSettings, proxySettings -> Signal in return postbox.transaction { transaction -> (PostboxCoding?, LocalizationSettings?, ProxySettings?, NetworkSettings?) in @@ -740,22 +678,30 @@ public struct MasterNotificationKey: Codable { } public func masterNotificationsKey(account: Account, ignoreDisabled: Bool) -> Signal { - return masterNotificationsKey(masterNotificationKeyValue: account.masterNotificationKey, postbox: account.postbox, ignoreDisabled: ignoreDisabled) + return masterNotificationsKey(masterNotificationKeyValue: account.masterNotificationKey, postbox: account.postbox, ignoreDisabled: ignoreDisabled, createIfNotExists: true) + |> map { value -> MasterNotificationKey in + return value! + } } -private func masterNotificationsKey(masterNotificationKeyValue: Atomic, postbox: Postbox, ignoreDisabled: Bool) -> Signal { +public func existingMasterNotificationsKey(postbox: Postbox) -> Signal { + let value = Atomic(value: nil) + return masterNotificationsKey(masterNotificationKeyValue: value, postbox: postbox, ignoreDisabled: true, createIfNotExists: false) +} + +private func masterNotificationsKey(masterNotificationKeyValue: Atomic, postbox: Postbox, ignoreDisabled: Bool, createIfNotExists: Bool) -> Signal { if let key = masterNotificationKeyValue.with({ $0 }) { return .single(key) } - return postbox.transaction(ignoreDisabled: ignoreDisabled, { transaction -> MasterNotificationKey in + return postbox.transaction(ignoreDisabled: ignoreDisabled, { transaction -> MasterNotificationKey? in if let value = transaction.keychainEntryForKey("master-notification-secret"), !value.isEmpty { let authKeyHash = sha1Digest(value) let authKeyId = authKeyHash.subdata(in: authKeyHash.count - 8 ..< authKeyHash.count) let keyData = MasterNotificationKey(id: authKeyId, data: value) let _ = masterNotificationKeyValue.swap(keyData) return keyData - } else { + } else if createIfNotExists { var secretData = Data(count: 256) let secretDataCount = secretData.count if !secretData.withUnsafeMutableBytes({ rawBytes -> Bool in @@ -772,6 +718,8 @@ private func masterNotificationsKey(masterNotificationKeyValue: Atomic Signal { - return masterNotificationsKey(masterNotificationKeyValue: account.masterNotificationKey, postbox: account.postbox, ignoreDisabled: true) + return masterNotificationsKey(masterNotificationKeyValue: account.masterNotificationKey, postbox: account.postbox, ignoreDisabled: true, createIfNotExists: false) |> map { secret -> Data? in + guard let secret = secret else { + return nil + } return decryptedNotificationPayload(key: secret, data: data) } } @@ -969,12 +920,8 @@ public class Account { let networkStateQueue = Queue() - let networkStateSignal = combineLatest(queue: networkStateQueue, self.stateManager.isUpdating, network.connectionStatus/*, delayNetworkStatus*/) - |> map { isUpdating, connectionStatus/*, delayNetworkStatus*/ -> AccountNetworkState in - /*if delayNetworkStatus { - return .online(proxy: nil) - }*/ - + let networkStateSignal = combineLatest(queue: networkStateQueue, self.stateManager.isUpdating, network.connectionStatus) + |> map { isUpdating, connectionStatus -> AccountNetworkState in switch connectionStatus { case .waitingForNetwork: return .waitingForNetwork @@ -1076,7 +1023,10 @@ public class Account { self.managedOperationsDisposable.add(managedApplyPendingMessageReactionsActions(postbox: self.postbox, network: self.network, stateManager: self.stateManager).start()) self.managedOperationsDisposable.add(managedSynchronizeEmojiKeywordsOperations(postbox: self.postbox, network: self.network).start()) self.managedOperationsDisposable.add(managedApplyPendingScheduledMessagesActions(postbox: self.postbox, network: self.network, stateManager: self.stateManager).start()) - self.managedOperationsDisposable.add(managedChatListFilters(postbox: self.postbox, network: self.network, accountPeerId: self.peerId).start()) + + if !supplementary { + self.managedOperationsDisposable.add(managedChatListFilters(postbox: self.postbox, network: self.network, accountPeerId: self.peerId).start()) + } let importantBackgroundOperations: [Signal] = [ managedSynchronizeChatInputStateOperations(postbox: self.postbox, network: self.network) |> map { $0 ? AccountRunningImportantTasks.other : [] }, @@ -1140,7 +1090,7 @@ public class Account { self.managedOperationsDisposable.add(managedSynchronizeAppLogEventsOperations(postbox: self.postbox, network: self.network).start()) self.managedOperationsDisposable.add(managedNotificationSettingsBehaviors(postbox: self.postbox).start()) self.managedOperationsDisposable.add(managedThemesUpdates(accountManager: accountManager, postbox: self.postbox, network: self.network).start()) - if !self.testingEnvironment { + if !self.testingEnvironment && !supplementary { self.managedOperationsDisposable.add(managedChatThemesUpdates(accountManager: accountManager, network: self.network).start()) } @@ -1161,7 +1111,7 @@ public class Account { }) } - let _ = masterNotificationsKey(masterNotificationKeyValue: self.masterNotificationKey, postbox: self.postbox, ignoreDisabled: false).start(next: { key in + let _ = masterNotificationsKey(masterNotificationKeyValue: self.masterNotificationKey, postbox: self.postbox, ignoreDisabled: false, createIfNotExists: true).start(next: { key in let encoder = JSONEncoder() if let data = try? encoder.encode(key) { let _ = try? data.write(to: URL(fileURLWithPath: "\(basePath)/notificationsKey")) @@ -1301,3 +1251,95 @@ public func setupAccount(_ account: Account, fetchCachedResourceRepresentation: account.pendingMessageManager.transformOutgoingMessageMedia = transformOutgoingMessageMedia account.pendingUpdateMessageManager.transformOutgoingMessageMedia = transformOutgoingMessageMedia } + +public func standaloneStateManager( + accountManager: AccountManager, + networkArguments: NetworkInitializationArguments, + id: AccountRecordId, + encryptionParameters: ValueBoxEncryptionParameters, + rootPath: String, + auxiliaryMethods: AccountAuxiliaryMethods +) -> Signal { + let path = "\(rootPath)/\(accountRecordIdPathName(id))" + + let postbox = openPostbox( + basePath: path + "/postbox", + seedConfiguration: telegramPostboxSeedConfiguration, + encryptionParameters: encryptionParameters, + timestampForAbsoluteTimeBasedOperations: Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970), + isTemporary: false, + isReadOnly: false, + useCopy: false, + useCaches: false + ) + + return postbox + |> take(1) + |> mapToSignal { result -> Signal in + switch result { + case .upgrading: + return .single(nil) + case .error: + return .single(nil) + case let .postbox(postbox): + return accountManager.transaction { transaction -> (LocalizationSettings?, ProxySettings?) in + return (nil, transaction.getSharedData(SharedDataKeys.proxySettings)?.get(ProxySettings.self)) + } + |> mapToSignal { localizationSettings, proxySettings -> Signal in + return postbox.transaction { transaction -> (PostboxCoding?, LocalizationSettings?, ProxySettings?, NetworkSettings?) in + let state = transaction.getState() + + return (state, localizationSettings, proxySettings, transaction.getPreferencesEntry(key: PreferencesKeys.networkSettings)?.get(NetworkSettings.self)) + } + |> mapToSignal { accountState, localizationSettings, proxySettings, networkSettings -> Signal in + let keychain = makeExclusiveKeychain(id: id, postbox: postbox) + + if let accountState = accountState { + switch accountState { + case _ as UnauthorizedAccountState: + return .single(nil) + case let authorizedState as AuthorizedAccountState: + return postbox.transaction { transaction -> String? in + return (transaction.getPeer(authorizedState.peerId) as? TelegramUser)?.phone + } + |> mapToSignal { phoneNumber in + return initializedNetwork( + accountId: id, + arguments: networkArguments, + supplementary: true, + datacenterId: Int(authorizedState.masterDatacenterId), + keychain: keychain, + basePath: path, + testingEnvironment: authorizedState.isTestingEnvironment, + languageCode: localizationSettings?.primaryComponent.languageCode, + proxySettings: proxySettings, + networkSettings: networkSettings, + phoneNumber: phoneNumber + ) + |> map { network -> AccountStateManager? in + return AccountStateManager( + accountPeerId: authorizedState.peerId, + accountManager: accountManager, + postbox: postbox, + network: network, + callSessionManager: nil, + addIsContactUpdates: { _ in + }, + shouldKeepOnlinePresence: .single(false), + peerInputActivityManager: nil, + auxiliaryMethods: auxiliaryMethods + ) + } + } + default: + assertionFailure("Unexpected accountState \(accountState)") + return .single(nil) + } + } else { + return .single(nil) + } + } + } + } + } +} diff --git a/submodules/TelegramCore/Sources/Account/AccountManager.swift b/submodules/TelegramCore/Sources/Account/AccountManager.swift index 52b68a2775..6c36ccaab2 100644 --- a/submodules/TelegramCore/Sources/Account/AccountManager.swift +++ b/submodules/TelegramCore/Sources/Account/AccountManager.swift @@ -282,36 +282,6 @@ public func performAppGroupUpgrades(appGroupPath: String, rootPath: String) { } } -public final class TemporaryAccount { - public let id: AccountRecordId - public let basePath: String - public let postbox: Postbox - - init(id: AccountRecordId, basePath: String, postbox: Postbox) { - self.id = id - self.basePath = basePath - self.postbox = postbox - } -} - -public func temporaryAccount(manager: AccountManager, rootPath: String, encryptionParameters: ValueBoxEncryptionParameters) -> Signal { - return manager.allocatedTemporaryAccountId() - |> mapToSignal { id -> Signal in - let path = "\(rootPath)/\(accountRecordIdPathName(id))" - return openPostbox(basePath: path + "/postbox", seedConfiguration: telegramPostboxSeedConfiguration, encryptionParameters: encryptionParameters, timestampForAbsoluteTimeBasedOperations: Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970), isTemporary: false, isReadOnly: false, useCopy: false) - |> mapToSignal { result -> Signal in - switch result { - case .upgrading: - return .complete() - case .error: - return .complete() - case let .postbox(postbox): - return .single(TemporaryAccount(id: id, basePath: path, postbox: postbox)) - } - } - } -} - public func currentAccount(allocateIfNotExists: Bool, networkArguments: NetworkInitializationArguments, supplementary: Bool, manager: AccountManager, rootPath: String, auxiliaryMethods: AccountAuxiliaryMethods, encryptionParameters: ValueBoxEncryptionParameters) -> Signal { return manager.currentAccountRecord(allocateIfNotExists: allocateIfNotExists) |> distinctUntilChanged(isEqual: { lhs, rhs in diff --git a/submodules/TelegramCore/Sources/Network/Network.swift b/submodules/TelegramCore/Sources/Network/Network.swift index af638d717a..438201a3a5 100644 --- a/submodules/TelegramCore/Sources/Network/Network.swift +++ b/submodules/TelegramCore/Sources/Network/Network.swift @@ -423,16 +423,6 @@ public struct NetworkInitializationArguments { private let cloudDataContext = Atomic(value: nil) #endif -private final class SharedContextStore { - struct Key: Hashable { - var accountId: AccountRecordId - } - - var contexts: [Key: MTContext] = [:] -} - -private let sharedContexts = Atomic(value: SharedContextStore()) - func initializedNetwork(accountId: AccountRecordId, arguments: NetworkInitializationArguments, supplementary: Bool, datacenterId: Int, keychain: Keychain, basePath: String, testingEnvironment: Bool, languageCode: String?, proxySettings: ProxySettings?, networkSettings: NetworkSettings?, phoneNumber: String?) -> Signal { return Signal { subscriber in let queue = Queue() @@ -475,19 +465,7 @@ func initializedNetwork(accountId: AccountRecordId, arguments: NetworkInitializa let useTempAuthKeys: Bool = true - var contextValue: MTContext? - sharedContexts.with { store in - let key = SharedContextStore.Key(accountId: accountId) - - let context: MTContext - - context = MTContext(serialization: serialization, encryptionProvider: arguments.encryptionProvider, apiEnvironment: apiEnvironment, isTestingEnvironment: testingEnvironment, useTempAuthKeys: useTempAuthKeys) - store.contexts[key] = context - - contextValue = context - } - - let context = contextValue! + let context = MTContext(serialization: serialization, encryptionProvider: arguments.encryptionProvider, apiEnvironment: apiEnvironment, isTestingEnvironment: testingEnvironment, useTempAuthKeys: useTempAuthKeys) let seedAddressList: [Int: [String]] @@ -539,10 +517,6 @@ func initializedNetwork(accountId: AccountRecordId, arguments: NetworkInitializa #endif context.setDiscoverBackupAddressListSignal(MTBackupAddressSignals.fetchBackupIps(testingEnvironment, currentContext: context, additionalSource: wrappedAdditionalSource, phoneNumber: phoneNumber)) - #if DEBUG - //let _ = MTBackupAddressSignals.fetchBackupIps(testingEnvironment, currentContext: context, additionalSource: wrappedAdditionalSource, phoneNumber: phoneNumber).start(next: nil) - #endif - let mtProto = MTProto(context: context, datacenterId: datacenterId, usageCalculationInfo: usageCalculationInfo(basePath: basePath, category: nil), requiredAuthToken: nil, authTokenMasterDatacenterId: 0)! mtProto.useTempAuthKeys = context.useTempAuthKeys mtProto.checkForProxyConnectionIssues = true diff --git a/submodules/TelegramCore/Sources/State/AccountStateManager.swift b/submodules/TelegramCore/Sources/State/AccountStateManager.swift index bbed49334d..5082cf9a8d 100644 --- a/submodules/TelegramCore/Sources/State/AccountStateManager.swift +++ b/submodules/TelegramCore/Sources/State/AccountStateManager.swift @@ -52,15 +52,15 @@ public enum DeletedMessageId: Hashable { public final class AccountStateManager { private let queue = Queue() - private let accountPeerId: PeerId + public let accountPeerId: PeerId private let accountManager: AccountManager - private let postbox: Postbox - private let network: Network - private let callSessionManager: CallSessionManager + public let postbox: Postbox + public let network: Network + private let callSessionManager: CallSessionManager? private let addIsContactUpdates: ([(PeerId, Bool)]) -> Void private let shouldKeepOnlinePresence: Signal - private let peerInputActivityManager: PeerInputActivityManager + private let peerInputActivityManager: PeerInputActivityManager? let auxiliaryMethods: AccountAuxiliaryMethods var transformOutgoingMessageMedia: TransformOutgoingMessageMedia? @@ -166,7 +166,7 @@ public final class AccountStateManager { private let appliedQtsPromise = Promise(nil) private let appliedQtsDisposable = MetaDisposable() - init(accountPeerId: PeerId, accountManager: AccountManager, postbox: Postbox, network: Network, callSessionManager: CallSessionManager, addIsContactUpdates: @escaping ([(PeerId, Bool)]) -> Void, shouldKeepOnlinePresence: Signal, peerInputActivityManager: PeerInputActivityManager, auxiliaryMethods: AccountAuxiliaryMethods) { + init(accountPeerId: PeerId, accountManager: AccountManager, postbox: Postbox, network: Network, callSessionManager: CallSessionManager?, addIsContactUpdates: @escaping ([(PeerId, Bool)]) -> Void, shouldKeepOnlinePresence: Signal, peerInputActivityManager: PeerInputActivityManager?, auxiliaryMethods: AccountAuxiliaryMethods) { self.accountPeerId = accountPeerId self.accountManager = accountManager self.postbox = postbox @@ -183,9 +183,14 @@ public final class AccountStateManager { self.operationDisposable.dispose() self.appliedMaxMessageIdDisposable.dispose() self.appliedQtsDisposable.dispose() + + var postbox: Postbox? = self.postbox + postbox?.queue.async { + postbox = nil + } } - func reset() { + public func reset() { self.queue.async { if self.updateService == nil { self.updateService = UpdateMessageService(peerId: self.accountPeerId) @@ -641,7 +646,7 @@ public final class AccountStateManager { let topOperation = strongSelf.operations.removeFirst() if case .processEvents(operationId, _) = topOperation.content { if !events.updatedTypingActivities.isEmpty { - strongSelf.peerInputActivityManager.transaction { manager in + strongSelf.peerInputActivityManager?.transaction { manager in for (chatPeerId, peerActivities) in events.updatedTypingActivities { for (peerId, activity) in peerActivities { if let activity = activity { @@ -661,12 +666,12 @@ public final class AccountStateManager { } if !events.updatedCalls.isEmpty { for call in events.updatedCalls { - strongSelf.callSessionManager.updateSession(call, completion: { _ in }) + strongSelf.callSessionManager?.updateSession(call, completion: { _ in }) } } if !events.addedCallSignalingData.isEmpty { for (id, data) in events.addedCallSignalingData { - strongSelf.callSessionManager.addCallSignalingData(id: id, data: data) + strongSelf.callSessionManager?.addCallSignalingData(id: id, data: data) } } if !events.updatedGroupCallParticipants.isEmpty { @@ -1046,9 +1051,13 @@ public final class AccountStateManager { for update in updates { switch update { case let .updatePhoneCall(phoneCall): - self.callSessionManager.updateSession(phoneCall, completion: { result in - completion(result) - }) + if let callSessionManager = self.callSessionManager { + callSessionManager.updateSession(phoneCall, completion: { result in + completion(result) + }) + } else { + completion(nil) + } return default: break diff --git a/submodules/TelegramCore/Sources/SyncCore/SyncCore_StandaloneAccountTransaction.swift b/submodules/TelegramCore/Sources/SyncCore/SyncCore_StandaloneAccountTransaction.swift index 6127a574fd..09d01b0d08 100644 --- a/submodules/TelegramCore/Sources/SyncCore/SyncCore_StandaloneAccountTransaction.swift +++ b/submodules/TelegramCore/Sources/SyncCore/SyncCore_StandaloneAccountTransaction.swift @@ -97,9 +97,9 @@ public enum AccountTransactionError { case couldNotOpen } -public func accountTransaction(rootPath: String, id: AccountRecordId, encryptionParameters: ValueBoxEncryptionParameters, isReadOnly: Bool, useCopy: Bool = false, transaction: @escaping (Postbox, Transaction) -> T) -> Signal { +public func accountTransaction(rootPath: String, id: AccountRecordId, encryptionParameters: ValueBoxEncryptionParameters, isReadOnly: Bool, useCopy: Bool = false, useCaches: Bool = true, transaction: @escaping (Postbox, Transaction) -> T) -> Signal { let path = "\(rootPath)/\(accountRecordIdPathName(id))" - let postbox = openPostbox(basePath: path + "/postbox", seedConfiguration: telegramPostboxSeedConfiguration, encryptionParameters: encryptionParameters, timestampForAbsoluteTimeBasedOperations: Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970), isTemporary: true, isReadOnly: isReadOnly, useCopy: useCopy) + let postbox = openPostbox(basePath: path + "/postbox", seedConfiguration: telegramPostboxSeedConfiguration, encryptionParameters: encryptionParameters, timestampForAbsoluteTimeBasedOperations: Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970), isTemporary: true, isReadOnly: isReadOnly, useCopy: useCopy, useCaches: useCaches) return postbox |> castError(AccountTransactionError.self) |> mapToSignal { value -> Signal in diff --git a/submodules/TelegramUI/Sources/AppDelegate.swift b/submodules/TelegramUI/Sources/AppDelegate.swift index e4e14c547f..2051507394 100644 --- a/submodules/TelegramUI/Sources/AppDelegate.swift +++ b/submodules/TelegramUI/Sources/AppDelegate.swift @@ -677,7 +677,7 @@ final class SharedApplicationContext { }) let accountManagerSignal = Signal, NoError> { subscriber in - let accountManager = AccountManager(basePath: rootPath + "/accounts-metadata", isTemporary: false, isReadOnly: false) + let accountManager = AccountManager(basePath: rootPath + "/accounts-metadata", isTemporary: false, isReadOnly: false, useCaches: true) return (upgradedAccounts(accountManager: accountManager, rootPath: rootPath, encryptionParameters: encryptionParameters) |> deliverOnMainQueue).start(next: { progress in if self.dataImportSplash == nil { @@ -1489,6 +1489,10 @@ final class SharedApplicationContext { } public func pushRegistry(_ registry: PKPushRegistry, didReceiveIncomingPushWith payload: PKPushPayload, for type: PKPushType) { + if "".isEmpty { + return; + } + if #available(iOS 9.0, *) { /*guard var encryptedPayload = payload.dictionaryPayload["p"] as? String else { return diff --git a/submodules/TelegramUI/Sources/NotificationContentContext.swift b/submodules/TelegramUI/Sources/NotificationContentContext.swift index 7389aea8f2..e7a3058301 100644 --- a/submodules/TelegramUI/Sources/NotificationContentContext.swift +++ b/submodules/TelegramUI/Sources/NotificationContentContext.swift @@ -94,7 +94,7 @@ public final class NotificationViewControllerImpl { if sharedAccountContext == nil { initializeAccountManagement() - let accountManager = AccountManager(basePath: rootPath + "/accounts-metadata", isTemporary: true, isReadOnly: false) + let accountManager = AccountManager(basePath: rootPath + "/accounts-metadata", isTemporary: true, isReadOnly: false, useCaches: false) var initialPresentationDataAndSettings: InitialPresentationDataAndSettings? let semaphore = DispatchSemaphore(value: 0) diff --git a/submodules/TelegramUI/Sources/OpenUrl.swift b/submodules/TelegramUI/Sources/OpenUrl.swift index a53cf2e052..a3aeba2cfd 100644 --- a/submodules/TelegramUI/Sources/OpenUrl.swift +++ b/submodules/TelegramUI/Sources/OpenUrl.swift @@ -624,10 +624,10 @@ func openExternalUrlImpl(context: AccountContext, urlContext: OpenURLContext, ur game = value } else if queryItem.name == "post" { post = value - } else if queryItem.name == "voicechat" { + } else if queryItem.name == "voicechat" || queryItem.name == "videochat" || queryItem.name == "livestream" { voiceChat = value } - } else if queryItem.name == "voicechat" { + } else if queryItem.name == "voicechat" || queryItem.name == "videochat" || queryItem.name == "livestream" { voiceChat = "" } } diff --git a/submodules/TelegramUI/Sources/ShareExtensionContext.swift b/submodules/TelegramUI/Sources/ShareExtensionContext.swift index c27a0ad02e..cc908889e4 100644 --- a/submodules/TelegramUI/Sources/ShareExtensionContext.swift +++ b/submodules/TelegramUI/Sources/ShareExtensionContext.swift @@ -205,7 +205,7 @@ public class ShareRootControllerImpl { let internalContext: InternalContext - let accountManager = AccountManager(basePath: rootPath + "/accounts-metadata", isTemporary: true, isReadOnly: false) + let accountManager = AccountManager(basePath: rootPath + "/accounts-metadata", isTemporary: true, isReadOnly: false, useCaches: false) if let globalInternalContext = globalInternalContext { internalContext = globalInternalContext diff --git a/submodules/TelegramUI/Sources/UpgradedAccounts.swift b/submodules/TelegramUI/Sources/UpgradedAccounts.swift index 8423358e4f..756300e25d 100644 --- a/submodules/TelegramUI/Sources/UpgradedAccounts.swift +++ b/submodules/TelegramUI/Sources/UpgradedAccounts.swift @@ -111,204 +111,11 @@ public func upgradedAccounts(accountManager: AccountManager mapToSignal { version, currentId -> Signal in - guard let version = version else { - return accountManager.transaction { transaction -> Void in - transaction.setVersion(4) - } - |> ignoreValues - |> mapToSignal { _ -> Signal in - } + return accountManager.transaction { transaction -> Void in + transaction.setVersion(4) } - var signal: Signal = .complete() - if version < 1 { - if let currentId = currentId { - let upgradePreferences = accountPreferenceEntries(rootPath: rootPath, id: currentId, keys: Set(preferencesKeyMapping.keys.map({ $0.key }) + applicationSpecificPreferencesKeyMapping.keys.map({ $0.key })), encryptionParameters: encryptionParameters) - |> mapToSignal { result -> Signal in - switch result { - case let .progress(progress): - return .single(progress) - case let .result(path, values): - return accountManager.transaction { transaction -> Void in - for (key, value) in values { - var upgradedKey: ValueBoxKey? - for (k, v) in preferencesKeyMapping { - if k.key == key { - upgradedKey = v.key - break - } - } - for (k, v) in applicationSpecificPreferencesKeyMapping { - if k.key == key { - upgradedKey = v.key - break - } - } - if let upgradedKey = upgradedKey { - transaction.updateSharedData(upgradedKey, { _ in - return upgradedSharedDataValue(value) - }) - } - } - - if let value = values[LegacyApplicationSpecificPreferencesKeyValues.presentationThemeSettings.key]?.get(PresentationThemeSettings.self) { - let mediaBox = MediaBox(basePath: path + "/postbox/media") - let wallpapers = Array(value.themeSpecificChatWallpapers.values) - for wallpaper in wallpapers { - switch wallpaper { - case let .file(file): - if let path = mediaBox.completedResourcePath(file.file.resource), let data = try? Data(contentsOf: URL(fileURLWithPath: path), options: .mappedRead) { - accountManager.mediaBox.storeResourceData(file.file.resource.id, data: data) - let _ = accountManager.mediaBox.cachedResourceRepresentation(file.file.resource, representation: CachedScaledImageRepresentation(size: CGSize(width: 720.0, height: 720.0), mode: .aspectFit), complete: true, fetch: true).start() - if wallpaper.isPattern { - } else { - if file.settings.blur { - let _ = accountManager.mediaBox.cachedResourceRepresentation(file.file.resource, representation: CachedBlurredWallpaperRepresentation(), complete: true, fetch: true).start() - } - } - } - case let .image(representations, _): - for representation in representations { - let resource = representation.resource - if let path = mediaBox.completedResourcePath(resource), let data = try? Data(contentsOf: URL(fileURLWithPath: path), options: .mappedRead) { - accountManager.mediaBox.storeResourceData(resource.id, data: data) - let _ = mediaBox.cachedResourceRepresentation(resource, representation: CachedScaledImageRepresentation(size: CGSize(width: 720.0, height: 720.0), mode: .aspectFit), complete: true, fetch: true).start() - } - } - default: - break - } - } - } - - transaction.setVersion(1) - } - |> mapToSignal { _ -> Signal in - return .complete() - } - } - } - signal = signal |> then(upgradePreferences) - } else { - let upgradePreferences = accountManager.transaction { transaction -> Void in - transaction.setVersion(1) - } - |> mapToSignal { _ -> Signal in - return .complete() - } - signal = signal |> then(upgradePreferences) + |> ignoreValues + |> mapToSignal { _ -> Signal in } - } - if version < 2 { - if let currentId = currentId { - let upgradeNotices = accountNoticeEntries(rootPath: rootPath, id: currentId, encryptionParameters: encryptionParameters) - |> mapToSignal { result -> Signal in - switch result { - case let .progress(progress): - return .single(progress) - case let .result(_, values): - return accountManager.transaction { transaction -> Void in - for (key, value) in values { - transaction.setNotice(NoticeEntryKey(namespace: ValueBoxKey(length: 0), key: key), value) - } - - transaction.setVersion(2) - } - |> mapToSignal { _ -> Signal in - return .complete() - } - } - } - signal = signal |> then(upgradeNotices) - } else { - let upgradeNotices = accountManager.transaction { transaction -> Void in - transaction.setVersion(2) - } - |> mapToSignal { _ -> Signal in - return .complete() - } - signal = signal |> then(upgradeNotices) - } - - let upgradeSortOrder = accountManager.transaction { transaction -> Void in - var index: Int32 = 0 - for record in transaction.getRecords() { - transaction.updateRecord(record.id, { _ in - return AccountRecord(id: record.id, attributes: record.attributes + [.sortOrder(AccountSortOrderAttribute(order: index))], temporarySessionId: record.temporarySessionId) - }) - index += 1 - } - } - |> mapToSignal { _ -> Signal in - return .complete() - } - signal = signal |> then(upgradeSortOrder) - } - if version < 3 { - if let currentId = currentId { - let upgradeAccessChallengeData = accountLegacyAccessChallengeData(rootPath: rootPath, id: currentId, encryptionParameters: encryptionParameters) - |> mapToSignal { result -> Signal in - switch result { - case let .progress(progress): - return .single(progress) - case let .result(accessChallengeData): - return accountManager.transaction { transaction -> Void in - if case .none = transaction.getAccessChallengeData() { - transaction.setAccessChallengeData(accessChallengeData) - } - - transaction.setVersion(3) - } - |> mapToSignal { _ -> Signal in - return .complete() - } - } - } - signal = signal |> then(upgradeAccessChallengeData) - } else { - let upgradeAccessChallengeData = accountManager.transaction { transaction -> Void in - transaction.setVersion(3) - } - |> mapToSignal { _ -> Signal in - return .complete() - } - signal = signal |> then(upgradeAccessChallengeData) - } - } - if version < 4 { - let updatedContactSynchronizationSettings = accountManager.transaction { transaction -> (ContactSynchronizationSettings, [AccountRecordId]) in - return (transaction.getSharedData(ApplicationSpecificSharedDataKeys.contactSynchronizationSettings)?.get(ContactSynchronizationSettings.self) ?? ContactSynchronizationSettings.defaultSettings, transaction.getRecords().map({ $0.id })) - } - |> mapToSignal { globalSettings, ids -> Signal in - var importSignal: Signal = .complete() - for id in ids { - let importInfoAccounttSignal = accountTransaction(rootPath: rootPath, id: id, encryptionParameters: encryptionParameters, isReadOnly: false, transaction: { _, transaction -> Void in - transaction.updatePreferencesEntry(key: PreferencesKeys.contactsSettings, { current in - var settings = current?.get(ContactsSettings.self) ?? ContactsSettings.defaultSettings - settings.synchronizeContacts = globalSettings._legacySynchronizeDeviceContacts - return PreferencesEntry(settings) - }) - }) - |> ignoreValues - |> `catch` { _ -> Signal in - return .complete() - } - importSignal = importSignal |> then(importInfoAccounttSignal) - } - return importSignal - } - - let applyVersion = accountManager.transaction { transaction -> Void in - transaction.setVersion(4) - } - |> ignoreValues - signal = signal |> then( - (updatedContactSynchronizationSettings - |> then( - applyVersion - )) |> mapToSignal { _ -> Signal in - } - ) - } - return signal } } diff --git a/submodules/UrlHandling/Sources/UrlHandling.swift b/submodules/UrlHandling/Sources/UrlHandling.swift index 17d07d9177..bb4b21503c 100644 --- a/submodules/UrlHandling/Sources/UrlHandling.swift +++ b/submodules/UrlHandling/Sources/UrlHandling.swift @@ -136,10 +136,10 @@ public func parseInternalUrl(query: String) -> ParsedInternalUrl? { return .peerName(peerName, .groupBotStart(value)) } else if queryItem.name == "game" { return nil - } else if queryItem.name == "voicechat" { + } else if queryItem.name == "voicechat" || queryItem.name == "videochat" || queryItem.name == "livestream" { return .peerName(peerName, .voiceChat(value)) } - } else if queryItem.name == "voicechat" { + } else if queryItem.name == "voicechat" || queryItem.name == "videochat" || queryItem.name == "livestream" { return .peerName(peerName, .voiceChat(nil)) } } From d04f8798c68a4b3a8f1d0fd12da8d581076efc94 Mon Sep 17 00:00:00 2001 From: Ali <> Date: Tue, 14 Sep 2021 18:47:43 +0400 Subject: [PATCH 07/30] Separate regular and channel state sync --- .../Sources/NotificationService.swift | 126 +++++++++++++++- .../State/AccountStateManagementUtils.swift | 43 ++++-- .../Sources/State/AccountStateManager.swift | 138 ++++++++++++++++-- 3 files changed, 280 insertions(+), 27 deletions(-) diff --git a/Telegram/NotificationService/Sources/NotificationService.swift b/Telegram/NotificationService/Sources/NotificationService.swift index 0b919542ea..92d9b2181f 100644 --- a/Telegram/NotificationService/Sources/NotificationService.swift +++ b/Telegram/NotificationService/Sources/NotificationService.swift @@ -35,7 +35,11 @@ private struct NotificationContent { var title: String? var subtitle: String? var body: String? + var threadId: String? + var sound: String? var badge: Int? + var category: String? + var userInfo: [AnyHashable: Any] = [:] func asNotificationContent() -> UNNotificationContent { let content = UNMutableNotificationContent() @@ -44,10 +48,24 @@ private struct NotificationContent { content.subtitle = self.subtitle ?? "" content.body = self.body ?? "" + if let threadId = self.threadId { + content.threadIdentifier = threadId + } + + if let sound = self.sound { + content.sound = UNNotificationSound(named: UNNotificationSoundName(rawValue: sound)) + } + if let badge = self.badge { content.badge = badge as NSNumber } + if let category = self.category { + content.categoryIdentifier = category + } + + content.userInfo = self.userInfo + return content } } @@ -174,11 +192,79 @@ private final class NotificationServiceHandler { return } + var peerId: PeerId? + var messageId: MessageId.Id? + + if let messageIdString = payloadJson["msg_id"] as? String { + content.userInfo["msg_id"] = messageIdString + messageId = Int32(messageIdString) + } + + if let fromIdString = payloadJson["from_id"] as? String { + content.userInfo["from_id"] = fromIdString + if let userIdValue = Int64(fromIdString) { + peerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(userIdValue)) + } + } else if let chatIdString = payloadJson["chat_id"] as? String { + content.userInfo["chat_id"] = chatIdString + if let chatIdValue = Int64(chatIdString) { + peerId = PeerId(namespace: Namespaces.Peer.CloudGroup, id: PeerId.Id._internalFromInt64Value(chatIdValue)) + } + } else if let channelIdString = payloadJson["channel_id"] as? String { + content.userInfo["channel_id"] = channelIdString + if let channelIdValue = Int64(channelIdString) { + peerId = PeerId(namespace: Namespaces.Peer.CloudChannel, id: PeerId.Id._internalFromInt64Value(channelIdValue)) + } + } + + if let silentString = payloadJson["silent"] as? String { + if let silentValue = Int(silentString), silentValue != 0 { + if let title = content.title { + content.title = "\(title) 🔕" + } + } + } + + if let threadId = aps["thread-id"] as? String { + content.threadId = threadId + } + + if let sound = aps["sound"] as? String { + content.sound = sound + } + + if let category = aps["category"] as? String { + content.category = category + + let _ = messageId + + /*if (peerId != 0 && messageId != 0 && parsedAttachment != nil && attachmentData != nil) { + userInfo[@"peerId"] = @(peerId); + userInfo[@"messageId.namespace"] = @(0); + userInfo[@"messageId.id"] = @(messageId); + + userInfo[@"media"] = [attachmentData base64EncodedStringWithOptions:0]; + + if (isExpandableMedia) { + if ([categoryString isEqualToString:@"r"]) { + _bestAttemptContent.categoryIdentifier = @"withReplyMedia"; + } else if ([categoryString isEqualToString:@"m"]) { + _bestAttemptContent.categoryIdentifier = @"withMuteMedia"; + } + } + }*/ + } + + /*if (accountInfos.accounts.count > 1) { + if (_bestAttemptContent.title.length != 0 && account.peerName.length != 0) { + _bestAttemptContent.title = [NSString stringWithFormat:@"%@ → %@", _bestAttemptContent.title, account.peerName]; + } + }*/ + updateCurrentContent(content.asNotificationContent()) - if let stateManager = strongSelf.stateManager { - stateManager.network.shouldKeepConnection.set(.single(true)) - strongSelf.pollDisposable.set(stateManager.pollStateUpdateCompletion().start(completed: { + if let stateManager = strongSelf.stateManager, let peerId = peerId { + let pollCompletion: () -> Void = { queue.async { guard let strongSelf = self, let stateManager = strongSelf.stateManager else { completed() @@ -197,8 +283,38 @@ private final class NotificationServiceHandler { completed() }) } - })) - stateManager.reset() + } + + stateManager.network.shouldKeepConnection.set(.single(true)) + if peerId.namespace == Namespaces.Peer.CloudChannel { + strongSelf.pollDisposable.set(pollChannelOnce( + postbox: stateManager.postbox, + network: stateManager.network, + peerId: peerId, + stateManager: stateManager, + delayCompletion: false + ).start(completed: { + pollCompletion() + })) + } else { + enum ControlError { + case restart + } + let signal = stateManager.standalonePollDifference() + |> castError(ControlError.self) + |> mapToSignal { result -> Signal in + if result { + return .complete() + } else { + return .fail(.restart) + } + } + |> restartIfError + + strongSelf.pollDisposable.set(signal.start(completed: { + pollCompletion() + })) + } } else { completed() } diff --git a/submodules/TelegramCore/Sources/State/AccountStateManagementUtils.swift b/submodules/TelegramCore/Sources/State/AccountStateManagementUtils.swift index a0da227306..acb08d5154 100644 --- a/submodules/TelegramCore/Sources/State/AccountStateManagementUtils.swift +++ b/submodules/TelegramCore/Sources/State/AccountStateManagementUtils.swift @@ -1706,8 +1706,8 @@ private func resolveMissingPeerChatInfos(network: Network, state: AccountMutable } } -func keepPollingChannel(postbox: Postbox, network: Network, peerId: PeerId, stateManager: AccountStateManager) -> Signal { - let signal: Signal = postbox.transaction { transaction -> Signal in +public func pollChannelOnce(postbox: Postbox, network: Network, peerId: PeerId, stateManager: AccountStateManager, delayCompletion: Bool) -> Signal { + return postbox.transaction { transaction -> Signal in guard let accountState = (transaction.getState() as? AuthorizedAccountState)?.state, let peer = transaction.getPeer(peerId) else { return .complete() |> delay(30.0, queue: Queue.concurrentDefaultQueue()) @@ -1745,15 +1745,25 @@ func keepPollingChannel(postbox: Postbox, network: Network, peerId: PeerId, stat |> mapToSignal { finalState -> Signal in return stateManager.addReplayAsynchronouslyBuiltFinalState(finalState) |> mapToSignal { _ -> Signal in - return .single(timeout ?? 30) |> then(.complete() |> delay(Double(timeout ?? 30), queue: Queue.concurrentDefaultQueue())) + if delayCompletion { + return .single(timeout ?? 30) + |> then( + .complete() + |> delay(Double(timeout ?? 30), queue: Queue.concurrentDefaultQueue()) + ) + } else { + return .single(timeout ?? 30) + } } } } } |> switchToLatest +} + +func keepPollingChannel(postbox: Postbox, network: Network, peerId: PeerId, stateManager: AccountStateManager) -> Signal { + return pollChannelOnce(postbox: postbox, network: network, peerId: peerId, stateManager: stateManager, delayCompletion: true) |> restart - - return signal |> delay(1.0, queue: .concurrentDefaultQueue()) } @@ -2254,7 +2264,18 @@ private func recordPeerActivityTimestamp(peerId: PeerId, timestamp: Int32, into } } -func replayFinalState(accountManager: AccountManager, postbox: Postbox, accountPeerId: PeerId, mediaBox: MediaBox, encryptionProvider: EncryptionProvider, transaction: Transaction, auxiliaryMethods: AccountAuxiliaryMethods, finalState: AccountFinalState, removePossiblyDeliveredMessagesUniqueIds: [Int64: PeerId]) -> AccountReplayedFinalState? { +func replayFinalState( + accountManager: AccountManager, + postbox: Postbox, + accountPeerId: PeerId, + mediaBox: MediaBox, + encryptionProvider: EncryptionProvider, + transaction: Transaction, + auxiliaryMethods: AccountAuxiliaryMethods, + finalState: AccountFinalState, + removePossiblyDeliveredMessagesUniqueIds: [Int64: PeerId], + ignoreDate: Bool +) -> AccountReplayedFinalState? { let verified = verifyTransaction(transaction, finalState: finalState.state) if !verified { Logger.shared.log("State", "failed to verify final state") @@ -2780,10 +2801,14 @@ func replayFinalState(accountManager: AccountManager(nil) private let appliedQtsDisposable = MetaDisposable() - init(accountPeerId: PeerId, accountManager: AccountManager, postbox: Postbox, network: Network, callSessionManager: CallSessionManager?, addIsContactUpdates: @escaping ([(PeerId, Bool)]) -> Void, shouldKeepOnlinePresence: Signal, peerInputActivityManager: PeerInputActivityManager?, auxiliaryMethods: AccountAuxiliaryMethods) { + init( + accountPeerId: PeerId, + accountManager: AccountManager, + postbox: Postbox, + network: Network, + callSessionManager: CallSessionManager?, + addIsContactUpdates: @escaping ([(PeerId, Bool)]) -> Void, + shouldKeepOnlinePresence: Signal, + peerInputActivityManager: PeerInputActivityManager?, + auxiliaryMethods: AccountAuxiliaryMethods + ) { self.accountPeerId = accountPeerId self.accountManager = accountManager self.postbox = postbox @@ -423,10 +433,7 @@ public final class AccountStateManager { if let authorizedState = state.state { let flags: Int32 = 0 let ptsTotalLimit: Int32? = nil - #if DEBUG - //flags = 1 << 0 - //ptsTotalLimit = 1000 - #endif + let request = network.request(Api.functions.updates.getDifference(flags: flags, pts: authorizedState.pts, ptsTotalLimit: ptsTotalLimit, date: authorizedState.date, qts: authorizedState.qts)) |> map(Optional.init) |> `catch` { error -> Signal in @@ -446,10 +453,6 @@ public final class AccountStateManager { switch difference { case .differenceTooLong: preconditionFailure() - /*return accountStateReset(postbox: postbox, network: network, accountPeerId: accountPeerId) |> mapToSignal { _ -> Signal<(Api.updates.Difference?, AccountReplayedFinalState?), NoError> in - return .complete() - } - |> then(.single((nil, nil)))*/ default: return initialStateWithDifference(postbox: postbox, difference: difference) |> mapToSignal { state -> Signal<(difference: Api.updates.Difference?, finalStatte: AccountReplayedFinalState?, skipBecauseOfError: Bool), NoError> in @@ -468,7 +471,7 @@ public final class AccountStateManager { let removePossiblyDeliveredMessagesUniqueIds = self?.removePossiblyDeliveredMessagesUniqueIds ?? Dictionary() return postbox.transaction { transaction -> (difference: Api.updates.Difference?, finalStatte: AccountReplayedFinalState?, skipBecauseOfError: Bool) in let startTime = CFAbsoluteTimeGetCurrent() - let replayedState = replayFinalState(accountManager: accountManager, postbox: postbox, accountPeerId: accountPeerId, mediaBox: mediaBox, encryptionProvider: network.encryptionProvider, transaction: transaction, auxiliaryMethods: auxiliaryMethods, finalState: finalState, removePossiblyDeliveredMessagesUniqueIds: removePossiblyDeliveredMessagesUniqueIds) + let replayedState = replayFinalState(accountManager: accountManager, postbox: postbox, accountPeerId: accountPeerId, mediaBox: mediaBox, encryptionProvider: network.encryptionProvider, transaction: transaction, auxiliaryMethods: auxiliaryMethods, finalState: finalState, removePossiblyDeliveredMessagesUniqueIds: removePossiblyDeliveredMessagesUniqueIds, ignoreDate: false) let deltaTime = CFAbsoluteTimeGetCurrent() - startTime if deltaTime > 1.0 { Logger.shared.log("State", "replayFinalState took \(deltaTime)s") @@ -515,7 +518,7 @@ public final class AccountStateManager { if let difference = difference { switch difference { case .differenceSlice: - strongSelf.addOperation(.pollDifference(events), position: .first) + strongSelf.addOperation(.pollDifference(events), position: .first) default: if !events.isEmpty { strongSelf.insertProcessEvents(events) @@ -586,7 +589,7 @@ public final class AccountStateManager { return nil } else { let startTime = CFAbsoluteTimeGetCurrent() - let result = replayFinalState(accountManager: accountManager, postbox: postbox, accountPeerId: accountPeerId, mediaBox: mediaBox, encryptionProvider: network.encryptionProvider, transaction: transaction, auxiliaryMethods: auxiliaryMethods, finalState: finalState, removePossiblyDeliveredMessagesUniqueIds: removePossiblyDeliveredMessagesUniqueIds) + let result = replayFinalState(accountManager: accountManager, postbox: postbox, accountPeerId: accountPeerId, mediaBox: mediaBox, encryptionProvider: network.encryptionProvider, transaction: transaction, auxiliaryMethods: auxiliaryMethods, finalState: finalState, removePossiblyDeliveredMessagesUniqueIds: removePossiblyDeliveredMessagesUniqueIds, ignoreDate: false) let deltaTime = CFAbsoluteTimeGetCurrent() - startTime if deltaTime > 1.0 { Logger.shared.log("State", "replayFinalState took \(deltaTime)s") @@ -806,7 +809,7 @@ public final class AccountStateManager { let removePossiblyDeliveredMessagesUniqueIds = self.removePossiblyDeliveredMessagesUniqueIds let signal = self.postbox.transaction { transaction -> AccountReplayedFinalState? in let startTime = CFAbsoluteTimeGetCurrent() - let result = replayFinalState(accountManager: accountManager, postbox: postbox, accountPeerId: accountPeerId, mediaBox: mediaBox, encryptionProvider: network.encryptionProvider, transaction: transaction, auxiliaryMethods: auxiliaryMethods, finalState: finalState, removePossiblyDeliveredMessagesUniqueIds: removePossiblyDeliveredMessagesUniqueIds) + let result = replayFinalState(accountManager: accountManager, postbox: postbox, accountPeerId: accountPeerId, mediaBox: mediaBox, encryptionProvider: network.encryptionProvider, transaction: transaction, auxiliaryMethods: auxiliaryMethods, finalState: finalState, removePossiblyDeliveredMessagesUniqueIds: removePossiblyDeliveredMessagesUniqueIds, ignoreDate: false) let deltaTime = CFAbsoluteTimeGetCurrent() - startTime if deltaTime > 1.0 { Logger.shared.log("State", "replayFinalState took \(deltaTime)s") @@ -834,6 +837,115 @@ public final class AccountStateManager { }) } } + + public func standalonePollDifference() -> Signal { + let queue = self.queue + let accountManager = self.accountManager + let postbox = self.postbox + let network = self.network + let mediaBox = postbox.mediaBox + let accountPeerId = self.accountPeerId + let auxiliaryMethods = self.auxiliaryMethods + + let signal = postbox.stateView() + |> mapToSignal { view -> Signal in + if let state = view.state as? AuthorizedAccountState { + return .single(state) + } else { + return .complete() + } + } + |> take(1) + |> mapToSignal { [weak self] state -> Signal<(difference: Api.updates.Difference?, finalStatte: AccountReplayedFinalState?, skipBecauseOfError: Bool), NoError> in + if let authorizedState = state.state { + let flags: Int32 = 0 + let ptsTotalLimit: Int32? = nil + + let request = network.request(Api.functions.updates.getDifference(flags: flags, pts: authorizedState.pts, ptsTotalLimit: ptsTotalLimit, date: Int32.max, qts: authorizedState.qts)) + |> map(Optional.init) + |> `catch` { error -> Signal in + if error.errorCode == 406 && error.errorDescription == "AUTH_KEY_DUPLICATED" { + return .single(nil) + } else { + return .fail(error) + } + } + |> retryRequest + + return request + |> mapToSignal { difference -> Signal<(difference: Api.updates.Difference?, finalStatte: AccountReplayedFinalState?, skipBecauseOfError: Bool), NoError> in + guard let difference = difference else { + return .single((nil, nil, true)) + } + switch difference { + case .differenceTooLong: + preconditionFailure() + default: + return initialStateWithDifference(postbox: postbox, difference: difference) + |> mapToSignal { state -> Signal<(difference: Api.updates.Difference?, finalStatte: AccountReplayedFinalState?, skipBecauseOfError: Bool), NoError> in + if state.initialState.state != authorizedState { + Logger.shared.log("State", "pollDifference initial state \(authorizedState) != current state \(state.initialState.state)") + return .single((nil, nil, false)) + } else { + return finalStateWithDifference(postbox: postbox, network: network, state: state, difference: difference) + |> deliverOn(queue) + |> mapToSignal { finalState -> Signal<(difference: Api.updates.Difference?, finalStatte: AccountReplayedFinalState?, skipBecauseOfError: Bool), NoError> in + if !finalState.state.preCachedResources.isEmpty { + for (resource, data) in finalState.state.preCachedResources { + mediaBox.storeResourceData(resource.id, data: data) + } + } + let removePossiblyDeliveredMessagesUniqueIds = self?.removePossiblyDeliveredMessagesUniqueIds ?? Dictionary() + return postbox.transaction { transaction -> (difference: Api.updates.Difference?, finalStatte: AccountReplayedFinalState?, skipBecauseOfError: Bool) in + let startTime = CFAbsoluteTimeGetCurrent() + let replayedState = replayFinalState( + accountManager: accountManager, + postbox: postbox, + accountPeerId: accountPeerId, + mediaBox: mediaBox, + encryptionProvider: network.encryptionProvider, + transaction: transaction, + auxiliaryMethods: auxiliaryMethods, + finalState: finalState, + removePossiblyDeliveredMessagesUniqueIds: removePossiblyDeliveredMessagesUniqueIds, + ignoreDate: true + ) + let deltaTime = CFAbsoluteTimeGetCurrent() - startTime + if deltaTime > 1.0 { + Logger.shared.log("State", "replayFinalState took \(deltaTime)s") + } + + if let replayedState = replayedState { + return (difference, replayedState, false) + } else { + return (nil, nil, false) + } + } + } + } + } + } + } + } else { + return .single((nil, nil, false)) + } + } + |> deliverOn(self.queue) + + return signal + |> mapToSignal { difference, _, _ -> Signal in + if let difference = difference { + switch difference { + case .differenceSlice: + return .single(false) + default: + return .single(true) + } + } else { + return .single(true) + } + } + } private func insertProcessEvents(_ events: AccountFinalStateEvents) { if !events.isEmpty { From 4f2c77dcbb4990d1a7dcea7c3450d489549e472d Mon Sep 17 00:00:00 2001 From: Ali <> Date: Tue, 14 Sep 2021 21:13:50 +0400 Subject: [PATCH 08/30] Update sync --- .../Sources/State/AccountStateManager.swift | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/submodules/TelegramCore/Sources/State/AccountStateManager.swift b/submodules/TelegramCore/Sources/State/AccountStateManager.swift index 7de8b25437..6cc2f7b43f 100644 --- a/submodules/TelegramCore/Sources/State/AccountStateManager.swift +++ b/submodules/TelegramCore/Sources/State/AccountStateManager.swift @@ -838,6 +838,50 @@ public final class AccountStateManager { } } + func standaloneReplayAsynchronouslyBuiltFinalState(finalState: AccountFinalState) { + if !finalState.state.preCachedResources.isEmpty { + for (resource, data) in finalState.state.preCachedResources { + self.postbox.mediaBox.storeResourceData(resource.id, data: data) + } + } + + let accountPeerId = self.accountPeerId + let accountManager = self.accountManager + let postbox = self.postbox + let mediaBox = self.postbox.mediaBox + let network = self.network + let auxiliaryMethods = self.auxiliaryMethods + let removePossiblyDeliveredMessagesUniqueIds = self.removePossiblyDeliveredMessagesUniqueIds + let signal = self.postbox.transaction { transaction -> AccountReplayedFinalState? in + let startTime = CFAbsoluteTimeGetCurrent() + let result = replayFinalState(accountManager: accountManager, postbox: postbox, accountPeerId: accountPeerId, mediaBox: mediaBox, encryptionProvider: network.encryptionProvider, transaction: transaction, auxiliaryMethods: auxiliaryMethods, finalState: finalState, removePossiblyDeliveredMessagesUniqueIds: removePossiblyDeliveredMessagesUniqueIds, ignoreDate: false) + let deltaTime = CFAbsoluteTimeGetCurrent() - startTime + if deltaTime > 1.0 { + Logger.shared.log("State", "replayFinalState took \(deltaTime)s") + } + return result + } + |> map({ ($0, finalState) }) + |> deliverOn(self.queue) + + let _ = signal.start(next: { [weak self] replayedState, finalState in + if let strongSelf = self { + if case .replayAsynchronouslyBuiltFinalState = strongSelf.operations.removeFirst().content { + if let replayedState = replayedState { + let events = AccountFinalStateEvents(state: replayedState) + if !events.isEmpty { + strongSelf.insertProcessEvents(events) + } + } + strongSelf.startFirstOperation() + } else { + assertionFailure() + } + completion() + } + }) + } + public func standalonePollDifference() -> Signal { let queue = self.queue let accountManager = self.accountManager From 0f478d3506926299c95ac08226154cef3a59959b Mon Sep 17 00:00:00 2001 From: Ali <> Date: Tue, 14 Sep 2021 21:43:19 +0400 Subject: [PATCH 09/30] Fix build --- .../Sources/NotificationService.swift | 5 +- .../State/AccountStateManagementUtils.swift | 53 +++++++++++++++++-- .../Sources/State/AccountStateManager.swift | 20 ++----- 3 files changed, 55 insertions(+), 23 deletions(-) diff --git a/Telegram/NotificationService/Sources/NotificationService.swift b/Telegram/NotificationService/Sources/NotificationService.swift index 92d9b2181f..4b3e477fa1 100644 --- a/Telegram/NotificationService/Sources/NotificationService.swift +++ b/Telegram/NotificationService/Sources/NotificationService.swift @@ -287,12 +287,11 @@ private final class NotificationServiceHandler { stateManager.network.shouldKeepConnection.set(.single(true)) if peerId.namespace == Namespaces.Peer.CloudChannel { - strongSelf.pollDisposable.set(pollChannelOnce( + strongSelf.pollDisposable.set(standalonePollChannelOnce( postbox: stateManager.postbox, network: stateManager.network, peerId: peerId, - stateManager: stateManager, - delayCompletion: false + stateManager: stateManager ).start(completed: { pollCompletion() })) diff --git a/submodules/TelegramCore/Sources/State/AccountStateManagementUtils.swift b/submodules/TelegramCore/Sources/State/AccountStateManagementUtils.swift index acb08d5154..ae9f48f816 100644 --- a/submodules/TelegramCore/Sources/State/AccountStateManagementUtils.swift +++ b/submodules/TelegramCore/Sources/State/AccountStateManagementUtils.swift @@ -1706,11 +1706,15 @@ private func resolveMissingPeerChatInfos(network: Network, state: AccountMutable } } -public func pollChannelOnce(postbox: Postbox, network: Network, peerId: PeerId, stateManager: AccountStateManager, delayCompletion: Bool) -> Signal { +func pollChannelOnce(postbox: Postbox, network: Network, peerId: PeerId, stateManager: AccountStateManager, delayCompletion: Bool) -> Signal { return postbox.transaction { transaction -> Signal in guard let accountState = (transaction.getState() as? AuthorizedAccountState)?.state, let peer = transaction.getPeer(peerId) else { - return .complete() - |> delay(30.0, queue: Queue.concurrentDefaultQueue()) + if delayCompletion { + return .complete() + |> delay(30.0, queue: Queue.concurrentDefaultQueue()) + } else { + return .complete() + } } var channelStates: [PeerId: AccountStateChannelState] = [:] @@ -1761,6 +1765,49 @@ public func pollChannelOnce(postbox: Postbox, network: Network, peerId: PeerId, |> switchToLatest } +public func standalonePollChannelOnce(postbox: Postbox, network: Network, peerId: PeerId, stateManager: AccountStateManager) -> Signal { + return postbox.transaction { transaction -> Signal in + guard let accountState = (transaction.getState() as? AuthorizedAccountState)?.state, let peer = transaction.getPeer(peerId) else { + return .complete() + } + + var channelStates: [PeerId: AccountStateChannelState] = [:] + if let channelState = transaction.getPeerChatState(peerId) as? ChannelState { + channelStates[peerId] = AccountStateChannelState(pts: channelState.pts) + } + let initialPeers: [PeerId: Peer] = [peerId: peer] + var peerChatInfos: [PeerId: PeerChatInfo] = [:] + let inclusion = transaction.getPeerChatListInclusion(peerId) + var hasValidInclusion = false + switch inclusion { + case .ifHasMessagesOrOneOf: + hasValidInclusion = true + case .notIncluded: + hasValidInclusion = false + } + if hasValidInclusion { + if let notificationSettings = transaction.getPeerNotificationSettings(peerId) as? TelegramPeerNotificationSettings { + peerChatInfos[peerId] = PeerChatInfo(notificationSettings: notificationSettings) + } + } + let initialState = AccountMutableState(initialState: AccountInitialState(state: accountState, peerIds: Set(), peerIdsRequiringLocalChatState: Set(), channelStates: channelStates, peerChatInfos: peerChatInfos, locallyGeneratedMessageTimestamps: [:], cloudReadStates: [:], channelsToPollExplicitely: Set()), initialPeers: initialPeers, initialReferencedMessageIds: Set(), initialStoredMessages: Set(), initialReadInboxMaxIds: [:], storedMessagesByPeerIdAndTimestamp: [:]) + return pollChannel(network: network, peer: peer, state: initialState) + |> mapToSignal { (finalState, _, timeout) -> Signal in + return resolveAssociatedMessages(network: network, state: finalState) + |> mapToSignal { resultingState -> Signal in + return resolveMissingPeerChatInfos(network: network, state: resultingState) + |> map { resultingState, _ -> AccountFinalState in + return AccountFinalState(state: resultingState, shouldPoll: false, incomplete: false, missingUpdatesFromChannels: Set(), discard: false) + } + } + |> mapToSignal { finalState -> Signal in + return stateManager.standaloneReplayAsynchronouslyBuiltFinalState(finalState: finalState) + } + } + } + |> switchToLatest +} + func keepPollingChannel(postbox: Postbox, network: Network, peerId: PeerId, stateManager: AccountStateManager) -> Signal { return pollChannelOnce(postbox: postbox, network: network, peerId: peerId, stateManager: stateManager, delayCompletion: true) |> restart diff --git a/submodules/TelegramCore/Sources/State/AccountStateManager.swift b/submodules/TelegramCore/Sources/State/AccountStateManager.swift index 6cc2f7b43f..f7d93256f4 100644 --- a/submodules/TelegramCore/Sources/State/AccountStateManager.swift +++ b/submodules/TelegramCore/Sources/State/AccountStateManager.swift @@ -838,7 +838,7 @@ public final class AccountStateManager { } } - func standaloneReplayAsynchronouslyBuiltFinalState(finalState: AccountFinalState) { + func standaloneReplayAsynchronouslyBuiltFinalState(finalState: AccountFinalState) -> Signal { if !finalState.state.preCachedResources.isEmpty { for (resource, data) in finalState.state.preCachedResources { self.postbox.mediaBox.storeResourceData(resource.id, data: data) @@ -864,22 +864,8 @@ public final class AccountStateManager { |> map({ ($0, finalState) }) |> deliverOn(self.queue) - let _ = signal.start(next: { [weak self] replayedState, finalState in - if let strongSelf = self { - if case .replayAsynchronouslyBuiltFinalState = strongSelf.operations.removeFirst().content { - if let replayedState = replayedState { - let events = AccountFinalStateEvents(state: replayedState) - if !events.isEmpty { - strongSelf.insertProcessEvents(events) - } - } - strongSelf.startFirstOperation() - } else { - assertionFailure() - } - completion() - } - }) + return signal + |> ignoreValues } public func standalonePollDifference() -> Signal { From ce36439bd2e8f900385219410afb26c9565bb4bb Mon Sep 17 00:00:00 2001 From: Ali <> Date: Sun, 19 Sep 2021 13:55:17 +0300 Subject: [PATCH 10/30] Refactoring --- .../Sources/Node/ChatListNode.swift | 2 +- .../Sources/CachedInstantPages.swift | 26 +- .../Sources/InstantPageStoredState.swift | 46 +- .../LocationUI/Sources/CachedGeocodes.swift | 24 +- .../Sources/MediaPlaybackStoredState.swift | 24 +- .../Postbox/Sources/AccountManager.swift | 4 +- .../AdditionalMessageHistoryViewData.swift | 2 +- .../Postbox/Sources/CachedItemView.swift | 4 +- .../Postbox/Sources/ItemCacheTable.swift | 25 +- .../Postbox/Sources/NoticeEntryView.swift | 4 +- submodules/Postbox/Sources/NoticeTable.swift | 28 +- submodules/Postbox/Sources/Postbox.swift | 37 +- ...aptedPostboxUnkeyedEncodingContainer.swift | 12 + .../Sources/Account/AccountManager.swift | 44 -- .../State/CachedSentMediaReferences.swift | 7 +- .../SyncCore/SyncCore_CachedChannelData.swift | 4 +- .../SyncCore/SyncCore_CachedGroupData.swift | 4 +- .../SyncCore_CachedLocalizationInfos.swift | 14 +- .../SyncCore/SyncCore_CachedRecentPeers.swift | 18 +- .../SyncCore_CachedResolvedByNamePeer.swift | 26 +- ...SyncCore_CachedSecureIdConfiguration.swift | 34 +- .../SyncCore/SyncCore_CachedStickerPack.swift | 36 +- .../SyncCore_CachedStickerQueryResult.swift | 27 +- .../SyncCore_CachedThemesConfiguration.swift | 14 +- ...ncCore_CachedWallpapersConfiguration.swift | 16 +- .../SyncCore_ExportedInvitation.swift | 62 ++- ...ncCore_TemporaryTwoStepPasswordToken.swift | 22 +- .../Auth/TwoStepVerification.swift | 4 +- .../TelegramEngine/Calls/GroupCalls.swift | 24 +- .../Localization/Localizations.swift | 6 +- .../TelegramEngine/Messages/AdMessages.swift | 8 +- .../TelegramEngine/Messages/Polls.swift | 28 +- .../Messages/RequestChatContextResults.swift | 24 +- .../Peers/InvitationLinks.swift | 60 ++- .../TelegramEngine/Peers/RecentPeers.swift | 34 +- .../Peers/ResolvePeerByName.swift | 6 +- .../SecureId/SecureIdConfiguration.swift | 6 +- .../Stickers/CachedStickerPack.swift | 32 +- .../Stickers/SearchStickers.swift | 6 +- submodules/TelegramCore/Sources/Themes.swift | 6 +- .../TelegramCore/Sources/Wallpapers.swift | 6 +- .../TelegramNotices/Sources/Notices.swift | 401 +++++++++--------- .../TelegramUI/Sources/ChatController.swift | 2 +- .../Sources/ChatHistoryEntriesForView.swift | 2 +- .../Sources/DeclareEncodables.swift | 36 -- .../Sources/CachedChannelAdmins.swift | 79 +++- .../Sources/WallpaperCache.swift | 26 +- 47 files changed, 718 insertions(+), 644 deletions(-) diff --git a/submodules/ChatListUI/Sources/Node/ChatListNode.swift b/submodules/ChatListUI/Sources/Node/ChatListNode.swift index 0a8889f411..6121b32cb9 100644 --- a/submodules/ChatListUI/Sources/Node/ChatListNode.swift +++ b/submodules/ChatListUI/Sources/Node/ChatListNode.swift @@ -815,7 +815,7 @@ public final class ChatListNode: ListView { if Namespaces.PeerGroup.archive == groupId { displayArchiveIntro = context.sharedContext.accountManager.noticeEntry(key: ApplicationSpecificNotice.archiveIntroDismissedKey()) |> map { entry -> Bool in - if let value = entry.value as? ApplicationSpecificVariantNotice { + if let value = entry.value?.get(ApplicationSpecificVariantNotice.self) { return !value.value } else { return true diff --git a/submodules/InstantPageCache/Sources/CachedInstantPages.swift b/submodules/InstantPageCache/Sources/CachedInstantPages.swift index 8b528633c6..569d02f99e 100644 --- a/submodules/InstantPageCache/Sources/CachedInstantPages.swift +++ b/submodules/InstantPageCache/Sources/CachedInstantPages.swift @@ -6,7 +6,7 @@ import TelegramCore import TelegramUIPreferences import PersistentStringHash -public final class CachedInstantPage: PostboxCoding { +public final class CachedInstantPage: Codable { public let webPage: TelegramMediaWebpage public let timestamp: Int32 @@ -15,14 +15,20 @@ public final class CachedInstantPage: PostboxCoding { self.timestamp = timestamp } - public init(decoder: PostboxDecoder) { - self.webPage = decoder.decodeObjectForKey("webpage", decoder: { TelegramMediaWebpage(decoder: $0) }) as! TelegramMediaWebpage - self.timestamp = decoder.decodeInt32ForKey("timestamp", orElse: 0) + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: StringCodingKey.self) + + let webPageData = try container.decode(AdaptedPostboxDecoder.RawObjectData.self, forKey: "webpage") + self.webPage = TelegramMediaWebpage(decoder: PostboxDecoder(buffer: MemoryBuffer(data: webPageData.data))) + + self.timestamp = try container.decode(Int32.self, forKey: "timestamp") } - public func encode(_ encoder: PostboxEncoder) { - encoder.encodeObject(self.webPage, forKey: "webpage") - encoder.encodeInt32(self.timestamp, forKey: "timestamp") + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: StringCodingKey.self) + + try container.encode(PostboxEncoder().encodeObjectToRawData(self.webPage), forKey: "webpage") + try container.encode(self.timestamp, forKey: "timestamp") } } @@ -30,7 +36,7 @@ public func cachedInstantPage(postbox: Postbox, url: String) -> Signal CachedInstantPage? in let key = ValueBoxKey(length: 8) key.setInt64(0, value: Int64(bitPattern: url.persistentHashValue)) - if let entry = transaction.retrieveItemCacheEntry(id: ItemCacheEntryId(collectionId: ApplicationSpecificItemCacheCollectionId.cachedInstantPages, key: key)) as? CachedInstantPage { + if let entry = transaction.retrieveItemCacheEntry(id: ItemCacheEntryId(collectionId: ApplicationSpecificItemCacheCollectionId.cachedInstantPages, key: key))?.get(CachedInstantPage.self) { return entry } else { return nil @@ -45,8 +51,8 @@ public func updateCachedInstantPage(postbox: Postbox, url: String, webPage: Tele let key = ValueBoxKey(length: 8) key.setInt64(0, value: Int64(bitPattern: url.persistentHashValue)) let id = ItemCacheEntryId(collectionId: ApplicationSpecificItemCacheCollectionId.cachedInstantPages, key: key) - if let webPage = webPage { - transaction.putItemCacheEntry(id: id, entry: CachedInstantPage(webPage: webPage, timestamp: Int32(CFAbsoluteTimeGetCurrent())), collectionSpec: collectionSpec) + if let webPage = webPage, let entry = CodableEntry(CachedInstantPage(webPage: webPage, timestamp: Int32(CFAbsoluteTimeGetCurrent()))) { + transaction.putItemCacheEntry(id: id, entry: entry, collectionSpec: collectionSpec) } else { transaction.removeItemCacheEntry(id: id) } diff --git a/submodules/InstantPageUI/Sources/InstantPageStoredState.swift b/submodules/InstantPageUI/Sources/InstantPageStoredState.swift index 3334d421cb..992f9e55f0 100644 --- a/submodules/InstantPageUI/Sources/InstantPageStoredState.swift +++ b/submodules/InstantPageUI/Sources/InstantPageStoredState.swift @@ -5,7 +5,7 @@ import Postbox import TelegramCore import TelegramUIPreferences -public final class InstantPageStoredDetailsState: PostboxCoding { +public final class InstantPageStoredDetailsState: Codable { public let index: Int32 public let expanded: Bool public let details: [InstantPageStoredDetailsState] @@ -16,20 +16,24 @@ public final class InstantPageStoredDetailsState: PostboxCoding { self.details = details } - public init(decoder: PostboxDecoder) { - self.index = decoder.decodeInt32ForKey("index", orElse: 0) - self.expanded = decoder.decodeBoolForKey("expanded", orElse: false) - self.details = decoder.decodeObjectArrayForKey("details") + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: StringCodingKey.self) + + self.index = try container.decode(Int32.self, forKey: "index") + self.expanded = try container.decode(Bool.self, forKey: "expanded") + self.details = try container.decode([InstantPageStoredDetailsState].self, forKey: "details") } - public func encode(_ encoder: PostboxEncoder) { - encoder.encodeInt32(self.index, forKey: "index") - encoder.encodeBool(self.expanded, forKey: "expanded") - encoder.encodeObjectArray(self.details, forKey: "details") + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: StringCodingKey.self) + + try container.encode(self.index, forKey: "index") + try container.encode(self.expanded, forKey: "expanded") + try container.encode(self.details, forKey: "details") } } -public final class InstantPageStoredState: PostboxCoding { +public final class InstantPageStoredState: Codable { public let contentOffset: Double public let details: [InstantPageStoredDetailsState] @@ -38,14 +42,18 @@ public final class InstantPageStoredState: PostboxCoding { self.details = details } - public init(decoder: PostboxDecoder) { - self.contentOffset = decoder.decodeDoubleForKey("offset", orElse: 0.0) - self.details = decoder.decodeObjectArrayForKey("details") + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: StringCodingKey.self) + + self.contentOffset = try container.decode(Double.self, forKey: "offset") + self.details = try container.decode([InstantPageStoredDetailsState].self, forKey: "details") } - public func encode(_ encoder: PostboxEncoder) { - encoder.encodeDouble(self.contentOffset, forKey: "offset") - encoder.encodeObjectArray(self.details, forKey: "details") + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: StringCodingKey.self) + + try container.encode(self.contentOffset, forKey: "offset") + try container.encode(self.details, forKey: "details") } } @@ -53,7 +61,7 @@ public func instantPageStoredState(postbox: Postbox, webPage: TelegramMediaWebpa return postbox.transaction { transaction -> InstantPageStoredState? in let key = ValueBoxKey(length: 8) key.setInt64(0, value: webPage.webpageId.id) - if let entry = transaction.retrieveItemCacheEntry(id: ItemCacheEntryId(collectionId: ApplicationSpecificItemCacheCollectionId.instantPageStoredState, key: key)) as? InstantPageStoredState { + if let entry = transaction.retrieveItemCacheEntry(id: ItemCacheEntryId(collectionId: ApplicationSpecificItemCacheCollectionId.instantPageStoredState, key: key))?.get(InstantPageStoredState.self) { return entry } else { return nil @@ -68,8 +76,8 @@ public func updateInstantPageStoredStateInteractively(postbox: Postbox, webPage: let key = ValueBoxKey(length: 8) key.setInt64(0, value: webPage.webpageId.id) let id = ItemCacheEntryId(collectionId: ApplicationSpecificItemCacheCollectionId.instantPageStoredState, key: key) - if let state = state { - transaction.putItemCacheEntry(id: id, entry: state, collectionSpec: collectionSpec) + if let state = state, let entry = CodableEntry(state) { + transaction.putItemCacheEntry(id: id, entry: entry, collectionSpec: collectionSpec) } else { transaction.removeItemCacheEntry(id: id) } diff --git a/submodules/LocationUI/Sources/CachedGeocodes.swift b/submodules/LocationUI/Sources/CachedGeocodes.swift index bb2f6e9267..5b76e80543 100644 --- a/submodules/LocationUI/Sources/CachedGeocodes.swift +++ b/submodules/LocationUI/Sources/CachedGeocodes.swift @@ -8,7 +8,7 @@ import PersistentStringHash import AccountContext import Geocoding -public final class CachedGeocode: PostboxCoding { +public final class CachedGeocode: Codable { public let latitude: Double public let longitude: Double @@ -17,14 +17,18 @@ public final class CachedGeocode: PostboxCoding { self.longitude = longitude } - public init(decoder: PostboxDecoder) { - self.latitude = decoder.decodeDoubleForKey("lat", orElse: 0.0) - self.longitude = decoder.decodeDoubleForKey("lon", orElse: 0.0) + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: StringCodingKey.self) + + self.latitude = try container.decode(Double.self, forKey: "lat") + self.longitude = try container.decode(Double.self, forKey: "lon") } - public func encode(_ encoder: PostboxEncoder) { - encoder.encodeDouble(self.latitude, forKey: "lat") - encoder.encodeDouble(self.longitude, forKey: "lon") + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: StringCodingKey.self) + + try container.encode(self.latitude, forKey: "lat") + try container.encode(self.longitude, forKey: "lon") } } @@ -32,7 +36,7 @@ private func cachedGeocode(postbox: Postbox, address: DeviceContactAddressData) return postbox.transaction { transaction -> CachedGeocode? in let key = ValueBoxKey(length: 8) key.setInt64(0, value: Int64(bitPattern: address.string.persistentHashValue)) - if let entry = transaction.retrieveItemCacheEntry(id: ItemCacheEntryId(collectionId: ApplicationSpecificItemCacheCollectionId.cachedGeocodes, key: key)) as? CachedGeocode { + if let entry = transaction.retrieveItemCacheEntry(id: ItemCacheEntryId(collectionId: ApplicationSpecificItemCacheCollectionId.cachedGeocodes, key: key))?.get(CachedGeocode.self) { return entry } else { return nil @@ -47,7 +51,9 @@ private func updateCachedGeocode(postbox: Postbox, address: DeviceContactAddress let key = ValueBoxKey(length: 8) key.setInt64(0, value: Int64(bitPattern: address.string.persistentHashValue)) let id = ItemCacheEntryId(collectionId: ApplicationSpecificItemCacheCollectionId.cachedGeocodes, key: key) - transaction.putItemCacheEntry(id: id, entry: CachedGeocode(latitude: latitude, longitude: longitude), collectionSpec: collectionSpec) + if let entry = CodableEntry(CachedGeocode(latitude: latitude, longitude: longitude)) { + transaction.putItemCacheEntry(id: id, entry: entry, collectionSpec: collectionSpec) + } return (latitude, longitude) } } diff --git a/submodules/MediaResources/Sources/MediaPlaybackStoredState.swift b/submodules/MediaResources/Sources/MediaPlaybackStoredState.swift index c3fb8009c6..372b7eb347 100644 --- a/submodules/MediaResources/Sources/MediaPlaybackStoredState.swift +++ b/submodules/MediaResources/Sources/MediaPlaybackStoredState.swift @@ -5,7 +5,7 @@ import Postbox import TelegramCore import TelegramUIPreferences -public final class MediaPlaybackStoredState: PostboxCoding { +public final class MediaPlaybackStoredState: Codable { public let timestamp: Double public let playbackRate: AudioPlaybackRate @@ -14,14 +14,18 @@ public final class MediaPlaybackStoredState: PostboxCoding { self.playbackRate = playbackRate } - public init(decoder: PostboxDecoder) { - self.timestamp = decoder.decodeDoubleForKey("timestamp", orElse: 0.0) - self.playbackRate = AudioPlaybackRate(rawValue: decoder.decodeInt32ForKey("playbackRate", orElse: AudioPlaybackRate.x1.rawValue)) ?? .x1 + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: StringCodingKey.self) + + self.timestamp = try container.decode(Double.self, forKey: "timestamp") + self.playbackRate = AudioPlaybackRate(rawValue: try container.decode(Int32.self, forKey: "playbackRate")) ?? .x1 } - public func encode(_ encoder: PostboxEncoder) { - encoder.encodeDouble(self.timestamp, forKey: "timestamp") - encoder.encodeInt32(self.playbackRate.rawValue, forKey: "playbackRate") + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: StringCodingKey.self) + + try container.encode(self.timestamp, forKey: "timestamp") + try container.encode(self.playbackRate.rawValue, forKey: "playbackRate") } } @@ -30,7 +34,7 @@ public func mediaPlaybackStoredState(postbox: Postbox, messageId: MessageId) -> let key = ValueBoxKey(length: 8) key.setInt32(0, value: messageId.namespace) key.setInt32(4, value: messageId.id) - if let entry = transaction.retrieveItemCacheEntry(id: ItemCacheEntryId(collectionId: ApplicationSpecificItemCacheCollectionId.mediaPlaybackStoredState, key: key)) as? MediaPlaybackStoredState { + if let entry = transaction.retrieveItemCacheEntry(id: ItemCacheEntryId(collectionId: ApplicationSpecificItemCacheCollectionId.mediaPlaybackStoredState, key: key))?.get(MediaPlaybackStoredState.self) { return entry } else { return nil @@ -46,8 +50,8 @@ public func updateMediaPlaybackStoredStateInteractively(postbox: Postbox, messag key.setInt32(0, value: messageId.namespace) key.setInt32(4, value: messageId.id) let id = ItemCacheEntryId(collectionId: ApplicationSpecificItemCacheCollectionId.mediaPlaybackStoredState, key: key) - if let state = state { - transaction.putItemCacheEntry(id: id, entry: state, collectionSpec: collectionSpec) + if let state = state, let entry = CodableEntry(state) { + transaction.putItemCacheEntry(id: id, entry: entry, collectionSpec: collectionSpec) } else { transaction.removeItemCacheEntry(id: id) } diff --git a/submodules/Postbox/Sources/AccountManager.swift b/submodules/Postbox/Sources/AccountManager.swift index 3cdd47d984..520560921a 100644 --- a/submodules/Postbox/Sources/AccountManager.swift +++ b/submodules/Postbox/Sources/AccountManager.swift @@ -20,8 +20,8 @@ public struct AccountManagerModifier { public let setAccessChallengeData: (PostboxAccessChallengeData) -> Void public let getVersion: () -> Int32? public let setVersion: (Int32) -> Void - public let getNotice: (NoticeEntryKey) -> NoticeEntry? - public let setNotice: (NoticeEntryKey, NoticeEntry?) -> Void + public let getNotice: (NoticeEntryKey) -> CodableEntry? + public let setNotice: (NoticeEntryKey, CodableEntry?) -> Void public let clearNotices: () -> Void } diff --git a/submodules/Postbox/Sources/AdditionalMessageHistoryViewData.swift b/submodules/Postbox/Sources/AdditionalMessageHistoryViewData.swift index 357cf6ce5c..9cf5cb60e6 100644 --- a/submodules/Postbox/Sources/AdditionalMessageHistoryViewData.swift +++ b/submodules/Postbox/Sources/AdditionalMessageHistoryViewData.swift @@ -19,7 +19,7 @@ public enum AdditionalMessageHistoryViewDataEntry { case peerChatState(PeerId, PeerChatState?) case totalUnreadState(ChatListTotalUnreadState) case peerNotificationSettings(PeerNotificationSettings?) - case cacheEntry(ItemCacheEntryId, PostboxCoding?) + case cacheEntry(ItemCacheEntryId, CodableEntry?) case preferencesEntry(ValueBoxKey, PreferencesEntry?) case peerIsContact(PeerId, Bool) case peer(PeerId, Peer?) diff --git a/submodules/Postbox/Sources/CachedItemView.swift b/submodules/Postbox/Sources/CachedItemView.swift index b1048fd3a6..2a6d676eb2 100644 --- a/submodules/Postbox/Sources/CachedItemView.swift +++ b/submodules/Postbox/Sources/CachedItemView.swift @@ -2,7 +2,7 @@ import Foundation final class MutableCachedItemView: MutablePostboxView { private let id: ItemCacheEntryId - fileprivate var value: PostboxCoding? + fileprivate var value: CodableEntry? init(postbox: Postbox, id: ItemCacheEntryId) { self.id = id @@ -23,7 +23,7 @@ final class MutableCachedItemView: MutablePostboxView { } public final class CachedItemView: PostboxView { - public let value: PostboxCoding? + public let value: CodableEntry? init(_ view: MutableCachedItemView) { self.value = view.value diff --git a/submodules/Postbox/Sources/ItemCacheTable.swift b/submodules/Postbox/Sources/ItemCacheTable.swift index cb59ab21fe..9fc7de9f06 100644 --- a/submodules/Postbox/Sources/ItemCacheTable.swift +++ b/submodules/Postbox/Sources/ItemCacheTable.swift @@ -64,29 +64,14 @@ final class ItemCacheTable: Table { key.setInt32(2, value: index) return key } - - func put(id: ItemCacheEntryId, entry: PostboxCoding, metaTable: ItemCacheMetaTable) { - let encoder = PostboxEncoder() - encoder.encodeRootObject(entry) - withExtendedLifetime(encoder, { - self.valueBox.set(self.table, key: self.itemKey(id: id), value: encoder.readBufferNoCopy()) - }) + + func put(id: ItemCacheEntryId, entry: CodableEntry, metaTable: ItemCacheMetaTable) { + self.valueBox.set(self.table, key: self.itemKey(id: id), value: ReadBuffer(data: entry.data)) } - func putData(id: ItemCacheEntryId, entry: Data, metaTable: ItemCacheMetaTable) { - self.valueBox.set(self.table, key: self.itemKey(id: id), value: ReadBuffer(data: entry)) - } - - func retrieve(id: ItemCacheEntryId, metaTable: ItemCacheMetaTable) -> PostboxCoding? { - if let value = self.valueBox.get(self.table, key: self.itemKey(id: id)), let entry = PostboxDecoder(buffer: value).decodeRootObject() { - return entry - } - return nil - } - - func retrieveData(id: ItemCacheEntryId, metaTable: ItemCacheMetaTable) -> Data? { + func retrieve(id: ItemCacheEntryId, metaTable: ItemCacheMetaTable) -> CodableEntry? { if let value = self.valueBox.get(self.table, key: self.itemKey(id: id)) { - return value.makeData() + return CodableEntry(data: value.makeData()) } return nil } diff --git a/submodules/Postbox/Sources/NoticeEntryView.swift b/submodules/Postbox/Sources/NoticeEntryView.swift index 99c5c84560..bdbd8ad107 100644 --- a/submodules/Postbox/Sources/NoticeEntryView.swift +++ b/submodules/Postbox/Sources/NoticeEntryView.swift @@ -2,7 +2,7 @@ import Foundation final class MutableNoticeEntryView { private let key: NoticeEntryKey - fileprivate var value: NoticeEntry? + fileprivate var value: CodableEntry? init(accountManagerImpl: AccountManagerImpl, key: NoticeEntryKey) { self.key = key @@ -23,7 +23,7 @@ final class MutableNoticeEntryView { } public final class NoticeEntryView { - public let value: NoticeEntry? + public let value: CodableEntry? init(_ view: MutableNoticeEntryView) { self.value = view.value diff --git a/submodules/Postbox/Sources/NoticeTable.swift b/submodules/Postbox/Sources/NoticeTable.swift index 8b9fb22e6d..5c8f7b39d0 100644 --- a/submodules/Postbox/Sources/NoticeTable.swift +++ b/submodules/Postbox/Sources/NoticeTable.swift @@ -26,11 +26,7 @@ public struct NoticeEntryKey: Hashable { } private struct CachedEntry { - let entry: NoticeEntry? -} - -public protocol NoticeEntry: PostboxCoding { - func isEqual(to: NoticeEntry) -> Bool + let entry: CodableEntry? } final class NoticeTable: Table { @@ -41,22 +37,22 @@ final class NoticeTable: Table { return ValueBoxTable(id: id, keyType: .binary, compactValuesOnCreation: true) } - func getAll() -> [ValueBoxKey: NoticeEntry] { - var result: [ValueBoxKey: NoticeEntry] = [:] + func getAll() -> [ValueBoxKey: CodableEntry] { + var result: [ValueBoxKey: CodableEntry] = [:] self.valueBox.scan(self.table, values: { key, value in - if let object = PostboxDecoder(buffer: value).decodeRootObject() as? NoticeEntry { - result[key] = object - } + let object = CodableEntry(data: value.makeData()) + result[key] = object return true }) return result } - func get(key: NoticeEntryKey) -> NoticeEntry? { + func get(key: NoticeEntryKey) -> CodableEntry? { if let cached = self.cachedEntries[key] { return cached.entry } else { - if let value = self.valueBox.get(self.table, key: key.combinedKey), let object = PostboxDecoder(buffer: value).decodeRootObject() as? NoticeEntry { + if let value = self.valueBox.get(self.table, key: key.combinedKey) { + let object = CodableEntry(data: value.makeData()) self.cachedEntries[key] = CachedEntry(entry: object) return object } else { @@ -66,7 +62,7 @@ final class NoticeTable: Table { } } - func set(key: NoticeEntryKey, value: NoticeEntry?) { + func set(key: NoticeEntryKey, value: CodableEntry?) { self.cachedEntries[key] = CachedEntry(entry: value) updatedEntryKeys.insert(key) } @@ -92,11 +88,7 @@ final class NoticeTable: Table { if !self.updatedEntryKeys.isEmpty { for key in self.updatedEntryKeys { if let value = self.cachedEntries[key]?.entry { - let encoder = PostboxEncoder() - encoder.encodeRootObject(value) - withExtendedLifetime(encoder, { - self.valueBox.set(self.table, key: key.combinedKey, value: encoder.readBufferNoCopy()) - }) + self.valueBox.set(self.table, key: key.combinedKey, value: ReadBuffer(data: value.data)) } else { self.valueBox.remove(self.table, key: key.combinedKey, secure: false) } diff --git a/submodules/Postbox/Sources/Postbox.swift b/submodules/Postbox/Sources/Postbox.swift index 605c4a4fae..d9f7a4cab6 100644 --- a/submodules/Postbox/Sources/Postbox.swift +++ b/submodules/Postbox/Sources/Postbox.swift @@ -712,30 +712,20 @@ public final class Transaction { return self.postbox?.storedMessageId(peerId: peerId, namespace: namespace, timestamp: timestamp) } - public func putItemCacheEntry(id: ItemCacheEntryId, entry: PostboxCoding, collectionSpec: ItemCacheCollectionSpec) { + public func putItemCacheEntry(id: ItemCacheEntryId, entry: CodableEntry, collectionSpec: ItemCacheCollectionSpec) { assert(!self.disposed) self.postbox?.putItemCacheEntry(id: id, entry: entry, collectionSpec: collectionSpec) } - - public func putItemCacheEntryData(id: ItemCacheEntryId, entry: Data, collectionSpec: ItemCacheCollectionSpec) { - assert(!self.disposed) - self.postbox?.putItemCacheEntryData(id: id, entry: entry, collectionSpec: collectionSpec) - } public func removeItemCacheEntry(id: ItemCacheEntryId) { assert(!self.disposed) self.postbox?.removeItemCacheEntry(id: id) } - public func retrieveItemCacheEntry(id: ItemCacheEntryId) -> PostboxCoding? { + public func retrieveItemCacheEntry(id: ItemCacheEntryId) -> CodableEntry? { assert(!self.disposed) return self.postbox?.retrieveItemCacheEntry(id: id) } - - public func retrieveItemCacheEntryData(id: ItemCacheEntryId) -> Data? { - assert(!self.disposed) - return self.postbox?.retrieveItemCacheEntryData(id: id) - } public func clearItemCacheCollection(collectionId: ItemCacheCollectionId) { assert(!self.disposed) @@ -942,7 +932,7 @@ public final class Transaction { } } - public func getAllNoticeEntries() -> [ValueBoxKey: NoticeEntry] { + public func getAllNoticeEntries() -> [ValueBoxKey: CodableEntry] { assert(!self.disposed) if let postbox = self.postbox { return postbox.noticeTable.getAll() @@ -951,7 +941,7 @@ public final class Transaction { } } - public func getNoticeEntry(key: NoticeEntryKey) -> PostboxCoding? { + public func getNoticeEntry(key: NoticeEntryKey) -> CodableEntry? { assert(!self.disposed) if let postbox = self.postbox { return postbox.noticeTable.get(key: key) @@ -960,7 +950,7 @@ public final class Transaction { } } - public func setNoticeEntry(key: NoticeEntryKey, value: NoticeEntry?) { + public func setNoticeEntry(key: NoticeEntryKey, value: CodableEntry?) { assert(!self.disposed) self.postbox?.setNoticeEntry(key: key, value: value) } @@ -2347,23 +2337,14 @@ public final class Postbox { } } - fileprivate func putItemCacheEntry(id: ItemCacheEntryId, entry: PostboxCoding, collectionSpec: ItemCacheCollectionSpec) { + fileprivate func putItemCacheEntry(id: ItemCacheEntryId, entry: CodableEntry, collectionSpec: ItemCacheCollectionSpec) { self.itemCacheTable.put(id: id, entry: entry, metaTable: self.itemCacheMetaTable) self.currentUpdatedCacheEntryKeys.insert(id) } - - fileprivate func putItemCacheEntryData(id: ItemCacheEntryId, entry: Data, collectionSpec: ItemCacheCollectionSpec) { - self.itemCacheTable.putData(id: id, entry: entry, metaTable: self.itemCacheMetaTable) - self.currentUpdatedCacheEntryKeys.insert(id) - } - func retrieveItemCacheEntry(id: ItemCacheEntryId) -> PostboxCoding? { + func retrieveItemCacheEntry(id: ItemCacheEntryId) -> CodableEntry? { return self.itemCacheTable.retrieve(id: id, metaTable: self.itemCacheMetaTable) } - - func retrieveItemCacheEntryData(id: ItemCacheEntryId) -> Data? { - return self.itemCacheTable.retrieveData(id: id, metaTable: self.itemCacheMetaTable) - } func clearItemCacheCollection(collectionId: ItemCacheCollectionId) { return self.itemCacheTable.removeAll(collectionId: collectionId) @@ -2400,11 +2381,11 @@ public final class Postbox { } } - fileprivate func setNoticeEntry(key: NoticeEntryKey, value: NoticeEntry?) { + fileprivate func setNoticeEntry(key: NoticeEntryKey, value: CodableEntry?) { let current = self.noticeTable.get(key: key) let updated: Bool if let current = current, let value = value { - updated = !current.isEqual(to: value) + updated = current.data != value.data } else if (current != nil) != (value != nil) { updated = true } else { diff --git a/submodules/Postbox/Sources/Utils/Encoder/AdaptedPostboxUnkeyedEncodingContainer.swift b/submodules/Postbox/Sources/Utils/Encoder/AdaptedPostboxUnkeyedEncodingContainer.swift index c9dc3ce412..365aa0e83d 100644 --- a/submodules/Postbox/Sources/Utils/Encoder/AdaptedPostboxUnkeyedEncodingContainer.swift +++ b/submodules/Postbox/Sources/Utils/Encoder/AdaptedPostboxUnkeyedEncodingContainer.swift @@ -120,6 +120,18 @@ extension _AdaptedPostboxEncoder.UnkeyedContainer: UnkeyedEncodingContainer { try self.encode(value as! String) } else if value is Data { try self.encode(value as! Data) + } else if let value = value as? AdaptedPostboxEncoder.RawObjectData { + let buffer = WriteBuffer() + + var typeHash: Int32 = value.typeHash + buffer.write(&typeHash, offset: 0, length: 4) + + var length: Int32 = Int32(value.data.count) + buffer.write(&length, offset: 0, length: 4) + + buffer.write(value.data) + + self.items.append(.object(buffer.makeData())) } else { let typeHash: Int32 = murMurHashString32("\(type(of: value))") diff --git a/submodules/TelegramCore/Sources/Account/AccountManager.swift b/submodules/TelegramCore/Sources/Account/AccountManager.swift index 6c36ccaab2..4fa3e0ed8e 100644 --- a/submodules/TelegramCore/Sources/Account/AccountManager.swift +++ b/submodules/TelegramCore/Sources/Account/AccountManager.swift @@ -116,7 +116,6 @@ private var declaredEncodables: Void = { declareEncodable(SourceReferenceMessageAttribute.self, f: { SourceReferenceMessageAttribute(decoder: $0) }) declareEncodable(EditedMessageAttribute.self, f: { EditedMessageAttribute(decoder: $0) }) declareEncodable(ReplyMarkupMessageAttribute.self, f: { ReplyMarkupMessageAttribute(decoder: $0) }) - declareEncodable(CachedResolvedByNamePeer.self, f: { CachedResolvedByNamePeer(decoder: $0) }) declareEncodable(OutgoingChatContextResultMessageAttribute.self, f: { OutgoingChatContextResultMessageAttribute(decoder: $0) }) declareEncodable(HttpReferenceMediaResource.self, f: { HttpReferenceMediaResource(decoder: $0) }) declareEncodable(WebFileReferenceMediaResource.self, f: { WebFileReferenceMediaResource(decoder: $0) }) @@ -151,51 +150,24 @@ private var declaredEncodables: Void = { declareEncodable(SynchronizeSavedGifsOperation.self, f: { SynchronizeSavedGifsOperation(decoder: $0) }) declareEncodable(SynchronizeSavedStickersOperation.self, f: { SynchronizeSavedStickersOperation(decoder: $0) }) declareEncodable(SynchronizeRecentlyUsedMediaOperation.self, f: { SynchronizeRecentlyUsedMediaOperation(decoder: $0) }) - /*declareEncodable(CacheStorageSettings.self, f: { CacheStorageSettings(decoder: $0) }) - declareEncodable(LocalizationSettings.self, f: { LocalizationSettings(decoder: $0) }) - declareEncodable(LocalizationListState.self, f: { LocalizationListState(decoder: $0) }) - declareEncodable(ProxySettings.self, f: { ProxySettings(decoder: $0) }) - declareEncodable(NetworkSettings.self, f: { NetworkSettings(decoder: $0) }) - declareEncodable(RemoteStorageConfiguration.self, f: { RemoteStorageConfiguration(decoder: $0) }) - declareEncodable(LimitsConfiguration.self, f: { LimitsConfiguration(decoder: $0) }) - declareEncodable(VoipConfiguration.self, f: { VoipConfiguration(decoder: $0) }) - declareEncodable(SuggestedLocalizationEntry.self, f: { SuggestedLocalizationEntry(decoder: $0) })*/ declareEncodable(SynchronizeLocalizationUpdatesOperation.self, f: { SynchronizeLocalizationUpdatesOperation(decoder: $0) }) declareEncodable(ChannelMessageStateVersionAttribute.self, f: { ChannelMessageStateVersionAttribute(decoder: $0) }) declareEncodable(PeerGroupMessageStateVersionAttribute.self, f: { PeerGroupMessageStateVersionAttribute(decoder: $0) }) declareEncodable(CachedSecretChatData.self, f: { CachedSecretChatData(decoder: $0) }) - declareEncodable(TemporaryTwoStepPasswordToken.self, f: { TemporaryTwoStepPasswordToken(decoder: $0) }) declareEncodable(AuthorSignatureMessageAttribute.self, f: { AuthorSignatureMessageAttribute(decoder: $0) }) declareEncodable(TelegramMediaExpiredContent.self, f: { TelegramMediaExpiredContent(decoder: $0) }) declareEncodable(SavedStickerItem.self, f: { SavedStickerItem(decoder: $0) }) declareEncodable(ConsumablePersonalMentionMessageAttribute.self, f: { ConsumablePersonalMentionMessageAttribute(decoder: $0) }) declareEncodable(ConsumePersonalMessageAction.self, f: { ConsumePersonalMessageAction(decoder: $0) }) - declareEncodable(CachedStickerPack.self, f: { CachedStickerPack(decoder: $0) }) - //declareEncodable(LoggingSettings.self, f: { LoggingSettings(decoder: $0) }) - declareEncodable(CachedLocalizationInfos.self, f: { CachedLocalizationInfos(decoder: $0) }) - declareEncodable(CachedSecureIdConfiguration.self, f: { CachedSecureIdConfiguration(decoder: $0) }) - declareEncodable(CachedWallpapersConfiguration.self, f: { CachedWallpapersConfiguration(decoder: $0) }) - declareEncodable(CachedThemesConfiguration.self, f: { CachedThemesConfiguration(decoder: $0) }) declareEncodable(SynchronizeGroupedPeersOperation.self, f: { SynchronizeGroupedPeersOperation(decoder: $0) }) - //declareEncodable(ContentPrivacySettings.self, f: { ContentPrivacySettings(decoder: $0) }) declareEncodable(TelegramDeviceContactImportedData.self, f: { TelegramDeviceContactImportedData(decoder: $0) }) declareEncodable(SecureFileMediaResource.self, f: { SecureFileMediaResource(decoder: $0) }) - declareEncodable(CachedStickerQueryResult.self, f: { CachedStickerQueryResult(decoder: $0) }) declareEncodable(TelegramWallpaper.self, f: { TelegramWallpaper(decoder: $0) }) declareEncodable(TelegramTheme.self, f: { TelegramTheme(decoder: $0) }) - //declareEncodable(ThemeSettings.self, f: { ThemeSettings(decoder: $0) }) declareEncodable(SynchronizeMarkAllUnseenPersonalMessagesOperation.self, f: { SynchronizeMarkAllUnseenPersonalMessagesOperation(decoder: $0) }) declareEncodable(SynchronizeAppLogEventsOperation.self, f: { SynchronizeAppLogEventsOperation(decoder: $0) }) - declareEncodable(CachedRecentPeers.self, f: { CachedRecentPeers(decoder: $0) }) - //declareEncodable(AppChangelogState.self, f: { AppChangelogState(decoder: $0) }) - //declareEncodable(AppConfiguration.self, f: { AppConfiguration(decoder: $0) }) - //declareEncodable(JSON.self, f: { JSON(decoder: $0) }) - //declareEncodable(SearchBotsConfiguration.self, f: { SearchBotsConfiguration(decoder: $0) }) - //declareEncodable(AutodownloadSettings.self, f: { AutodownloadSettings(decoder: $0 )}) declareEncodable(TelegramMediaPoll.self, f: { TelegramMediaPoll(decoder: $0) }) declareEncodable(TelegramMediaUnsupported.self, f: { TelegramMediaUnsupported(decoder: $0) }) - //declareEncodable(ContactsSettings.self, f: { ContactsSettings(decoder: $0) }) - //declareEncodable(SecretChatSettings.self, f: { SecretChatSettings(decoder: $0) }) declareEncodable(EmojiKeywordCollectionInfo.self, f: { EmojiKeywordCollectionInfo(decoder: $0) }) declareEncodable(EmojiKeywordItem.self, f: { EmojiKeywordItem(decoder: $0) }) declareEncodable(SynchronizeEmojiKeywordsOperation.self, f: { SynchronizeEmojiKeywordsOperation(decoder: $0) }) @@ -209,34 +181,18 @@ private var declaredEncodables: Void = { declareEncodable(UpdateMessageReactionsAction.self, f: { UpdateMessageReactionsAction(decoder: $0) }) declareEncodable(RestrictedContentMessageAttribute.self, f: { RestrictedContentMessageAttribute(decoder: $0) }) declareEncodable(SendScheduledMessageImmediatelyAction.self, f: { SendScheduledMessageImmediatelyAction(decoder: $0) }) - //declareEncodable(WalletCollection.self, f: { WalletCollection(decoder: $0) }) declareEncodable(EmbeddedMediaStickersMessageAttribute.self, f: { EmbeddedMediaStickersMessageAttribute(decoder: $0) }) declareEncodable(TelegramMediaWebpageAttribute.self, f: { TelegramMediaWebpageAttribute(decoder: $0) }) - declareEncodable(CachedPollOptionResult.self, f: { CachedPollOptionResult(decoder: $0) }) - //declareEncodable(ChatListFiltersState.self, f: { ChatListFiltersState(decoder: $0) }) - //declareEncodable(PeersNearbyState.self, f: { PeersNearbyState(decoder: $0) }) declareEncodable(TelegramMediaDice.self, f: { TelegramMediaDice(decoder: $0) }) - //declareEncodable(ChatListFiltersFeaturedState.self, f: { ChatListFiltersFeaturedState(decoder: $0) }) declareEncodable(SynchronizeChatListFiltersOperation.self, f: { SynchronizeChatListFiltersOperation(decoder: $0) }) declareEncodable(PromoChatListItem.self, f: { PromoChatListItem(decoder: $0) }) declareEncodable(TelegramMediaFile.VideoThumbnail.self, f: { TelegramMediaFile.VideoThumbnail(decoder: $0) }) - declareEncodable(CachedChatContextResult.self, f: { CachedChatContextResult(decoder: $0) }) declareEncodable(PeerAccessRestrictionInfo.self, f: { PeerAccessRestrictionInfo(decoder: $0) }) declareEncodable(TelegramMediaImage.VideoRepresentation.self, f: { TelegramMediaImage.VideoRepresentation(decoder: $0) }) - //declareEncodable(Country.self, f: { Country(decoder: $0) }) - //declareEncodable(Country.CountryCode.self, f: { Country.CountryCode(decoder: $0) }) - //declareEncodable(CountriesList.self, f: { CountriesList(decoder: $0) }) declareEncodable(ValidationMessageAttribute.self, f: { ValidationMessageAttribute(decoder: $0) }) declareEncodable(EmojiSearchQueryMessageAttribute.self, f: { EmojiSearchQueryMessageAttribute(decoder: $0) }) - declareEncodable(CachedPeerInvitationImporters.self, f: { CachedPeerInvitationImporters(decoder: $0) }) - declareEncodable(CachedPeerExportedInvitations.self, f: { CachedPeerExportedInvitations(decoder: $0) }) - declareEncodable(ExportedInvitation.self, f: { ExportedInvitation(decoder: $0) }) - declareEncodable(CachedDisplayAsPeers.self, f: { CachedDisplayAsPeers(decoder: $0) }) - //declareEncodable(WallpapersState.self, f: { WallpapersState(decoder: $0) }) declareEncodable(WallpaperDataResource.self, f: { WallpaperDataResource(decoder: $0) }) declareEncodable(ForwardOptionsMessageAttribute.self, f: { ForwardOptionsMessageAttribute(decoder: $0) }) - //declareEncodable(ChatTheme.self, f: { ChatTheme(decoder: $0) }) - //declareEncodable(ChatThemes.self, f: { ChatThemes(decoder: $0) }) return }() diff --git a/submodules/TelegramCore/Sources/State/CachedSentMediaReferences.swift b/submodules/TelegramCore/Sources/State/CachedSentMediaReferences.swift index d7af4e5d03..307a8f24e0 100644 --- a/submodules/TelegramCore/Sources/State/CachedSentMediaReferences.swift +++ b/submodules/TelegramCore/Sources/State/CachedSentMediaReferences.swift @@ -32,11 +32,12 @@ enum CachedSentMediaReferenceKey { } func cachedSentMediaReference(postbox: Postbox, key: CachedSentMediaReferenceKey) -> Signal { - return postbox.transaction { transaction -> Media? in + return .single(nil) + /*return postbox.transaction { transaction -> Media? in return transaction.retrieveItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedSentMediaReferences, key: key.key)) as? Media - } + }*/ } func storeCachedSentMediaReference(transaction: Transaction, key: CachedSentMediaReferenceKey, media: Media) { - transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedSentMediaReferences, key: key.key), entry: media, collectionSpec: cachedSentMediaCollectionSpec) + //transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedSentMediaReferences, key: key.key), entry: media, collectionSpec: cachedSentMediaCollectionSpec) } diff --git a/submodules/TelegramCore/Sources/SyncCore/SyncCore_CachedChannelData.swift b/submodules/TelegramCore/Sources/SyncCore/SyncCore_CachedChannelData.swift index 8616c3980a..e3da6270b9 100644 --- a/submodules/TelegramCore/Sources/SyncCore/SyncCore_CachedChannelData.swift +++ b/submodules/TelegramCore/Sources/SyncCore/SyncCore_CachedChannelData.swift @@ -413,7 +413,7 @@ public final class CachedChannelData: CachedPeerData { self.flags = CachedChannelFlags(rawValue: decoder.decodeInt32ForKey("f", orElse: 0)) self.about = decoder.decodeOptionalStringForKey("a") self.participantsSummary = CachedChannelParticipantsSummary(decoder: decoder) - self.exportedInvitation = decoder.decodeObjectForKey("i", decoder: { ExportedInvitation(decoder: $0) }) as? ExportedInvitation + self.exportedInvitation = decoder.decode(ExportedInvitation.self, forKey: "i") self.botInfos = decoder.decodeObjectArrayWithDecoderForKey("b") as [CachedPeerBotInfo] var peerIds = Set() @@ -515,7 +515,7 @@ public final class CachedChannelData: CachedPeerData { } self.participantsSummary.encode(encoder) if let exportedInvitation = self.exportedInvitation { - encoder.encodeObject(exportedInvitation, forKey: "i") + encoder.encode(exportedInvitation, forKey: "i") } else { encoder.encodeNil(forKey: "i") } diff --git a/submodules/TelegramCore/Sources/SyncCore/SyncCore_CachedGroupData.swift b/submodules/TelegramCore/Sources/SyncCore/SyncCore_CachedGroupData.swift index d05ae4fd76..624b1122a6 100644 --- a/submodules/TelegramCore/Sources/SyncCore/SyncCore_CachedGroupData.swift +++ b/submodules/TelegramCore/Sources/SyncCore/SyncCore_CachedGroupData.swift @@ -118,7 +118,7 @@ public final class CachedGroupData: CachedPeerData { public init(decoder: PostboxDecoder) { let participants = decoder.decodeObjectForKey("p", decoder: { CachedGroupParticipants(decoder: $0) }) as? CachedGroupParticipants self.participants = participants - self.exportedInvitation = decoder.decodeObjectForKey("i", decoder: { ExportedInvitation(decoder: $0) }) as? ExportedInvitation + self.exportedInvitation = decoder.decode(ExportedInvitation.self, forKey: "i") self.botInfos = decoder.decodeObjectArrayWithDecoderForKey("b") as [CachedPeerBotInfo] if let legacyValue = decoder.decodeOptionalInt32ForKey("pcs") { self.peerStatusSettings = PeerStatusSettings(flags: PeerStatusSettings.Flags(rawValue: legacyValue), geoDistance: nil) @@ -181,7 +181,7 @@ public final class CachedGroupData: CachedPeerData { encoder.encodeNil(forKey: "p") } if let exportedInvitation = self.exportedInvitation { - encoder.encodeObject(exportedInvitation, forKey: "i") + encoder.encode(exportedInvitation, forKey: "i") } else { encoder.encodeNil(forKey: "i") } diff --git a/submodules/TelegramCore/Sources/SyncCore/SyncCore_CachedLocalizationInfos.swift b/submodules/TelegramCore/Sources/SyncCore/SyncCore_CachedLocalizationInfos.swift index 9026af12b2..c4e84b4ce9 100644 --- a/submodules/TelegramCore/Sources/SyncCore/SyncCore_CachedLocalizationInfos.swift +++ b/submodules/TelegramCore/Sources/SyncCore/SyncCore_CachedLocalizationInfos.swift @@ -1,17 +1,21 @@ import Postbox -public final class CachedLocalizationInfos: PostboxCoding { +public final class CachedLocalizationInfos: Codable { public let list: [LocalizationInfo] public init(list: [LocalizationInfo]) { self.list = list } - public init(decoder: PostboxDecoder) { - self.list = decoder.decodeObjectArrayWithDecoderForKey("l") + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: StringCodingKey.self) + + self.list = try container.decode([LocalizationInfo].self, forKey: "t") } - public func encode(_ encoder: PostboxEncoder) { - encoder.encodeObjectArray(self.list, forKey: "l") + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: StringCodingKey.self) + + try container.encode(self.list, forKey: "l") } } diff --git a/submodules/TelegramCore/Sources/SyncCore/SyncCore_CachedRecentPeers.swift b/submodules/TelegramCore/Sources/SyncCore/SyncCore_CachedRecentPeers.swift index 0ac338c6b6..bb750e0d49 100644 --- a/submodules/TelegramCore/Sources/SyncCore/SyncCore_CachedRecentPeers.swift +++ b/submodules/TelegramCore/Sources/SyncCore/SyncCore_CachedRecentPeers.swift @@ -1,6 +1,6 @@ import Postbox -public final class CachedRecentPeers: PostboxCoding { +public final class CachedRecentPeers: Codable { public let enabled: Bool public let ids: [PeerId] @@ -9,14 +9,18 @@ public final class CachedRecentPeers: PostboxCoding { self.ids = ids } - public init(decoder: PostboxDecoder) { - self.enabled = decoder.decodeInt32ForKey("enabled", orElse: 0) != 0 - self.ids = decoder.decodeInt64ArrayForKey("ids").map(PeerId.init) + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: StringCodingKey.self) + + self.enabled = try container.decode(Int32.self, forKey: "enabled") != 0 + self.ids = (try container.decode([Int64].self, forKey: "ids")).map(PeerId.init) } - public func encode(_ encoder: PostboxEncoder) { - encoder.encodeInt32(self.enabled ? 1 : 0, forKey: "enabled") - encoder.encodeInt64Array(self.ids.map({ $0.toInt64() }), forKey: "ids") + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: StringCodingKey.self) + + try container.encode((self.enabled ? 1 : 0) as Int32, forKey: "enabled") + try container.encode(self.ids.map({ $0.toInt64() }), forKey: "ids") } public static func cacheKey() -> ValueBoxKey { diff --git a/submodules/TelegramCore/Sources/SyncCore/SyncCore_CachedResolvedByNamePeer.swift b/submodules/TelegramCore/Sources/SyncCore/SyncCore_CachedResolvedByNamePeer.swift index 10d47173cb..2a9dab4083 100644 --- a/submodules/TelegramCore/Sources/SyncCore/SyncCore_CachedResolvedByNamePeer.swift +++ b/submodules/TelegramCore/Sources/SyncCore/SyncCore_CachedResolvedByNamePeer.swift @@ -1,7 +1,7 @@ import Foundation import Postbox -public final class CachedResolvedByNamePeer: PostboxCoding { +public final class CachedResolvedByNamePeer: Codable { public let peerId: PeerId? public let timestamp: Int32 @@ -25,21 +25,17 @@ public final class CachedResolvedByNamePeer: PostboxCoding { self.timestamp = timestamp } - public init(decoder: PostboxDecoder) { - if let peerId = decoder.decodeOptionalInt64ForKey("p") { - self.peerId = PeerId(peerId) - } else { - self.peerId = nil - } - self.timestamp = decoder.decodeInt32ForKey("t", orElse: 0) + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: StringCodingKey.self) + + self.peerId = (try container.decodeIfPresent(Int64.self, forKey: "p")).flatMap(PeerId.init) + self.timestamp = try container.decode(Int32.self, forKey: "t") } - public func encode(_ encoder: PostboxEncoder) { - if let peerId = self.peerId { - encoder.encodeInt64(peerId.toInt64(), forKey: "p") - } else { - encoder.encodeNil(forKey: "p") - } - encoder.encodeInt32(self.timestamp, forKey: "t") + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: StringCodingKey.self) + + try container.encodeIfPresent(self.peerId?.toInt64(), forKey: "p") + try container.encode(self.timestamp, forKey: "t") } } diff --git a/submodules/TelegramCore/Sources/SyncCore/SyncCore_CachedSecureIdConfiguration.swift b/submodules/TelegramCore/Sources/SyncCore/SyncCore_CachedSecureIdConfiguration.swift index 8d8200bfb9..0dbd442908 100644 --- a/submodules/TelegramCore/Sources/SyncCore/SyncCore_CachedSecureIdConfiguration.swift +++ b/submodules/TelegramCore/Sources/SyncCore/SyncCore_CachedSecureIdConfiguration.swift @@ -1,25 +1,29 @@ import Foundation import Postbox -public struct SecureIdConfiguration: PostboxCoding { +public struct SecureIdConfiguration: Codable { public let nativeLanguageByCountry: [String: String] public init(jsonString: String) { self.nativeLanguageByCountry = (try? JSONDecoder().decode(Dictionary.self, from: jsonString.data(using: .utf8) ?? Data())) ?? [:] } - public init(decoder: PostboxDecoder) { - let nativeLanguageByCountryData = decoder.decodeBytesForKey("nativeLanguageByCountry")! - self.nativeLanguageByCountry = (try? JSONDecoder().decode(Dictionary.self, from: nativeLanguageByCountryData.dataNoCopy())) ?? [:] + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: StringCodingKey.self) + + let nativeLanguageByCountryData = try container.decode(Data.self, forKey: "nativeLanguageByCountry") + self.nativeLanguageByCountry = (try? JSONDecoder().decode(Dictionary.self, from: nativeLanguageByCountryData)) ?? [:] } - public func encode(_ encoder: PostboxEncoder) { + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: StringCodingKey.self) + let nativeLanguageByCountryData = (try? JSONEncoder().encode(self.nativeLanguageByCountry)) ?? Data() - encoder.encodeBytes(MemoryBuffer(data: nativeLanguageByCountryData), forKey: "nativeLanguageByCountry") + try container.encode(nativeLanguageByCountryData, forKey: "nativeLanguageByCountry") } } -public final class CachedSecureIdConfiguration: PostboxCoding { +public final class CachedSecureIdConfiguration: Codable { public let value: SecureIdConfiguration public let hash: Int32 @@ -28,13 +32,17 @@ public final class CachedSecureIdConfiguration: PostboxCoding { self.hash = hash } - public init(decoder: PostboxDecoder) { - self.value = decoder.decodeObjectForKey("value", decoder: { SecureIdConfiguration(decoder: $0) }) as! SecureIdConfiguration - self.hash = decoder.decodeInt32ForKey("hash", orElse: 0) + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: StringCodingKey.self) + + self.value = try container.decode(SecureIdConfiguration.self, forKey: "value") + self.hash = try container.decode(Int32.self, forKey: "hash") } - public func encode(_ encoder: PostboxEncoder) { - encoder.encodeObject(self.value, forKey: "value") - encoder.encodeInt32(self.hash, forKey: "hash") + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: StringCodingKey.self) + + try container.encode(self.value, forKey: "value") + try container.encode(self.hash, forKey: "hash") } } diff --git a/submodules/TelegramCore/Sources/SyncCore/SyncCore_CachedStickerPack.swift b/submodules/TelegramCore/Sources/SyncCore/SyncCore_CachedStickerPack.swift index ea4f51d4e6..dd8774e9e3 100644 --- a/submodules/TelegramCore/Sources/SyncCore/SyncCore_CachedStickerPack.swift +++ b/submodules/TelegramCore/Sources/SyncCore/SyncCore_CachedStickerPack.swift @@ -1,6 +1,6 @@ import Postbox -public final class CachedStickerPack: PostboxCoding { +public final class CachedStickerPack: Codable { public let info: StickerPackCollectionInfo? public let items: [StickerPackItem] public let hash: Int32 @@ -11,20 +11,36 @@ public final class CachedStickerPack: PostboxCoding { self.hash = hash } - public init(decoder: PostboxDecoder) { - self.info = decoder.decodeObjectForKey("in", decoder: { StickerPackCollectionInfo(decoder: $0) }) as? StickerPackCollectionInfo - self.items = decoder.decodeObjectArrayForKey("it").map { $0 as! StickerPackItem } - self.hash = decoder.decodeInt32ForKey("h", orElse: 0) + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: StringCodingKey.self) + + if let infoData = try container.decodeIfPresent(AdaptedPostboxDecoder.RawObjectData.self, forKey: "in") { + self.info = StickerPackCollectionInfo(decoder: PostboxDecoder(buffer: MemoryBuffer(data: infoData.data))) + } else { + self.info = nil + } + + self.items = (try container.decode([AdaptedPostboxDecoder.RawObjectData].self, forKey: "it")).map { itemData in + return StickerPackItem(decoder: PostboxDecoder(buffer: MemoryBuffer(data: itemData.data))) + } + + self.hash = try container.decode(Int32.self, forKey: "h") } - public func encode(_ encoder: PostboxEncoder) { + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: StringCodingKey.self) + if let info = self.info { - encoder.encodeObject(info, forKey: "in") + try container.encode(PostboxEncoder().encodeObjectToRawData(info), forKey: "in") } else { - encoder.encodeNil(forKey: "in") + try container.encodeNil(forKey: "in") } - encoder.encodeObjectArray(self.items, forKey: "it") - encoder.encodeInt32(self.hash, forKey: "h") + + try container.encode(self.items.map { item in + return PostboxEncoder().encodeObjectToRawData(item) + }, forKey: "it") + + try container.encode(self.hash, forKey: "h") } public static func cacheKey(_ id: ItemCollectionId) -> ValueBoxKey { diff --git a/submodules/TelegramCore/Sources/SyncCore/SyncCore_CachedStickerQueryResult.swift b/submodules/TelegramCore/Sources/SyncCore/SyncCore_CachedStickerQueryResult.swift index 7a0d7769ec..eeda71abff 100644 --- a/submodules/TelegramCore/Sources/SyncCore/SyncCore_CachedStickerQueryResult.swift +++ b/submodules/TelegramCore/Sources/SyncCore/SyncCore_CachedStickerQueryResult.swift @@ -1,6 +1,6 @@ import Postbox -public final class CachedStickerQueryResult: PostboxCoding { +public final class CachedStickerQueryResult: Codable { public let items: [TelegramMediaFile] public let hash: Int64 public let timestamp: Int32 @@ -11,16 +11,25 @@ public final class CachedStickerQueryResult: PostboxCoding { self.timestamp = timestamp } - public init(decoder: PostboxDecoder) { - self.items = decoder.decodeObjectArrayForKey("it").map { $0 as! TelegramMediaFile } - self.hash = decoder.decodeInt64ForKey("h6", orElse: 0) - self.timestamp = decoder.decodeInt32ForKey("t", orElse: 0) + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: StringCodingKey.self) + + self.items = (try container.decode([AdaptedPostboxDecoder.RawObjectData].self, forKey: "it")).map { itemData in + return TelegramMediaFile(decoder: PostboxDecoder(buffer: MemoryBuffer(data: itemData.data))) + } + + self.hash = try container.decode(Int64.self, forKey: "h6") + self.timestamp = try container.decode(Int32.self, forKey: "t") } - public func encode(_ encoder: PostboxEncoder) { - encoder.encodeObjectArray(self.items, forKey: "it") - encoder.encodeInt64(self.hash, forKey: "h6") - encoder.encodeInt32(self.timestamp, forKey: "t") + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: StringCodingKey.self) + + try container.encode(self.items.map { item in + return PostboxEncoder().encodeObjectToRawData(item) + }, forKey: "it") + try container.encode(self.hash, forKey: "h6") + try container.encode(self.timestamp, forKey: "t") } public static func cacheKey(_ query: String) -> ValueBoxKey { diff --git a/submodules/TelegramCore/Sources/SyncCore/SyncCore_CachedThemesConfiguration.swift b/submodules/TelegramCore/Sources/SyncCore/SyncCore_CachedThemesConfiguration.swift index 2b9f2127d7..c7de0fcc55 100644 --- a/submodules/TelegramCore/Sources/SyncCore/SyncCore_CachedThemesConfiguration.swift +++ b/submodules/TelegramCore/Sources/SyncCore/SyncCore_CachedThemesConfiguration.swift @@ -1,17 +1,21 @@ import Postbox -public final class CachedThemesConfiguration: PostboxCoding { +public final class CachedThemesConfiguration: Codable { public let hash: Int64 public init(hash: Int64) { self.hash = hash } - public init(decoder: PostboxDecoder) { - self.hash = decoder.decodeInt64ForKey("hash6", orElse: 0) + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: StringCodingKey.self) + + self.hash = try container.decode(Int64.self, forKey: "hash6") } - public func encode(_ encoder: PostboxEncoder) { - encoder.encodeInt64(self.hash, forKey: "hash6") + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: StringCodingKey.self) + + try container.encode(self.hash, forKey: "hash6") } } diff --git a/submodules/TelegramCore/Sources/SyncCore/SyncCore_CachedWallpapersConfiguration.swift b/submodules/TelegramCore/Sources/SyncCore/SyncCore_CachedWallpapersConfiguration.swift index 0d6d2ac9da..d380b2076e 100644 --- a/submodules/TelegramCore/Sources/SyncCore/SyncCore_CachedWallpapersConfiguration.swift +++ b/submodules/TelegramCore/Sources/SyncCore/SyncCore_CachedWallpapersConfiguration.swift @@ -1,17 +1,21 @@ import Postbox -public final class CachedWallpapersConfiguration: PostboxCoding { +public final class CachedWallpapersConfiguration: Codable { public let hash: Int64 public init(hash: Int64) { self.hash = hash } - public init(decoder: PostboxDecoder) { - self.hash = decoder.decodeInt64ForKey("hash6", orElse: 0) + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: StringCodingKey.self) + + self.hash = try container.decode(Int64.self, forKey: "hash6") } - - public func encode(_ encoder: PostboxEncoder) { - encoder.encodeInt64(self.hash, forKey: "hash6") + + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: StringCodingKey.self) + + try container.encode(self.hash, forKey: "hash6") } } diff --git a/submodules/TelegramCore/Sources/SyncCore/SyncCore_ExportedInvitation.swift b/submodules/TelegramCore/Sources/SyncCore/SyncCore_ExportedInvitation.swift index 152245caa0..1842dbdd4b 100644 --- a/submodules/TelegramCore/Sources/SyncCore/SyncCore_ExportedInvitation.swift +++ b/submodules/TelegramCore/Sources/SyncCore/SyncCore_ExportedInvitation.swift @@ -1,6 +1,6 @@ import Postbox -public struct ExportedInvitation: PostboxCoding, Equatable { +public struct ExportedInvitation: Codable, Equatable { public let link: String public let isPermanent: Bool public let isRevoked: Bool @@ -23,44 +23,32 @@ public struct ExportedInvitation: PostboxCoding, Equatable { self.count = count } - public init(decoder: PostboxDecoder) { - self.link = decoder.decodeStringForKey("l", orElse: "") - self.isPermanent = decoder.decodeBoolForKey("permanent", orElse: false) - self.isRevoked = decoder.decodeBoolForKey("revoked", orElse: false) - self.adminId = PeerId(decoder.decodeInt64ForKey("adminId", orElse: 0)) - self.date = decoder.decodeInt32ForKey("date", orElse: 0) - self.startDate = decoder.decodeOptionalInt32ForKey("startDate") - self.expireDate = decoder.decodeOptionalInt32ForKey("expireDate") - self.usageLimit = decoder.decodeOptionalInt32ForKey("usageLimit") - self.count = decoder.decodeOptionalInt32ForKey("count") + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: StringCodingKey.self) + + self.link = try container.decode(String.self, forKey: "l") + self.isPermanent = try container.decode(Bool.self, forKey: "permanent") + self.isRevoked = try container.decode(Bool.self, forKey: "revoked") + self.adminId = PeerId(try container.decode(Int64.self, forKey: "adminId")) + self.date = try container.decode(Int32.self, forKey: "date") + self.startDate = try container.decodeIfPresent(Int32.self, forKey: "startDate") + self.expireDate = try container.decodeIfPresent(Int32.self, forKey: "expireDate") + self.usageLimit = try container.decodeIfPresent(Int32.self, forKey: "usageLimit") + self.count = try container.decodeIfPresent(Int32.self, forKey: "count") } - public func encode(_ encoder: PostboxEncoder) { - encoder.encodeString(self.link, forKey: "l") - encoder.encodeBool(self.isPermanent, forKey: "permanent") - encoder.encodeBool(self.isRevoked, forKey: "revoked") - encoder.encodeInt64(self.adminId.toInt64(), forKey: "adminId") - encoder.encodeInt32(self.date, forKey: "date") - if let startDate = self.startDate { - encoder.encodeInt32(startDate, forKey: "startDate") - } else { - encoder.encodeNil(forKey: "startDate") - } - if let expireDate = self.expireDate { - encoder.encodeInt32(expireDate, forKey: "expireDate") - } else { - encoder.encodeNil(forKey: "expireDate") - } - if let usageLimit = self.usageLimit { - encoder.encodeInt32(usageLimit, forKey: "usageLimit") - } else { - encoder.encodeNil(forKey: "usageLimit") - } - if let count = self.count { - encoder.encodeInt32(count, forKey: "count") - } else { - encoder.encodeNil(forKey: "count") - } + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: StringCodingKey.self) + + try container.encode(self.link, forKey: "l") + try container.encode(self.isPermanent, forKey: "permanent") + try container.encode(self.isRevoked, forKey: "revoked") + try container.encode(self.adminId.toInt64(), forKey: "adminId") + try container.encode(self.date, forKey: "date") + try container.encodeIfPresent(self.startDate, forKey: "startDate") + try container.encodeIfPresent(self.expireDate, forKey: "expireDate") + try container.encodeIfPresent(self.usageLimit, forKey: "usageLimit") + try container.encodeIfPresent(self.count, forKey: "count") } public static func ==(lhs: ExportedInvitation, rhs: ExportedInvitation) -> Bool { diff --git a/submodules/TelegramCore/Sources/SyncCore/SyncCore_TemporaryTwoStepPasswordToken.swift b/submodules/TelegramCore/Sources/SyncCore/SyncCore_TemporaryTwoStepPasswordToken.swift index 81d327eff3..f64a920627 100644 --- a/submodules/TelegramCore/Sources/SyncCore/SyncCore_TemporaryTwoStepPasswordToken.swift +++ b/submodules/TelegramCore/Sources/SyncCore/SyncCore_TemporaryTwoStepPasswordToken.swift @@ -1,7 +1,7 @@ import Foundation import Postbox -public struct TemporaryTwoStepPasswordToken: PostboxCoding, Equatable { +public struct TemporaryTwoStepPasswordToken: Codable, Equatable { public let token: Data public let validUntilDate: Int32 public let requiresBiometrics: Bool @@ -12,16 +12,20 @@ public struct TemporaryTwoStepPasswordToken: PostboxCoding, Equatable { self.requiresBiometrics = requiresBiometrics } - public init(decoder: PostboxDecoder) { - self.token = decoder.decodeBytesForKey("t")!.makeData() - self.validUntilDate = decoder.decodeInt32ForKey("d", orElse: 0) - self.requiresBiometrics = decoder.decodeInt32ForKey("b", orElse: 0) != 0 + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: StringCodingKey.self) + + self.token = try container.decode(Data.self, forKey: "t") + self.validUntilDate = try container.decode(Int32.self, forKey: "d") + self.requiresBiometrics = try container.decode(Int32.self, forKey: "b") != 0 } - public func encode(_ encoder: PostboxEncoder) { - encoder.encodeBytes(MemoryBuffer(data: self.token), forKey: "t") - encoder.encodeInt32(self.validUntilDate, forKey: "d") - encoder.encodeInt32(self.requiresBiometrics ? 1 : 0, forKey: "b") + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: StringCodingKey.self) + + try container.encode(self.token, forKey: "t") + try container.encode(self.validUntilDate, forKey: "d") + try container.encode((self.requiresBiometrics ? 1 : 0) as Int32, forKey: "b") } public static func ==(lhs: TemporaryTwoStepPasswordToken, rhs: TemporaryTwoStepPasswordToken) -> Bool { diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Auth/TwoStepVerification.swift b/submodules/TelegramCore/Sources/TelegramEngine/Auth/TwoStepVerification.swift index c87dd353b5..01c1c18da7 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Auth/TwoStepVerification.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Auth/TwoStepVerification.swift @@ -344,7 +344,7 @@ func _internal_cachedTwoStepPasswordToken(postbox: Postbox) -> Signal TemporaryTwoStepPasswordToken? in let key = ValueBoxKey(length: 1) key.setUInt8(0, value: 0) - return transaction.retrieveItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedTwoStepToken, key: key)) as? TemporaryTwoStepPasswordToken + return transaction.retrieveItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedTwoStepToken, key: key))?.get(TemporaryTwoStepPasswordToken.self) } } @@ -352,7 +352,7 @@ func _internal_cacheTwoStepPasswordToken(postbox: Postbox, token: TemporaryTwoSt return postbox.transaction { transaction -> Void in let key = ValueBoxKey(length: 1) key.setUInt8(0, value: 0) - if let token = token { + if let token = token.flatMap(CodableEntry.init) { transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedTwoStepToken, key: key), entry: token, collectionSpec: ItemCacheCollectionSpec(lowWaterItemCount: 1, highWaterItemCount: 1)) } else { transaction.removeItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedTwoStepToken, key: key)) diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Calls/GroupCalls.swift b/submodules/TelegramCore/Sources/TelegramEngine/Calls/GroupCalls.swift index e4255094a1..f66890acae 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Calls/GroupCalls.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Calls/GroupCalls.swift @@ -2264,7 +2264,7 @@ func _internal_groupCallDisplayAsAvailablePeers(network: Network, postbox: Postb } } -public final class CachedDisplayAsPeers: PostboxCoding { +public final class CachedDisplayAsPeers: Codable { public let peerIds: [PeerId] public let timestamp: Int32 @@ -2273,14 +2273,18 @@ public final class CachedDisplayAsPeers: PostboxCoding { self.timestamp = timestamp } - public init(decoder: PostboxDecoder) { - self.peerIds = decoder.decodeInt64ArrayForKey("peerIds").map { PeerId($0) } - self.timestamp = decoder.decodeInt32ForKey("timestamp", orElse: 0) + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: StringCodingKey.self) + + self.peerIds = (try container.decode([Int64].self, forKey: "peerIds")).map(PeerId.init) + self.timestamp = try container.decode(Int32.self, forKey: "timestamp") } - public func encode(_ encoder: PostboxEncoder) { - encoder.encodeInt64Array(self.peerIds.map { $0.toInt64() }, forKey: "peerIds") - encoder.encodeInt32(self.timestamp, forKey: "timestamp") + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: StringCodingKey.self) + + try container.encode(self.peerIds.map { $0.toInt64() }, forKey: "peerIds") + try container.encode(self.timestamp, forKey: "timestamp") } } @@ -2297,7 +2301,7 @@ func _internal_cachedGroupCallDisplayAsAvailablePeers(account: Account, peerId: let key = ValueBoxKey(length: 8) key.setInt64(0, value: peerId.toInt64()) return account.postbox.transaction { transaction -> ([FoundPeer], Int32)? in - let cached = transaction.retrieveItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedGroupCallDisplayAsPeers, key: key)) as? CachedDisplayAsPeers + let cached = transaction.retrieveItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedGroupCallDisplayAsPeers, key: key))?.get(CachedDisplayAsPeers.self) if let cached = cached { var peers: [FoundPeer] = [] for peerId in cached.peerIds { @@ -2323,7 +2327,9 @@ func _internal_cachedGroupCallDisplayAsAvailablePeers(account: Account, peerId: |> mapToSignal { peers -> Signal<[FoundPeer], NoError> in return account.postbox.transaction { transaction -> [FoundPeer] in let currentTimestamp = Int32(CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970) - transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedGroupCallDisplayAsPeers, key: key), entry: CachedDisplayAsPeers(peerIds: peers.map { $0.peer.id }, timestamp: currentTimestamp), collectionSpec: ItemCacheCollectionSpec(lowWaterItemCount: 10, highWaterItemCount: 20)) + if let entry = CodableEntry(CachedDisplayAsPeers(peerIds: peers.map { $0.peer.id }, timestamp: currentTimestamp)) { + transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedGroupCallDisplayAsPeers, key: key), entry: entry, collectionSpec: ItemCacheCollectionSpec(lowWaterItemCount: 10, highWaterItemCount: 20)) + } return peers } } diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Localization/Localizations.swift b/submodules/TelegramCore/Sources/TelegramEngine/Localization/Localizations.swift index a2533fb7c7..11f8604116 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Localization/Localizations.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Localization/Localizations.swift @@ -43,7 +43,7 @@ func _internal_availableLocalizations(postbox: Postbox, network: Network, allowC let cached: Signal<[LocalizationInfo], NoError> if allowCached { cached = postbox.transaction { transaction -> Signal<[LocalizationInfo], NoError> in - if let entry = transaction.retrieveItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedAvailableLocalizations, key: ValueBoxKey(length: 0))) as? CachedLocalizationInfos { + if let entry = transaction.retrieveItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedAvailableLocalizations, key: ValueBoxKey(length: 0)))?.get(CachedLocalizationInfos.self) { return .single(entry.list) } return .complete() @@ -56,7 +56,9 @@ func _internal_availableLocalizations(postbox: Postbox, network: Network, allowC |> mapToSignal { languages -> Signal<[LocalizationInfo], NoError> in let infos: [LocalizationInfo] = languages.map(LocalizationInfo.init(apiLanguage:)) return postbox.transaction { transaction -> [LocalizationInfo] in - transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedAvailableLocalizations, key: ValueBoxKey(length: 0)), entry: CachedLocalizationInfos(list: infos), collectionSpec: ItemCacheCollectionSpec(lowWaterItemCount: 1, highWaterItemCount: 1)) + if let entry = CodableEntry(CachedLocalizationInfos(list: infos)) { + transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedAvailableLocalizations, key: ValueBoxKey(length: 0)), entry: entry, collectionSpec: ItemCacheCollectionSpec(lowWaterItemCount: 1, highWaterItemCount: 1)) + } return infos } } diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Messages/AdMessages.swift b/submodules/TelegramCore/Sources/TelegramEngine/Messages/AdMessages.swift index e6603c5c21..6c87d81cb6 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Messages/AdMessages.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Messages/AdMessages.swift @@ -201,8 +201,8 @@ private class AdMessagesHistoryContextImpl { return postbox.transaction { transaction -> CachedState? in let key = ValueBoxKey(length: 8) key.setInt64(0, value: peerId.toInt64()) - if let entry = transaction.retrieveItemCacheEntryData(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedAdMessageStates, key: key)) { - return try? AdaptedPostboxDecoder().decode(CachedState.self, from: entry) + if let entry = transaction.retrieveItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedAdMessageStates, key: key))?.get(CachedState.self) { + return entry } else { return nil } @@ -213,8 +213,8 @@ private class AdMessagesHistoryContextImpl { let key = ValueBoxKey(length: 8) key.setInt64(0, value: peerId.toInt64()) let id = ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedAdMessageStates, key: key) - if let state = state, let stateData = try? AdaptedPostboxEncoder().encode(state) { - transaction.putItemCacheEntryData(id: id, entry: stateData, collectionSpec: collectionSpec) + if let state = state, let entry = CodableEntry(state) { + transaction.putItemCacheEntry(id: id, entry: entry, collectionSpec: collectionSpec) } else { transaction.removeItemCacheEntry(id: id) } diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Messages/Polls.swift b/submodules/TelegramCore/Sources/TelegramEngine/Messages/Polls.swift index 2f95cd54c3..e4290a9a73 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Messages/Polls.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Messages/Polls.swift @@ -151,7 +151,7 @@ func _internal_requestClosePoll(postbox: Postbox, network: Network, stateManager private let cachedPollResultsCollectionSpec = ItemCacheCollectionSpec(lowWaterItemCount: 20, highWaterItemCount: 40) -final class CachedPollOptionResult: PostboxCoding { +final class CachedPollOptionResult: Codable { let peerIds: [PeerId] let count: Int32 @@ -168,14 +168,18 @@ final class CachedPollOptionResult: PostboxCoding { self.count = count } - public init(decoder: PostboxDecoder) { - self.peerIds = decoder.decodeInt64ArrayForKey("peerIds").map(PeerId.init) - self.count = decoder.decodeInt32ForKey("count", orElse: 0) + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: StringCodingKey.self) + + self.peerIds = (try container.decode([Int64].self, forKey: "peerIds")).map(PeerId.init) + self.count = try container.decode(Int32.self, forKey: "count") } - public func encode(_ encoder: PostboxEncoder) { - encoder.encodeInt64Array(self.peerIds.map { $0.toInt64() }, forKey: "peerIds") - encoder.encodeInt32(self.count, forKey: "count") + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: StringCodingKey.self) + + try container.encode(self.peerIds.map { $0.toInt64() }, forKey: "peerIds") + try container.encode(self.count, forKey: "count") } } @@ -206,7 +210,7 @@ private final class PollResultsOptionContext { self.isLoadingMore = true self.disposable.set((account.postbox.transaction { transaction -> (peers: [RenderedPeer], canLoadMore: Bool)? in - let cachedResult = transaction.retrieveItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedPollResults, key: CachedPollOptionResult.key(pollId: pollId, optionOpaqueIdentifier: opaqueIdentifier))) as? CachedPollOptionResult + let cachedResult = transaction.retrieveItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedPollResults, key: CachedPollOptionResult.key(pollId: pollId, optionOpaqueIdentifier: opaqueIdentifier)))?.get(CachedPollOptionResult.self) if let cachedResult = cachedResult, Int(cachedResult.count) == count { var result: [RenderedPeer] = [] for peerId in cachedResult.peerIds { @@ -294,15 +298,15 @@ private final class PollResultsOptionContext { } } if populateCache { - transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedPollResults, key: CachedPollOptionResult.key(pollId: pollId, optionOpaqueIdentifier: opaqueIdentifier)), entry: CachedPollOptionResult(peerIds: resultPeers.map { $0.peerId }, count: count), collectionSpec: cachedPollResultsCollectionSpec) + if let entry = CodableEntry(CachedPollOptionResult(peerIds: resultPeers.map { $0.peerId }, count: count)) { + transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedPollResults, key: CachedPollOptionResult.key(pollId: pollId, optionOpaqueIdentifier: opaqueIdentifier)), entry: entry, collectionSpec: cachedPollResultsCollectionSpec) + } } return (resultPeers, Int(count), nextOffset) } } } - #if DEBUG - //return signal |> delay(4.0, queue: .concurrentDefaultQueue()) - #endif + return signal } else { return .single(([], 0, nil)) diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Messages/RequestChatContextResults.swift b/submodules/TelegramCore/Sources/TelegramEngine/Messages/RequestChatContextResults.swift index 14f865ad8f..42394a57d6 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Messages/RequestChatContextResults.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Messages/RequestChatContextResults.swift @@ -9,7 +9,7 @@ public enum RequestChatContextResultsError { case locationRequired } -public final class CachedChatContextResult: PostboxCoding { +public final class CachedChatContextResult: Codable { public let data: Data public let timestamp: Int32 @@ -18,14 +18,18 @@ public final class CachedChatContextResult: PostboxCoding { self.timestamp = timestamp } - public init(decoder: PostboxDecoder) { - self.data = decoder.decodeDataForKey("data") ?? Data() - self.timestamp = decoder.decodeInt32ForKey("timestamp", orElse: 0) + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: StringCodingKey.self) + + self.data = try container.decode(Data.self, forKey: "data") + self.timestamp = try container.decode(Int32.self, forKey: "timestamp") } - public func encode(_ encoder: PostboxEncoder) { - encoder.encodeData(self.data, forKey: "data") - encoder.encodeInt32(self.timestamp, forKey: "timestamp") + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: StringCodingKey.self) + + try container.encode(self.data, forKey: "data") + try container.encode(self.timestamp, forKey: "timestamp") } } @@ -82,7 +86,7 @@ func _internal_requestChatContextResults(account: Account, botId: PeerId, peerId let requestData = RequestData(version: requestVersion, botId: botId, peerId: peerId, query: query) if let keyData = try? JSONEncoder().encode(requestData) { let key = ValueBoxKey(MemoryBuffer(data: keyData)) - if let cachedEntry = transaction.retrieveItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedContextResults, key: key)) as? CachedChatContextResult { + if let cachedEntry = transaction.retrieveItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedContextResults, key: key))?.get(CachedChatContextResult.self) { if let cachedResult = try? JSONDecoder().decode(ChatContextResultCollection.self, from: cachedEntry.data) { let timestamp = Int32(Date().timeIntervalSince1970) if cachedEntry.timestamp + cachedResult.cacheTimeout > timestamp { @@ -141,7 +145,9 @@ func _internal_requestChatContextResults(account: Account, botId: PeerId, peerId let requestData = RequestData(version: requestVersion, botId: botId, peerId: peerId, query: query) if let keyData = try? JSONEncoder().encode(requestData) { let key = ValueBoxKey(MemoryBuffer(data: keyData)) - transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedContextResults, key: key), entry: CachedChatContextResult(data: resultData, timestamp: Int32(Date().timeIntervalSince1970)), collectionSpec: collectionSpec) + if let entry = CodableEntry(CachedChatContextResult(data: resultData, timestamp: Int32(Date().timeIntervalSince1970))) { + transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedContextResults, key: key), entry: entry, collectionSpec: collectionSpec) + } } } } diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Peers/InvitationLinks.swift b/submodules/TelegramCore/Sources/TelegramEngine/Peers/InvitationLinks.swift index 115e641426..7a0915833a 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Peers/InvitationLinks.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Peers/InvitationLinks.swift @@ -296,7 +296,7 @@ public struct PeerExportedInvitationsState: Equatable { } } -final class CachedPeerExportedInvitations: PostboxCoding { +final class CachedPeerExportedInvitations: Codable { let invitations: [ExportedInvitation] let canLoadMore: Bool let count: Int32 @@ -314,16 +314,20 @@ final class CachedPeerExportedInvitations: PostboxCoding { self.count = count } - init(decoder: PostboxDecoder) { - self.invitations = decoder.decodeObjectArrayForKey("invitations") - self.canLoadMore = decoder.decodeBoolForKey("canLoadMore", orElse: false) - self.count = decoder.decodeInt32ForKey("count", orElse: 0) + init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: StringCodingKey.self) + + self.invitations = try container.decode([ExportedInvitation].self, forKey: "invitations") + self.canLoadMore = try container.decode(Bool.self, forKey: "canLoadMore") + self.count = try container.decode(Int32.self, forKey: "count") } - func encode(_ encoder: PostboxEncoder) { - encoder.encodeObjectArray(self.invitations, forKey: "invitations") - encoder.encodeBool(self.canLoadMore, forKey: "canLoadMore") - encoder.encodeInt32(self.count, forKey: "count") + func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: StringCodingKey.self) + + try container.encode(self.invitations, forKey: "invitations") + try container.encode(self.canLoadMore, forKey: "canLoadMore") + try container.encode(self.count, forKey: "count") } } @@ -361,7 +365,7 @@ private final class PeerExportedInvitationsContextImpl { if adminId == nil { self.isLoadingMore = true self.disposable.set((account.postbox.transaction { transaction -> CachedPeerExportedInvitations? in - return transaction.retrieveItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedPeerExportedInvitations, key: CachedPeerExportedInvitations.key(peerId: peerId, revoked: revoked))) as? CachedPeerExportedInvitations + return transaction.retrieveItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedPeerExportedInvitations, key: CachedPeerExportedInvitations.key(peerId: peerId, revoked: revoked)))?.get(CachedPeerExportedInvitations.self) } |> deliverOn(self.queue)).start(next: { [weak self] cachedResult in guard let strongSelf = self else { @@ -448,7 +452,9 @@ private final class PeerExportedInvitationsContextImpl { }) let invitations: [ExportedInvitation] = invites.compactMap { ExportedInvitation(apiExportedInvite: $0) } if populateCache { - transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedPeerExportedInvitations, key: CachedPeerExportedInvitations.key(peerId: peerId, revoked: revoked)), entry: CachedPeerExportedInvitations(invitations: invitations, canLoadMore: count >= 50, count: count), collectionSpec: cachedPeerExportedInvitationsCollectionSpec) + if let entry = CodableEntry(CachedPeerExportedInvitations(invitations: invitations, canLoadMore: count >= 50, count: count)) { + transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedPeerExportedInvitations, key: CachedPeerExportedInvitations.key(peerId: peerId, revoked: revoked)), entry: entry, collectionSpec: cachedPeerExportedInvitationsCollectionSpec) + } } return (invitations, count) } @@ -536,7 +542,9 @@ private final class PeerExportedInvitationsContextImpl { let canLoadMore = self.canLoadMore let count = self.count self.updateDisposable.set(self.account.postbox.transaction({ transaction in - transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedPeerExportedInvitations, key: CachedPeerExportedInvitations.key(peerId: peerId, revoked: revoked)), entry: CachedPeerExportedInvitations(invitations: invitations, canLoadMore: canLoadMore, count: count), collectionSpec: cachedPeerExportedInvitationsCollectionSpec) + if let entry = CodableEntry(CachedPeerExportedInvitations(invitations: invitations, canLoadMore: canLoadMore, count: count)) { + transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedPeerExportedInvitations, key: CachedPeerExportedInvitations.key(peerId: peerId, revoked: revoked)), entry: entry, collectionSpec: cachedPeerExportedInvitationsCollectionSpec) + } }).start()) } @@ -621,7 +629,7 @@ public struct PeerInvitationImportersState: Equatable { public var count: Int32 } -final class CachedPeerInvitationImporters: PostboxCoding { +final class CachedPeerInvitationImporters: Codable { let peerIds: [PeerId] let dates: [PeerId: Int32] let count: Int32 @@ -647,11 +655,13 @@ final class CachedPeerInvitationImporters: PostboxCoding { self.count = count } - init(decoder: PostboxDecoder) { - self.peerIds = decoder.decodeInt64ArrayForKey("peerIds").map(PeerId.init) + init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: StringCodingKey.self) + + self.peerIds = (try container.decode([Int64].self, forKey: "peerIds")).map(PeerId.init) var dates: [PeerId: Int32] = [:] - let datesArray = decoder.decodeInt64ArrayForKey("dates") + let datesArray = try container.decode([Int64].self, forKey: "dates") for index in stride(from: 0, to: datesArray.endIndex, by: 2) { let userId = datesArray[index] let date = datesArray[index + 1] @@ -660,20 +670,22 @@ final class CachedPeerInvitationImporters: PostboxCoding { } self.dates = dates - self.count = decoder.decodeInt32ForKey("count", orElse: 0) + self.count = try container.decode(Int32.self, forKey: "count") } - func encode(_ encoder: PostboxEncoder) { - encoder.encodeInt64Array(self.peerIds.map { $0.toInt64() }, forKey: "peerIds") + func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: StringCodingKey.self) + + try container.encode(self.peerIds.map { $0.toInt64() }, forKey: "peerIds") var dates: [Int64] = [] for (peerId, date) in self.dates { dates.append(peerId.id._internalGetInt64Value()) dates.append(Int64(date)) } - encoder.encodeInt64Array(dates, forKey: "dates") + try container.encode(dates, forKey: "dates") - encoder.encodeInt32(self.count, forKey: "count") + try container.encode(self.count, forKey: "count") } } @@ -704,7 +716,7 @@ private final class PeerInvitationImportersContextImpl { self.isLoadingMore = true self.disposable.set((account.postbox.transaction { transaction -> (peers: [PeerInvitationImportersState.Importer], canLoadMore: Bool)? in - let cachedResult = transaction.retrieveItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedPeerInvitationImporters, key: CachedPeerInvitationImporters.key(peerId: peerId, link: invite.link))) as? CachedPeerInvitationImporters + let cachedResult = transaction.retrieveItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedPeerInvitationImporters, key: CachedPeerInvitationImporters.key(peerId: peerId, link: invite.link)))?.get(CachedPeerInvitationImporters.self) if let cachedResult = cachedResult, Int(cachedResult.count) == count { var result: [PeerInvitationImportersState.Importer] = [] for peerId in cachedResult.peerIds { @@ -796,7 +808,9 @@ private final class PeerInvitationImportersContextImpl { } } if populateCache { - transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedPeerInvitationImporters, key: CachedPeerInvitationImporters.key(peerId: peerId, link: link)), entry: CachedPeerInvitationImporters(importers: resultImporters, count: count), collectionSpec: cachedPeerInvitationImportersCollectionSpec) + if let entry = CodableEntry(CachedPeerInvitationImporters(importers: resultImporters, count: count)) { + transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedPeerInvitationImporters, key: CachedPeerInvitationImporters.key(peerId: peerId, link: link)), entry: entry, collectionSpec: cachedPeerInvitationImportersCollectionSpec) + } } return (resultImporters, count) } diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Peers/RecentPeers.swift b/submodules/TelegramCore/Sources/TelegramEngine/Peers/RecentPeers.swift index 64021a5452..e5ccd9eaf3 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Peers/RecentPeers.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Peers/RecentPeers.swift @@ -19,7 +19,7 @@ func _internal_recentPeers(account: Account) -> Signal { let key = PostboxViewKey.cachedItem(cachedRecentPeersEntryId()) return account.postbox.combinedView(keys: [key]) |> mapToSignal { views -> Signal in - if let value = (views.views[key] as? CachedItemView)?.value as? CachedRecentPeers { + if let value = (views.views[key] as? CachedItemView)?.value?.get(CachedRecentPeers.self) { if value.enabled { return account.postbox.multiplePeersView(value.ids) |> map { view -> RecentPeers in @@ -41,7 +41,7 @@ func _internal_recentPeers(account: Account) -> Signal { } public func _internal_getRecentPeers(transaction: Transaction) -> [PeerId] { - guard let entry = transaction.retrieveItemCacheEntry(id: cachedRecentPeersEntryId()) as? CachedRecentPeers else { + guard let entry = transaction.retrieveItemCacheEntry(id: cachedRecentPeersEntryId())?.get(CachedRecentPeers.self) else { return [] } return entry.ids @@ -51,7 +51,7 @@ func _internal_managedUpdatedRecentPeers(accountPeerId: PeerId, postbox: Postbox let key = PostboxViewKey.cachedItem(cachedRecentPeersEntryId()) let peersEnabled = postbox.combinedView(keys: [key]) |> map { views -> Bool in - if let value = (views.views[key] as? CachedItemView)?.value as? CachedRecentPeers { + if let value = (views.views[key] as? CachedItemView)?.value?.get(CachedRecentPeers.self) { return value.enabled } else { return true @@ -80,12 +80,16 @@ func _internal_managedUpdatedRecentPeers(accountPeerId: PeerId, postbox: Postbox updatePeers(transaction: transaction, peers: peers, update: { return $1 }) updatePeerPresences(transaction: transaction, accountPeerId: accountPeerId, peerPresences: peerPresences) - - transaction.putItemCacheEntry(id: cachedRecentPeersEntryId(), entry: CachedRecentPeers(enabled: true, ids: peers.map { $0.id }), collectionSpec: collectionSpec) + + if let entry = CodableEntry(CachedRecentPeers(enabled: true, ids: peers.map { $0.id })) { + transaction.putItemCacheEntry(id: cachedRecentPeersEntryId(), entry: entry, collectionSpec: collectionSpec) + } case .topPeersNotModified: break case .topPeersDisabled: - transaction.putItemCacheEntry(id: cachedRecentPeersEntryId(), entry: CachedRecentPeers(enabled: false, ids: []), collectionSpec: collectionSpec) + if let entry = CodableEntry(CachedRecentPeers(enabled: false, ids: [])) { + transaction.putItemCacheEntry(id: cachedRecentPeersEntryId(), entry: entry, collectionSpec: collectionSpec) + } } } } @@ -97,14 +101,16 @@ func _internal_managedUpdatedRecentPeers(accountPeerId: PeerId, postbox: Postbox func _internal_removeRecentPeer(account: Account, peerId: PeerId) -> Signal { return account.postbox.transaction { transaction -> Signal in - guard let entry = transaction.retrieveItemCacheEntry(id: cachedRecentPeersEntryId()) as? CachedRecentPeers else { + guard let entry = transaction.retrieveItemCacheEntry(id: cachedRecentPeersEntryId())?.get(CachedRecentPeers.self) else { return .complete() } if let index = entry.ids.firstIndex(of: peerId) { var updatedIds = entry.ids updatedIds.remove(at: index) - transaction.putItemCacheEntry(id: cachedRecentPeersEntryId(), entry: CachedRecentPeers(enabled: entry.enabled, ids: updatedIds), collectionSpec: collectionSpec) + if let entry = CodableEntry(CachedRecentPeers(enabled: entry.enabled, ids: updatedIds)) { + transaction.putItemCacheEntry(id: cachedRecentPeersEntryId(), entry: entry, collectionSpec: collectionSpec) + } } if let peer = transaction.getPeer(peerId), let apiPeer = apiInputPeer(peer) { return account.network.request(Api.functions.contacts.resetTopPeerRating(category: .topPeerCategoryCorrespondents, peer: apiPeer)) @@ -123,7 +129,7 @@ func _internal_removeRecentPeer(account: Account, peerId: PeerId) -> Signal Signal { return postbox.transaction { transaction -> Signal in var currentValue = true - if let entry = transaction.retrieveItemCacheEntry(id: cachedRecentPeersEntryId()) as? CachedRecentPeers { + if let entry = transaction.retrieveItemCacheEntry(id: cachedRecentPeersEntryId())?.get(CachedRecentPeers.self) { currentValue = entry.enabled } @@ -138,10 +144,14 @@ func _internal_updateRecentPeersEnabled(postbox: Postbox, network: Network, enab |> mapToSignal { _ -> Signal in return postbox.transaction { transaction -> Void in if !enabled { - transaction.putItemCacheEntry(id: cachedRecentPeersEntryId(), entry: CachedRecentPeers(enabled: false, ids: []), collectionSpec: collectionSpec) + if let entry = CodableEntry(CachedRecentPeers(enabled: false, ids: [])) { + transaction.putItemCacheEntry(id: cachedRecentPeersEntryId(), entry: entry, collectionSpec: collectionSpec) + } } else { - let entry = transaction.retrieveItemCacheEntry(id: cachedRecentPeersEntryId()) as? CachedRecentPeers - transaction.putItemCacheEntry(id: cachedRecentPeersEntryId(), entry: CachedRecentPeers(enabled: true, ids: entry?.ids ?? []), collectionSpec: collectionSpec) + let entry = transaction.retrieveItemCacheEntry(id: cachedRecentPeersEntryId())?.get(CachedRecentPeers.self) + if let codableEntry = CodableEntry(CachedRecentPeers(enabled: true, ids: entry?.ids ?? [])) { + transaction.putItemCacheEntry(id: cachedRecentPeersEntryId(), entry: codableEntry, collectionSpec: collectionSpec) + } } } } diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Peers/ResolvePeerByName.swift b/submodules/TelegramCore/Sources/TelegramEngine/Peers/ResolvePeerByName.swift index 22a4261fd5..c35dd5f68c 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Peers/ResolvePeerByName.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Peers/ResolvePeerByName.swift @@ -24,7 +24,7 @@ func _internal_resolvePeerByName(account: Account, name: String, ageLimit: Int32 } return account.postbox.transaction { transaction -> CachedResolvedByNamePeer? in - return transaction.retrieveItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.resolvedByNamePeers, key: CachedResolvedByNamePeer.key(name: normalizedName))) as? CachedResolvedByNamePeer + return transaction.retrieveItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.resolvedByNamePeers, key: CachedResolvedByNamePeer.key(name: normalizedName)))?.get(CachedResolvedByNamePeer.self) } |> mapToSignal { cachedEntry -> Signal in let timestamp = Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970) if let cachedEntry = cachedEntry, cachedEntry.timestamp <= timestamp && cachedEntry.timestamp >= timestamp - ageLimit { @@ -64,7 +64,9 @@ func _internal_resolvePeerByName(account: Account, name: String, ageLimit: Int32 } let timestamp = Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970) - transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.resolvedByNamePeers, key: CachedResolvedByNamePeer.key(name: normalizedName)), entry: CachedResolvedByNamePeer(peerId: peerId, timestamp: timestamp), collectionSpec: resolvedByNamePeersCollectionSpec) + if let entry = CodableEntry(CachedResolvedByNamePeer(peerId: peerId, timestamp: timestamp)) { + transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.resolvedByNamePeers, key: CachedResolvedByNamePeer.key(name: normalizedName)), entry: entry, collectionSpec: resolvedByNamePeersCollectionSpec) + } return peerId } |> castError(Void.self) diff --git a/submodules/TelegramCore/Sources/TelegramEngine/SecureId/SecureIdConfiguration.swift b/submodules/TelegramCore/Sources/TelegramEngine/SecureId/SecureIdConfiguration.swift index 4ddc2382d5..c101294da2 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/SecureId/SecureIdConfiguration.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/SecureId/SecureIdConfiguration.swift @@ -7,7 +7,7 @@ import TelegramApi public func secureIdConfiguration(postbox: Postbox, network: Network) -> Signal { let cached: Signal = postbox.transaction { transaction -> CachedSecureIdConfiguration? in - if let entry = transaction.retrieveItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedSecureIdConfiguration, key: ValueBoxKey(length: 0))) as? CachedSecureIdConfiguration { + if let entry = transaction.retrieveItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedSecureIdConfiguration, key: ValueBoxKey(length: 0)))?.get(CachedSecureIdConfiguration.self) { return entry } else { return nil @@ -35,7 +35,9 @@ public func secureIdConfiguration(postbox: Postbox, network: Network) -> Signal< } } return postbox.transaction { transaction -> SecureIdConfiguration in - transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedSecureIdConfiguration, key: ValueBoxKey(length: 0)), entry: parsed, collectionSpec: ItemCacheCollectionSpec(lowWaterItemCount: 1, highWaterItemCount: 1)) + if let entry = CodableEntry(parsed) { + transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedSecureIdConfiguration, key: ValueBoxKey(length: 0)), entry: entry, collectionSpec: ItemCacheCollectionSpec(lowWaterItemCount: 1, highWaterItemCount: 1)) + } return parsed.value } } diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Stickers/CachedStickerPack.swift b/submodules/TelegramCore/Sources/TelegramEngine/Stickers/CachedStickerPack.swift index eac6c812bd..675a037196 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Stickers/CachedStickerPack.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Stickers/CachedStickerPack.swift @@ -13,8 +13,12 @@ public enum CachedStickerPackResult { } func cacheStickerPack(transaction: Transaction, info: StickerPackCollectionInfo, items: [ItemCollectionItem], reference: StickerPackReference? = nil) { - transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedStickerPacks, key: CachedStickerPack.cacheKey(info.id)), entry: CachedStickerPack(info: info, items: items.map { $0 as! StickerPackItem }, hash: info.hash), collectionSpec: collectionSpec) - transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedStickerPacks, key: CachedStickerPack.cacheKey(shortName: info.shortName.lowercased())), entry: CachedStickerPack(info: info, items: items.map { $0 as! StickerPackItem }, hash: info.hash), collectionSpec: collectionSpec) + if let entry = CodableEntry(CachedStickerPack(info: info, items: items.map { $0 as! StickerPackItem }, hash: info.hash)) { + transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedStickerPacks, key: CachedStickerPack.cacheKey(info.id)), entry: entry, collectionSpec: collectionSpec) + } + if let entry = CodableEntry(CachedStickerPack(info: info, items: items.map { $0 as! StickerPackItem }, hash: info.hash)) { + transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedStickerPacks, key: CachedStickerPack.cacheKey(shortName: info.shortName.lowercased())), entry: entry, collectionSpec: collectionSpec) + } if let reference = reference { var namespace: Int32? @@ -33,7 +37,9 @@ func cacheStickerPack(transaction: Transaction, info: StickerPackCollectionInfo, break } if let namespace = namespace, let id = id { - transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedStickerPacks, key: CachedStickerPack.cacheKey(ItemCollectionId(namespace: namespace, id: id))), entry: CachedStickerPack(info: info, items: items.map { $0 as! StickerPackItem }, hash: info.hash), collectionSpec: collectionSpec) + if let entry = CodableEntry(CachedStickerPack(info: info, items: items.map { $0 as! StickerPackItem }, hash: info.hash)) { + transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedStickerPacks, key: CachedStickerPack.cacheKey(ItemCollectionId(namespace: namespace, id: id))), entry: entry, collectionSpec: collectionSpec) + } } } } @@ -56,7 +62,7 @@ func _internal_cachedStickerPack(postbox: Postbox, network: Network, reference: var previousHash: Int32? switch reference { case let .id(id, _): - if let cached = transaction.retrieveItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedStickerPacks, key: CachedStickerPack.cacheKey(ItemCollectionId(namespace: namespace, id: id)))) as? CachedStickerPack, let info = cached.info { + if let cached = transaction.retrieveItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedStickerPacks, key: CachedStickerPack.cacheKey(ItemCollectionId(namespace: namespace, id: id))))?.get(CachedStickerPack.self), let info = cached.info { previousHash = cached.hash let current: CachedStickerPackResult = .result(info, cached.items, false) if cached.hash != info.hash { @@ -68,7 +74,7 @@ func _internal_cachedStickerPack(postbox: Postbox, network: Network, reference: return (.fetching, true, nil) } case let .name(shortName): - if let cached = transaction.retrieveItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedStickerPacks, key: CachedStickerPack.cacheKey(shortName: shortName.lowercased()))) as? CachedStickerPack, let info = cached.info { + if let cached = transaction.retrieveItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedStickerPacks, key: CachedStickerPack.cacheKey(shortName: shortName.lowercased())))?.get(CachedStickerPack.self), let info = cached.info { previousHash = cached.hash let current: CachedStickerPackResult = .result(info, cached.items, false) if cached.hash != info.hash { @@ -82,7 +88,7 @@ func _internal_cachedStickerPack(postbox: Postbox, network: Network, reference: case .animatedEmoji: let namespace = Namespaces.ItemCollection.CloudAnimatedEmoji let id: ItemCollectionId.Id = 0 - if let cached = transaction.retrieveItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedStickerPacks, key: CachedStickerPack.cacheKey(ItemCollectionId(namespace: namespace, id: id)))) as? CachedStickerPack, let info = cached.info { + if let cached = transaction.retrieveItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedStickerPacks, key: CachedStickerPack.cacheKey(ItemCollectionId(namespace: namespace, id: id))))?.get(CachedStickerPack.self), let info = cached.info { previousHash = cached.hash let current: CachedStickerPackResult = .result(info, cached.items, false) if cached.hash != info.hash { @@ -96,7 +102,7 @@ func _internal_cachedStickerPack(postbox: Postbox, network: Network, reference: case let .dice(emoji): let namespace = Namespaces.ItemCollection.CloudDice let id: ItemCollectionId.Id = Int64(murMurHashString32(emoji)) - if let cached = transaction.retrieveItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedStickerPacks, key: CachedStickerPack.cacheKey(ItemCollectionId(namespace: namespace, id: id)))) as? CachedStickerPack, let info = cached.info { + if let cached = transaction.retrieveItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedStickerPacks, key: CachedStickerPack.cacheKey(ItemCollectionId(namespace: namespace, id: id))))?.get(CachedStickerPack.self), let info = cached.info { previousHash = cached.hash let current: CachedStickerPackResult = .result(info, cached.items, false) if cached.hash != info.hash { @@ -110,7 +116,7 @@ func _internal_cachedStickerPack(postbox: Postbox, network: Network, reference: case .animatedEmojiAnimations: let namespace = Namespaces.ItemCollection.CloudAnimatedEmojiAnimations let id: ItemCollectionId.Id = 0 - if let cached = transaction.retrieveItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedStickerPacks, key: CachedStickerPack.cacheKey(ItemCollectionId(namespace: namespace, id: id)))) as? CachedStickerPack, let info = cached.info { + if let cached = transaction.retrieveItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedStickerPacks, key: CachedStickerPack.cacheKey(ItemCollectionId(namespace: namespace, id: id))))?.get(CachedStickerPack.self), let info = cached.info { previousHash = cached.hash let current: CachedStickerPackResult = .result(info, cached.items, false) if cached.hash != info.hash { @@ -161,7 +167,7 @@ func cachedStickerPack(transaction: Transaction, reference: StickerPackReference return (currentInfo, items, true) } } - if let cached = transaction.retrieveItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedStickerPacks, key: CachedStickerPack.cacheKey(ItemCollectionId(namespace: namespace, id: id)))) as? CachedStickerPack, let info = cached.info { + if let cached = transaction.retrieveItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedStickerPacks, key: CachedStickerPack.cacheKey(ItemCollectionId(namespace: namespace, id: id))))?.get(CachedStickerPack.self), let info = cached.info { return (info, cached.items, false) } } @@ -178,7 +184,7 @@ func cachedStickerPack(transaction: Transaction, reference: StickerPackReference } } } - if let cached = transaction.retrieveItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedStickerPacks, key: CachedStickerPack.cacheKey(shortName: shortName.lowercased()))) as? CachedStickerPack, let info = cached.info { + if let cached = transaction.retrieveItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedStickerPacks, key: CachedStickerPack.cacheKey(shortName: shortName.lowercased())))?.get(CachedStickerPack.self), let info = cached.info { return (info, cached.items, false) } case .animatedEmoji: @@ -190,7 +196,7 @@ func cachedStickerPack(transaction: Transaction, reference: StickerPackReference return (currentInfo, items, true) } } - if let cached = transaction.retrieveItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedStickerPacks, key: CachedStickerPack.cacheKey(ItemCollectionId(namespace: namespace, id: id)))) as? CachedStickerPack, let info = cached.info { + if let cached = transaction.retrieveItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedStickerPacks, key: CachedStickerPack.cacheKey(ItemCollectionId(namespace: namespace, id: id))))?.get(CachedStickerPack.self), let info = cached.info { return (info, cached.items, false) } case let .dice(emoji): @@ -202,7 +208,7 @@ func cachedStickerPack(transaction: Transaction, reference: StickerPackReference return (currentInfo, items, true) } } - if let cached = transaction.retrieveItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedStickerPacks, key: CachedStickerPack.cacheKey(ItemCollectionId(namespace: namespace, id: id)))) as? CachedStickerPack, let info = cached.info { + if let cached = transaction.retrieveItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedStickerPacks, key: CachedStickerPack.cacheKey(ItemCollectionId(namespace: namespace, id: id))))?.get(CachedStickerPack.self), let info = cached.info { return (info, cached.items, false) } case .animatedEmojiAnimations: @@ -214,7 +220,7 @@ func cachedStickerPack(transaction: Transaction, reference: StickerPackReference return (currentInfo, items, true) } } - if let cached = transaction.retrieveItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedStickerPacks, key: CachedStickerPack.cacheKey(ItemCollectionId(namespace: namespace, id: id)))) as? CachedStickerPack, let info = cached.info { + if let cached = transaction.retrieveItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedStickerPacks, key: CachedStickerPack.cacheKey(ItemCollectionId(namespace: namespace, id: id))))?.get(CachedStickerPack.self), let info = cached.info { return (info, cached.items, false) } } diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Stickers/SearchStickers.swift b/submodules/TelegramCore/Sources/TelegramEngine/Stickers/SearchStickers.swift index b94dbe42dc..04e39fc56d 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Stickers/SearchStickers.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Stickers/SearchStickers.swift @@ -172,7 +172,7 @@ func _internal_searchStickers(account: Account, query: String, scope: SearchStic result.append(contentsOf: installedItems) } - var cached = transaction.retrieveItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedStickerQueryResults, key: CachedStickerQueryResult.cacheKey(query))) as? CachedStickerQueryResult + var cached = transaction.retrieveItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedStickerQueryResults, key: CachedStickerQueryResult.cacheKey(query)))?.get(CachedStickerQueryResult.self) let currentTime = Int32(CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970) let appConfiguration: AppConfiguration = transaction.getPreferencesEntry(key: PreferencesKeys.appConfiguration)?.get(AppConfiguration.self) ?? AppConfiguration.defaultValue @@ -240,7 +240,9 @@ func _internal_searchStickers(account: Account, query: String, scope: SearchStic result.append(contentsOf: items) let currentTime = Int32(CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970) - transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedStickerQueryResults, key: CachedStickerQueryResult.cacheKey(query)), entry: CachedStickerQueryResult(items: files, hash: hash, timestamp: currentTime), collectionSpec: collectionSpec) + if let entry = CodableEntry(CachedStickerQueryResult(items: files, hash: hash, timestamp: currentTime)) { + transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedStickerQueryResults, key: CachedStickerQueryResult.cacheKey(query)), entry: entry, collectionSpec: collectionSpec) + } return result case .stickersNotModified: diff --git a/submodules/TelegramCore/Sources/Themes.swift b/submodules/TelegramCore/Sources/Themes.swift index b1fa0f1e36..5bed3c4841 100644 --- a/submodules/TelegramCore/Sources/Themes.swift +++ b/submodules/TelegramCore/Sources/Themes.swift @@ -52,7 +52,9 @@ public func telegramThemes(postbox: Postbox, network: Network, accountManager: A entries.append(OrderedItemListEntry(id: id, contents: item)) } transaction.replaceOrderedItemListItems(collectionId: Namespaces.OrderedItemList.CloudThemes, items: entries) - transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedThemesConfiguration, key: ValueBoxKey(length: 0)), entry: CachedThemesConfiguration(hash: hash), collectionSpec: ItemCacheCollectionSpec(lowWaterItemCount: 1, highWaterItemCount: 1)) + if let entry = CodableEntry(CachedThemesConfiguration(hash: hash)) { + transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedThemesConfiguration, key: ValueBoxKey(length: 0)), entry: entry, collectionSpec: ItemCacheCollectionSpec(lowWaterItemCount: 1, highWaterItemCount: 1)) + } return items } } |> then( @@ -71,7 +73,7 @@ public func telegramThemes(postbox: Postbox, network: Network, accountManager: A return fetch(nil, nil) } else { return postbox.transaction { transaction -> ([TelegramTheme], Int64?) in - let configuration = transaction.retrieveItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedThemesConfiguration, key: ValueBoxKey(length: 0))) as? CachedThemesConfiguration + let configuration = transaction.retrieveItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedThemesConfiguration, key: ValueBoxKey(length: 0)))?.get(CachedThemesConfiguration.self) let items = transaction.getOrderedListItems(collectionId: Namespaces.OrderedItemList.CloudThemes) return (items.map { $0.contents as! TelegramTheme }, configuration?.hash) } diff --git a/submodules/TelegramCore/Sources/Wallpapers.swift b/submodules/TelegramCore/Sources/Wallpapers.swift index 5722c84d27..891b43380f 100644 --- a/submodules/TelegramCore/Sources/Wallpapers.swift +++ b/submodules/TelegramCore/Sources/Wallpapers.swift @@ -46,7 +46,9 @@ public func telegramWallpapers(postbox: Postbox, network: Network, forceUpdate: entries.append(OrderedItemListEntry(id: id, contents: item)) } transaction.replaceOrderedItemListItems(collectionId: Namespaces.OrderedItemList.CloudWallpapers, items: entries) - transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedWallpapersConfiguration, key: ValueBoxKey(length: 0)), entry: CachedWallpapersConfiguration(hash: hash), collectionSpec: ItemCacheCollectionSpec(lowWaterItemCount: 1, highWaterItemCount: 1)) + if let entry = CodableEntry(CachedWallpapersConfiguration(hash: hash)) { + transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedWallpapersConfiguration, key: ValueBoxKey(length: 0)), entry: entry, collectionSpec: ItemCacheCollectionSpec(lowWaterItemCount: 1, highWaterItemCount: 1)) + } return items } } @@ -56,7 +58,7 @@ public func telegramWallpapers(postbox: Postbox, network: Network, forceUpdate: return fetch(nil, nil) } else { return postbox.transaction { transaction -> ([TelegramWallpaper], Int64?) in - let configuration = transaction.retrieveItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedWallpapersConfiguration, key: ValueBoxKey(length: 0))) as? CachedWallpapersConfiguration + let configuration = transaction.retrieveItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedWallpapersConfiguration, key: ValueBoxKey(length: 0)))?.get(CachedWallpapersConfiguration.self) let items = transaction.getOrderedListItems(collectionId: Namespaces.OrderedItemList.CloudWallpapers) if items.count == 0 { return ([.builtin(WallpaperSettings())], 0) diff --git a/submodules/TelegramNotices/Sources/Notices.swift b/submodules/TelegramNotices/Sources/Notices.swift index d45d82d04b..ffe9f04c8c 100644 --- a/submodules/TelegramNotices/Sources/Notices.swift +++ b/submodules/TelegramNotices/Sources/Notices.swift @@ -4,107 +4,78 @@ import TelegramCore import SwiftSignalKit import TelegramPermissions -public final class ApplicationSpecificBoolNotice: NoticeEntry { +public final class ApplicationSpecificBoolNotice: Codable { public init() { } - public init(decoder: PostboxDecoder) { + public init(from decoder: Decoder) throws { } - public func encode(_ encoder: PostboxEncoder) { - } - - public func isEqual(to: NoticeEntry) -> Bool { - if let _ = to as? ApplicationSpecificBoolNotice { - return true - } else { - return false - } + public func encode(to encoder: Encoder) throws { } } -public final class ApplicationSpecificVariantNotice: NoticeEntry { +public final class ApplicationSpecificVariantNotice: Codable { public let value: Bool public init(value: Bool) { self.value = value } - public init(decoder: PostboxDecoder) { - self.value = decoder.decodeInt32ForKey("v", orElse: 0) != 0 + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: StringCodingKey.self) + + self.value = try container.decode(Int32.self, forKey: "v") != 0 } - public func encode(_ encoder: PostboxEncoder) { - encoder.encodeInt32(self.value ? 1 : 0, forKey: "v") - } - - public func isEqual(to: NoticeEntry) -> Bool { - if let to = to as? ApplicationSpecificVariantNotice { - if self.value != to.value { - return false - } - return true - } else { - return false - } + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: StringCodingKey.self) + + try container.encode((self.value ? 1 : 0) as Int32, forKey: "v") } } -public final class ApplicationSpecificCounterNotice: NoticeEntry { +public final class ApplicationSpecificCounterNotice: Codable { public let value: Int32 public init(value: Int32) { self.value = value } - public init(decoder: PostboxDecoder) { - self.value = decoder.decodeInt32ForKey("v", orElse: 0) + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: StringCodingKey.self) + + self.value = try container.decode(Int32.self, forKey: "v") } - public func encode(_ encoder: PostboxEncoder) { - encoder.encodeInt32(self.value, forKey: "v") - } - - public func isEqual(to: NoticeEntry) -> Bool { - if let to = to as? ApplicationSpecificCounterNotice { - if self.value != to.value { - return false - } - return true - } else { - return false - } + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: StringCodingKey.self) + + try container.encode(self.value, forKey: "v") } } -public final class ApplicationSpecificTimestampNotice: NoticeEntry { +public final class ApplicationSpecificTimestampNotice: Codable { public let value: Int32 public init(value: Int32) { self.value = value } - public init(decoder: PostboxDecoder) { - self.value = decoder.decodeInt32ForKey("v", orElse: 0) + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: StringCodingKey.self) + + self.value = try container.decode(Int32.self, forKey: "v") } - - public func encode(_ encoder: PostboxEncoder) { - encoder.encodeInt32(self.value, forKey: "v") - } - - public func isEqual(to: NoticeEntry) -> Bool { - if let to = to as? ApplicationSpecificTimestampNotice { - if self.value != to.value { - return false - } - return true - } else { - return false - } + + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: StringCodingKey.self) + + try container.encode(self.value, forKey: "v") } } -public final class ApplicationSpecificTimestampAndCounterNotice: NoticeEntry { +public final class ApplicationSpecificTimestampAndCounterNotice: Codable { public let counter: Int32 public let timestamp: Int32 @@ -112,53 +83,39 @@ public final class ApplicationSpecificTimestampAndCounterNotice: NoticeEntry { self.counter = counter self.timestamp = timestamp } - - public init(decoder: PostboxDecoder) { - self.counter = decoder.decodeInt32ForKey("v", orElse: 0) - self.timestamp = decoder.decodeInt32ForKey("t", orElse: 0) + + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: StringCodingKey.self) + + self.counter = try container.decode(Int32.self, forKey: "v") + self.timestamp = try container.decode(Int32.self, forKey: "t") } - - public func encode(_ encoder: PostboxEncoder) { - encoder.encodeInt32(self.counter, forKey: "v") - encoder.encodeInt32(self.timestamp, forKey: "t") - } - - public func isEqual(to: NoticeEntry) -> Bool { - if let to = to as? ApplicationSpecificTimestampAndCounterNotice { - if self.counter != to.counter || self.timestamp != to.timestamp { - return false - } - return true - } else { - return false - } + + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: StringCodingKey.self) + + try container.encode(self.counter, forKey: "v") + try container.encode(self.timestamp, forKey: "t") } } -public final class ApplicationSpecificInt64ArrayNotice: NoticeEntry { +public final class ApplicationSpecificInt64ArrayNotice: Codable { public let values: [Int64] public init(values: [Int64]) { self.values = values } - public init(decoder: PostboxDecoder) { - self.values = decoder.decodeInt64ArrayForKey("v") + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: StringCodingKey.self) + + self.values = try container.decode([Int64].self, forKey: "v") } - public func encode(_ encoder: PostboxEncoder) { - encoder.encodeInt64Array(self.values, forKey: "v") - } - - public func isEqual(to: NoticeEntry) -> Bool { - if let to = to as? ApplicationSpecificInt64ArrayNotice { - if self.values != to.values { - return false - } - return true - } else { - return false - } + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: StringCodingKey.self) + + try container.encode(self.values, forKey: "v") } } @@ -366,13 +323,15 @@ public struct ApplicationSpecificNotice { public static func setIrrelevantPeerGeoReport(postbox: Postbox, peerId: PeerId) -> Signal { return postbox.transaction { transaction -> Void in - transaction.setNoticeEntry(key: ApplicationSpecificNoticeKeys.irrelevantPeerGeoNotice(peerId: peerId), value: ApplicationSpecificBoolNotice()) + if let entry = CodableEntry(ApplicationSpecificBoolNotice()) { + transaction.setNoticeEntry(key: ApplicationSpecificNoticeKeys.irrelevantPeerGeoNotice(peerId: peerId), value: entry) + } } } public static func getBotPaymentLiability(accountManager: AccountManager, peerId: PeerId) -> Signal { return accountManager.transaction { transaction -> Bool in - if let _ = transaction.getNotice(ApplicationSpecificNoticeKeys.botPaymentLiabilityNotice(peerId: peerId)) as? ApplicationSpecificBoolNotice { + if let _ = transaction.getNotice(ApplicationSpecificNoticeKeys.botPaymentLiabilityNotice(peerId: peerId))?.get(ApplicationSpecificBoolNotice.self) { return true } else { return false @@ -382,13 +341,15 @@ public struct ApplicationSpecificNotice { public static func setBotPaymentLiability(accountManager: AccountManager, peerId: PeerId) -> Signal { return accountManager.transaction { transaction -> Void in - transaction.setNotice(ApplicationSpecificNoticeKeys.botPaymentLiabilityNotice(peerId: peerId), ApplicationSpecificBoolNotice()) + if let entry = CodableEntry(ApplicationSpecificBoolNotice()) { + transaction.setNotice(ApplicationSpecificNoticeKeys.botPaymentLiabilityNotice(peerId: peerId), entry) + } } } public static func getBotGameNotice(accountManager: AccountManager, peerId: PeerId) -> Signal { return accountManager.transaction { transaction -> Bool in - if let _ = transaction.getNotice(ApplicationSpecificNoticeKeys.botGameNotice(peerId: peerId)) as? ApplicationSpecificBoolNotice { + if let _ = transaction.getNotice(ApplicationSpecificNoticeKeys.botGameNotice(peerId: peerId))?.get(ApplicationSpecificBoolNotice.self) { return true } else { return false @@ -398,13 +359,15 @@ public struct ApplicationSpecificNotice { public static func setBotGameNotice(accountManager: AccountManager, peerId: PeerId) -> Signal { return accountManager.transaction { transaction -> Void in - transaction.setNotice(ApplicationSpecificNoticeKeys.botGameNotice(peerId: peerId), ApplicationSpecificBoolNotice()) + if let entry = CodableEntry(ApplicationSpecificBoolNotice()) { + transaction.setNotice(ApplicationSpecificNoticeKeys.botGameNotice(peerId: peerId), entry) + } } } public static func getInlineBotLocationRequest(accountManager: AccountManager, peerId: PeerId) -> Signal { return accountManager.transaction { transaction -> Int32? in - if let notice = transaction.getNotice(ApplicationSpecificNoticeKeys.inlineBotLocationRequestNotice(peerId: peerId)) as? ApplicationSpecificTimestampNotice { + if let notice = transaction.getNotice(ApplicationSpecificNoticeKeys.inlineBotLocationRequestNotice(peerId: peerId))?.get(ApplicationSpecificTimestampNotice.self) { return notice.value } else { return nil @@ -415,7 +378,7 @@ public struct ApplicationSpecificNotice { public static func inlineBotLocationRequestStatus(accountManager: AccountManager, peerId: PeerId) -> Signal { return accountManager.noticeEntry(key: ApplicationSpecificNoticeKeys.inlineBotLocationRequestNotice(peerId: peerId)) |> map { view -> Bool in - guard let value = view.value as? ApplicationSpecificTimestampNotice else { + guard let value = view.value?.get(ApplicationSpecificTimestampNotice.self) else { return false } if value.value == 0 { @@ -428,11 +391,13 @@ public struct ApplicationSpecificNotice { public static func updateInlineBotLocationRequestState(accountManager: AccountManager, peerId: PeerId, timestamp: Int32) -> Signal { return accountManager.transaction { transaction -> Bool in - if let notice = transaction.getNotice(ApplicationSpecificNoticeKeys.inlineBotLocationRequestNotice(peerId: peerId)) as? ApplicationSpecificTimestampNotice, (notice.value == 0 || timestamp <= notice.value + 10 * 60) { + if let notice = transaction.getNotice(ApplicationSpecificNoticeKeys.inlineBotLocationRequestNotice(peerId: peerId))?.get(ApplicationSpecificTimestampNotice.self), (notice.value == 0 || timestamp <= notice.value + 10 * 60) { return false } - - transaction.setNotice(ApplicationSpecificNoticeKeys.inlineBotLocationRequestNotice(peerId: peerId), ApplicationSpecificTimestampNotice(value: timestamp)) + + if let entry = CodableEntry(ApplicationSpecificTimestampNotice(value: timestamp)) { + transaction.setNotice(ApplicationSpecificNoticeKeys.inlineBotLocationRequestNotice(peerId: peerId), entry) + } return true } @@ -440,13 +405,15 @@ public struct ApplicationSpecificNotice { public static func setInlineBotLocationRequest(accountManager: AccountManager, peerId: PeerId, value: Int32) -> Signal { return accountManager.transaction { transaction -> Void in - transaction.setNotice(ApplicationSpecificNoticeKeys.inlineBotLocationRequestNotice(peerId: peerId), ApplicationSpecificTimestampNotice(value: value)) + if let entry = CodableEntry(ApplicationSpecificTimestampNotice(value: value)) { + transaction.setNotice(ApplicationSpecificNoticeKeys.inlineBotLocationRequestNotice(peerId: peerId), entry) + } } } public static func getSecretChatInlineBotUsage(accountManager: AccountManager) -> Signal { return accountManager.transaction { transaction -> Bool in - if let _ = transaction.getNotice(ApplicationSpecificNoticeKeys.secretChatInlineBotUsage()) as? ApplicationSpecificBoolNotice { + if let _ = transaction.getNotice(ApplicationSpecificNoticeKeys.secretChatInlineBotUsage())?.get(ApplicationSpecificBoolNotice.self) { return true } else { return false @@ -456,17 +423,21 @@ public struct ApplicationSpecificNotice { public static func setSecretChatInlineBotUsage(accountManager: AccountManager) -> Signal { return accountManager.transaction { transaction -> Void in - transaction.setNotice(ApplicationSpecificNoticeKeys.secretChatInlineBotUsage(), ApplicationSpecificBoolNotice()) + if let entry = CodableEntry(ApplicationSpecificBoolNotice()) { + transaction.setNotice(ApplicationSpecificNoticeKeys.secretChatInlineBotUsage(), entry) + } } } public static func setSecretChatInlineBotUsage(transaction: AccountManagerModifier) { - transaction.setNotice(ApplicationSpecificNoticeKeys.secretChatInlineBotUsage(), ApplicationSpecificBoolNotice()) + if let entry = CodableEntry(ApplicationSpecificBoolNotice()) { + transaction.setNotice(ApplicationSpecificNoticeKeys.secretChatInlineBotUsage(), entry) + } } public static func getSecretChatLinkPreviews(accountManager: AccountManager) -> Signal { return accountManager.transaction { transaction -> Bool? in - if let value = transaction.getNotice(ApplicationSpecificNoticeKeys.secretChatLinkPreviews()) as? ApplicationSpecificVariantNotice { + if let value = transaction.getNotice(ApplicationSpecificNoticeKeys.secretChatLinkPreviews())?.get(ApplicationSpecificVariantNotice.self) { return value.value } else { return nil @@ -474,8 +445,8 @@ public struct ApplicationSpecificNotice { } } - public static func getSecretChatLinkPreviews(_ entry: NoticeEntry) -> Bool? { - if let value = entry as? ApplicationSpecificVariantNotice { + public static func getSecretChatLinkPreviews(_ entry: CodableEntry) -> Bool? { + if let value = entry.get(ApplicationSpecificVariantNotice.self) { return value.value } else { return nil @@ -484,12 +455,16 @@ public struct ApplicationSpecificNotice { public static func setSecretChatLinkPreviews(accountManager: AccountManager, value: Bool) -> Signal { return accountManager.transaction { transaction -> Void in - transaction.setNotice(ApplicationSpecificNoticeKeys.secretChatLinkPreviews(), ApplicationSpecificVariantNotice(value: value)) + if let entry = CodableEntry(ApplicationSpecificVariantNotice(value: value)) { + transaction.setNotice(ApplicationSpecificNoticeKeys.secretChatLinkPreviews(), entry) + } } } public static func setSecretChatLinkPreviews(transaction: AccountManagerModifier, value: Bool) { - transaction.setNotice(ApplicationSpecificNoticeKeys.secretChatLinkPreviews(), ApplicationSpecificVariantNotice(value: value)) + if let entry = CodableEntry(ApplicationSpecificVariantNotice(value: value)) { + transaction.setNotice(ApplicationSpecificNoticeKeys.secretChatLinkPreviews(), entry) + } } public static func secretChatLinkPreviewsKey() -> NoticeEntryKey { @@ -498,7 +473,7 @@ public struct ApplicationSpecificNotice { public static func getChatMediaMediaRecordingTips(accountManager: AccountManager) -> Signal { return accountManager.transaction { transaction -> Int32 in - if let value = transaction.getNotice(ApplicationSpecificNoticeKeys.chatMediaMediaRecordingTips()) as? ApplicationSpecificCounterNotice { + if let value = transaction.getNotice(ApplicationSpecificNoticeKeys.chatMediaMediaRecordingTips())?.get(ApplicationSpecificCounterNotice.self) { return value.value } else { return 0 @@ -509,18 +484,20 @@ public struct ApplicationSpecificNotice { public static func incrementChatMediaMediaRecordingTips(accountManager: AccountManager, count: Int32 = 1) -> Signal { return accountManager.transaction { transaction -> Void in var currentValue: Int32 = 0 - if let value = transaction.getNotice(ApplicationSpecificNoticeKeys.chatMediaMediaRecordingTips()) as? ApplicationSpecificCounterNotice { + if let value = transaction.getNotice(ApplicationSpecificNoticeKeys.chatMediaMediaRecordingTips())?.get(ApplicationSpecificCounterNotice.self) { currentValue = value.value } currentValue += count - - transaction.setNotice(ApplicationSpecificNoticeKeys.chatMediaMediaRecordingTips(), ApplicationSpecificCounterNotice(value: currentValue)) + + if let entry = CodableEntry(ApplicationSpecificCounterNotice(value: currentValue)) { + transaction.setNotice(ApplicationSpecificNoticeKeys.chatMediaMediaRecordingTips(), entry) + } } } public static func getArchiveChatTips(accountManager: AccountManager) -> Signal { return accountManager.transaction { transaction -> Int32 in - if let value = transaction.getNotice(ApplicationSpecificNoticeKeys.archiveChatTips()) as? ApplicationSpecificCounterNotice { + if let value = transaction.getNotice(ApplicationSpecificNoticeKeys.archiveChatTips())?.get(ApplicationSpecificCounterNotice.self) { return value.value } else { return 0 @@ -531,13 +508,15 @@ public struct ApplicationSpecificNotice { public static func incrementArchiveChatTips(accountManager: AccountManager, count: Int = 1) -> Signal { return accountManager.transaction { transaction -> Int in var currentValue: Int32 = 0 - if let value = transaction.getNotice(ApplicationSpecificNoticeKeys.archiveChatTips()) as? ApplicationSpecificCounterNotice { + if let value = transaction.getNotice(ApplicationSpecificNoticeKeys.archiveChatTips())?.get(ApplicationSpecificCounterNotice.self) { currentValue = value.value } let previousValue = currentValue currentValue += Int32(count) - - transaction.setNotice(ApplicationSpecificNoticeKeys.archiveChatTips(), ApplicationSpecificCounterNotice(value: currentValue)) + + if let entry = CodableEntry(ApplicationSpecificCounterNotice(value: currentValue)) { + transaction.setNotice(ApplicationSpecificNoticeKeys.archiveChatTips(), entry) + } return Int(previousValue) } @@ -546,20 +525,24 @@ public struct ApplicationSpecificNotice { public static func incrementChatFolderTips(accountManager: AccountManager, count: Int = 1) -> Signal { return accountManager.transaction { transaction -> Int in var currentValue: Int32 = 0 - if let value = transaction.getNotice(ApplicationSpecificNoticeKeys.chatFolderTips()) as? ApplicationSpecificCounterNotice { + if let value = transaction.getNotice(ApplicationSpecificNoticeKeys.chatFolderTips())?.get(ApplicationSpecificCounterNotice.self) { currentValue = value.value } let previousValue = currentValue currentValue += Int32(count) - - transaction.setNotice(ApplicationSpecificNoticeKeys.chatFolderTips(), ApplicationSpecificCounterNotice(value: currentValue)) + + if let entry = CodableEntry(ApplicationSpecificCounterNotice(value: currentValue)) { + transaction.setNotice(ApplicationSpecificNoticeKeys.chatFolderTips(), entry) + } return Int(previousValue) } } public static func setArchiveIntroDismissed(transaction: AccountManagerModifier, value: Bool) { - transaction.setNotice(ApplicationSpecificNoticeKeys.archiveIntroDismissed(), ApplicationSpecificVariantNotice(value: value)) + if let entry = CodableEntry(ApplicationSpecificVariantNotice(value: value)) { + transaction.setNotice(ApplicationSpecificNoticeKeys.archiveIntroDismissed(), entry) + } } public static func archiveIntroDismissedKey() -> NoticeEntryKey { @@ -568,7 +551,7 @@ public struct ApplicationSpecificNotice { public static func getProfileCallTips(accountManager: AccountManager) -> Signal { return accountManager.transaction { transaction -> Int32 in - if let value = transaction.getNotice(ApplicationSpecificNoticeKeys.profileCallTips()) as? ApplicationSpecificCounterNotice { + if let value = transaction.getNotice(ApplicationSpecificNoticeKeys.profileCallTips())?.get(ApplicationSpecificCounterNotice.self) { return value.value } else { return 0 @@ -579,18 +562,20 @@ public struct ApplicationSpecificNotice { public static func incrementProfileCallTips(accountManager: AccountManager, count: Int32 = 1) -> Signal { return accountManager.transaction { transaction -> Void in var currentValue: Int32 = 0 - if let value = transaction.getNotice(ApplicationSpecificNoticeKeys.profileCallTips()) as? ApplicationSpecificCounterNotice { + if let value = transaction.getNotice(ApplicationSpecificNoticeKeys.profileCallTips())?.get(ApplicationSpecificCounterNotice.self) { currentValue = value.value } currentValue += count - - transaction.setNotice(ApplicationSpecificNoticeKeys.profileCallTips(), ApplicationSpecificCounterNotice(value: currentValue)) + + if let entry = CodableEntry(ApplicationSpecificCounterNotice(value: currentValue)) { + transaction.setNotice(ApplicationSpecificNoticeKeys.profileCallTips(), entry) + } } } public static func getSetPublicChannelLink(accountManager: AccountManager) -> Signal { return accountManager.transaction { transaction -> Bool in - if let value = transaction.getNotice(ApplicationSpecificNoticeKeys.profileCallTips()) as? ApplicationSpecificCounterNotice { + if let value = transaction.getNotice(ApplicationSpecificNoticeKeys.profileCallTips())?.get(ApplicationSpecificCounterNotice.self) { return value.value < 1 } else { return true @@ -600,13 +585,15 @@ public struct ApplicationSpecificNotice { public static func markAsSeenSetPublicChannelLink(accountManager: AccountManager) -> Signal { return accountManager.transaction { transaction -> Void in - transaction.setNotice(ApplicationSpecificNoticeKeys.profileCallTips(), ApplicationSpecificCounterNotice(value: 1)) + if let entry = CodableEntry(ApplicationSpecificCounterNotice(value: 1)) { + transaction.setNotice(ApplicationSpecificNoticeKeys.profileCallTips(), entry) + } } } public static func getProxyAdsAcknowledgment(accountManager: AccountManager) -> Signal { return accountManager.transaction { transaction -> Bool in - if let _ = transaction.getNotice(ApplicationSpecificNoticeKeys.proxyAdsAcknowledgment()) as? ApplicationSpecificBoolNotice { + if let _ = transaction.getNotice(ApplicationSpecificNoticeKeys.proxyAdsAcknowledgment())?.get(ApplicationSpecificBoolNotice.self) { return true } else { return false @@ -616,13 +603,15 @@ public struct ApplicationSpecificNotice { public static func setProxyAdsAcknowledgment(accountManager: AccountManager) -> Signal { return accountManager.transaction { transaction -> Void in - transaction.setNotice(ApplicationSpecificNoticeKeys.proxyAdsAcknowledgment(), ApplicationSpecificBoolNotice()) + if let entry = CodableEntry(ApplicationSpecificBoolNotice()) { + transaction.setNotice(ApplicationSpecificNoticeKeys.proxyAdsAcknowledgment(), entry) + } } } public static func getPsaAcknowledgment(accountManager: AccountManager, peerId: PeerId) -> Signal { return accountManager.transaction { transaction -> Bool in - if let _ = transaction.getNotice(ApplicationSpecificNoticeKeys.psaAdsAcknowledgment(peerId: peerId)) as? ApplicationSpecificBoolNotice { + if let _ = transaction.getNotice(ApplicationSpecificNoticeKeys.psaAdsAcknowledgment(peerId: peerId))?.get(ApplicationSpecificBoolNotice.self) { return true } else { return false @@ -632,13 +621,15 @@ public struct ApplicationSpecificNotice { public static func setPsaAcknowledgment(accountManager: AccountManager, peerId: PeerId) -> Signal { return accountManager.transaction { transaction -> Void in - transaction.setNotice(ApplicationSpecificNoticeKeys.psaAdsAcknowledgment(peerId: peerId), ApplicationSpecificBoolNotice()) + if let entry = CodableEntry(ApplicationSpecificBoolNotice()) { + transaction.setNotice(ApplicationSpecificNoticeKeys.psaAdsAcknowledgment(peerId: peerId), entry) + } } } public static func getPasscodeLockTips(accountManager: AccountManager) -> Signal { return accountManager.transaction { transaction -> Bool in - if let _ = transaction.getNotice(ApplicationSpecificNoticeKeys.passcodeLockTips()) as? ApplicationSpecificBoolNotice { + if let _ = transaction.getNotice(ApplicationSpecificNoticeKeys.passcodeLockTips())?.get(ApplicationSpecificBoolNotice.self) { return true } else { return false @@ -648,7 +639,9 @@ public struct ApplicationSpecificNotice { public static func setPasscodeLockTips(accountManager: AccountManager) -> Signal { return accountManager.transaction { transaction -> Void in - transaction.setNotice(ApplicationSpecificNoticeKeys.passcodeLockTips(), ApplicationSpecificBoolNotice()) + if let entry = CodableEntry(ApplicationSpecificBoolNotice()) { + transaction.setNotice(ApplicationSpecificNoticeKeys.passcodeLockTips(), entry) + } } } @@ -660,13 +653,15 @@ public struct ApplicationSpecificNotice { guard let noticeKey = permission.noticeKey else { return } - let _ = accountManager.transaction { transaction -> Void in - transaction.setNotice(noticeKey, ApplicationSpecificTimestampNotice(value: value)) - }.start() + let _ = (accountManager.transaction { transaction -> Void in + if let entry = CodableEntry(ApplicationSpecificTimestampNotice(value: value)) { + transaction.setNotice(noticeKey, entry) + } + }).start() } - public static func getTimestampValue(_ entry: NoticeEntry) -> Int32? { - if let value = entry as? ApplicationSpecificTimestampNotice { + public static func getTimestampValue(_ entry: CodableEntry) -> Int32? { + if let value = entry.get(ApplicationSpecificTimestampNotice.self) { return value.value } else { return nil @@ -675,7 +670,7 @@ public struct ApplicationSpecificNotice { public static func getVolumeButtonToUnmute(accountManager: AccountManager) -> Signal { return accountManager.transaction { transaction -> Bool in - if let _ = transaction.getNotice(ApplicationSpecificNoticeKeys.volumeButtonToUnmuteTip()) as? ApplicationSpecificBoolNotice { + if let _ = transaction.getNotice(ApplicationSpecificNoticeKeys.volumeButtonToUnmuteTip())?.get(ApplicationSpecificBoolNotice.self) { return true } else { return false @@ -685,13 +680,15 @@ public struct ApplicationSpecificNotice { public static func setVolumeButtonToUnmute(accountManager: AccountManager) { let _ = accountManager.transaction { transaction -> Void in - transaction.setNotice(ApplicationSpecificNoticeKeys.volumeButtonToUnmuteTip(), ApplicationSpecificBoolNotice()) + if let entry = CodableEntry(ApplicationSpecificBoolNotice()) { + transaction.setNotice(ApplicationSpecificNoticeKeys.volumeButtonToUnmuteTip(), entry) + } }.start() } public static func getCallsTabTip(accountManager: AccountManager) -> Signal { return accountManager.transaction { transaction -> Int32 in - if let value = transaction.getNotice(ApplicationSpecificNoticeKeys.callsTabTip()) as? ApplicationSpecificCounterNotice { + if let value = transaction.getNotice(ApplicationSpecificNoticeKeys.callsTabTip())?.get(ApplicationSpecificCounterNotice.self) { return value.value } else { return 0 @@ -702,13 +699,15 @@ public struct ApplicationSpecificNotice { public static func incrementCallsTabTips(accountManager: AccountManager, count: Int = 1) -> Signal { return accountManager.transaction { transaction -> Int in var currentValue: Int32 = 0 - if let value = transaction.getNotice(ApplicationSpecificNoticeKeys.callsTabTip()) as? ApplicationSpecificCounterNotice { + if let value = transaction.getNotice(ApplicationSpecificNoticeKeys.callsTabTip())?.get(ApplicationSpecificCounterNotice.self) { currentValue = value.value } let previousValue = currentValue currentValue += min(3, Int32(count)) - - transaction.setNotice(ApplicationSpecificNoticeKeys.callsTabTip(), ApplicationSpecificCounterNotice(value: currentValue)) + + if let entry = CodableEntry(ApplicationSpecificCounterNotice(value: currentValue)) { + transaction.setNotice(ApplicationSpecificNoticeKeys.callsTabTip(), entry) + } return Int(previousValue) } @@ -716,14 +715,16 @@ public struct ApplicationSpecificNotice { public static func setCallsTabTip(accountManager: AccountManager) -> Signal { return accountManager.transaction { transaction -> Void in - transaction.setNotice(ApplicationSpecificNoticeKeys.callsTabTip(), ApplicationSpecificBoolNotice()) + if let entry = CodableEntry(ApplicationSpecificBoolNotice()) { + transaction.setNotice(ApplicationSpecificNoticeKeys.callsTabTip(), entry) + } } } public static func getChatMessageSearchResultsTip(accountManager: AccountManager) -> Signal { return accountManager.transaction { transaction -> Int32 in - if let value = transaction.getNotice(ApplicationSpecificNoticeKeys.chatMessageSearchResultsTip()) as? ApplicationSpecificCounterNotice { + if let value = transaction.getNotice(ApplicationSpecificNoticeKeys.chatMessageSearchResultsTip())?.get(ApplicationSpecificCounterNotice.self) { return value.value } else { return 0 @@ -734,18 +735,20 @@ public struct ApplicationSpecificNotice { public static func incrementChatMessageSearchResultsTip(accountManager: AccountManager, count: Int32 = 1) -> Signal { return accountManager.transaction { transaction -> Void in var currentValue: Int32 = 0 - if let value = transaction.getNotice(ApplicationSpecificNoticeKeys.chatMessageSearchResultsTip()) as? ApplicationSpecificCounterNotice { + if let value = transaction.getNotice(ApplicationSpecificNoticeKeys.chatMessageSearchResultsTip())?.get(ApplicationSpecificCounterNotice.self) { currentValue = value.value } currentValue += count - - transaction.setNotice(ApplicationSpecificNoticeKeys.chatMessageSearchResultsTip(), ApplicationSpecificCounterNotice(value: currentValue)) + + if let entry = CodableEntry(ApplicationSpecificCounterNotice(value: currentValue)) { + transaction.setNotice(ApplicationSpecificNoticeKeys.chatMessageSearchResultsTip(), entry) + } } } public static func getChatMessageOptionsTip(accountManager: AccountManager) -> Signal { return accountManager.transaction { transaction -> Int32 in - if let value = transaction.getNotice(ApplicationSpecificNoticeKeys.chatMessageOptionsTip()) as? ApplicationSpecificCounterNotice { + if let value = transaction.getNotice(ApplicationSpecificNoticeKeys.chatMessageOptionsTip())?.get(ApplicationSpecificCounterNotice.self) { return value.value } else { return 0 @@ -756,18 +759,20 @@ public struct ApplicationSpecificNotice { public static func incrementChatMessageOptionsTip(accountManager: AccountManager, count: Int32 = 1) -> Signal { return accountManager.transaction { transaction -> Void in var currentValue: Int32 = 0 - if let value = transaction.getNotice(ApplicationSpecificNoticeKeys.chatMessageOptionsTip()) as? ApplicationSpecificCounterNotice { + if let value = transaction.getNotice(ApplicationSpecificNoticeKeys.chatMessageOptionsTip())?.get(ApplicationSpecificCounterNotice.self) { currentValue = value.value } currentValue += count - - transaction.setNotice(ApplicationSpecificNoticeKeys.chatMessageOptionsTip(), ApplicationSpecificCounterNotice(value: currentValue)) + + if let entry = CodableEntry(ApplicationSpecificCounterNotice(value: currentValue)) { + transaction.setNotice(ApplicationSpecificNoticeKeys.chatMessageOptionsTip(), entry) + } } } public static func getChatTextSelectionTips(accountManager: AccountManager) -> Signal { return accountManager.transaction { transaction -> Int32 in - if let value = transaction.getNotice(ApplicationSpecificNoticeKeys.chatTextSelectionTip()) as? ApplicationSpecificCounterNotice { + if let value = transaction.getNotice(ApplicationSpecificNoticeKeys.chatTextSelectionTip())?.get(ApplicationSpecificCounterNotice.self) { return value.value } else { return 0 @@ -778,18 +783,20 @@ public struct ApplicationSpecificNotice { public static func incrementChatTextSelectionTips(accountManager: AccountManager, count: Int32 = 1) -> Signal { return accountManager.transaction { transaction -> Void in var currentValue: Int32 = 0 - if let value = transaction.getNotice(ApplicationSpecificNoticeKeys.chatTextSelectionTip()) as? ApplicationSpecificCounterNotice { + if let value = transaction.getNotice(ApplicationSpecificNoticeKeys.chatTextSelectionTip())?.get(ApplicationSpecificCounterNotice.self) { currentValue = value.value } currentValue += count - - transaction.setNotice(ApplicationSpecificNoticeKeys.chatTextSelectionTip(), ApplicationSpecificCounterNotice(value: currentValue)) + + if let entry = CodableEntry(ApplicationSpecificCounterNotice(value: currentValue)) { + transaction.setNotice(ApplicationSpecificNoticeKeys.chatTextSelectionTip(), entry) + } } } public static func getMessageViewsPrivacyTips(accountManager: AccountManager) -> Signal { return accountManager.transaction { transaction -> Int32 in - if let value = transaction.getNotice(ApplicationSpecificNoticeKeys.messageViewsPrivacyTips()) as? ApplicationSpecificCounterNotice { + if let value = transaction.getNotice(ApplicationSpecificNoticeKeys.messageViewsPrivacyTips())?.get(ApplicationSpecificCounterNotice.self) { return value.value } else { return 0 @@ -800,18 +807,20 @@ public struct ApplicationSpecificNotice { public static func incrementMessageViewsPrivacyTips(accountManager: AccountManager, count: Int32 = 1) -> Signal { return accountManager.transaction { transaction -> Void in var currentValue: Int32 = 0 - if let value = transaction.getNotice(ApplicationSpecificNoticeKeys.messageViewsPrivacyTips()) as? ApplicationSpecificCounterNotice { + if let value = transaction.getNotice(ApplicationSpecificNoticeKeys.messageViewsPrivacyTips())?.get(ApplicationSpecificCounterNotice.self) { currentValue = value.value } currentValue += count - transaction.setNotice(ApplicationSpecificNoticeKeys.messageViewsPrivacyTips(), ApplicationSpecificCounterNotice(value: currentValue)) + if let entry = CodableEntry(ApplicationSpecificCounterNotice(value: currentValue)) { + transaction.setNotice(ApplicationSpecificNoticeKeys.messageViewsPrivacyTips(), entry) + } } } public static func getThemeChangeTip(accountManager: AccountManager) -> Signal { return accountManager.transaction { transaction -> Bool in - if let _ = transaction.getNotice(ApplicationSpecificNoticeKeys.themeChangeTip()) as? ApplicationSpecificBoolNotice { + if let _ = transaction.getNotice(ApplicationSpecificNoticeKeys.themeChangeTip())?.get(ApplicationSpecificBoolNotice.self) { return true } else { return false @@ -821,13 +830,15 @@ public struct ApplicationSpecificNotice { public static func markThemeChangeTipAsSeen(accountManager: AccountManager) { let _ = accountManager.transaction { transaction -> Void in - transaction.setNotice(ApplicationSpecificNoticeKeys.themeChangeTip(), ApplicationSpecificBoolNotice()) + if let entry = CodableEntry(ApplicationSpecificBoolNotice()) { + transaction.setNotice(ApplicationSpecificNoticeKeys.themeChangeTip(), entry) + } }.start() } public static func getLocationProximityAlertTip(accountManager: AccountManager) -> Signal { return accountManager.transaction { transaction -> Int32 in - if let value = transaction.getNotice(ApplicationSpecificNoticeKeys.chatMessageOptionsTip()) as? ApplicationSpecificCounterNotice { + if let value = transaction.getNotice(ApplicationSpecificNoticeKeys.chatMessageOptionsTip())?.get(ApplicationSpecificCounterNotice.self) { return value.value } else { return 0 @@ -838,18 +849,20 @@ public struct ApplicationSpecificNotice { public static func incrementLocationProximityAlertTip(accountManager: AccountManager, count: Int32 = 1) -> Signal { return accountManager.transaction { transaction -> Void in var currentValue: Int32 = 0 - if let value = transaction.getNotice(ApplicationSpecificNoticeKeys.chatMessageOptionsTip()) as? ApplicationSpecificCounterNotice { + if let value = transaction.getNotice(ApplicationSpecificNoticeKeys.chatMessageOptionsTip())?.get(ApplicationSpecificCounterNotice.self) { currentValue = value.value } currentValue += count - - transaction.setNotice(ApplicationSpecificNoticeKeys.chatMessageOptionsTip(), ApplicationSpecificCounterNotice(value: currentValue)) + + if let entry = CodableEntry(ApplicationSpecificCounterNotice(value: currentValue)) { + transaction.setNotice(ApplicationSpecificNoticeKeys.chatMessageOptionsTip(), entry) + } } } public static func getNextChatSuggestionTip(accountManager: AccountManager) -> Signal { return accountManager.transaction { transaction -> Int32 in - if let value = transaction.getNotice(ApplicationSpecificNoticeKeys.nextChatSuggestionTip()) as? ApplicationSpecificCounterNotice { + if let value = transaction.getNotice(ApplicationSpecificNoticeKeys.nextChatSuggestionTip())?.get(ApplicationSpecificCounterNotice.self) { return value.value } else { return 0 @@ -860,19 +873,21 @@ public struct ApplicationSpecificNotice { public static func incrementNextChatSuggestionTip(accountManager: AccountManager, count: Int32 = 1) -> Signal { return accountManager.transaction { transaction -> Void in var currentValue: Int32 = 0 - if let value = transaction.getNotice(ApplicationSpecificNoticeKeys.nextChatSuggestionTip()) as? ApplicationSpecificCounterNotice { + if let value = transaction.getNotice(ApplicationSpecificNoticeKeys.nextChatSuggestionTip())?.get(ApplicationSpecificCounterNotice.self) { currentValue = value.value } currentValue += count - transaction.setNotice(ApplicationSpecificNoticeKeys.nextChatSuggestionTip(), ApplicationSpecificCounterNotice(value: currentValue)) + if let entry = CodableEntry(ApplicationSpecificCounterNotice(value: currentValue)) { + transaction.setNotice(ApplicationSpecificNoticeKeys.nextChatSuggestionTip(), entry) + } } } public static func dismissedTrendingStickerPacks(accountManager: AccountManager) -> Signal<[Int64]?, NoError> { return accountManager.noticeEntry(key: ApplicationSpecificNoticeKeys.dismissedTrendingStickerPacks()) |> map { view -> [Int64]? in - if let value = view.value as? ApplicationSpecificInt64ArrayNotice { + if let value = view.value?.get(ApplicationSpecificInt64ArrayNotice.self) { return value.values } else { return nil @@ -882,13 +897,15 @@ public struct ApplicationSpecificNotice { public static func setDismissedTrendingStickerPacks(accountManager: AccountManager, values: [Int64]) -> Signal { return accountManager.transaction { transaction -> Void in - transaction.setNotice(ApplicationSpecificNoticeKeys.dismissedTrendingStickerPacks(), ApplicationSpecificInt64ArrayNotice(values: values)) + if let entry = CodableEntry(ApplicationSpecificInt64ArrayNotice(values: values)) { + transaction.setNotice(ApplicationSpecificNoticeKeys.dismissedTrendingStickerPacks(), entry) + } } } public static func getChatSpecificThemeLightPreviewTip(accountManager: AccountManager) -> Signal<(Int32, Int32), NoError> { return accountManager.transaction { transaction -> (Int32, Int32) in - if let value = transaction.getNotice(ApplicationSpecificNoticeKeys.chatSpecificThemeLightPreviewTip()) as? ApplicationSpecificTimestampAndCounterNotice { + if let value = transaction.getNotice(ApplicationSpecificNoticeKeys.chatSpecificThemeLightPreviewTip())?.get(ApplicationSpecificTimestampAndCounterNotice.self) { return (value.counter, value.timestamp) } else { return (0, 0) @@ -899,13 +916,15 @@ public struct ApplicationSpecificNotice { public static func incrementChatSpecificThemeLightPreviewTip(accountManager: AccountManager, count: Int = 1, timestamp: Int32) -> Signal { return accountManager.transaction { transaction -> Int in var currentValue: Int32 = 0 - if let value = transaction.getNotice(ApplicationSpecificNoticeKeys.chatSpecificThemeLightPreviewTip()) as? ApplicationSpecificTimestampAndCounterNotice { + if let value = transaction.getNotice(ApplicationSpecificNoticeKeys.chatSpecificThemeLightPreviewTip())?.get(ApplicationSpecificTimestampAndCounterNotice.self) { currentValue = value.counter } let previousValue = currentValue currentValue += Int32(count) - - transaction.setNotice(ApplicationSpecificNoticeKeys.chatSpecificThemeLightPreviewTip(), ApplicationSpecificTimestampAndCounterNotice(counter: currentValue, timestamp: timestamp)) + + if let entry = CodableEntry(ApplicationSpecificTimestampAndCounterNotice(counter: currentValue, timestamp: timestamp)) { + transaction.setNotice(ApplicationSpecificNoticeKeys.chatSpecificThemeLightPreviewTip(), entry) + } return Int(previousValue) } @@ -913,7 +932,7 @@ public struct ApplicationSpecificNotice { public static func getChatSpecificThemeDarkPreviewTip(accountManager: AccountManager) -> Signal<(Int32, Int32), NoError> { return accountManager.transaction { transaction -> (Int32, Int32) in - if let value = transaction.getNotice(ApplicationSpecificNoticeKeys.chatSpecificThemeDarkPreviewTip()) as? ApplicationSpecificTimestampAndCounterNotice { + if let value = transaction.getNotice(ApplicationSpecificNoticeKeys.chatSpecificThemeDarkPreviewTip())?.get(ApplicationSpecificTimestampAndCounterNotice.self) { return (value.counter, value.timestamp) } else { return (0, 0) @@ -924,13 +943,15 @@ public struct ApplicationSpecificNotice { public static func incrementChatSpecificThemeDarkPreviewTip(accountManager: AccountManager, count: Int = 1, timestamp: Int32) -> Signal { return accountManager.transaction { transaction -> Int in var currentValue: Int32 = 0 - if let value = transaction.getNotice(ApplicationSpecificNoticeKeys.chatSpecificThemeDarkPreviewTip()) as? ApplicationSpecificTimestampAndCounterNotice { + if let value = transaction.getNotice(ApplicationSpecificNoticeKeys.chatSpecificThemeDarkPreviewTip())?.get(ApplicationSpecificTimestampAndCounterNotice.self) { currentValue = value.counter } let previousValue = currentValue currentValue += Int32(count) - - transaction.setNotice(ApplicationSpecificNoticeKeys.chatSpecificThemeDarkPreviewTip(), ApplicationSpecificTimestampAndCounterNotice(counter: currentValue, timestamp: timestamp)) + + if let entry = CodableEntry(ApplicationSpecificTimestampAndCounterNotice(counter: currentValue, timestamp: timestamp)) { + transaction.setNotice(ApplicationSpecificNoticeKeys.chatSpecificThemeDarkPreviewTip(), entry) + } return Int(previousValue) } @@ -938,7 +959,7 @@ public struct ApplicationSpecificNotice { public static func getChatForwardOptionsTip(accountManager: AccountManager) -> Signal { return accountManager.transaction { transaction -> Int32 in - if let value = transaction.getNotice(ApplicationSpecificNoticeKeys.chatForwardOptionsTip()) as? ApplicationSpecificCounterNotice { + if let value = transaction.getNotice(ApplicationSpecificNoticeKeys.chatForwardOptionsTip())?.get(ApplicationSpecificCounterNotice.self) { return value.value } else { return 0 @@ -949,13 +970,15 @@ public struct ApplicationSpecificNotice { public static func incrementChatForwardOptionsTip(accountManager: AccountManager, count: Int = 1) -> Signal { return accountManager.transaction { transaction -> Int in var currentValue: Int32 = 0 - if let value = transaction.getNotice(ApplicationSpecificNoticeKeys.chatForwardOptionsTip()) as? ApplicationSpecificCounterNotice { + if let value = transaction.getNotice(ApplicationSpecificNoticeKeys.chatForwardOptionsTip())?.get(ApplicationSpecificCounterNotice.self) { currentValue = value.value } let previousValue = currentValue currentValue += Int32(count) - - transaction.setNotice(ApplicationSpecificNoticeKeys.chatForwardOptionsTip(), ApplicationSpecificCounterNotice(value: currentValue)) + + if let entry = CodableEntry(ApplicationSpecificCounterNotice(value: currentValue)) { + transaction.setNotice(ApplicationSpecificNoticeKeys.chatForwardOptionsTip(), entry) + } return Int(previousValue) } diff --git a/submodules/TelegramUI/Sources/ChatController.swift b/submodules/TelegramUI/Sources/ChatController.swift index afd513db1b..36591ad279 100644 --- a/submodules/TelegramUI/Sources/ChatController.swift +++ b/submodules/TelegramUI/Sources/ChatController.swift @@ -3056,7 +3056,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G onlineMemberCount = recentOnlineSignal self.reportIrrelvantGeoNoticePromise.set(context.account.postbox.transaction { transaction -> Bool? in - if let _ = transaction.getNoticeEntry(key: ApplicationSpecificNotice.irrelevantPeerGeoReportKey(peerId: peerId)) as? ApplicationSpecificBoolNotice { + if let _ = transaction.getNoticeEntry(key: ApplicationSpecificNotice.irrelevantPeerGeoReportKey(peerId: peerId))?.get(ApplicationSpecificBoolNotice.self) { return true } else { return false diff --git a/submodules/TelegramUI/Sources/ChatHistoryEntriesForView.swift b/submodules/TelegramUI/Sources/ChatHistoryEntriesForView.swift index 3048de66d5..c4ea94c708 100644 --- a/submodules/TelegramUI/Sources/ChatHistoryEntriesForView.swift +++ b/submodules/TelegramUI/Sources/ChatHistoryEntriesForView.swift @@ -35,7 +35,7 @@ func chatHistoryEntriesForView( if case let .peer(peerId) = location, peerId.namespace == Namespaces.Peer.CloudChannel { for additionalEntry in view.additionalData { if case let .cacheEntry(id, data) = additionalEntry { - if id == cachedChannelAdminRanksEntryId(peerId: peerId), let data = data as? CachedChannelAdminRanks { + if id == cachedChannelAdminRanksEntryId(peerId: peerId), let data = data?.get(CachedChannelAdminRanks.self) { adminRanks = data.ranks } } else if case let .peer(_, peer) = additionalEntry, let channel = peer as? TelegramChannel, !channel.flags.contains(.isGigagroup) { diff --git a/submodules/TelegramUI/Sources/DeclareEncodables.swift b/submodules/TelegramUI/Sources/DeclareEncodables.swift index ab9d486b56..fb6a3a086f 100644 --- a/submodules/TelegramUI/Sources/DeclareEncodables.swift +++ b/submodules/TelegramUI/Sources/DeclareEncodables.swift @@ -14,50 +14,14 @@ import LocationUI import ChatInterfaceState private var telegramUIDeclaredEncodables: Void = { - //declareEncodable(InAppNotificationSettings.self, f: { InAppNotificationSettings(decoder: $0) }) declareEncodable(VideoLibraryMediaResource.self, f: { VideoLibraryMediaResource(decoder: $0) }) declareEncodable(LocalFileVideoMediaResource.self, f: { LocalFileVideoMediaResource(decoder: $0) }) declareEncodable(LocalFileGifMediaResource.self, f: { LocalFileGifMediaResource(decoder: $0) }) declareEncodable(PhotoLibraryMediaResource.self, f: { PhotoLibraryMediaResource(decoder: $0) }) - //declareEncodable(PresentationPasscodeSettings.self, f: { PresentationPasscodeSettings(decoder: $0) }) - //declareEncodable(MediaAutoDownloadSettings.self, f: { MediaAutoDownloadSettings(decoder: $0) }) - //declareEncodable(AutomaticMediaDownloadSettings.self, f: { AutomaticMediaDownloadSettings(decoder: $0) }) - //declareEncodable(GeneratedMediaStoreSettings.self, f: { GeneratedMediaStoreSettings(decoder: $0) }) - //declareEncodable(PresentationThemeSettings.self, f: { PresentationThemeSettings(decoder: $0) }) - declareEncodable(ApplicationSpecificBoolNotice.self, f: { ApplicationSpecificBoolNotice(decoder: $0) }) - declareEncodable(ApplicationSpecificVariantNotice.self, f: { ApplicationSpecificVariantNotice(decoder: $0) }) - declareEncodable(ApplicationSpecificCounterNotice.self, f: { ApplicationSpecificCounterNotice(decoder: $0) }) - declareEncodable(ApplicationSpecificTimestampNotice.self, f: { ApplicationSpecificTimestampNotice(decoder: $0) }) - declareEncodable(ApplicationSpecificTimestampAndCounterNotice.self, f: { ApplicationSpecificTimestampAndCounterNotice(decoder: $0) }) - declareEncodable(ApplicationSpecificInt64ArrayNotice.self, f: { ApplicationSpecificInt64ArrayNotice(decoder: $0) }) - //declareEncodable(CallListSettings.self, f: { CallListSettings(decoder: $0) }) - //declareEncodable(VoiceCallSettings.self, f: { VoiceCallSettings(decoder: $0) }) - //declareEncodable(ExperimentalSettings.self, f: { ExperimentalSettings(decoder: $0) }) - //declareEncodable(ExperimentalUISettings.self, f: { ExperimentalUISettings(decoder: $0) }) - //declareEncodable(MusicPlaybackSettings.self, f: { MusicPlaybackSettings(decoder: $0) }) declareEncodable(ICloudFileResource.self, f: { ICloudFileResource(decoder: $0) }) - //declareEncodable(MediaInputSettings.self, f: { MediaInputSettings(decoder: $0) }) - //declareEncodable(ContactSynchronizationSettings.self, f: { ContactSynchronizationSettings(decoder: $0) }) - declareEncodable(CachedChannelAdminRanks.self, f: { CachedChannelAdminRanks(decoder: $0) }) - //declareEncodable(StickerSettings.self, f: { StickerSettings(decoder: $0) }) - //declareEncodable(InstantPagePresentationSettings.self, f: { InstantPagePresentationSettings(decoder: $0) }) - declareEncodable(InstantPageStoredState.self, f: { InstantPageStoredState(decoder: $0) }) - declareEncodable(InstantPageStoredDetailsState.self, f: { InstantPageStoredDetailsState(decoder: $0) }) - declareEncodable(CachedInstantPage.self, f: { CachedInstantPage(decoder: $0) }) - declareEncodable(CachedWallpaper.self, f: { CachedWallpaper(decoder: $0) }) - //declareEncodable(WatchPresetSettings.self, f: { WatchPresetSettings(decoder: $0) }) - //declareEncodable(WebSearchSettings.self, f: { WebSearchSettings(decoder: $0) }) declareEncodable(RecentWebSearchQueryItem.self, f: { RecentWebSearchQueryItem(decoder: $0) }) declareEncodable(RecentWallpaperSearchQueryItem.self, f: { RecentWallpaperSearchQueryItem(decoder: $0) }) declareEncodable(RecentSettingsSearchQueryItem.self, f: { RecentSettingsSearchQueryItem(decoder: $0) }) - //declareEncodable(VoipDerivedState.self, f: { VoipDerivedState(decoder: $0) }) - //declareEncodable(ChatArchiveSettings.self, f: { ChatArchiveSettings(decoder: $0) }) - declareEncodable(MediaPlaybackStoredState.self, f: { MediaPlaybackStoredState(decoder: $0) }) - //declareEncodable(WebBrowserSettings.self, f: { WebBrowserSettings(decoder: $0) }) - //declareEncodable(IntentsSettings.self, f: { IntentsSettings(decoder: $0) }) - declareEncodable(CachedGeocode.self, f: { CachedGeocode(decoder: $0) }) - //declareEncodable(ChatListFilterSettings.self, f: { ChatListFilterSettings(decoder: $0) }) - //declareEncodable(WidgetSettings.self, f: { WidgetSettings(decoder: $0) }) return }() diff --git a/submodules/TemporaryCachedPeerDataManager/Sources/CachedChannelAdmins.swift b/submodules/TemporaryCachedPeerDataManager/Sources/CachedChannelAdmins.swift index 65f2c6b33b..59f0192f55 100644 --- a/submodules/TemporaryCachedPeerDataManager/Sources/CachedChannelAdmins.swift +++ b/submodules/TemporaryCachedPeerDataManager/Sources/CachedChannelAdmins.swift @@ -3,57 +3,88 @@ import Postbox import TelegramCore import SwiftSignalKit -public enum CachedChannelAdminRank: PostboxCoding, Equatable { +public enum CachedChannelAdminRank: Codable, Equatable { case owner case admin case custom(String) - public init(decoder: PostboxDecoder) { - let value: Int32 = decoder.decodeInt32ForKey("v", orElse: 0) + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: StringCodingKey.self) + + let value: Int32 = try container.decode(Int32.self, forKey: "v") switch value { case 0: self = .owner case 1: self = .admin case 2: - self = .custom(decoder.decodeStringForKey("s", orElse: "")) + self = .custom(try container.decode(String.self, forKey: "s")) default: self = .admin } } - public func encode(_ encoder: PostboxEncoder) { + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: StringCodingKey.self) + switch self { case .owner: - encoder.encodeInt32(0, forKey: "v") + try container.encode(0 as Int32, forKey: "v") case .admin: - encoder.encodeInt32(1, forKey: "v") + try container.encode(1 as Int32, forKey: "v") case let .custom(rank): - encoder.encodeInt32(2, forKey: "v") - encoder.encodeString(rank, forKey: "s") + try container.encode(2 as Int32, forKey: "v") + try container.encode(rank, forKey: "s") } } } -public final class CachedChannelAdminRanks: PostboxCoding { - public let ranks: Dictionary +public final class CachedChannelAdminRanks: Codable { + private struct DictionaryKey: Codable, Hashable { + var key: PeerId + + init(_ key: PeerId) { + self.key = key + } + + init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: StringCodingKey.self) + + self.key = PeerId(try container.decode(Int64.self, forKey: "k")) + } + + func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: StringCodingKey.self) + + try container.encode(self.key.toInt64(), forKey: "k") + } + } - public init(ranks: Dictionary) { + public let ranks: [PeerId: CachedChannelAdminRank] + + public init(ranks: [PeerId: CachedChannelAdminRank]) { self.ranks = ranks } - public init(decoder: PostboxDecoder) { - self.ranks = decoder.decodeObjectDictionaryForKey("ranks", keyDecoder: { decoder in - return PeerId(decoder.decodeInt64ForKey("k", orElse: 0)) - }, valueDecoder: { decoder in - return CachedChannelAdminRank(decoder: decoder) - }) + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: StringCodingKey.self) + + let dict = try container.decode([DictionaryKey: CachedChannelAdminRank].self, forKey: "ranks") + var mappedDict: [PeerId: CachedChannelAdminRank] = [:] + for (key, value) in dict { + mappedDict[key.key] = value + } + self.ranks = mappedDict } - public func encode(_ encoder: PostboxEncoder) { - encoder.encodeObjectDictionary(self.ranks, forKey: "ranks", keyEncoder: { key, encoder in - encoder.encodeInt64(key.toInt64(), forKey: "k") - }) + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: StringCodingKey.self) + + var mappedDict: [DictionaryKey: CachedChannelAdminRank] = [:] + for (k, v) in self.ranks { + mappedDict[DictionaryKey(k)] = v + } + try container.encode(mappedDict, forKey: "ranks") } public static func cacheKey(peerId: PeerId) -> ValueBoxKey { @@ -71,6 +102,8 @@ public func cachedChannelAdminRanksEntryId(peerId: PeerId) -> ItemCacheEntryId { public func updateCachedChannelAdminRanks(postbox: Postbox, peerId: PeerId, ranks: Dictionary) -> Signal { return postbox.transaction { transaction -> Void in - transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: 100, key: CachedChannelAdminRanks.cacheKey(peerId: peerId)), entry: CachedChannelAdminRanks(ranks: ranks), collectionSpec: collectionSpec) + if let entry = CodableEntry(CachedChannelAdminRanks(ranks: ranks)) { + transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: 100, key: CachedChannelAdminRanks.cacheKey(peerId: peerId)), entry: entry, collectionSpec: collectionSpec) + } } } diff --git a/submodules/WallpaperResources/Sources/WallpaperCache.swift b/submodules/WallpaperResources/Sources/WallpaperCache.swift index 3a0a933cd7..97d4d182b5 100644 --- a/submodules/WallpaperResources/Sources/WallpaperCache.swift +++ b/submodules/WallpaperResources/Sources/WallpaperCache.swift @@ -7,19 +7,24 @@ import TelegramCore import TelegramUIPreferences import PersistentStringHash -public final class CachedWallpaper: PostboxCoding { +public final class CachedWallpaper: Codable { public let wallpaper: TelegramWallpaper public init(wallpaper: TelegramWallpaper) { self.wallpaper = wallpaper } - public init(decoder: PostboxDecoder) { - self.wallpaper = decoder.decodeObjectForKey("wallpaper", decoder: { TelegramWallpaper(decoder: $0) }) as! TelegramWallpaper + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: StringCodingKey.self) + + let wallpaperData = try container.decode(AdaptedPostboxDecoder.RawObjectData.self, forKey: "wallpaper") + self.wallpaper = TelegramWallpaper(decoder: PostboxDecoder(buffer: MemoryBuffer(data: wallpaperData.data))) } - public func encode(_ encoder: PostboxEncoder) { - encoder.encodeObject(self.wallpaper, forKey: "wallpaper") + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: StringCodingKey.self) + + try container.encode(PostboxEncoder().encodeObjectToRawData(self.wallpaper), forKey: "wallpaper") } } @@ -29,7 +34,7 @@ public func cachedWallpaper(account: Account, slug: String, settings: WallpaperS return account.postbox.transaction { transaction -> Signal in let key = ValueBoxKey(length: 8) key.setInt64(0, value: Int64(bitPattern: slug.persistentHashValue)) - if !update, let entry = transaction.retrieveItemCacheEntry(id: ItemCacheEntryId(collectionId: ApplicationSpecificItemCacheCollectionId.cachedWallpapers, key: key)) as? CachedWallpaper { + if !update, let entry = transaction.retrieveItemCacheEntry(id: ItemCacheEntryId(collectionId: ApplicationSpecificItemCacheCollectionId.cachedWallpapers, key: key))?.get(CachedWallpaper.self) { if let settings = settings { return .single(CachedWallpaper(wallpaper: entry.wallpaper.withUpdatedSettings(settings))) } else { @@ -53,8 +58,9 @@ public func cachedWallpaper(account: Account, slug: String, settings: WallpaperS default: break } - let entry = CachedWallpaper(wallpaper: wallpaper) - transaction.putItemCacheEntry(id: id, entry: entry, collectionSpec: collectionSpec) + if let entry = CodableEntry(CachedWallpaper(wallpaper: wallpaper)) { + transaction.putItemCacheEntry(id: id, entry: entry, collectionSpec: collectionSpec) + } if let settings = settings { return CachedWallpaper(wallpaper: wallpaper.withUpdatedSettings(settings)) } else { @@ -78,6 +84,8 @@ public func updateCachedWallpaper(account: Account, wallpaper: TelegramWallpaper let key = ValueBoxKey(length: 8) key.setInt64(0, value: Int64(bitPattern: file.slug.persistentHashValue)) let id = ItemCacheEntryId(collectionId: ApplicationSpecificItemCacheCollectionId.cachedWallpapers, key: key) - transaction.putItemCacheEntry(id: id, entry: CachedWallpaper(wallpaper: wallpaper), collectionSpec: collectionSpec) + if let entry = CodableEntry(CachedWallpaper(wallpaper: wallpaper)) { + transaction.putItemCacheEntry(id: id, entry: entry, collectionSpec: collectionSpec) + } }).start() } From f23d5ef97ac4f070ceef48b30b5ded8befacdcd5 Mon Sep 17 00:00:00 2001 From: Ali <> Date: Mon, 20 Sep 2021 01:12:06 +0300 Subject: [PATCH 11/30] Refactoring --- .../Sources/OrderedItemListEntry.swift | 8 +- .../Sources/OrderedItemListIndexTable.swift | 14 +- .../Sources/OrderedItemListTable.swift | 10 +- submodules/Postbox/Sources/Postbox.swift | 8 +- .../Search/SettingsSearchRecentQueries.swift | 10 +- .../Themes/WallpaperSearchRecentQueries.swift | 10 +- .../Sources/Account/AccountManager.swift | 8 - .../Network/FetchedMediaResource.swift | 3 +- .../State/AccountStateManagementUtils.swift | 18 +- .../Sources/State/AccountViewTracker.swift | 2 +- .../Sources/State/ApplyUpdateMessage.swift | 16 +- .../Sources/State/ManagedRecentStickers.swift | 16 +- .../Sources/State/StickerManagement.swift | 18 +- ...nchronizeRecentlyUsedMediaOperations.swift | 4 +- .../State/SynchronizeSavedGifsOperation.swift | 9 +- .../SynchronizeSavedStickersOperation.swift | 8 +- .../SyncCore_ArchivedStickerPacksInfo.swift | 15 +- .../SyncCore_FeaturedStickerPack.swift | 30 ++- .../SyncCore/SyncCore_RecentHashtagItem.swift | 6 +- .../SyncCore/SyncCore_RecentMediaItem.swift | 19 +- .../SyncCore/SyncCore_RecentPeerItem.swift | 14 +- .../SyncCore/SyncCore_SavedStickerItem.swift | 18 +- .../SyncCore_TelegramMediaWebpage.swift | 4 +- .../SyncCore/SyncCore_TelegramTheme.swift | 145 +++++++----- .../SyncCore/SyncCore_TelegramWallpaper.swift | 218 ++++++++++-------- .../SyncCore/SyncCore_ThemeSettings.swift | 9 +- .../SyncCore/SyncCore_wallapersState.swift | 6 +- .../Messages/RecentlyUsedHashtags.swift | 4 +- .../TelegramEngine/Peers/RecentPeers.swift | 16 +- .../Peers/RecentlySearchedPeerIds.swift | 4 +- .../Stickers/SearchStickers.swift | 9 +- .../StickerPackInteractiveOperations.swift | 6 +- .../TelegramEngine/Themes/ChatThemes.swift | 11 +- submodules/TelegramCore/Sources/Themes.swift | 40 ++-- .../TelegramCore/Sources/Wallpapers.swift | 6 +- .../Sources/PresentationThemeCodable.swift | 28 ++- .../Sources/ChatMediaInputGifPane.swift | 2 +- .../Sources/ChatMediaInputNode.swift | 10 +- .../Sources/DeclareEncodables.swift | 3 - .../Sources/PresentationThemeSettings.swift | 25 +- .../Sources/WallpaperCache.swift | 5 +- .../Sources/WatchRequestHandlers.swift | 8 +- .../Sources/WebSearchRecentQueries.swift | 10 +- 43 files changed, 484 insertions(+), 349 deletions(-) diff --git a/submodules/Postbox/Sources/OrderedItemListEntry.swift b/submodules/Postbox/Sources/OrderedItemListEntry.swift index edefb701dc..b34ac776f4 100644 --- a/submodules/Postbox/Sources/OrderedItemListEntry.swift +++ b/submodules/Postbox/Sources/OrderedItemListEntry.swift @@ -1,14 +1,10 @@ import Foundation -public protocol OrderedItemListEntryContents: PostboxCoding { - -} - public struct OrderedItemListEntry { public let id: MemoryBuffer - public let contents: OrderedItemListEntryContents + public let contents: CodableEntry - public init(id: MemoryBuffer, contents: OrderedItemListEntryContents) { + public init(id: MemoryBuffer, contents: CodableEntry) { self.id = id self.contents = contents } diff --git a/submodules/Postbox/Sources/OrderedItemListIndexTable.swift b/submodules/Postbox/Sources/OrderedItemListIndexTable.swift index e1ce8d1f42..612cf4b4ec 100644 --- a/submodules/Postbox/Sources/OrderedItemListIndexTable.swift +++ b/submodules/Postbox/Sources/OrderedItemListIndexTable.swift @@ -12,9 +12,9 @@ final class OrderedItemListIndexTable: Table { return key } - func get(collectionId: Int32, id: MemoryBuffer) -> PostboxCoding? { - if let value = self.valueBox.get(self.table, key: self.key(collectionId: collectionId, id: id)), let content = PostboxDecoder(buffer: value).decodeRootObject() { - return content + func get(collectionId: Int32, id: MemoryBuffer) -> CodableEntry? { + if let value = self.valueBox.get(self.table, key: self.key(collectionId: collectionId, id: id)) { + return CodableEntry(data: value.makeData()) } else { return nil } @@ -24,12 +24,8 @@ final class OrderedItemListIndexTable: Table { self.valueBox.remove(self.table, key: self.key(collectionId: collectionId, id: id), secure: false) } - func set(collectionId: Int32, id: MemoryBuffer, content: PostboxCoding) { - let encoder = PostboxEncoder() - encoder.encodeRootObject(content) - withExtendedLifetime(encoder, { - self.valueBox.set(self.table, key: self.key(collectionId: collectionId, id: id), value: encoder.readBufferNoCopy()) - }) + func set(collectionId: Int32, id: MemoryBuffer, content: CodableEntry) { + self.valueBox.set(self.table, key: self.key(collectionId: collectionId, id: id), value: ReadBuffer(data: content.data)) } func getAllItemIds(collectionId: Int32) -> [MemoryBuffer] { diff --git a/submodules/Postbox/Sources/OrderedItemListTable.swift b/submodules/Postbox/Sources/OrderedItemListTable.swift index 6a7dfde6cb..0754986fd3 100644 --- a/submodules/Postbox/Sources/OrderedItemListTable.swift +++ b/submodules/Postbox/Sources/OrderedItemListTable.swift @@ -4,7 +4,7 @@ enum OrderedItemListOperation { case replace([OrderedItemListEntry]) case addOrMoveToFirstPosition(OrderedItemListEntry, Int?) case remove(MemoryBuffer) - case update(MemoryBuffer, OrderedItemListEntryContents) + case update(MemoryBuffer, CodableEntry) } private enum OrderedItemListKeyNamespace: UInt8 { @@ -97,7 +97,7 @@ final class OrderedItemListTable: Table { }, limit: 0) var items: [OrderedItemListEntry] = [] for id in currentIds { - if let contents = self.indexTable.get(collectionId: collectionId, id: id) as? OrderedItemListEntryContents { + if let contents = self.indexTable.get(collectionId: collectionId, id: id) { items.append(OrderedItemListEntry(id: id, contents: contents)) } else { assertionFailure() @@ -107,15 +107,15 @@ final class OrderedItemListTable: Table { } func getItem(collectionId: Int32, itemId: MemoryBuffer) -> OrderedItemListEntry? { - if let contents = self.indexTable.get(collectionId: collectionId, id: itemId) as? OrderedItemListEntryContents { + if let contents = self.indexTable.get(collectionId: collectionId, id: itemId) { return OrderedItemListEntry(id: itemId, contents: contents) } else { return nil } } - func updateItem(collectionId: Int32, itemId: MemoryBuffer, item: OrderedItemListEntryContents, operations: inout [Int32: [OrderedItemListOperation]]) { - if let _ = self.indexTable.get(collectionId: collectionId, id: itemId) as? OrderedItemListEntryContents { + func updateItem(collectionId: Int32, itemId: MemoryBuffer, item: CodableEntry, operations: inout [Int32: [OrderedItemListOperation]]) { + if let _ = self.indexTable.get(collectionId: collectionId, id: itemId) { self.indexTable.set(collectionId: collectionId, id: itemId, content: item) if operations[collectionId] == nil { operations[collectionId] = [] diff --git a/submodules/Postbox/Sources/Postbox.swift b/submodules/Postbox/Sources/Postbox.swift index d9f7a4cab6..924a699338 100644 --- a/submodules/Postbox/Sources/Postbox.swift +++ b/submodules/Postbox/Sources/Postbox.swift @@ -2,6 +2,10 @@ import Foundation import SwiftSignalKit +public protocol PostboxTypes { + associatedtype Media +} + public protocol PeerChatState: PostboxCoding { func equals(_ other: PeerChatState) -> Bool } @@ -649,7 +653,7 @@ public final class Transaction { return self.postbox?.getOrderedItemListItem(collectionId: collectionId, itemId: itemId) } - public func updateOrderedItemListItem(collectionId: Int32, itemId: MemoryBuffer, item: OrderedItemListEntryContents) { + public func updateOrderedItemListItem(collectionId: Int32, itemId: MemoryBuffer, item: CodableEntry) { assert(!self.disposed) self.postbox?.updateOrderedItemListItem(collectionId: collectionId, itemId: itemId, item: item) } @@ -3400,7 +3404,7 @@ public final class Postbox { return self.orderedItemListTable.getItem(collectionId: collectionId, itemId: itemId) } - fileprivate func updateOrderedItemListItem(collectionId: Int32, itemId: MemoryBuffer, item: OrderedItemListEntryContents) { + fileprivate func updateOrderedItemListItem(collectionId: Int32, itemId: MemoryBuffer, item: CodableEntry) { self.orderedItemListTable.updateItem(collectionId: collectionId, itemId: itemId, item: item, operations: &self.currentOrderedItemListOperations) } diff --git a/submodules/SettingsUI/Sources/Search/SettingsSearchRecentQueries.swift b/submodules/SettingsUI/Sources/Search/SettingsSearchRecentQueries.swift index 32317752fb..158a5645f6 100644 --- a/submodules/SettingsUI/Sources/Search/SettingsSearchRecentQueries.swift +++ b/submodules/SettingsUI/Sources/Search/SettingsSearchRecentQueries.swift @@ -26,21 +26,23 @@ private struct SettingsSearchRecentQueryItemId { } } -public final class RecentSettingsSearchQueryItem: OrderedItemListEntryContents { +public final class RecentSettingsSearchQueryItem: Codable { public init() { } - public init(decoder: PostboxDecoder) { + public init(from decoder: Decoder) throws { } - public func encode(_ encoder: PostboxEncoder) { + public func encode(to encoder: Encoder) throws { } } func addRecentSettingsSearchItem(postbox: Postbox, item: SettingsSearchableItemId) { let _ = (postbox.transaction { transaction in let itemId = SettingsSearchRecentQueryItemId(item.index) - transaction.addOrMoveToFirstPositionOrderedItemListItem(collectionId: ApplicationSpecificOrderedItemListCollectionId.settingsSearchRecentItems, item: OrderedItemListEntry(id: itemId.rawValue, contents: RecentSettingsSearchQueryItem()), removeTailIfCountExceeds: 100) + if let entry = CodableEntry(RecentSettingsSearchQueryItem()) { + transaction.addOrMoveToFirstPositionOrderedItemListItem(collectionId: ApplicationSpecificOrderedItemListCollectionId.settingsSearchRecentItems, item: OrderedItemListEntry(id: itemId.rawValue, contents: entry), removeTailIfCountExceeds: 100) + } }).start() } diff --git a/submodules/SettingsUI/Sources/Themes/WallpaperSearchRecentQueries.swift b/submodules/SettingsUI/Sources/Themes/WallpaperSearchRecentQueries.swift index 8dd9078b9e..0f4bd3a2cd 100644 --- a/submodules/SettingsUI/Sources/Themes/WallpaperSearchRecentQueries.swift +++ b/submodules/SettingsUI/Sources/Themes/WallpaperSearchRecentQueries.swift @@ -23,21 +23,23 @@ private struct WallpaperSearchRecentQueryItemId { } } -public final class RecentWallpaperSearchQueryItem: OrderedItemListEntryContents { +public final class RecentWallpaperSearchQueryItem: Codable { public init() { } - public init(decoder: PostboxDecoder) { + public init(from decoder: Decoder) throws { } - public func encode(_ encoder: PostboxEncoder) { + public func encode(to encoder: Encoder) throws { } } func addRecentWallpaperSearchQuery(postbox: Postbox, string: String) -> Signal { return postbox.transaction { transaction in if let itemId = WallpaperSearchRecentQueryItemId(string) { - transaction.addOrMoveToFirstPositionOrderedItemListItem(collectionId: ApplicationSpecificOrderedItemListCollectionId.wallpaperSearchRecentQueries, item: OrderedItemListEntry(id: itemId.rawValue, contents: RecentWallpaperSearchQueryItem()), removeTailIfCountExceeds: 100) + if let entry = CodableEntry(RecentWallpaperSearchQueryItem()) { + transaction.addOrMoveToFirstPositionOrderedItemListItem(collectionId: ApplicationSpecificOrderedItemListCollectionId.wallpaperSearchRecentQueries, item: OrderedItemListEntry(id: itemId.rawValue, contents: entry), removeTailIfCountExceeds: 100) + } } } } diff --git a/submodules/TelegramCore/Sources/Account/AccountManager.swift b/submodules/TelegramCore/Sources/Account/AccountManager.swift index 4fa3e0ed8e..c7c4726a5b 100644 --- a/submodules/TelegramCore/Sources/Account/AccountManager.swift +++ b/submodules/TelegramCore/Sources/Account/AccountManager.swift @@ -133,9 +133,6 @@ private var declaredEncodables: Void = { declareEncodable(CloudChatRemoveChatOperation.self, f: { CloudChatRemoveChatOperation(decoder: $0) }) declareEncodable(SynchronizePinnedChatsOperation.self, f: { SynchronizePinnedChatsOperation(decoder: $0) }) declareEncodable(SynchronizeConsumeMessageContentsOperation.self, f: { SynchronizeConsumeMessageContentsOperation(decoder: $0) }) - declareEncodable(RecentMediaItem.self, f: { RecentMediaItem(decoder: $0) }) - declareEncodable(RecentPeerItem.self, f: { RecentPeerItem(decoder: $0) }) - declareEncodable(RecentHashtagItem.self, f: { RecentHashtagItem(decoder: $0) }) declareEncodable(CloudChatClearHistoryOperation.self, f: { CloudChatClearHistoryOperation(decoder: $0) }) declareEncodable(OutgoingContentInfoMessageAttribute.self, f: { OutgoingContentInfoMessageAttribute(decoder: $0) }) declareEncodable(ConsumableContentMessageAttribute.self, f: { ConsumableContentMessageAttribute(decoder: $0) }) @@ -143,9 +140,7 @@ private var declaredEncodables: Void = { declareEncodable(TelegramMediaInvoice.self, f: { TelegramMediaInvoice(decoder: $0) }) declareEncodable(TelegramMediaWebFile.self, f: { TelegramMediaWebFile(decoder: $0) }) declareEncodable(SynchronizeInstalledStickerPacksOperation.self, f: { SynchronizeInstalledStickerPacksOperation(decoder: $0) }) - declareEncodable(FeaturedStickerPackItem.self, f: { FeaturedStickerPackItem(decoder: $0) }) declareEncodable(SynchronizeMarkFeaturedStickerPacksAsSeenOperation.self, f: { SynchronizeMarkFeaturedStickerPacksAsSeenOperation(decoder: $0) }) - declareEncodable(ArchivedStickerPacksInfo.self, f: { ArchivedStickerPacksInfo(decoder: $0) }) declareEncodable(SynchronizeChatInputStateOperation.self, f: { SynchronizeChatInputStateOperation(decoder: $0) }) declareEncodable(SynchronizeSavedGifsOperation.self, f: { SynchronizeSavedGifsOperation(decoder: $0) }) declareEncodable(SynchronizeSavedStickersOperation.self, f: { SynchronizeSavedStickersOperation(decoder: $0) }) @@ -156,14 +151,11 @@ private var declaredEncodables: Void = { declareEncodable(CachedSecretChatData.self, f: { CachedSecretChatData(decoder: $0) }) declareEncodable(AuthorSignatureMessageAttribute.self, f: { AuthorSignatureMessageAttribute(decoder: $0) }) declareEncodable(TelegramMediaExpiredContent.self, f: { TelegramMediaExpiredContent(decoder: $0) }) - declareEncodable(SavedStickerItem.self, f: { SavedStickerItem(decoder: $0) }) declareEncodable(ConsumablePersonalMentionMessageAttribute.self, f: { ConsumablePersonalMentionMessageAttribute(decoder: $0) }) declareEncodable(ConsumePersonalMessageAction.self, f: { ConsumePersonalMessageAction(decoder: $0) }) declareEncodable(SynchronizeGroupedPeersOperation.self, f: { SynchronizeGroupedPeersOperation(decoder: $0) }) declareEncodable(TelegramDeviceContactImportedData.self, f: { TelegramDeviceContactImportedData(decoder: $0) }) declareEncodable(SecureFileMediaResource.self, f: { SecureFileMediaResource(decoder: $0) }) - declareEncodable(TelegramWallpaper.self, f: { TelegramWallpaper(decoder: $0) }) - declareEncodable(TelegramTheme.self, f: { TelegramTheme(decoder: $0) }) declareEncodable(SynchronizeMarkAllUnseenPersonalMessagesOperation.self, f: { SynchronizeMarkAllUnseenPersonalMessagesOperation(decoder: $0) }) declareEncodable(SynchronizeAppLogEventsOperation.self, f: { SynchronizeAppLogEventsOperation(decoder: $0) }) declareEncodable(TelegramMediaPoll.self, f: { TelegramMediaPoll(decoder: $0) }) diff --git a/submodules/TelegramCore/Sources/Network/FetchedMediaResource.swift b/submodules/TelegramCore/Sources/Network/FetchedMediaResource.swift index 9c5b99c7a5..5bcfc3659f 100644 --- a/submodules/TelegramCore/Sources/Network/FetchedMediaResource.swift +++ b/submodules/TelegramCore/Sources/Network/FetchedMediaResource.swift @@ -350,7 +350,8 @@ final class MediaReferenceRevalidationContext { return self.genericItem(key: .savedGifs, background: background, request: { next, error in let loadRecentGifs: Signal<[TelegramMediaFile], NoError> = postbox.transaction { transaction -> [TelegramMediaFile] in return transaction.getOrderedListItems(collectionId: Namespaces.OrderedItemList.CloudRecentGifs).compactMap({ item -> TelegramMediaFile? in - if let contents = item.contents as? RecentMediaItem, let file = contents.media as? TelegramMediaFile { + if let contents = item.contents.get(RecentMediaItem.self) { + let file = contents.media return file } return nil diff --git a/submodules/TelegramCore/Sources/State/AccountStateManagementUtils.swift b/submodules/TelegramCore/Sources/State/AccountStateManagementUtils.swift index ae9f48f816..a489df1672 100644 --- a/submodules/TelegramCore/Sources/State/AccountStateManagementUtils.swift +++ b/submodules/TelegramCore/Sources/State/AccountStateManagementUtils.swift @@ -3409,7 +3409,9 @@ func replayFinalState( return $0.0 < $1.0 }).map({ $0.1 }) for file in stickerFiles { - transaction.addOrMoveToFirstPositionOrderedItemListItem(collectionId: Namespaces.OrderedItemList.CloudRecentStickers, item: OrderedItemListEntry(id: RecentMediaItemId(file.fileId).rawValue, contents: RecentMediaItem(file)), removeTailIfCountExceeds: 20) + if let entry = CodableEntry(RecentMediaItem(file)) { + transaction.addOrMoveToFirstPositionOrderedItemListItem(collectionId: Namespaces.OrderedItemList.CloudRecentStickers, item: OrderedItemListEntry(id: RecentMediaItemId(file.fileId).rawValue, contents: entry), removeTailIfCountExceeds: 20) + } } } @@ -3448,7 +3450,9 @@ func replayFinalState( }).map({ $0.1 }) for file in gifFiles { if !file.hasLinkedStickers { - transaction.addOrMoveToFirstPositionOrderedItemListItem(collectionId: Namespaces.OrderedItemList.CloudRecentGifs, item: OrderedItemListEntry(id: RecentMediaItemId(file.fileId).rawValue, contents: RecentMediaItem(file)), removeTailIfCountExceeds: 200) + if let entry = CodableEntry(RecentMediaItem(file)) { + transaction.addOrMoveToFirstPositionOrderedItemListItem(collectionId: Namespaces.OrderedItemList.CloudRecentGifs, item: OrderedItemListEntry(id: RecentMediaItemId(file.fileId).rawValue, contents: entry), removeTailIfCountExceeds: 200) + } } } } @@ -3552,18 +3556,20 @@ func replayFinalState( if !updatedThemes.isEmpty { let entries = transaction.getOrderedListItems(collectionId: Namespaces.OrderedItemList.CloudThemes) let themes = entries.map { entry -> TelegramTheme in - let theme = entry.contents as! TelegramTheme - if let updatedTheme = updatedThemes[theme.id] { + let theme = entry.contents.get(TelegramThemeNativeCodable.self)! + if let updatedTheme = updatedThemes[theme.value.id] { return updatedTheme } else { - return theme + return theme.value } } var updatedEntries: [OrderedItemListEntry] = [] for theme in themes { var intValue = Int32(updatedEntries.count) let id = MemoryBuffer(data: Data(bytes: &intValue, count: 4)) - updatedEntries.append(OrderedItemListEntry(id: id, contents: theme)) + if let entry = CodableEntry(TelegramThemeNativeCodable(theme)) { + updatedEntries.append(OrderedItemListEntry(id: id, contents: entry)) + } } transaction.replaceOrderedItemListItems(collectionId: Namespaces.OrderedItemList.CloudThemes, items: updatedEntries) let _ = accountManager.transaction { transaction in diff --git a/submodules/TelegramCore/Sources/State/AccountViewTracker.swift b/submodules/TelegramCore/Sources/State/AccountViewTracker.swift index db38aa4c90..b2b667e250 100644 --- a/submodules/TelegramCore/Sources/State/AccountViewTracker.swift +++ b/submodules/TelegramCore/Sources/State/AccountViewTracker.swift @@ -1581,7 +1581,7 @@ public final class AccountViewTracker { if let account = self.account { let view = account.postbox.combinedView(keys: [.orderedItemList(id: Namespaces.OrderedItemList.CloudFeaturedStickerPacks)]).start(next: { next in if let view = next.views[.orderedItemList(id: Namespaces.OrderedItemList.CloudFeaturedStickerPacks)] as? OrderedItemListView { - subscriber.putNext(view.items.map { $0.contents as! FeaturedStickerPackItem }) + subscriber.putNext(view.items.map { $0.contents.get(FeaturedStickerPackItem.self)! }) } else { subscriber.putNext([]) } diff --git a/submodules/TelegramCore/Sources/State/ApplyUpdateMessage.swift b/submodules/TelegramCore/Sources/State/ApplyUpdateMessage.swift index 8fed6be810..50997bc665 100644 --- a/submodules/TelegramCore/Sources/State/ApplyUpdateMessage.swift +++ b/submodules/TelegramCore/Sources/State/ApplyUpdateMessage.swift @@ -244,11 +244,15 @@ func applyUpdateMessage(postbox: Postbox, stateManager: AccountStateManager, mes } } for file in sentStickers { - transaction.addOrMoveToFirstPositionOrderedItemListItem(collectionId: Namespaces.OrderedItemList.CloudRecentStickers, item: OrderedItemListEntry(id: RecentMediaItemId(file.fileId).rawValue, contents: RecentMediaItem(file)), removeTailIfCountExceeds: 20) + if let entry = CodableEntry(RecentMediaItem(file)) { + transaction.addOrMoveToFirstPositionOrderedItemListItem(collectionId: Namespaces.OrderedItemList.CloudRecentStickers, item: OrderedItemListEntry(id: RecentMediaItemId(file.fileId).rawValue, contents: entry), removeTailIfCountExceeds: 20) + } } for file in sentGifs { if !file.hasLinkedStickers { - transaction.addOrMoveToFirstPositionOrderedItemListItem(collectionId: Namespaces.OrderedItemList.CloudRecentGifs, item: OrderedItemListEntry(id: RecentMediaItemId(file.fileId).rawValue, contents: RecentMediaItem(file)), removeTailIfCountExceeds: 200) + if let entry = CodableEntry(RecentMediaItem(file)) { + transaction.addOrMoveToFirstPositionOrderedItemListItem(collectionId: Namespaces.OrderedItemList.CloudRecentGifs, item: OrderedItemListEntry(id: RecentMediaItemId(file.fileId).rawValue, contents: entry), removeTailIfCountExceeds: 200) + } } } @@ -385,11 +389,15 @@ func applyUpdateGroupMessages(postbox: Postbox, stateManager: AccountStateManage } for file in sentStickers { - transaction.addOrMoveToFirstPositionOrderedItemListItem(collectionId: Namespaces.OrderedItemList.CloudRecentStickers, item: OrderedItemListEntry(id: RecentMediaItemId(file.fileId).rawValue, contents: RecentMediaItem(file)), removeTailIfCountExceeds: 20) + if let entry = CodableEntry(RecentMediaItem(file)) { + transaction.addOrMoveToFirstPositionOrderedItemListItem(collectionId: Namespaces.OrderedItemList.CloudRecentStickers, item: OrderedItemListEntry(id: RecentMediaItemId(file.fileId).rawValue, contents: entry), removeTailIfCountExceeds: 20) + } } for file in sentGifs { if !file.hasLinkedStickers { - transaction.addOrMoveToFirstPositionOrderedItemListItem(collectionId: Namespaces.OrderedItemList.CloudRecentGifs, item: OrderedItemListEntry(id: RecentMediaItemId(file.fileId).rawValue, contents: RecentMediaItem(file)), removeTailIfCountExceeds: 200) + if let entry = CodableEntry(RecentMediaItem(file)) { + transaction.addOrMoveToFirstPositionOrderedItemListItem(collectionId: Namespaces.OrderedItemList.CloudRecentGifs, item: OrderedItemListEntry(id: RecentMediaItemId(file.fileId).rawValue, contents: entry), removeTailIfCountExceeds: 200) + } } } stateManager.addUpdates(result) diff --git a/submodules/TelegramCore/Sources/State/ManagedRecentStickers.swift b/submodules/TelegramCore/Sources/State/ManagedRecentStickers.swift index 178d0ace56..8ac1e27de4 100644 --- a/submodules/TelegramCore/Sources/State/ManagedRecentStickers.swift +++ b/submodules/TelegramCore/Sources/State/ManagedRecentStickers.swift @@ -55,7 +55,9 @@ func managedRecentStickers(postbox: Postbox, network: Network) -> Signal Signal Signal Signal Signal OrderedItemListEntry? in + if let entry = CodableEntry(item) { + return OrderedItemListEntry(id: FeaturedStickerPackItemId(item.info.id.id).rawValue, contents: entry) + } else { + return nil + } + }) } } } @@ -83,7 +89,7 @@ public func requestOldFeaturedStickerPacks(network: Network, postbox: Postbox, o public func preloadedFeaturedStickerSet(network: Network, postbox: Postbox, id: ItemCollectionId) -> Signal { return postbox.transaction { transaction -> Signal in - if let pack = transaction.getOrderedItemListItem(collectionId: Namespaces.OrderedItemList.CloudFeaturedStickerPacks, itemId: FeaturedStickerPackItemId(id.id).rawValue)?.contents as? FeaturedStickerPackItem { + if let pack = transaction.getOrderedItemListItem(collectionId: Namespaces.OrderedItemList.CloudFeaturedStickerPacks, itemId: FeaturedStickerPackItemId(id.id).rawValue)?.contents.get(FeaturedStickerPackItem.self) { if pack.topItems.count < 5 && pack.topItems.count < pack.info.count { return _internal_requestStickerSet(postbox: postbox, network: network, reference: .id(id: pack.info.id.id, accessHash: pack.info.accessHash)) |> map(Optional.init) @@ -93,12 +99,14 @@ public func preloadedFeaturedStickerSet(network: Network, postbox: Postbox, id: |> mapToSignal { result -> Signal in if let result = result { return postbox.transaction { transaction -> Void in - if let pack = transaction.getOrderedItemListItem(collectionId: Namespaces.OrderedItemList.CloudFeaturedStickerPacks, itemId: FeaturedStickerPackItemId(id.id).rawValue)?.contents as? FeaturedStickerPackItem { + if let pack = transaction.getOrderedItemListItem(collectionId: Namespaces.OrderedItemList.CloudFeaturedStickerPacks, itemId: FeaturedStickerPackItemId(id.id).rawValue)?.contents.get(FeaturedStickerPackItem.self) { var items = result.items.map({ $0 as? StickerPackItem }).compactMap({ $0 }) if items.count > 5 { items.removeSubrange(5 ..< items.count) } - transaction.updateOrderedItemListItem(collectionId: Namespaces.OrderedItemList.CloudFeaturedStickerPacks, itemId: FeaturedStickerPackItemId(id.id).rawValue, item: FeaturedStickerPackItem(info: pack.info, topItems: items, unread: pack.unread)) + if let entry = CodableEntry(FeaturedStickerPackItem(info: pack.info, topItems: items, unread: pack.unread)) { + transaction.updateOrderedItemListItem(collectionId: Namespaces.OrderedItemList.CloudFeaturedStickerPacks, itemId: FeaturedStickerPackItemId(id.id).rawValue, item: entry) + } } } } else { diff --git a/submodules/TelegramCore/Sources/State/SynchronizeRecentlyUsedMediaOperations.swift b/submodules/TelegramCore/Sources/State/SynchronizeRecentlyUsedMediaOperations.swift index 867364f432..b3b5d74eb4 100644 --- a/submodules/TelegramCore/Sources/State/SynchronizeRecentlyUsedMediaOperations.swift +++ b/submodules/TelegramCore/Sources/State/SynchronizeRecentlyUsedMediaOperations.swift @@ -33,7 +33,9 @@ func addSynchronizeRecentlyUsedMediaOperation(transaction: Transaction, category func addRecentlyUsedSticker(transaction: Transaction, fileReference: FileMediaReference) { if let resource = fileReference.media.resource as? CloudDocumentMediaResource { - transaction.addOrMoveToFirstPositionOrderedItemListItem(collectionId: Namespaces.OrderedItemList.CloudRecentStickers, item: OrderedItemListEntry(id: RecentMediaItemId(fileReference.media.fileId).rawValue, contents: RecentMediaItem(fileReference.media)), removeTailIfCountExceeds: 20) + if let entry = CodableEntry(RecentMediaItem(fileReference.media)) { + transaction.addOrMoveToFirstPositionOrderedItemListItem(collectionId: Namespaces.OrderedItemList.CloudRecentStickers, item: OrderedItemListEntry(id: RecentMediaItemId(fileReference.media.fileId).rawValue, contents: entry), removeTailIfCountExceeds: 20) + } addSynchronizeRecentlyUsedMediaOperation(transaction: transaction, category: .stickers, operation: .add(id: resource.fileId, accessHash: resource.accessHash, fileReference: fileReference)) } } diff --git a/submodules/TelegramCore/Sources/State/SynchronizeSavedGifsOperation.swift b/submodules/TelegramCore/Sources/State/SynchronizeSavedGifsOperation.swift index 5d2ea8bd2d..d9dd0f2602 100644 --- a/submodules/TelegramCore/Sources/State/SynchronizeSavedGifsOperation.swift +++ b/submodules/TelegramCore/Sources/State/SynchronizeSavedGifsOperation.swift @@ -33,7 +33,9 @@ public func isGifSaved(transaction: Transaction, mediaId: MediaId) -> Bool { public func addSavedGif(postbox: Postbox, fileReference: FileMediaReference) -> Signal { return postbox.transaction { transaction -> Void in if let resource = fileReference.media.resource as? CloudDocumentMediaResource { - transaction.addOrMoveToFirstPositionOrderedItemListItem(collectionId: Namespaces.OrderedItemList.CloudRecentGifs, item: OrderedItemListEntry(id: RecentMediaItemId(fileReference.media.fileId).rawValue, contents: RecentMediaItem(fileReference.media)), removeTailIfCountExceeds: 200) + if let entry = CodableEntry(RecentMediaItem(fileReference.media)) { + transaction.addOrMoveToFirstPositionOrderedItemListItem(collectionId: Namespaces.OrderedItemList.CloudRecentGifs, item: OrderedItemListEntry(id: RecentMediaItemId(fileReference.media.fileId).rawValue, contents: entry), removeTailIfCountExceeds: 200) + } addSynchronizeSavedGifsOperation(transaction: transaction, operation: .add(id: resource.fileId, accessHash: resource.accessHash, fileReference: fileReference)) } } @@ -41,8 +43,9 @@ public func addSavedGif(postbox: Postbox, fileReference: FileMediaReference) -> public func removeSavedGif(postbox: Postbox, mediaId: MediaId) -> Signal { return postbox.transaction { transaction -> Void in - if let entry = transaction.getOrderedItemListItem(collectionId: Namespaces.OrderedItemList.CloudRecentGifs, itemId: RecentMediaItemId(mediaId).rawValue), let item = entry.contents as? RecentMediaItem { - if let file = item.media as? TelegramMediaFile, let resource = file.resource as? CloudDocumentMediaResource { + if let entry = transaction.getOrderedItemListItem(collectionId: Namespaces.OrderedItemList.CloudRecentGifs, itemId: RecentMediaItemId(mediaId).rawValue), let item = entry.contents.get(RecentMediaItem.self) { + let file = item.media + if let resource = file.resource as? CloudDocumentMediaResource { transaction.removeOrderedItemListItem(collectionId: Namespaces.OrderedItemList.CloudRecentGifs, itemId: entry.id) addSynchronizeSavedGifsOperation(transaction: transaction, operation: .remove(id: resource.fileId, accessHash: resource.accessHash)) } diff --git a/submodules/TelegramCore/Sources/State/SynchronizeSavedStickersOperation.swift b/submodules/TelegramCore/Sources/State/SynchronizeSavedStickersOperation.swift index 1bf6f161ef..5cd4ad4144 100644 --- a/submodules/TelegramCore/Sources/State/SynchronizeSavedStickersOperation.swift +++ b/submodules/TelegramCore/Sources/State/SynchronizeSavedStickersOperation.swift @@ -107,13 +107,15 @@ public func addSavedSticker(postbox: Postbox, network: Network, file: TelegramMe public func addSavedSticker(transaction: Transaction, file: TelegramMediaFile, stringRepresentations: [String]) { if let resource = file.resource as? CloudDocumentMediaResource { - transaction.addOrMoveToFirstPositionOrderedItemListItem(collectionId: Namespaces.OrderedItemList.CloudSavedStickers, item: OrderedItemListEntry(id: RecentMediaItemId(file.fileId).rawValue, contents: SavedStickerItem(file: file, stringRepresentations: stringRepresentations)), removeTailIfCountExceeds: 5) + if let entry = CodableEntry(SavedStickerItem(file: file, stringRepresentations: stringRepresentations)) { + transaction.addOrMoveToFirstPositionOrderedItemListItem(collectionId: Namespaces.OrderedItemList.CloudSavedStickers, item: OrderedItemListEntry(id: RecentMediaItemId(file.fileId).rawValue, contents: entry), removeTailIfCountExceeds: 5) + } addSynchronizeSavedStickersOperation(transaction: transaction, operation: .add(id: resource.fileId, accessHash: resource.accessHash, fileReference: .standalone(media: file))) } } public func removeSavedSticker(transaction: Transaction, mediaId: MediaId) { - if let entry = transaction.getOrderedItemListItem(collectionId: Namespaces.OrderedItemList.CloudSavedStickers, itemId: RecentMediaItemId(mediaId).rawValue), let item = entry.contents as? SavedStickerItem { + if let entry = transaction.getOrderedItemListItem(collectionId: Namespaces.OrderedItemList.CloudSavedStickers, itemId: RecentMediaItemId(mediaId).rawValue), let item = entry.contents.get(SavedStickerItem.self) { if let resource = item.file.resource as? CloudDocumentMediaResource { transaction.removeOrderedItemListItem(collectionId: Namespaces.OrderedItemList.CloudSavedStickers, itemId: entry.id) addSynchronizeSavedStickersOperation(transaction: transaction, operation: .remove(id: resource.fileId, accessHash: resource.accessHash)) @@ -123,7 +125,7 @@ public func removeSavedSticker(transaction: Transaction, mediaId: MediaId) { public func removeSavedSticker(postbox: Postbox, mediaId: MediaId) -> Signal { return postbox.transaction { transaction in - if let entry = transaction.getOrderedItemListItem(collectionId: Namespaces.OrderedItemList.CloudSavedStickers, itemId: RecentMediaItemId(mediaId).rawValue), let item = entry.contents as? SavedStickerItem { + if let entry = transaction.getOrderedItemListItem(collectionId: Namespaces.OrderedItemList.CloudSavedStickers, itemId: RecentMediaItemId(mediaId).rawValue), let item = entry.contents.get(SavedStickerItem.self) { if let resource = item.file.resource as? CloudDocumentMediaResource { transaction.removeOrderedItemListItem(collectionId: Namespaces.OrderedItemList.CloudSavedStickers, itemId: entry.id) addSynchronizeSavedStickersOperation(transaction: transaction, operation: .remove(id: resource.fileId, accessHash: resource.accessHash)) diff --git a/submodules/TelegramCore/Sources/SyncCore/SyncCore_ArchivedStickerPacksInfo.swift b/submodules/TelegramCore/Sources/SyncCore/SyncCore_ArchivedStickerPacksInfo.swift index da13628cac..351efd445d 100644 --- a/submodules/TelegramCore/Sources/SyncCore/SyncCore_ArchivedStickerPacksInfo.swift +++ b/submodules/TelegramCore/Sources/SyncCore/SyncCore_ArchivedStickerPacksInfo.swift @@ -1,7 +1,6 @@ import Foundation import Postbox - public struct ArchivedStickerPacksInfoId { public let rawValue: MemoryBuffer public let id: Int32 @@ -22,18 +21,22 @@ public struct ArchivedStickerPacksInfoId { } } -public final class ArchivedStickerPacksInfo: OrderedItemListEntryContents { +public final class ArchivedStickerPacksInfo: Codable { public let count: Int32 init(count: Int32) { self.count = count } - public init(decoder: PostboxDecoder) { - self.count = decoder.decodeInt32ForKey("c", orElse: 0) + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: StringCodingKey.self) + + self.count = try container.decode(Int32.self, forKey: "c") } - public func encode(_ encoder: PostboxEncoder) { - encoder.encodeInt32(self.count, forKey: "c") + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: StringCodingKey.self) + + try container.encode(self.count, forKey: "c") } } diff --git a/submodules/TelegramCore/Sources/SyncCore/SyncCore_FeaturedStickerPack.swift b/submodules/TelegramCore/Sources/SyncCore/SyncCore_FeaturedStickerPack.swift index 156cd8be14..701b940979 100644 --- a/submodules/TelegramCore/Sources/SyncCore/SyncCore_FeaturedStickerPack.swift +++ b/submodules/TelegramCore/Sources/SyncCore/SyncCore_FeaturedStickerPack.swift @@ -21,7 +21,7 @@ public struct FeaturedStickerPackItemId { } } -public final class FeaturedStickerPackItem: OrderedItemListEntryContents { +public final class FeaturedStickerPackItem: Codable { public let info: StickerPackCollectionInfo public let topItems: [StickerPackItem] public let unread: Bool @@ -32,15 +32,27 @@ public final class FeaturedStickerPackItem: OrderedItemListEntryContents { self.unread = unread } - public init(decoder: PostboxDecoder) { - self.info = decoder.decodeObjectForKey("i") as! StickerPackCollectionInfo - self.topItems = decoder.decodeObjectArrayForKey("t") - self.unread = decoder.decodeInt32ForKey("u", orElse: 0) != 0 + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: StringCodingKey.self) + + let infoData = try container.decode(AdaptedPostboxDecoder.RawObjectData.self, forKey: "i") + self.info = StickerPackCollectionInfo(decoder: PostboxDecoder(buffer: MemoryBuffer(data: infoData.data))) + + self.topItems = (try container.decode([AdaptedPostboxDecoder.RawObjectData].self, forKey: "t")).map { itemData in + return StickerPackItem(decoder: PostboxDecoder(buffer: MemoryBuffer(data: itemData.data))) + } + + self.unread = try container.decode(Int32.self, forKey: "u") != 0 } - public func encode(_ encoder: PostboxEncoder) { - encoder.encodeObject(self.info, forKey: "i") - encoder.encodeObjectArray(self.topItems, forKey: "t") - encoder.encodeInt32(self.unread ? 1 : 0, forKey: "u") + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: StringCodingKey.self) + + try container.encode(PostboxEncoder().encodeObjectToRawData(self.info), forKey: "i") + try container.encode(self.topItems.map { item in + return PostboxEncoder().encodeObjectToRawData(item) + }, forKey: "t") + + try container.encode((self.unread ? 1 : 0) as Int32, forKey: "u") } } diff --git a/submodules/TelegramCore/Sources/SyncCore/SyncCore_RecentHashtagItem.swift b/submodules/TelegramCore/Sources/SyncCore/SyncCore_RecentHashtagItem.swift index 1add80d86e..0b427b4e59 100644 --- a/submodules/TelegramCore/Sources/SyncCore/SyncCore_RecentHashtagItem.swift +++ b/submodules/TelegramCore/Sources/SyncCore/SyncCore_RecentHashtagItem.swift @@ -1,12 +1,12 @@ import Postbox -public final class RecentHashtagItem: OrderedItemListEntryContents { +public final class RecentHashtagItem: Codable { public init() { } - public init(decoder: PostboxDecoder) { + public init(from decoder: Decoder) throws { } - public func encode(_ encoder: PostboxEncoder) { + public func encode(to encoder: Encoder) throws { } } diff --git a/submodules/TelegramCore/Sources/SyncCore/SyncCore_RecentMediaItem.swift b/submodules/TelegramCore/Sources/SyncCore/SyncCore_RecentMediaItem.swift index 461c41cd7d..74999632b9 100644 --- a/submodules/TelegramCore/Sources/SyncCore/SyncCore_RecentMediaItem.swift +++ b/submodules/TelegramCore/Sources/SyncCore/SyncCore_RecentMediaItem.swift @@ -25,19 +25,24 @@ public struct RecentMediaItemId { } } -public final class RecentMediaItem: OrderedItemListEntryContents, Equatable { - public let media: Media +public final class RecentMediaItem: Codable, Equatable { + public let media: TelegramMediaFile - public init(_ media: Media) { + public init(_ media: TelegramMediaFile) { self.media = media } - public init(decoder: PostboxDecoder) { - self.media = decoder.decodeObjectForKey("m") as! Media + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: StringCodingKey.self) + + let mediaData = try container.decode(AdaptedPostboxDecoder.RawObjectData.self, forKey: "m") + self.media = TelegramMediaFile(decoder: PostboxDecoder(buffer: MemoryBuffer(data: mediaData.data))) } - public func encode(_ encoder: PostboxEncoder) { - encoder.encodeObject(self.media, forKey: "m") + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: StringCodingKey.self) + + try container.encode(PostboxEncoder().encodeObjectToRawData(self.media), forKey: "m") } public static func ==(lhs: RecentMediaItem, rhs: RecentMediaItem) -> Bool { diff --git a/submodules/TelegramCore/Sources/SyncCore/SyncCore_RecentPeerItem.swift b/submodules/TelegramCore/Sources/SyncCore/SyncCore_RecentPeerItem.swift index f7c66347c3..57b4c05528 100644 --- a/submodules/TelegramCore/Sources/SyncCore/SyncCore_RecentPeerItem.swift +++ b/submodules/TelegramCore/Sources/SyncCore/SyncCore_RecentPeerItem.swift @@ -21,18 +21,22 @@ public struct RecentPeerItemId { } } -public final class RecentPeerItem: OrderedItemListEntryContents { +public final class RecentPeerItem: Codable { public let rating: Double public init(rating: Double) { self.rating = rating } - public init(decoder: PostboxDecoder) { - self.rating = decoder.decodeDoubleForKey("r", orElse: 0.0) + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: StringCodingKey.self) + + self.rating = try container.decode(Double.self, forKey: "r") } - public func encode(_ encoder: PostboxEncoder) { - encoder.encodeDouble(self.rating, forKey: "r") + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: StringCodingKey.self) + + try container.encode(self.rating, forKey: "r") } } diff --git a/submodules/TelegramCore/Sources/SyncCore/SyncCore_SavedStickerItem.swift b/submodules/TelegramCore/Sources/SyncCore/SyncCore_SavedStickerItem.swift index b834f409a4..6c5c40ab1f 100644 --- a/submodules/TelegramCore/Sources/SyncCore/SyncCore_SavedStickerItem.swift +++ b/submodules/TelegramCore/Sources/SyncCore/SyncCore_SavedStickerItem.swift @@ -1,7 +1,7 @@ import Foundation import Postbox -public final class SavedStickerItem: OrderedItemListEntryContents, Equatable { +public final class SavedStickerItem: Codable, Equatable { public let file: TelegramMediaFile public let stringRepresentations: [String] @@ -10,14 +10,18 @@ public final class SavedStickerItem: OrderedItemListEntryContents, Equatable { self.stringRepresentations = stringRepresentations } - public init(decoder: PostboxDecoder) { - self.file = decoder.decodeObjectForKey("f") as! TelegramMediaFile - self.stringRepresentations = decoder.decodeStringArrayForKey("sr") + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: StringCodingKey.self) + + self.file = TelegramMediaFile(decoder: PostboxDecoder(buffer: MemoryBuffer(data: (try container.decode(AdaptedPostboxDecoder.RawObjectData.self, forKey: "f")).data))) + self.stringRepresentations = try container.decode([String].self, forKey: "sr") } - public func encode(_ encoder: PostboxEncoder) { - encoder.encodeObject(self.file, forKey: "f") - encoder.encodeStringArray(self.stringRepresentations, forKey: "sr") + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: StringCodingKey.self) + + try container.encode(PostboxEncoder().encodeObjectToRawData(self.file), forKey: "f") + try container.encode(self.stringRepresentations, forKey: "sr") } public static func ==(lhs: SavedStickerItem, rhs: SavedStickerItem) -> Bool { diff --git a/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramMediaWebpage.swift b/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramMediaWebpage.swift index 2e6eba6cbe..538cbefc82 100644 --- a/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramMediaWebpage.swift +++ b/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramMediaWebpage.swift @@ -56,13 +56,13 @@ public final class TelegraMediaWebpageThemeAttribute: PostboxCoding, Equatable { public init(decoder: PostboxDecoder) { self.files = decoder.decodeObjectArrayForKey("files") - self.settings = decoder.decodeObjectForKey("settings", decoder: { TelegramThemeSettings(decoder: $0) }) as? TelegramThemeSettings + self.settings = decoder.decode(TelegramThemeSettings.self, forKey: "settings") } public func encode(_ encoder: PostboxEncoder) { encoder.encodeObjectArray(self.files, forKey: "files") if let settings = self.settings { - encoder.encodeObject(settings, forKey: "settings") + encoder.encode(settings, forKey: "settings") } else { encoder.encodeNil(forKey: "settings") } diff --git a/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramTheme.swift b/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramTheme.swift index 2968b2299c..6a7fc782f6 100644 --- a/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramTheme.swift +++ b/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramTheme.swift @@ -14,7 +14,7 @@ public extension UInt32 { } } -public final class TelegramThemeSettings: PostboxCoding, Equatable { +public final class TelegramThemeSettings: Codable, Equatable { public static func == (lhs: TelegramThemeSettings, rhs: TelegramThemeSettings) -> Bool { if lhs.baseTheme != rhs.baseTheme { return false @@ -53,43 +53,108 @@ public final class TelegramThemeSettings: PostboxCoding, Equatable { self.wallpaper = wallpaper } - public init(decoder: PostboxDecoder) { - self.baseTheme = TelegramBaseTheme(rawValue: decoder.decodeInt32ForKey("baseTheme", orElse: 0)) ?? .classic - self.accentColor = UInt32(bitPattern: decoder.decodeInt32ForKey("accent", orElse: 0)) - self.outgoingAccentColor = decoder.decodeOptionalInt32ForKey("outgoingAccent").flatMap { UInt32(bitPattern: $0) } - let messageColors = decoder.decodeInt32ArrayForKey("messageColors") + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: StringCodingKey.self) + + self.baseTheme = TelegramBaseTheme(rawValue: try container.decode(Int32.self, forKey: "baseTheme")) ?? .classic + self.accentColor = UInt32(bitPattern: try container.decode(Int32.self, forKey: "accent")) + self.outgoingAccentColor = (try container.decodeIfPresent(Int32.self, forKey: "outgoingAccent")).flatMap { UInt32(bitPattern: $0) } + let messageColors = try container.decode([Int32].self, forKey: "messageColors") if !messageColors.isEmpty { self.messageColors = messageColors.map(UInt32.init(bitPattern:)) } else { - if let topMessageColor = decoder.decodeOptionalInt32ForKey("topMessage"), let bottomMessageColor = decoder.decodeOptionalInt32ForKey("bottomMessage") { + if let topMessageColor = try container.decodeIfPresent(Int32.self, forKey: "topMessage"), let bottomMessageColor = try container.decodeIfPresent(Int32.self, forKey: "bottomMessage") { self.messageColors = [UInt32(bitPattern: topMessageColor), UInt32(bitPattern: bottomMessageColor)] } else { self.messageColors = [] } } - self.animateMessageColors = decoder.decodeInt32ForKey("animateMessageColors", orElse: 0) != 0 - self.wallpaper = decoder.decodeObjectForKey("wallpaper", decoder: { TelegramWallpaper(decoder: $0) }) as? TelegramWallpaper + self.animateMessageColors = try container.decode(Int32.self, forKey: "animateMessageColors") != 0 + + self.wallpaper = (try container.decodeIfPresent(TelegramWallpaperNativeCodable.self, forKey: "wallpaper"))?.value } - public func encode(_ encoder: PostboxEncoder) { - encoder.encodeInt32(self.baseTheme.rawValue, forKey: "baseTheme") - encoder.encodeInt32(Int32(bitPattern: self.accentColor), forKey: "accent") + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: StringCodingKey.self) + + try container.encode(self.baseTheme.rawValue, forKey: "baseTheme") + try container.encode(Int32(bitPattern: self.accentColor), forKey: "accent") if let outgoingAccentColor = self.outgoingAccentColor { - encoder.encodeInt32(Int32(bitPattern: outgoingAccentColor), forKey: "outgoingAccent") + try container.encode(Int32(bitPattern: outgoingAccentColor), forKey: "outgoingAccent") } else { - encoder.encodeNil(forKey: "outgoingAccent") - } - encoder.encodeInt32Array(self.messageColors.map(Int32.init(bitPattern:)), forKey: "messageColors") - encoder.encodeInt32(self.animateMessageColors ? 1 : 0, forKey: "animateMessageColors") - if let wallpaper = self.wallpaper { - encoder.encodeObject(wallpaper, forKey: "wallpaper") - } else { - encoder.encodeNil(forKey: "wallpaper") + try container.encodeNil(forKey: "outgoingAccent") } + try container.encode(self.messageColors.map(Int32.init(bitPattern:)), forKey: "messageColors") + try container.encode((self.animateMessageColors ? 1 : 0) as Int32, forKey: "animateMessageColors") + try container.encodeIfPresent(self.wallpaper.flatMap(TelegramWallpaperNativeCodable.init), forKey: "wallpaper") } } -public final class TelegramTheme: OrderedItemListEntryContents, Equatable { +public struct TelegramThemeNativeCodable: Codable { + public let value: TelegramTheme + + public init(_ value: TelegramTheme) { + self.value = value + } + + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: StringCodingKey.self) + + let id = try container.decode(Int64.self, forKey: "id") + let accessHash = try container.decode(Int64.self, forKey: "accessHash") + let slug = try container.decode(String.self, forKey: "slug") + let title = try container.decode(String.self, forKey: "title") + + let file: TelegramMediaFile? + if let fileData = try container.decodeIfPresent(AdaptedPostboxDecoder.RawObjectData.self, forKey: "file") { + file = TelegramMediaFile(decoder: PostboxDecoder(buffer: MemoryBuffer(data: fileData.data))) + } else { + file = nil + } + + let settings = try container.decodeIfPresent(TelegramThemeSettings.self, forKey: "settings") + + let isCreator = try container.decode(Int32.self, forKey: "isCreator") != 0 + let isDefault = try container.decode(Int32.self, forKey: "isDefault") != 0 + let installCount = try container.decodeIfPresent(Int32.self, forKey: "installCount") + + self.value = TelegramTheme( + id: id, + accessHash: accessHash, + slug: slug, + title: title, + file: file, + settings: settings, + isCreator: isCreator, + isDefault: isDefault, + installCount: installCount + ) + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: StringCodingKey.self) + + try container.encode(self.value.id, forKey: "id") + try container.encode(self.value.accessHash, forKey: "accessHash") + try container.encode(self.value.slug, forKey: "slug") + try container.encode(self.value.title, forKey: "title") + + if let file = self.value.file { + try container.encode(PostboxEncoder().encodeObjectToRawData(file), forKey: "file") + } else { + try container.encodeNil(forKey: "file") + } + + try container.encodeIfPresent(self.value.settings, forKey: "settings") + + try container.encode((self.value.isCreator ? 1 : 0) as Int32, forKey: "isCreator") + try container.encode((self.value.isDefault ? 1 : 0) as Int32, forKey: "isDefault") + + try container.encodeIfPresent(self.value.installCount, forKey: "installCount") + } +} + +public final class TelegramTheme: Equatable { public let id: Int64 public let accessHash: Int64 public let slug: String @@ -112,42 +177,6 @@ public final class TelegramTheme: OrderedItemListEntryContents, Equatable { self.installCount = installCount } - public init(decoder: PostboxDecoder) { - self.id = decoder.decodeInt64ForKey("id", orElse: 0) - self.accessHash = decoder.decodeInt64ForKey("accessHash", orElse: 0) - self.slug = decoder.decodeStringForKey("slug", orElse: "") - self.title = decoder.decodeStringForKey("title", orElse: "") - self.file = decoder.decodeObjectForKey("file", decoder: { TelegramMediaFile(decoder: $0) }) as? TelegramMediaFile - self.settings = decoder.decodeObjectForKey("settings", decoder: { TelegramThemeSettings(decoder: $0) }) as? TelegramThemeSettings - self.isCreator = decoder.decodeInt32ForKey("isCreator", orElse: 0) != 0 - self.isDefault = decoder.decodeInt32ForKey("isDefault", orElse: 0) != 0 - self.installCount = decoder.decodeOptionalInt32ForKey("installCount") - } - - public func encode(_ encoder: PostboxEncoder) { - encoder.encodeInt64(self.id, forKey: "id") - encoder.encodeInt64(self.accessHash, forKey: "accessHash") - encoder.encodeString(self.slug, forKey: "slug") - encoder.encodeString(self.title, forKey: "title") - if let file = self.file { - encoder.encodeObject(file, forKey: "file") - } else { - encoder.encodeNil(forKey: "file") - } - if let settings = self.settings { - encoder.encodeObject(settings, forKey: "settings") - } else { - encoder.encodeNil(forKey: "settings") - } - encoder.encodeInt32(self.isCreator ? 1 : 0, forKey: "isCreator") - encoder.encodeInt32(self.isDefault ? 1 : 0, forKey: "isDefault") - if let installCount = self.installCount { - encoder.encodeInt32(installCount, forKey: "installCount") - } else { - encoder.encodeNil(forKey: "installCount") - } - } - public static func ==(lhs: TelegramTheme, rhs: TelegramTheme) -> Bool { if lhs.id != rhs.id { return false diff --git a/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramWallpaper.swift b/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramWallpaper.swift index 05e7b0224d..3645af6204 100644 --- a/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramWallpaper.swift +++ b/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramWallpaper.swift @@ -1,6 +1,6 @@ import Postbox -public struct WallpaperSettings: PostboxCoding, Equatable { +public struct WallpaperSettings: Codable, Equatable { public var blur: Bool public var motion: Bool public var colors: [UInt32] @@ -15,37 +15,33 @@ public struct WallpaperSettings: PostboxCoding, Equatable { self.rotation = rotation } - public init(decoder: PostboxDecoder) { - self.blur = decoder.decodeInt32ForKey("b", orElse: 0) != 0 - self.motion = decoder.decodeInt32ForKey("m", orElse: 0) != 0 - if let topColor = decoder.decodeOptionalInt32ForKey("c").flatMap(UInt32.init(bitPattern:)) { + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: StringCodingKey.self) + + self.blur = try container.decode(Int32.self, forKey: "b") != 0 + self.motion = try container.decode(Int32.self, forKey: "m") != 0 + if let topColor = (try container.decodeIfPresent(Int32.self, forKey: "c")).flatMap(UInt32.init(bitPattern:)) { var colors: [UInt32] = [topColor] - if let bottomColor = decoder.decodeOptionalInt32ForKey("bc").flatMap(UInt32.init(bitPattern:)) { + if let bottomColor = (try container.decodeIfPresent(Int32.self, forKey: "bc")).flatMap(UInt32.init(bitPattern:)) { colors.append(bottomColor) } self.colors = colors } else { - self.colors = decoder.decodeInt32ArrayForKey("colors").map(UInt32.init(bitPattern:)) + self.colors = (try container.decode([Int32].self, forKey: "colors")).map(UInt32.init(bitPattern:)) } - self.intensity = decoder.decodeOptionalInt32ForKey("i") - self.rotation = decoder.decodeOptionalInt32ForKey("r") + self.intensity = try container.decodeIfPresent(Int32.self, forKey: "i") + self.rotation = try container.decodeIfPresent(Int32.self, forKey: "r") } - public func encode(_ encoder: PostboxEncoder) { - encoder.encodeInt32(self.blur ? 1 : 0, forKey: "b") - encoder.encodeInt32(self.motion ? 1 : 0, forKey: "m") - encoder.encodeInt32Array(self.colors.map(Int32.init(bitPattern:)), forKey: "colors") - if let intensity = self.intensity { - encoder.encodeInt32(intensity, forKey: "i") - } else { - encoder.encodeNil(forKey: "i") - } - if let rotation = self.rotation { - encoder.encodeInt32(rotation, forKey: "r") - } else { - encoder.encodeNil(forKey: "r") - } + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: StringCodingKey.self) + + try container.encode((self.blur ? 1 : 0) as Int32, forKey: "b") + try container.encode((self.motion ? 1 : 0) as Int32, forKey: "m") + try container.encode(self.colors.map(Int32.init(bitPattern:)), forKey: "colors") + try container.encodeIfPresent(self.intensity, forKey: "i") + try container.encodeIfPresent(self.rotation, forKey: "r") } public static func ==(lhs: WallpaperSettings, rhs: WallpaperSettings) -> Bool { @@ -68,7 +64,108 @@ public struct WallpaperSettings: PostboxCoding, Equatable { } } -public enum TelegramWallpaper: OrderedItemListEntryContents, Equatable { +public struct TelegramWallpaperNativeCodable: Codable { + public let value: TelegramWallpaper + + public init(_ value: TelegramWallpaper) { + self.value = value + } + + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: StringCodingKey.self) + + switch try container.decode(Int32.self, forKey: "v") { + case 0: + let settings = try container.decode(WallpaperSettings.self, forKey: "settings") + self.value = .builtin(settings) + case 1: + self.value = .color(UInt32(bitPattern: try container.decode(Int32.self, forKey: "c"))) + case 2: + let settings = try container.decode(WallpaperSettings.self, forKey: "settings") + let representations = (try container.decode([AdaptedPostboxDecoder.RawObjectData].self, forKey: "i")).map { itemData in + return TelegramMediaImageRepresentation(decoder: PostboxDecoder(buffer: MemoryBuffer(data: itemData.data))) + } + self.value = .image(representations, settings) + case 3: + let settings = try container.decode(WallpaperSettings.self, forKey: "settings") + if let fileData = try container.decodeIfPresent(AdaptedPostboxDecoder.RawObjectData.self, forKey: "file") { + let file = TelegramMediaFile(decoder: PostboxDecoder(buffer: MemoryBuffer(data: fileData.data))) + self.value = .file(TelegramWallpaper.File( + id: try container.decode(Int64.self, forKey: "id"), + accessHash: try container.decode(Int64.self, forKey: "accessHash"), + isCreator: try container.decode(Int32.self, forKey: "isCreator") != 0, + isDefault: try container.decode(Int32.self, forKey: "isDefault") != 0, + isPattern: try container.decode(Int32.self, forKey: "isPattern") != 0, + isDark: try container.decode(Int32.self, forKey: "isDark") != 0, + slug: try container.decode(String.self, forKey: "slug"), + file: file, + settings: settings + )) + } else { + self.value = .color(0xffffff) + } + case 4: + let settings = try container.decode(WallpaperSettings.self, forKey: "settings") + + var colors: [UInt32] = [] + + if let topColor = (try container.decodeIfPresent(Int32.self, forKey: "c1")).flatMap(UInt32.init(bitPattern:)) { + colors.append(topColor) + if let bottomColor = (try container.decodeIfPresent(Int32.self, forKey: "c2")).flatMap(UInt32.init(bitPattern:)) { + colors.append(bottomColor) + } + } else { + colors = (try container.decode([Int32].self, forKey: "colors")).map(UInt32.init(bitPattern:)) + } + + self.value = .gradient(TelegramWallpaper.Gradient( + id: try container.decodeIfPresent(Int64.self, forKey: "id"), + colors: colors, + settings: settings + )) + default: + assertionFailure() + self.value = .color(0xffffff) + } + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: StringCodingKey.self) + + switch self.value { + case let .builtin(settings): + try container.encode(0 as Int32, forKey: "v") + try container.encode(settings, forKey: "settings") + case let .color(color): + try container.encode(1 as Int32, forKey: "v") + try container.encode(Int32(bitPattern: color), forKey: "c") + case let .gradient(gradient): + try container.encode(4 as Int32, forKey: "v") + try container.encodeIfPresent(gradient.id, forKey: "id") + try container.encode(gradient.colors.map(Int32.init(bitPattern:)), forKey: "colors") + try container.encode(gradient.settings, forKey: "settings") + case let .image(representations, settings): + try container.encode(2 as Int32, forKey: "v") + try container.encode(representations.map { item in + return PostboxEncoder().encodeObjectToRawData(item) + }, forKey: "i") + try container.encode(settings, forKey: "settings") + case let .file(file): + try container.encode(3 as Int32, forKey: "v") + try container.encode(file.id, forKey: "id") + try container.encode(file.accessHash, forKey: "accessHash") + try container.encode((file.isCreator ? 1 : 0) as Int32, forKey: "isCreator") + try container.encode((file.isDefault ? 1 : 0) as Int32, forKey: "isDefault") + try container.encode((file.isPattern ? 1 : 0) as Int32, forKey: "isPattern") + try container.encode((file.isDark ? 1 : 0) as Int32, forKey: "isDark") + try container.encode(file.slug, forKey: "slug") + try container.encode(PostboxEncoder().encodeObjectToRawData(file.file), forKey: "file") + try container.encode(file.settings, forKey: "settings") + } + } +} + +public enum TelegramWallpaper: Equatable { public struct Gradient: Equatable { public var id: Int64? public var colors: [UInt32] @@ -125,44 +222,6 @@ public enum TelegramWallpaper: OrderedItemListEntryContents, Equatable { case image([TelegramMediaImageRepresentation], WallpaperSettings) case file(File) - public init(decoder: PostboxDecoder) { - switch decoder.decodeInt32ForKey("v", orElse: 0) { - case 0: - let settings = decoder.decodeObjectForKey("settings", decoder: { WallpaperSettings(decoder: $0) }) as? WallpaperSettings ?? WallpaperSettings() - self = .builtin(settings) - case 1: - self = .color(UInt32(bitPattern: decoder.decodeInt32ForKey("c", orElse: 0))) - case 2: - let settings = decoder.decodeObjectForKey("settings", decoder: { WallpaperSettings(decoder: $0) }) as? WallpaperSettings ?? WallpaperSettings() - self = .image(decoder.decodeObjectArrayWithDecoderForKey("i"), settings) - case 3: - let settings = decoder.decodeObjectForKey("settings", decoder: { WallpaperSettings(decoder: $0) }) as? WallpaperSettings ?? WallpaperSettings() - if let file = decoder.decodeObjectForKey("file", decoder: { TelegramMediaFile(decoder: $0) }) as? TelegramMediaFile { - self = .file(File(id: decoder.decodeInt64ForKey("id", orElse: 0), accessHash: decoder.decodeInt64ForKey("accessHash", orElse: 0), isCreator: decoder.decodeInt32ForKey("isCreator", orElse: 0) != 0, isDefault: decoder.decodeInt32ForKey("isDefault", orElse: 0) != 0, isPattern: decoder.decodeInt32ForKey("isPattern", orElse: 0) != 0, isDark: decoder.decodeInt32ForKey("isDark", orElse: 0) != 0, slug: decoder.decodeStringForKey("slug", orElse: ""), file: file, settings: settings)) - } else { - self = .color(0xffffff) - } - case 4: - let settings = decoder.decodeObjectForKey("settings", decoder: { WallpaperSettings(decoder: $0) }) as? WallpaperSettings ?? WallpaperSettings() - - var colors: [UInt32] = [] - - if let topColor = decoder.decodeOptionalInt32ForKey("c1").flatMap(UInt32.init(bitPattern:)) { - colors.append(topColor) - if let bottomColor = decoder.decodeOptionalInt32ForKey("c2").flatMap(UInt32.init(bitPattern:)) { - colors.append(bottomColor) - } - } else { - colors = decoder.decodeInt32ArrayForKey("colors").map(UInt32.init(bitPattern:)) - } - - self = .gradient(Gradient(id: decoder.decodeOptionalInt64ForKey("id"), colors: colors, settings: settings)) - default: - assertionFailure() - self = .color(0xffffff) - } - } - public var hasWallpaper: Bool { switch self { case .color: @@ -172,41 +231,6 @@ public enum TelegramWallpaper: OrderedItemListEntryContents, Equatable { } } - public func encode(_ encoder: PostboxEncoder) { - switch self { - case let .builtin(settings): - encoder.encodeInt32(0, forKey: "v") - encoder.encodeObject(settings, forKey: "settings") - case let .color(color): - encoder.encodeInt32(1, forKey: "v") - encoder.encodeInt32(Int32(bitPattern: color), forKey: "c") - case let .gradient(gradient): - encoder.encodeInt32(4, forKey: "v") - if let id = gradient.id { - encoder.encodeInt64(id, forKey: "id") - } else { - encoder.encodeNil(forKey: "id") - } - encoder.encodeInt32Array(gradient.colors.map(Int32.init(bitPattern:)), forKey: "colors") - encoder.encodeObject(gradient.settings, forKey: "settings") - case let .image(representations, settings): - encoder.encodeInt32(2, forKey: "v") - encoder.encodeObjectArray(representations, forKey: "i") - encoder.encodeObject(settings, forKey: "settings") - case let .file(file): - encoder.encodeInt32(3, forKey: "v") - encoder.encodeInt64(file.id, forKey: "id") - encoder.encodeInt64(file.accessHash, forKey: "accessHash") - encoder.encodeInt32(file.isCreator ? 1 : 0, forKey: "isCreator") - encoder.encodeInt32(file.isDefault ? 1 : 0, forKey: "isDefault") - encoder.encodeInt32(file.isPattern ? 1 : 0, forKey: "isPattern") - encoder.encodeInt32(file.isDark ? 1 : 0, forKey: "isDark") - encoder.encodeString(file.slug, forKey: "slug") - encoder.encodeObject(file.file, forKey: "file") - encoder.encodeObject(file.settings, forKey: "settings") - } - } - public static func ==(lhs: TelegramWallpaper, rhs: TelegramWallpaper) -> Bool { switch lhs { case let .builtin(settings): diff --git a/submodules/TelegramCore/Sources/SyncCore/SyncCore_ThemeSettings.swift b/submodules/TelegramCore/Sources/SyncCore/SyncCore_ThemeSettings.swift index 9a28cee8bd..b213c8e88b 100644 --- a/submodules/TelegramCore/Sources/SyncCore/SyncCore_ThemeSettings.swift +++ b/submodules/TelegramCore/Sources/SyncCore/SyncCore_ThemeSettings.swift @@ -10,19 +10,14 @@ public final class ThemeSettings: Codable, Equatable { public init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: StringCodingKey.self) - if let currentThemeData = try container.decodeIfPresent(AdaptedPostboxDecoder.RawObjectData.self, forKey: "t") { - self.currentTheme = TelegramTheme(decoder: PostboxDecoder(buffer: MemoryBuffer(data: currentThemeData.data))) - } else { - self.currentTheme = nil - } + self.currentTheme = (try container.decodeIfPresent(TelegramThemeNativeCodable.self, forKey: "t"))?.value } public func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: StringCodingKey.self) if let currentTheme = self.currentTheme { - let currentThemeData = PostboxEncoder().encodeObjectToRawData(currentTheme) - try container.encode(currentThemeData, forKey: "t") + try container.encode(TelegramThemeNativeCodable(currentTheme), forKey: "t") } else { try container.encodeNil(forKey: "t") } diff --git a/submodules/TelegramCore/Sources/SyncCore/SyncCore_wallapersState.swift b/submodules/TelegramCore/Sources/SyncCore/SyncCore_wallapersState.swift index 8e44e097ca..bd2a589bd5 100644 --- a/submodules/TelegramCore/Sources/SyncCore/SyncCore_wallapersState.swift +++ b/submodules/TelegramCore/Sources/SyncCore/SyncCore_wallapersState.swift @@ -18,7 +18,7 @@ public struct WallpapersState: Codable, Equatable { let wallpapersData = try container.decode([Data].self, forKey: "wallpapers") self.wallpapers = wallpapersData.map { data in - return TelegramWallpaper(decoder: PostboxDecoder(buffer: MemoryBuffer(data: data))) + return (try! AdaptedPostboxDecoder().decode(TelegramWallpaperNativeCodable.self, from: data)).value } } @@ -26,9 +26,7 @@ public struct WallpapersState: Codable, Equatable { var container = encoder.container(keyedBy: StringCodingKey.self) let wallpapersData: [Data] = self.wallpapers.map { wallpaper in - let innerEncoder = PostboxEncoder() - wallpaper.encode(innerEncoder) - return innerEncoder.makeData() + return try! AdaptedPostboxEncoder().encode(TelegramWallpaperNativeCodable(wallpaper)) } try container.encode(wallpapersData, forKey: "wallpapers") diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Messages/RecentlyUsedHashtags.swift b/submodules/TelegramCore/Sources/TelegramEngine/Messages/RecentlyUsedHashtags.swift index 4588580322..5455c81eaf 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Messages/RecentlyUsedHashtags.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Messages/RecentlyUsedHashtags.swift @@ -25,7 +25,9 @@ private struct RecentHashtagItemId { func addRecentlyUsedHashtag(transaction: Transaction, string: String) { if let itemId = RecentHashtagItemId(string) { - transaction.addOrMoveToFirstPositionOrderedItemListItem(collectionId: Namespaces.OrderedItemList.RecentlyUsedHashtags, item: OrderedItemListEntry(id: itemId.rawValue, contents: RecentHashtagItem()), removeTailIfCountExceeds: 100) + if let entry = CodableEntry(RecentHashtagItem()) { + transaction.addOrMoveToFirstPositionOrderedItemListItem(collectionId: Namespaces.OrderedItemList.RecentlyUsedHashtags, item: OrderedItemListEntry(id: itemId.rawValue, contents: entry), removeTailIfCountExceeds: 100) + } } } diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Peers/RecentPeers.swift b/submodules/TelegramCore/Sources/TelegramEngine/Peers/RecentPeers.swift index e5ccd9eaf3..d595bae9a2 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Peers/RecentPeers.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Peers/RecentPeers.swift @@ -204,8 +204,12 @@ func _internal_managedRecentlyUsedInlineBots(postbox: Postbox, network: Network, let sortedPeersWithRating = peersWithRating.sorted(by: { $0.1 > $1.1 }) - transaction.replaceOrderedItemListItems(collectionId: Namespaces.OrderedItemList.CloudRecentInlineBots, items: sortedPeersWithRating.map { (peerId, rating) in - return OrderedItemListEntry(id: RecentPeerItemId(peerId).rawValue, contents: RecentPeerItem(rating: rating)) + transaction.replaceOrderedItemListItems(collectionId: Namespaces.OrderedItemList.CloudRecentInlineBots, items: sortedPeersWithRating.compactMap { (peerId, rating) in + if let entry = CodableEntry(RecentPeerItem(rating: rating)) { + return OrderedItemListEntry(id: RecentPeerItemId(peerId).rawValue, contents: entry) + } else { + return nil + } }) } } else { @@ -220,11 +224,13 @@ func _internal_addRecentlyUsedInlineBot(postbox: Postbox, peerId: PeerId) -> Sig return postbox.transaction { transaction -> Void in var maxRating = 1.0 for entry in transaction.getOrderedListItems(collectionId: Namespaces.OrderedItemList.CloudRecentInlineBots) { - if let contents = entry.contents as? RecentPeerItem { + if let contents = entry.contents.get(RecentPeerItem.self) { maxRating = max(maxRating, contents.rating) } } - transaction.addOrMoveToFirstPositionOrderedItemListItem(collectionId: Namespaces.OrderedItemList.CloudRecentInlineBots, item: OrderedItemListEntry(id: RecentPeerItemId(peerId).rawValue, contents: RecentPeerItem(rating: maxRating)), removeTailIfCountExceeds: 20) + if let entry = CodableEntry(RecentPeerItem(rating: maxRating)) { + transaction.addOrMoveToFirstPositionOrderedItemListItem(collectionId: Namespaces.OrderedItemList.CloudRecentInlineBots, item: OrderedItemListEntry(id: RecentPeerItemId(peerId).rawValue, contents: entry), removeTailIfCountExceeds: 20) + } } } @@ -237,7 +243,7 @@ func _internal_recentlyUsedInlineBots(postbox: Postbox) -> Signal<[(Peer, Double if let view = view.views[.orderedItemList(id: Namespaces.OrderedItemList.CloudRecentInlineBots)] as? OrderedItemListView { for item in view.items { let peerId = RecentPeerItemId(item.id).peerId - if let peer = transaction.getPeer(peerId), let contents = item.contents as? RecentPeerItem { + if let peer = transaction.getPeer(peerId), let contents = item.contents.get(RecentPeerItem.self) { peers.append((peer, contents.rating)) } } diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Peers/RecentlySearchedPeerIds.swift b/submodules/TelegramCore/Sources/TelegramEngine/Peers/RecentlySearchedPeerIds.swift index 21dcd8b3f5..a3e7e1ff4e 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Peers/RecentlySearchedPeerIds.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Peers/RecentlySearchedPeerIds.swift @@ -5,7 +5,9 @@ import SwiftSignalKit func _internal_addRecentlySearchedPeer(postbox: Postbox, peerId: PeerId) -> Signal { return postbox.transaction { transaction -> Void in - transaction.addOrMoveToFirstPositionOrderedItemListItem(collectionId: Namespaces.OrderedItemList.RecentlySearchedPeerIds, item: OrderedItemListEntry(id: RecentPeerItemId(peerId).rawValue, contents: RecentPeerItem(rating: 0.0)), removeTailIfCountExceeds: 20) + if let entry = CodableEntry(RecentPeerItem(rating: 0.0)) { + transaction.addOrMoveToFirstPositionOrderedItemListItem(collectionId: Namespaces.OrderedItemList.RecentlySearchedPeerIds, item: OrderedItemListEntry(id: RecentPeerItemId(peerId).rawValue, contents: entry), removeTailIfCountExceeds: 20) + } } } diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Stickers/SearchStickers.swift b/submodules/TelegramCore/Sources/TelegramEngine/Stickers/SearchStickers.swift index 04e39fc56d..21449c8dbc 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Stickers/SearchStickers.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Stickers/SearchStickers.swift @@ -71,7 +71,8 @@ func _internal_randomGreetingSticker(account: Account) -> Signal take(1) |> map { items -> FoundStickerItem? in - if let randomItem = items?.randomElement(), let item = randomItem.contents as? RecentMediaItem, let file = item.media as? TelegramMediaFile { + if let randomItem = items?.randomElement(), let item = randomItem.contents.get(RecentMediaItem.self) { + let file = item.media return FoundStickerItem(file: file, stringRepresentations: []) } return nil @@ -90,7 +91,7 @@ func _internal_searchStickers(account: Account, query: String, scope: SearchStic var result: [FoundStickerItem] = [] if scope.contains(.installed) { for entry in transaction.getOrderedListItems(collectionId: Namespaces.OrderedItemList.CloudSavedStickers) { - if let item = entry.contents as? SavedStickerItem { + if let item = entry.contents.get(SavedStickerItem.self) { for representation in item.stringRepresentations { if representation.hasPrefix(query) { result.append(FoundStickerItem(file: item.file, stringRepresentations: item.stringRepresentations)) @@ -107,7 +108,9 @@ func _internal_searchStickers(account: Account, query: String, scope: SearchStic var matchingRecentItemsIds = Set() for entry in transaction.getOrderedListItems(collectionId: Namespaces.OrderedItemList.CloudRecentStickers) { - if let item = entry.contents as? RecentMediaItem, let file = item.media as? TelegramMediaFile { + if let item = entry.contents.get(RecentMediaItem.self) { + let file = item.media + if !currentItems.contains(file.fileId) { for case let .Sticker(displayText, _, _) in file.attributes { if displayText.hasPrefix(query) { diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Stickers/StickerPackInteractiveOperations.swift b/submodules/TelegramCore/Sources/TelegramEngine/Stickers/StickerPackInteractiveOperations.swift index b1e1143232..4c40991bdd 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Stickers/StickerPackInteractiveOperations.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Stickers/StickerPackInteractiveOperations.swift @@ -98,10 +98,12 @@ func _internal_markFeaturedStickerPacksAsSeenInteractively(postbox: Postbox, ids var items = transaction.getOrderedListItems(collectionId: Namespaces.OrderedItemList.CloudFeaturedStickerPacks) var readIds = Set() for i in 0 ..< items.count { - let item = (items[i].contents as! FeaturedStickerPackItem) + let item = items[i].contents.get(FeaturedStickerPackItem.self)! if item.unread && idsSet.contains(item.info.id) { readIds.insert(item.info.id) - items[i] = OrderedItemListEntry(id: items[i].id, contents: FeaturedStickerPackItem(info: item.info, topItems: item.topItems, unread: false)) + if let entry = CodableEntry(FeaturedStickerPackItem(info: item.info, topItems: item.topItems, unread: false)) { + items[i] = OrderedItemListEntry(id: items[i].id, contents: entry) + } } } if !readIds.isEmpty { diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Themes/ChatThemes.swift b/submodules/TelegramCore/Sources/TelegramEngine/Themes/ChatThemes.swift index 84d65e7462..13bea9442f 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Themes/ChatThemes.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Themes/ChatThemes.swift @@ -23,19 +23,16 @@ public struct ChatTheme: Codable, Equatable { self.emoji = try container.decode(String.self, forKey: "e") - let themeData = try container.decode(AdaptedPostboxDecoder.RawObjectData.self, forKey: "t") - self.theme = TelegramTheme(decoder: PostboxDecoder(buffer: MemoryBuffer(data: themeData.data))) - - let darkThemeData = try container.decode(AdaptedPostboxDecoder.RawObjectData.self, forKey: "dt") - self.darkTheme = TelegramTheme(decoder: PostboxDecoder(buffer: MemoryBuffer(data: darkThemeData.data))) + self.theme = (try container.decode(TelegramThemeNativeCodable.self, forKey: "t")).value + self.darkTheme = (try container.decode(TelegramThemeNativeCodable.self, forKey: "dt")).value } public func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: StringCodingKey.self) try container.encode(self.emoji, forKey: "e") - try container.encode(PostboxEncoder().encodeObjectToRawData(self.theme), forKey: "t") - try container.encode(PostboxEncoder().encodeObjectToRawData(self.darkTheme), forKey: "dt") + try container.encode(TelegramThemeNativeCodable(self.theme), forKey: "t") + try container.encode(TelegramThemeNativeCodable(self.darkTheme), forKey: "dt") } } diff --git a/submodules/TelegramCore/Sources/Themes.swift b/submodules/TelegramCore/Sources/Themes.swift index 5bed3c4841..92fef899b2 100644 --- a/submodules/TelegramCore/Sources/Themes.swift +++ b/submodules/TelegramCore/Sources/Themes.swift @@ -49,7 +49,9 @@ public func telegramThemes(postbox: Postbox, network: Network, accountManager: A for item in items { var intValue = Int32(entries.count) let id = MemoryBuffer(data: Data(bytes: &intValue, count: 4)) - entries.append(OrderedItemListEntry(id: id, contents: item)) + if let entry = CodableEntry(TelegramThemeNativeCodable(item)) { + entries.append(OrderedItemListEntry(id: id, contents: entry)) + } } transaction.replaceOrderedItemListItems(collectionId: Namespaces.OrderedItemList.CloudThemes, items: entries) if let entry = CodableEntry(CachedThemesConfiguration(hash: hash)) { @@ -61,7 +63,7 @@ public func telegramThemes(postbox: Postbox, network: Network, accountManager: A postbox.combinedView(keys: [PostboxViewKey.orderedItemList(id: Namespaces.OrderedItemList.CloudThemes)]) |> map { view -> [TelegramTheme] in if let view = view.views[.orderedItemList(id: Namespaces.OrderedItemList.CloudThemes)] as? OrderedItemListView { - return view.items.compactMap { $0.contents as? TelegramTheme } + return view.items.compactMap { $0.contents.get(TelegramThemeNativeCodable.self)?.value } } else { return [] } @@ -75,7 +77,7 @@ public func telegramThemes(postbox: Postbox, network: Network, accountManager: A return postbox.transaction { transaction -> ([TelegramTheme], Int64?) in let configuration = transaction.retrieveItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedThemesConfiguration, key: ValueBoxKey(length: 0)))?.get(CachedThemesConfiguration.self) let items = transaction.getOrderedListItems(collectionId: Namespaces.OrderedItemList.CloudThemes) - return (items.map { $0.contents as! TelegramTheme }, configuration?.hash) + return (items.compactMap { $0.contents.get(TelegramThemeNativeCodable.self)?.value }, configuration?.hash) } |> mapToSignal { current, hash -> Signal<[TelegramTheme], NoError> in return .single(current) @@ -126,7 +128,7 @@ private func checkThemeUpdated(network: Network, theme: TelegramTheme) -> Signal private func saveUnsaveTheme(account: Account, accountManager: AccountManager, theme: TelegramTheme, unsave: Bool) -> Signal { return account.postbox.transaction { transaction -> Signal in let entries = transaction.getOrderedListItems(collectionId: Namespaces.OrderedItemList.CloudThemes) - var items = entries.map { $0.contents as! TelegramTheme } + var items = entries.compactMap { $0.contents.get(TelegramThemeNativeCodable.self)?.value } items = items.filter { $0.id != theme.id } if !unsave { items.insert(theme, at: 0) @@ -135,7 +137,9 @@ private func saveUnsaveTheme(account: Account, accountManager: AccountManager CreateThemeResult in let entries = transaction.getOrderedListItems(collectionId: Namespaces.OrderedItemList.CloudThemes) - var items = entries.map { $0.contents as! TelegramTheme } + var items = entries.compactMap { $0.contents.get(TelegramThemeNativeCodable.self)?.value } items.insert(theme, at: 0) var updatedEntries: [OrderedItemListEntry] = [] for item in items { var intValue = Int32(updatedEntries.count) let id = MemoryBuffer(data: Data(bytes: &intValue, count: 4)) - updatedEntries.append(OrderedItemListEntry(id: id, contents: item)) + if let entry = CodableEntry(TelegramThemeNativeCodable(item)) { + updatedEntries.append(OrderedItemListEntry(id: id, contents: entry)) + } } transaction.replaceOrderedItemListItems(collectionId: Namespaces.OrderedItemList.CloudThemes, items: updatedEntries) return .result(theme) @@ -343,13 +349,15 @@ public func createTheme(account: Account, title: String, resource: MediaResource return account.postbox.transaction { transaction -> CreateThemeResult in let entries = transaction.getOrderedListItems(collectionId: Namespaces.OrderedItemList.CloudThemes) - var items = entries.map { $0.contents as! TelegramTheme } + var items = entries.compactMap { $0.contents.get(TelegramThemeNativeCodable.self)?.value } items.insert(theme, at: 0) var updatedEntries: [OrderedItemListEntry] = [] for item in items { var intValue = Int32(updatedEntries.count) let id = MemoryBuffer(data: Data(bytes: &intValue, count: 4)) - updatedEntries.append(OrderedItemListEntry(id: id, contents: item)) + if let entry = CodableEntry(TelegramThemeNativeCodable(item)) { + updatedEntries.append(OrderedItemListEntry(id: id, contents: entry)) + } } transaction.replaceOrderedItemListItems(collectionId: Namespaces.OrderedItemList.CloudThemes, items: updatedEntries) return .result(theme) @@ -431,7 +439,7 @@ public func updateTheme(account: Account, accountManager: AccountManager CreateThemeResult in let entries = transaction.getOrderedListItems(collectionId: Namespaces.OrderedItemList.CloudThemes) let items = entries.map { entry -> TelegramTheme in - let theme = entry.contents as! TelegramTheme + let theme = entry.contents.get(TelegramThemeNativeCodable.self)!.value if theme.id == updatedTheme.id { return updatedTheme } else { @@ -442,7 +450,9 @@ public func updateTheme(account: Account, accountManager: AccountManager TelegramTheme in - let theme = entry.contents as! TelegramTheme + let theme = entry.contents.get(TelegramThemeNativeCodable.self)!.value if theme.id == updatedTheme.id { return updatedTheme } else { @@ -512,7 +522,9 @@ func managedThemesUpdates(accountManager: AccountManager map { view -> [TelegramTheme] in if let view = view.views[.orderedItemList(id: Namespaces.OrderedItemList.CloudThemes)] as? OrderedItemListView { - return view.items.compactMap { $0.contents as? TelegramTheme } + return view.items.compactMap { $0.contents.get(TelegramThemeNativeCodable.self)?.value } } else { return [] } diff --git a/submodules/TelegramCore/Sources/Wallpapers.swift b/submodules/TelegramCore/Sources/Wallpapers.swift index 891b43380f..8deb15b1e3 100644 --- a/submodules/TelegramCore/Sources/Wallpapers.swift +++ b/submodules/TelegramCore/Sources/Wallpapers.swift @@ -43,7 +43,9 @@ public func telegramWallpapers(postbox: Postbox, network: Network, forceUpdate: for item in items { var intValue = Int32(entries.count) let id = MemoryBuffer(data: Data(bytes: &intValue, count: 4)) - entries.append(OrderedItemListEntry(id: id, contents: item)) + if let entry = CodableEntry(TelegramWallpaperNativeCodable(item)) { + entries.append(OrderedItemListEntry(id: id, contents: entry)) + } } transaction.replaceOrderedItemListItems(collectionId: Namespaces.OrderedItemList.CloudWallpapers, items: entries) if let entry = CodableEntry(CachedWallpapersConfiguration(hash: hash)) { @@ -63,7 +65,7 @@ public func telegramWallpapers(postbox: Postbox, network: Network, forceUpdate: if items.count == 0 { return ([.builtin(WallpaperSettings())], 0) } else { - return (items.map { $0.contents as! TelegramWallpaper }, configuration?.hash) + return (items.map { $0.contents.get(TelegramWallpaperNativeCodable.self)!.value }, configuration?.hash) } } |> mapToSignal { current, hash -> Signal<[TelegramWallpaper], NoError> in diff --git a/submodules/TelegramPresentationData/Sources/PresentationThemeCodable.swift b/submodules/TelegramPresentationData/Sources/PresentationThemeCodable.swift index 6af0656c74..e5f27ae7d9 100644 --- a/submodules/TelegramPresentationData/Sources/PresentationThemeCodable.swift +++ b/submodules/TelegramPresentationData/Sources/PresentationThemeCodable.swift @@ -64,18 +64,24 @@ private func encodeColorList(_ values: inout KeyedEncodingContainer, _ try values.encode(stringList, forKey: key) } -extension TelegramWallpaper: Codable { - public init(from decoder: Decoder) throws { +struct TelegramWallpaperStandardizedCodable: Codable { + let value: TelegramWallpaper + + init(_ value: TelegramWallpaper) { + self.value = value + } + + init(from decoder: Decoder) throws { let values = try decoder.singleValueContainer() if let value = try? values.decode(String.self) { switch value.lowercased() { case "builtin": - self = .builtin(WallpaperSettings()) + self.value = .builtin(WallpaperSettings()) default: let optionKeys = ["motion", "blur"] if [6, 8].contains(value.count), let color = UIColor(hexString: value) { - self = .color(color.argb) + self.value = .color(color.argb) } else { let components = value.components(separatedBy: " ") var blur = false @@ -117,9 +123,9 @@ extension TelegramWallpaper: Codable { } if let slug = slug { - self = .file(TelegramWallpaper.File(id: 0, accessHash: 0, isCreator: false, isDefault: false, isPattern: !colors.isEmpty, isDark: false, slug: slug, file: TelegramMediaFile(fileId: MediaId(namespace: 0, id: 0), partialReference: nil, resource: WallpaperDataResource(slug: slug), previewRepresentations: [], videoThumbnails: [], immediateThumbnailData: nil, mimeType: "", size: nil, attributes: []), settings: WallpaperSettings(blur: blur, motion: motion, colors: colors.map { $0.argb }, intensity: intensity, rotation: rotation))) + self.value = .file(TelegramWallpaper.File(id: 0, accessHash: 0, isCreator: false, isDefault: false, isPattern: !colors.isEmpty, isDark: false, slug: slug, file: TelegramMediaFile(fileId: MediaId(namespace: 0, id: 0), partialReference: nil, resource: WallpaperDataResource(slug: slug), previewRepresentations: [], videoThumbnails: [], immediateThumbnailData: nil, mimeType: "", size: nil, attributes: []), settings: WallpaperSettings(blur: blur, motion: motion, colors: colors.map { $0.argb }, intensity: intensity, rotation: rotation))) } else if colors.count > 1 { - self = .gradient(TelegramWallpaper.Gradient(id: nil, colors: colors.map { $0.argb }, settings: WallpaperSettings(blur: blur, motion: motion, rotation: rotation))) + self.value = .gradient(TelegramWallpaper.Gradient(id: nil, colors: colors.map { $0.argb }, settings: WallpaperSettings(blur: blur, motion: motion, rotation: rotation))) } else { throw PresentationThemeDecodingError.generic } @@ -130,9 +136,9 @@ extension TelegramWallpaper: Codable { } } - public func encode(to encoder: Encoder) throws { + func encode(to encoder: Encoder) throws { var container = encoder.singleValueContainer() - switch self { + switch self.value { case .builtin: try container.encode("builtin") case let .color(color): @@ -155,7 +161,7 @@ extension TelegramWallpaper: Codable { case let .file(file): var components: [String] = [] components.append(file.slug) - if self.isPattern { + if self.value.isPattern { if file.settings.colors.count >= 1 { components.append(String(format: "%06x", file.settings.colors[0])) } @@ -1659,7 +1665,7 @@ extension PresentationThemeChat: Codable { public convenience init(from decoder: Decoder) throws { let values = try decoder.container(keyedBy: CodingKeys.self) - var wallpaper = try values.decode(TelegramWallpaper.self, forKey: .defaultWallpaper) + var wallpaper = (try values.decode(TelegramWallpaperStandardizedCodable.self, forKey: .defaultWallpaper)).value if let decoder = decoder as? PresentationThemeDecoding { if case .file = wallpaper, let resolvedWallpaper = decoder.resolvedWallpaper { wallpaper = resolvedWallpaper @@ -1678,7 +1684,7 @@ extension PresentationThemeChat: Codable { public func encode(to encoder: Encoder) throws { var values = encoder.container(keyedBy: CodingKeys.self) - try values.encode(self.defaultWallpaper, forKey: .defaultWallpaper) + try values.encode(TelegramWallpaperStandardizedCodable(self.defaultWallpaper), forKey: .defaultWallpaper) try values.encode(self.animateMessageColors, forKey: .animateMessageColors) try values.encode(self.message, forKey: .message) try values.encode(self.serviceMessage, forKey: .serviceMessage) diff --git a/submodules/TelegramUI/Sources/ChatMediaInputGifPane.swift b/submodules/TelegramUI/Sources/ChatMediaInputGifPane.swift index 00e647e07f..8b99eb83bd 100644 --- a/submodules/TelegramUI/Sources/ChatMediaInputGifPane.swift +++ b/submodules/TelegramUI/Sources/ChatMediaInputGifPane.swift @@ -300,7 +300,7 @@ final class ChatMediaInputGifPane: ChatMediaInputPane, UIScrollViewDelegate { if let recentGifs = recentGifs { saved = recentGifs.items.map { item in - let file = (item.contents as! RecentMediaItem).media as! TelegramMediaFile + let file = item.contents.get(RecentMediaItem.self)!.media return MultiplexedVideoNodeFile(file: .savedGif(media: file), contextResult: nil) } } else { diff --git a/submodules/TelegramUI/Sources/ChatMediaInputNode.swift b/submodules/TelegramUI/Sources/ChatMediaInputNode.swift index 4a2ad092b0..b07064aaf4 100644 --- a/submodules/TelegramUI/Sources/ChatMediaInputNode.swift +++ b/submodules/TelegramUI/Sources/ChatMediaInputNode.swift @@ -176,7 +176,7 @@ func chatMediaInputPanelEntries(view: ItemCollectionsView, savedStickers: Ordere var savedStickerIds = Set() if let savedStickers = savedStickers, !savedStickers.items.isEmpty { for i in 0 ..< savedStickers.items.count { - if let item = savedStickers.items[i].contents as? SavedStickerItem { + if let item = savedStickers.items[i].contents.get(SavedStickerItem.self) { savedStickerIds.insert(item.file.fileId.id) } } @@ -184,7 +184,7 @@ func chatMediaInputPanelEntries(view: ItemCollectionsView, savedStickers: Ordere if let recentStickers = recentStickers, !recentStickers.items.isEmpty { var found = false for item in recentStickers.items { - if let item = item.contents as? RecentMediaItem, let _ = item.media as? TelegramMediaFile, let mediaId = item.media.id { + if let item = item.contents.get(RecentMediaItem.self), let mediaId = item.media.id { if !savedStickerIds.contains(mediaId.id) { found = true break @@ -273,7 +273,7 @@ func chatMediaInputGridEntries(view: ItemCollectionsView, savedStickers: Ordered if let savedStickers = savedStickers, !savedStickers.items.isEmpty { let packInfo = StickerPackCollectionInfo(id: ItemCollectionId(namespace: ChatMediaInputPanelAuxiliaryNamespace.savedStickers.rawValue, id: 0), flags: [], accessHash: 0, title: strings.Stickers_FavoriteStickers.uppercased(), shortName: "", thumbnail: nil, immediateThumbnailData: nil, hash: 0, count: 0) for i in 0 ..< savedStickers.items.count { - if let item = savedStickers.items[i].contents as? SavedStickerItem { + if let item = savedStickers.items[i].contents.get(SavedStickerItem.self) { savedStickerIds.insert(item.file.fileId.id) let index = ItemCollectionItemIndex(index: Int32(i), id: item.file.fileId.id) let stickerItem = StickerPackItem(index: index, file: item.file, indexKeys: []) @@ -294,7 +294,9 @@ func chatMediaInputGridEntries(view: ItemCollectionsView, savedStickers: Ordered if addedCount >= 20 { break } - if let item = recentStickers.items[i].contents as? RecentMediaItem, let file = item.media as? TelegramMediaFile, let mediaId = item.media.id { + if let item = recentStickers.items[i].contents.get(RecentMediaItem.self), let mediaId = item.media.id { + let file = item.media + if !savedStickerIds.contains(mediaId.id) { let index = ItemCollectionItemIndex(index: Int32(i), id: mediaId.id) let stickerItem = StickerPackItem(index: index, file: file, indexKeys: []) diff --git a/submodules/TelegramUI/Sources/DeclareEncodables.swift b/submodules/TelegramUI/Sources/DeclareEncodables.swift index fb6a3a086f..e9ec2a4b80 100644 --- a/submodules/TelegramUI/Sources/DeclareEncodables.swift +++ b/submodules/TelegramUI/Sources/DeclareEncodables.swift @@ -19,9 +19,6 @@ private var telegramUIDeclaredEncodables: Void = { declareEncodable(LocalFileGifMediaResource.self, f: { LocalFileGifMediaResource(decoder: $0) }) declareEncodable(PhotoLibraryMediaResource.self, f: { PhotoLibraryMediaResource(decoder: $0) }) declareEncodable(ICloudFileResource.self, f: { ICloudFileResource(decoder: $0) }) - declareEncodable(RecentWebSearchQueryItem.self, f: { RecentWebSearchQueryItem(decoder: $0) }) - declareEncodable(RecentWallpaperSearchQueryItem.self, f: { RecentWallpaperSearchQueryItem(decoder: $0) }) - declareEncodable(RecentSettingsSearchQueryItem.self, f: { RecentSettingsSearchQueryItem(decoder: $0) }) return }() diff --git a/submodules/TelegramUIPreferences/Sources/PresentationThemeSettings.swift b/submodules/TelegramUIPreferences/Sources/PresentationThemeSettings.swift index 7800057498..f6501a0ef4 100644 --- a/submodules/TelegramUIPreferences/Sources/PresentationThemeSettings.swift +++ b/submodules/TelegramUIPreferences/Sources/PresentationThemeSettings.swift @@ -67,14 +67,14 @@ public struct PresentationLocalTheme: PostboxCoding, Equatable { public init(decoder: PostboxDecoder) { self.title = decoder.decodeStringForKey("title", orElse: "") self.resource = decoder.decodeObjectForKey("resource", decoder: { LocalFileMediaResource(decoder: $0) }) as! LocalFileMediaResource - self.resolvedWallpaper = decoder.decodeObjectForKey("wallpaper", decoder: { TelegramWallpaper(decoder: $0) }) as? TelegramWallpaper + self.resolvedWallpaper = decoder.decode(TelegramWallpaperNativeCodable.self, forKey: "wallpaper")?.value } public func encode(_ encoder: PostboxEncoder) { encoder.encodeString(self.title, forKey: "title") encoder.encodeObject(self.resource, forKey: "resource") if let resolvedWallpaper = self.resolvedWallpaper { - encoder.encodeObject(resolvedWallpaper, forKey: "wallpaper") + encoder.encode(TelegramWallpaperNativeCodable(resolvedWallpaper), forKey: "wallpaper") } else { encoder.encodeNil(forKey: "wallpaper") } @@ -106,15 +106,15 @@ public struct PresentationCloudTheme: PostboxCoding, Equatable { } public init(decoder: PostboxDecoder) { - self.theme = decoder.decodeObjectForKey("theme", decoder: { TelegramTheme(decoder: $0) }) as! TelegramTheme - self.resolvedWallpaper = decoder.decodeObjectForKey("wallpaper", decoder: { TelegramWallpaper(decoder: $0) }) as? TelegramWallpaper + self.theme = decoder.decode(TelegramThemeNativeCodable.self, forKey: "theme")!.value + self.resolvedWallpaper = decoder.decode(TelegramWallpaperNativeCodable.self, forKey: "wallpaper")?.value self.creatorAccountId = decoder.decodeOptionalInt64ForKey("account").flatMap { AccountRecordId(rawValue: $0) } } public func encode(_ encoder: PostboxEncoder) { - encoder.encodeObject(self.theme, forKey: "theme") + encoder.encode(TelegramThemeNativeCodable(self.theme), forKey: "theme") if let resolvedWallpaper = self.resolvedWallpaper { - encoder.encodeObject(resolvedWallpaper, forKey: "wallpaper") + encoder.encode(TelegramWallpaperNativeCodable(resolvedWallpaper), forKey: "wallpaper") } else { encoder.encodeNil(forKey: "wallpaper") } @@ -480,7 +480,7 @@ public struct PresentationThemeAccentColor: PostboxCoding, Equatable { } } - self.wallpaper = decoder.decodeObjectForKey("w", decoder: { TelegramWallpaper(decoder: $0) }) as? TelegramWallpaper + self.wallpaper = decoder.decode(TelegramWallpaperNativeCodable.self, forKey: "w")?.value self.themeIndex = decoder.decodeOptionalInt64ForKey("t") } @@ -494,7 +494,7 @@ public struct PresentationThemeAccentColor: PostboxCoding, Equatable { } encoder.encodeInt32Array(self.bubbleColors.map(Int32.init(bitPattern:)), forKey: "bubbleColors") if let wallpaper = self.wallpaper { - encoder.encodeObject(wallpaper, forKey: "w") + encoder.encode(TelegramWallpaperNativeCodable(wallpaper), forKey: "w") } else { encoder.encodeNil(forKey: "w") } @@ -649,11 +649,10 @@ public struct PresentationThemeSettings: Codable { self.theme = .builtin(.dayClassic) } - let themeSpecificChatWallpapersDict = try container.decode([DictionaryKey: AdaptedPostboxDecoder.RawObjectData].self, forKey: "themeSpecificChatWallpapers") + let themeSpecificChatWallpapersDict = try container.decode([DictionaryKey: TelegramWallpaperNativeCodable].self, forKey: "themeSpecificChatWallpapers") var mappedThemeSpecificChatWallpapers: [Int64: TelegramWallpaper] = [:] for (key, value) in themeSpecificChatWallpapersDict { - let innerDecoder = PostboxDecoder(buffer: MemoryBuffer(data: value.data)) - mappedThemeSpecificChatWallpapers[key.key] = TelegramWallpaper(decoder: innerDecoder) + mappedThemeSpecificChatWallpapers[key.key] = value.value } self.themeSpecificChatWallpapers = mappedThemeSpecificChatWallpapers @@ -689,9 +688,9 @@ public struct PresentationThemeSettings: Codable { } try container.encode(mappedThemeSpecificAccentColors, forKey: "themeSpecificAccentColors") - var mappedThemeSpecificChatWallpapers: [DictionaryKey: AdaptedPostboxEncoder.RawObjectData] = [:] + var mappedThemeSpecificChatWallpapers: [DictionaryKey: TelegramWallpaperNativeCodable] = [:] for (key, value) in self.themeSpecificChatWallpapers { - mappedThemeSpecificChatWallpapers[DictionaryKey(key)] = PostboxEncoder().encodeObjectToRawData(value) + mappedThemeSpecificChatWallpapers[DictionaryKey(key)] = TelegramWallpaperNativeCodable(value) } try container.encode(mappedThemeSpecificChatWallpapers, forKey: "themeSpecificChatWallpapers") diff --git a/submodules/WallpaperResources/Sources/WallpaperCache.swift b/submodules/WallpaperResources/Sources/WallpaperCache.swift index 97d4d182b5..29f42cdbe4 100644 --- a/submodules/WallpaperResources/Sources/WallpaperCache.swift +++ b/submodules/WallpaperResources/Sources/WallpaperCache.swift @@ -17,14 +17,13 @@ public final class CachedWallpaper: Codable { public init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: StringCodingKey.self) - let wallpaperData = try container.decode(AdaptedPostboxDecoder.RawObjectData.self, forKey: "wallpaper") - self.wallpaper = TelegramWallpaper(decoder: PostboxDecoder(buffer: MemoryBuffer(data: wallpaperData.data))) + self.wallpaper = (try container.decode(TelegramWallpaperNativeCodable.self, forKey: "wallpaper")).value } public func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: StringCodingKey.self) - try container.encode(PostboxEncoder().encodeObjectToRawData(self.wallpaper), forKey: "wallpaper") + try container.encode(TelegramWallpaperNativeCodable(self.wallpaper), forKey: "wallpaper") } } diff --git a/submodules/WatchBridge/Sources/WatchRequestHandlers.swift b/submodules/WatchBridge/Sources/WatchRequestHandlers.swift index dca4e0f729..923ac1176d 100644 --- a/submodules/WatchBridge/Sources/WatchRequestHandlers.swift +++ b/submodules/WatchBridge/Sources/WatchRequestHandlers.swift @@ -313,11 +313,11 @@ private func mediaForSticker(documentId: Int64, account: Account) -> Signal map { view -> TelegramMediaFile? in for view in view.orderedItemListsViews { for entry in view.items { - if let file = (entry.contents as? SavedStickerItem)?.file { + if let file = entry.contents.get(SavedStickerItem.self)?.file { if file.id?.id == documentId { return file } - } else if let file = (entry.contents as? RecentMediaItem)?.media as? TelegramMediaFile { + } else if let file = entry.contents.get(RecentMediaItem.self)?.media { if file.id?.id == documentId { return file } @@ -618,12 +618,12 @@ final class WatchStickersHandler: WatchRequestHandler { var added: Set = [] outer: for view in view.orderedItemListsViews { for entry in view.items { - if let file = (entry.contents as? SavedStickerItem)?.file { + if let file = entry.contents.get(SavedStickerItem.self)?.file { if let sticker = makeBridgeDocument(file), !added.contains(sticker.documentId) { stickers.append(sticker) added.insert(sticker.documentId) } - } else if let file = (entry.contents as? RecentMediaItem)?.media as? TelegramMediaFile { + } else if let file = entry.contents.get(RecentMediaItem.self)?.media { if let sticker = makeBridgeDocument(file), !added.contains(sticker.documentId) { stickers.append(sticker) added.insert(sticker.documentId) diff --git a/submodules/WebSearchUI/Sources/WebSearchRecentQueries.swift b/submodules/WebSearchUI/Sources/WebSearchRecentQueries.swift index bad36c2911..184f592585 100644 --- a/submodules/WebSearchUI/Sources/WebSearchRecentQueries.swift +++ b/submodules/WebSearchUI/Sources/WebSearchRecentQueries.swift @@ -24,21 +24,23 @@ private struct WebSearchRecentQueryItemId { } } -public final class RecentWebSearchQueryItem: OrderedItemListEntryContents { +public final class RecentWebSearchQueryItem: Codable { init() { } - public init(decoder: PostboxDecoder) { + public init(from decoder: Decoder) throws { } - public func encode(_ encoder: PostboxEncoder) { + public func encode(to encoder: Encoder) throws { } } func addRecentWebSearchQuery(postbox: Postbox, string: String) -> Signal { return postbox.transaction { transaction in if let itemId = WebSearchRecentQueryItemId(string) { - transaction.addOrMoveToFirstPositionOrderedItemListItem(collectionId: ApplicationSpecificOrderedItemListCollectionId.webSearchRecentQueries, item: OrderedItemListEntry(id: itemId.rawValue, contents: RecentWebSearchQueryItem()), removeTailIfCountExceeds: 100) + if let entry = CodableEntry(RecentWebSearchQueryItem()) { + transaction.addOrMoveToFirstPositionOrderedItemListItem(collectionId: ApplicationSpecificOrderedItemListCollectionId.webSearchRecentQueries, item: OrderedItemListEntry(id: itemId.rawValue, contents: entry), removeTailIfCountExceeds: 100) + } } } } From 6e5c503338d184edc8a2d2ae741d2536770a2dc8 Mon Sep 17 00:00:00 2001 From: Ali <> Date: Mon, 20 Sep 2021 14:51:46 +0300 Subject: [PATCH 12/30] Refactoring --- .../Sources/LiveLocationManager.swift | 9 +- submodules/AdUI/BUILD | 1 - submodules/AdUI/Sources/AdInfoScreen.swift | 1 - submodules/ArchivedStickerPacksNotice/BUILD | 1 - ...ArchivedStickerPacksNoticeController.swift | 5 +- .../Sources/CallListController.swift | 2 +- .../ChatListUI/Sources/ChatContextMenus.swift | 4 +- .../Sources/ChatListController.swift | 6 +- .../ChatListFilterPresetController.swift | 4 +- .../Sources/ChatListSearchContainerNode.swift | 12 +- .../Sources/ChatListSearchListPaneNode.swift | 10 +- .../Sources/Node/ChatListItem.swift | 24 +- .../Sources/Node/ChatListItemStrings.swift | 6 +- .../Sources/Node/ChatListNode.swift | 4 +- .../Sources/Node/ChatListTypingNode.swift | 8 +- submodules/ComposePollUI/BUILD | 1 - .../Sources/CreatePollController.swift | 47 +- .../Sources/ContactListNode.swift | 6 +- .../Sources/ContactsSearchContainerNode.swift | 4 +- .../InviteContactsControllerNode.swift | 2 +- submodules/ContactsPeerItem/BUILD | 1 - .../Sources/ContactsPeerItem.swift | 41 +- .../DeleteChatPeerActionSheetItem/BUILD | 1 - .../ChatItemGalleryFooterContentNode.swift | 30 +- .../GalleryUI/Sources/GalleryController.swift | 4 +- .../GalleryUI/Sources/GalleryTitleView.swift | 3 +- .../SecretMediaPreviewController.swift | 2 +- submodules/GameUI/BUILD | 1 - .../GameUI/Sources/GameController.swift | 9 +- .../GameUI/Sources/GameControllerNode.swift | 11 +- .../Sources/GameControllerTitleView.swift | 1 - submodules/GraphUI/BUILD | 1 - .../Sources/HashtagSearchControllerNode.swift | 2 +- .../InstantPagePeerReferenceNode.swift | 2 +- .../Sources/InviteLinkListController.swift | 6 +- .../Sources/InviteLinkViewController.swift | 4 +- .../ItemListAvatarAndNameInfoItem/BUILD | 1 - .../Sources/ItemListAvatarAndNameItem.swift | 34 +- submodules/ItemListPeerItem/BUILD | 1 - .../Sources/ItemListPeerItem.swift | 29 +- submodules/LanguageLinkPreviewUI/BUILD | 1 - .../LanguageLinkPreviewContentNode.swift | 3 +- .../LanguageLinkPreviewController.swift | 1 - .../LanguageLinkPreviewControllerNode.swift | 1 - .../Sources/LegacyAttachmentMenu.swift | 8 +- .../Sources/LegacyMediaPickers.swift | 4 +- .../Sources/ListMessageFileItemNode.swift | 12 +- .../Sources/ListMessageSnippetItemNode.swift | 2 +- submodules/LiveLocationManager/BUILD | 1 - .../Sources/LiveLocationManager.swift | 95 ++-- .../Sources/LiveLocationSummaryManager.swift | 65 ++- submodules/LiveLocationPositionNode/BUILD | 1 - submodules/LocalizedPeerData/BUILD | 1 - .../LocalizedPeerData/Sources/PeerTitle.swift | 31 +- .../Sources/LocationLiveListItem.swift | 2 +- .../Sources/LocationPickerController.swift | 2 +- .../Sources/LocationViewController.swift | 6 +- .../Sources/LocationViewControllerNode.swift | 2 +- .../NotificationMuteSettingsController.swift | 1 - .../Sources/NotificationSoundSelection.swift | 1 - .../Sources/SecureIdAuthFormContentNode.swift | 4 +- .../Sources/SecureIdAuthHeaderNode.swift | 2 +- .../AvatarGalleryItemFooterContentNode.swift | 2 +- .../Sources/ChannelAdminController.swift | 14 +- .../Sources/ChannelAdminsController.swift | 6 +- .../ChannelBannedMemberController.swift | 8 +- .../Sources/ChannelBlacklistController.swift | 8 +- ...hannelDiscussionGroupActionSheetItem.swift | 4 +- ...elDiscussionGroupSearchContainerNode.swift | 2 +- ...hannelDiscussionGroupSetupController.swift | 8 +- .../Sources/ChannelInfoController.swift | 10 +- .../Sources/ChannelMembersController.swift | 2 +- .../ChannelMembersSearchContainerNode.swift | 14 +- .../ChannelMembersSearchControllerNode.swift | 8 +- .../ChannelOwnershipTransferController.swift | 4 +- .../ChannelPermissionsController.swift | 2 +- .../Sources/ChannelVisibilityController.swift | 2 +- .../Sources/DeviceContactInfoController.swift | 4 +- .../Sources/OldChannelsController.swift | 2 +- .../Sources/OldChannelsSearch.swift | 2 +- .../Sources/SecretChatKeyControllerNode.swift | 2 +- .../Sources/UserInfoController.swift | 2 +- submodules/PeerPresenceStatusManager/BUILD | 1 - .../Sources/PeerPresenceStatusManager.swift | 6 +- .../Sources/PeersNearbyController.swift | 6 +- submodules/SettingsUI/BUILD | 1 - .../DataAndStorageSettingsController.swift | 26 +- .../IntentsSettingsController.swift | 2 +- .../StorageUsageController.swift | 2 +- .../NotificationExceptionControllerNode.swift | 10 +- ...ificationExceptionSettingsController.swift | 2 +- .../BlockedPeersController.swift | 2 +- .../Recent Sessions/ItemListWebsiteItem.swift | 2 +- .../SelectivePrivacySettingsController.swift | 3 +- ...ectivePrivacySettingsPeersController.swift | 2 +- .../TabBarAccountSwitchControllerNode.swift | 2 +- .../Sources/ShareContentContainerNode.swift | 3 +- .../Sources/ShareController.swift | 6 +- .../Sources/ShareControllerPeerGridItem.swift | 2 +- .../Sources/SharePeersContainerNode.swift | 2 +- .../Sources/GroupStatsController.swift | 6 +- .../Sources/MessageStatsController.swift | 2 +- ...ionBroadcastNavigationAccessoryPanel.swift | 9 +- .../MediaNavigationAccessoryHeaderNode.swift | 8 +- .../Sources/TelegramBaseController.swift | 32 +- .../Sources/CallControllerNode.swift | 14 +- .../Sources/CallStatusBarNode.swift | 4 +- .../Sources/LegacyCallControllerNode.swift | 6 +- .../Sources/PresentationGroupCall.swift | 2 +- .../Sources/VoiceChatController.swift | 52 +- .../Sources/VoiceChatJoinScreen.swift | 2 +- .../Sources/VoiceChatMainStageNode.swift | 4 +- .../Sources/Account/AccountManager.swift | 1 - .../TelegramEngine/Data/Messages.swift | 55 +++ .../Messages/TelegramEngineMessages.swift | 34 ++ .../Sources/TelegramIntents.swift | 4 +- .../TelegramNotices/Sources/Notices.swift | 10 +- .../Sources/PeerDisplayName.swift | 7 +- .../Sources/PresenceStrings.swift | 6 +- .../Sources/ServiceMessageStrings.swift | 16 +- .../TelegramUI/Sources/AccountContext.swift | 16 +- .../TelegramUI/Sources/AppDelegate.swift | 2 +- .../TelegramUI/Sources/ChatController.swift | 82 ++-- .../TelegramUI/Sources/ChatEmptyNode.swift | 4 +- .../ChatMediaInputPeerSpecificItem.swift | 2 +- .../ChatMessageActionUrlAuthController.swift | 2 +- .../ChatMessageAnimatedStickerItemNode.swift | 6 +- .../Sources/ChatMessageBubbleItemNode.swift | 8 +- .../Sources/ChatMessageForwardInfoNode.swift | 4 +- .../ChatMessageInstantVideoItemNode.swift | 6 +- .../Sources/ChatMessageItemView.swift | 10 +- .../Sources/ChatMessageNotificationItem.swift | 52 +- .../Sources/ChatMessageReplyInfoNode.swift | 4 +- .../Sources/ChatMessageStickerItemNode.swift | 6 +- .../Sources/ChatOverlayNavigationBar.swift | 2 +- .../ChatPinnedMessageTitlePanelNode.swift | 2 +- .../ChatRecentActionsFilterController.swift | 2 +- .../ChatRecentActionsHistoryTransition.swift | 102 ++-- .../ChatReportPeerTitlePanelNode.swift | 8 +- .../ChatSearchNavigationContentNode.swift | 2 +- .../TelegramUI/Sources/ChatTextFormat.swift | 5 +- .../TelegramUI/Sources/ChatTitleView.swift | 8 +- .../ContactMultiselectionController.swift | 2 +- .../Sources/CreateChannelController.swift | 2 +- .../Sources/CreateGroupController.swift | 4 +- .../Sources/ForwardAccessoryPanelNode.swift | 4 +- .../TelegramUI/Sources/LegacyCamera.swift | 2 +- .../OverlayAudioPlayerController.swift | 8 +- .../ListItems/PeerInfoScreenMemberItem.swift | 2 +- .../PeerInfoGroupsInCommonPaneNode.swift | 2 +- .../PeerInfo/Panes/PeerInfoMembersPane.swift | 2 +- .../Sources/PeerInfo/PeerInfoData.swift | 4 +- .../Sources/PeerInfo/PeerInfoHeaderNode.swift | 2 +- .../Sources/PeerInfo/PeerInfoScreen.swift | 74 +-- .../Sources/PollResultsController.swift | 2 +- .../Sources/ReplyAccessoryPanelNode.swift | 6 +- ...retChatHandshakeStatusInputPanelNode.swift | 2 +- .../Sources/ShareExtensionContext.swift | 8 +- .../Sources/SharedNotificationManager.swift | 2 +- .../StringForMessageTimestampStatus.swift | 2 +- .../Sources/LegacyWebSearchGallery.swift | 2 +- .../Sources/WebSearchGalleryController.swift | 2 +- submodules/WidgetSetupScreen/BUILD | 27 -- .../Sources/WidgetSetupScreen.swift | 451 ------------------ 164 files changed, 786 insertions(+), 1208 deletions(-) create mode 100644 submodules/TelegramCore/Sources/TelegramEngine/Data/Messages.swift delete mode 100644 submodules/WidgetSetupScreen/BUILD delete mode 100644 submodules/WidgetSetupScreen/Sources/WidgetSetupScreen.swift diff --git a/submodules/AccountContext/Sources/LiveLocationManager.swift b/submodules/AccountContext/Sources/LiveLocationManager.swift index e43ba071f0..6224e1a410 100644 --- a/submodules/AccountContext/Sources/LiveLocationManager.swift +++ b/submodules/AccountContext/Sources/LiveLocationManager.swift @@ -1,18 +1,17 @@ import Foundation import TelegramCore -import Postbox import SwiftSignalKit public protocol LiveLocationSummaryManager { - func broadcastingToMessages() -> Signal<[MessageId: Message], NoError> - func peersBroadcastingTo(peerId: PeerId) -> Signal<[(Peer, Message)]?, NoError> + func broadcastingToMessages() -> Signal<[EngineMessage.Id: EngineMessage], NoError> + func peersBroadcastingTo(peerId: EnginePeer.Id) -> Signal<[(EnginePeer, EngineMessage)]?, NoError> } public protocol LiveLocationManager { var summaryManager: LiveLocationSummaryManager { get } var isPolling: Signal { get } - func cancelLiveLocation(peerId: PeerId) + func cancelLiveLocation(peerId: EnginePeer.Id) func pollOnce() - func internalMessageForPeerId(_ peerId: PeerId) -> MessageId? + func internalMessageForPeerId(_ peerId: EnginePeer.Id) -> EngineMessage.Id? } diff --git a/submodules/AdUI/BUILD b/submodules/AdUI/BUILD index c9ec77d57d..3b30811950 100644 --- a/submodules/AdUI/BUILD +++ b/submodules/AdUI/BUILD @@ -13,7 +13,6 @@ swift_library( "//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit", "//submodules/AsyncDisplayKit:AsyncDisplayKit", "//submodules/Display:Display", - "//submodules/Postbox:Postbox", "//submodules/TelegramCore:TelegramCore", "//submodules/TelegramPresentationData:TelegramPresentationData", "//submodules/TelegramUIPreferences:TelegramUIPreferences", diff --git a/submodules/AdUI/Sources/AdInfoScreen.swift b/submodules/AdUI/Sources/AdInfoScreen.swift index c951e7d705..03a57eed51 100644 --- a/submodules/AdUI/Sources/AdInfoScreen.swift +++ b/submodules/AdUI/Sources/AdInfoScreen.swift @@ -3,7 +3,6 @@ import UIKit import Display import AsyncDisplayKit import SwiftSignalKit -import Postbox import TelegramCore import TelegramPresentationData import TelegramUIPreferences diff --git a/submodules/ArchivedStickerPacksNotice/BUILD b/submodules/ArchivedStickerPacksNotice/BUILD index cf24e9bda3..c9898e569d 100644 --- a/submodules/ArchivedStickerPacksNotice/BUILD +++ b/submodules/ArchivedStickerPacksNotice/BUILD @@ -13,7 +13,6 @@ swift_library( "//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit", "//submodules/AsyncDisplayKit:AsyncDisplayKit", "//submodules/Display:Display", - "//submodules/Postbox:Postbox", "//submodules/TelegramCore:TelegramCore", "//submodules/TelegramPresentationData:TelegramPresentationData", "//submodules/AccountContext:AccountContext", diff --git a/submodules/ArchivedStickerPacksNotice/Sources/ArchivedStickerPacksNoticeController.swift b/submodules/ArchivedStickerPacksNotice/Sources/ArchivedStickerPacksNoticeController.swift index 13a56523d3..4a272a62ee 100644 --- a/submodules/ArchivedStickerPacksNotice/Sources/ArchivedStickerPacksNoticeController.swift +++ b/submodules/ArchivedStickerPacksNotice/Sources/ArchivedStickerPacksNoticeController.swift @@ -3,7 +3,6 @@ import UIKit import AsyncDisplayKit import Display import SwiftSignalKit -import Postbox import TelegramCore import TelegramPresentationData import ActivityIndicator @@ -20,8 +19,8 @@ private struct ArchivedStickersNoticeEntry: Comparable, Identifiable { let topItem: StickerPackItem? let count: String - var stableId: ItemCollectionId { - return info.id + var stableId: AnyHashable { + return AnyHashable(self.info.id) } static func ==(lhs: ArchivedStickersNoticeEntry, rhs: ArchivedStickersNoticeEntry) -> Bool { diff --git a/submodules/CallListUI/Sources/CallListController.swift b/submodules/CallListUI/Sources/CallListController.swift index c7a01533bd..2c18b5e7ea 100644 --- a/submodules/CallListUI/Sources/CallListController.swift +++ b/submodules/CallListUI/Sources/CallListController.swift @@ -448,7 +448,7 @@ public final class CallListController: TelegramBaseController { if let cachedUserData = view.cachedData as? CachedUserData, cachedUserData.callsPrivate { let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 } - strongSelf.present(textAlertController(context: strongSelf.context, title: presentationData.strings.Call_ConnectionErrorTitle, text: presentationData.strings.Call_PrivacyErrorMessage(peer.compactDisplayTitle).string, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), in: .window(.root)) + strongSelf.present(textAlertController(context: strongSelf.context, title: presentationData.strings.Call_ConnectionErrorTitle, text: presentationData.strings.Call_PrivacyErrorMessage(EnginePeer(peer).compactDisplayTitle).string, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), in: .window(.root)) return } diff --git a/submodules/ChatListUI/Sources/ChatContextMenus.swift b/submodules/ChatListUI/Sources/ChatContextMenus.swift index fcfb5ffe9c..a5ebb5cc32 100644 --- a/submodules/ChatListUI/Sources/ChatContextMenus.swift +++ b/submodules/ChatListUI/Sources/ChatContextMenus.swift @@ -167,7 +167,7 @@ func chatContextMenuItems(context: AccountContext, peerId: PeerId, promoInfo: Ch } |> deliverOnMainQueue).start(completed: { c.dismiss(completion: { - chatListController?.present(UndoOverlayController(presentationData: presentationData, content: .chatRemovedFromFolder(chatTitle: peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), folderTitle: currentFilter.title), elevatedLayout: false, animateInAsReplacement: true, action: { _ in + chatListController?.present(UndoOverlayController(presentationData: presentationData, content: .chatRemovedFromFolder(chatTitle: EnginePeer(peer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), folderTitle: currentFilter.title), elevatedLayout: false, animateInAsReplacement: true, action: { _ in return false }), in: .current) }) @@ -239,7 +239,7 @@ func chatContextMenuItems(context: AccountContext, peerId: PeerId, promoInfo: Ch return filters }).start() - chatListController?.present(UndoOverlayController(presentationData: presentationData, content: .chatAddedToFolder(chatTitle: peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), folderTitle: filter.title), elevatedLayout: false, animateInAsReplacement: true, action: { _ in + chatListController?.present(UndoOverlayController(presentationData: presentationData, content: .chatAddedToFolder(chatTitle: EnginePeer(peer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), folderTitle: filter.title), elevatedLayout: false, animateInAsReplacement: true, action: { _ in return false }), in: .current) }) diff --git a/submodules/ChatListUI/Sources/ChatListController.swift b/submodules/ChatListUI/Sources/ChatListController.swift index 980ad4debf..fdb3d251ab 100644 --- a/submodules/ChatListUI/Sources/ChatListController.swift +++ b/submodules/ChatListUI/Sources/ChatListController.swift @@ -2338,7 +2338,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController beginClear(.forLocalPeer) actionSheet?.dismissAnimated() })) - items.append(ActionSheetButtonItem(title: strongSelf.presentationData.strings.ChatList_DeleteForEveryone(mainPeer.compactDisplayTitle).string, color: .destructive, action: { [weak actionSheet] in + items.append(ActionSheetButtonItem(title: strongSelf.presentationData.strings.ChatList_DeleteForEveryone(EnginePeer(mainPeer).compactDisplayTitle).string, color: .destructive, action: { [weak actionSheet] in beginClear(.forEveryone) actionSheet?.dismissAnimated() })) @@ -2367,7 +2367,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController } if chatPeer is TelegramSecretChat { - items.append(ActionSheetButtonItem(title: strongSelf.presentationData.strings.ChatList_DeleteForEveryone(mainPeer.compactDisplayTitle).string, color: .destructive, action: { [weak actionSheet] in + items.append(ActionSheetButtonItem(title: strongSelf.presentationData.strings.ChatList_DeleteForEveryone(EnginePeer(mainPeer).compactDisplayTitle).string, color: .destructive, action: { [weak actionSheet] in actionSheet?.dismissAnimated() guard let strongSelf = self else { return @@ -2509,7 +2509,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController }) completion(true) })) - items.append(ActionSheetButtonItem(title: self.presentationData.strings.ChatList_DeleteForEveryone(mainPeer.compactDisplayTitle).string, color: .destructive, action: { [weak self, weak actionSheet] in + items.append(ActionSheetButtonItem(title: self.presentationData.strings.ChatList_DeleteForEveryone(EnginePeer(mainPeer).compactDisplayTitle).string, color: .destructive, action: { [weak self, weak actionSheet] in actionSheet?.dismissAnimated() guard let strongSelf = self else { return diff --git a/submodules/ChatListUI/Sources/ChatListFilterPresetController.swift b/submodules/ChatListUI/Sources/ChatListFilterPresetController.swift index 6810b3f778..a5d4d91775 100644 --- a/submodules/ChatListUI/Sources/ChatListFilterPresetController.swift +++ b/submodules/ChatListUI/Sources/ChatListFilterPresetController.swift @@ -389,7 +389,7 @@ private enum ChatListFilterPresetEntry: ItemListNodeEntry { } ) case let .includePeer(_, peer, isRevealed): - return ItemListPeerItem(presentationData: presentationData, dateTimeFormat: PresentationDateTimeFormat(), nameDisplayOrder: .firstLast, context: arguments.context, peer: peer.chatMainPeer!, height: .peerList, aliasHandling: .threatSelfAsSaved, presence: nil, text: .none, label: .none, editing: ItemListPeerItemEditing(editable: true, editing: false, revealed: isRevealed), revealOptions: ItemListPeerItemRevealOptions(options: [ItemListPeerItemRevealOption(type: .destructive, title: presentationData.strings.Common_Delete, action: { + return ItemListPeerItem(presentationData: presentationData, dateTimeFormat: PresentationDateTimeFormat(), nameDisplayOrder: .firstLast, context: arguments.context, peer: EnginePeer(peer.chatMainPeer!), height: .peerList, aliasHandling: .threatSelfAsSaved, presence: nil, text: .none, label: .none, editing: ItemListPeerItemEditing(editable: true, editing: false, revealed: isRevealed), revealOptions: ItemListPeerItemRevealOptions(options: [ItemListPeerItemRevealOption(type: .destructive, title: presentationData.strings.Common_Delete, action: { arguments.deleteIncludePeer(peer.peerId) })]), switchValue: nil, enabled: true, selectable: false, sectionId: self.section, action: nil, setPeerIdWithRevealedOptions: { lhs, rhs in arguments.setItemIdWithRevealedOptions(lhs.flatMap { .peer($0) }, rhs.flatMap { .peer($0) }) @@ -397,7 +397,7 @@ private enum ChatListFilterPresetEntry: ItemListNodeEntry { arguments.deleteIncludePeer(id) }) case let .excludePeer(_, peer, isRevealed): - return ItemListPeerItem(presentationData: presentationData, dateTimeFormat: PresentationDateTimeFormat(), nameDisplayOrder: .firstLast, context: arguments.context, peer: peer.chatMainPeer!, height: .peerList, aliasHandling: .threatSelfAsSaved, presence: nil, text: .none, label: .none, editing: ItemListPeerItemEditing(editable: true, editing: false, revealed: isRevealed), revealOptions: ItemListPeerItemRevealOptions(options: [ItemListPeerItemRevealOption(type: .destructive, title: presentationData.strings.Common_Delete, action: { + return ItemListPeerItem(presentationData: presentationData, dateTimeFormat: PresentationDateTimeFormat(), nameDisplayOrder: .firstLast, context: arguments.context, peer: EnginePeer(peer.chatMainPeer!), height: .peerList, aliasHandling: .threatSelfAsSaved, presence: nil, text: .none, label: .none, editing: ItemListPeerItemEditing(editable: true, editing: false, revealed: isRevealed), revealOptions: ItemListPeerItemRevealOptions(options: [ItemListPeerItemRevealOption(type: .destructive, title: presentationData.strings.Common_Delete, action: { arguments.deleteExcludePeer(peer.peerId) })]), switchValue: nil, enabled: true, selectable: false, sectionId: self.section, action: nil, setPeerIdWithRevealedOptions: { lhs, rhs in arguments.setItemIdWithRevealedOptions(lhs.flatMap { .peer($0) }, rhs.flatMap { .peer($0) }) diff --git a/submodules/ChatListUI/Sources/ChatListSearchContainerNode.swift b/submodules/ChatListUI/Sources/ChatListSearchContainerNode.swift index ff32dc6c29..653800451a 100644 --- a/submodules/ChatListUI/Sources/ChatListSearchContainerNode.swift +++ b/submodules/ChatListUI/Sources/ChatListSearchContainerNode.swift @@ -362,8 +362,8 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo isGroup = false } - var title: String = peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) - var compactDisplayTitle = peer.compactDisplayTitle + var title: String = EnginePeer(peer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) + var compactDisplayTitle = EnginePeer(peer).compactDisplayTitle if peer.id == accountPeer?.id { title = presentationData.strings.DialogList_SavedMessages compactDisplayTitle = title @@ -962,14 +962,14 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo savedMessages = true } else { if displayPeers.count == 1, let peer = displayPeers.first { - let peerName = peer.id == strongSelf.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) + let peerName = peer.id == strongSelf.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : EnginePeer(peer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) text = messages.count == 1 ? presentationData.strings.Conversation_ForwardTooltip_Chat_One(peerName).string : presentationData.strings.Conversation_ForwardTooltip_Chat_Many(peerName).string } else if displayPeers.count == 2, let firstPeer = displayPeers.first, let secondPeer = displayPeers.last { - let firstPeerName = firstPeer.id == strongSelf.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : firstPeer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) - let secondPeerName = secondPeer.id == strongSelf.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : secondPeer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) + let firstPeerName = firstPeer.id == strongSelf.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : EnginePeer(firstPeer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) + let secondPeerName = secondPeer.id == strongSelf.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : EnginePeer(secondPeer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) text = messages.count == 1 ? presentationData.strings.Conversation_ForwardTooltip_TwoChats_One(firstPeerName, secondPeerName).string : presentationData.strings.Conversation_ForwardTooltip_TwoChats_Many(firstPeerName, secondPeerName).string } else if let peer = displayPeers.first { - let peerName = peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) + let peerName = EnginePeer(peer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) text = messages.count == 1 ? presentationData.strings.Conversation_ForwardTooltip_ManyChats_One(peerName, "\(displayPeers.count - 1)").string : presentationData.strings.Conversation_ForwardTooltip_ManyChats_Many(peerName, "\(displayPeers.count - 1)").string } else { text = "" diff --git a/submodules/ChatListUI/Sources/ChatListSearchListPaneNode.swift b/submodules/ChatListUI/Sources/ChatListSearchListPaneNode.swift index 1427f05a6f..da2a79ab18 100644 --- a/submodules/ChatListUI/Sources/ChatListSearchListPaneNode.swift +++ b/submodules/ChatListUI/Sources/ChatListSearchListPaneNode.swift @@ -161,7 +161,7 @@ private enum ChatListRecentEntry: Comparable, Identifiable { status = .custom(string: strings.Bot_GenericBotStatus, multiline: false) } else if user.id != context.account.peerId && !servicePeer { let presence = peer.presence ?? TelegramUserPresence(status: .none, lastActivity: 0) - status = .presence(presence, timeFormat) + status = .presence(EnginePeer.Presence(presence), timeFormat) } else { status = .none } @@ -194,7 +194,7 @@ private enum ChatListRecentEntry: Comparable, Identifiable { badge = ContactsPeerItemBadge(count: peer.unreadCount, type: isMuted ? .inactive : .active) } - return ContactsPeerItem(presentationData: ItemListPresentationData(theme: presentationData.theme, fontSize: presentationData.fontSize, strings: presentationData.strings), sortOrder: nameSortOrder, displayOrder: nameDisplayOrder, context: context, peerMode: .generalSearch, peer: .peer(peer: primaryPeer, chatPeer: chatPeer), status: status, badge: badge, enabled: enabled, selection: .none, editing: ContactsPeerItemEditing(editable: false, editing: false, revealed: false), index: nil, header: ChatListSearchItemHeader(type: .recentPeers, theme: theme, strings: strings, actionTitle: strings.WebSearch_RecentSectionClear, action: { + return ContactsPeerItem(presentationData: ItemListPresentationData(theme: presentationData.theme, fontSize: presentationData.fontSize, strings: presentationData.strings), sortOrder: nameSortOrder, displayOrder: nameDisplayOrder, context: context, peerMode: .generalSearch, peer: .peer(peer: EnginePeer(primaryPeer), chatPeer: chatPeer.flatMap(EnginePeer.init)), status: status, badge: badge, enabled: enabled, selection: .none, editing: ContactsPeerItemEditing(editable: false, editing: false, revealed: false), index: nil, header: ChatListSearchItemHeader(type: .recentPeers, theme: theme, strings: strings, actionTitle: strings.WebSearch_RecentSectionClear, action: { clearRecentlySearchedPeers() }), action: { _ in if let chatPeer = peer.peer.peers[peer.peer.peerId] { @@ -441,9 +441,9 @@ public enum ChatListSearchEntry: Comparable, Identifiable { }) } - return ContactsPeerItem(presentationData: ItemListPresentationData(presentationData), sortOrder: nameSortOrder, displayOrder: nameDisplayOrder, context: context, peerMode: .generalSearch, peer: .peer(peer: primaryPeer, chatPeer: chatPeer), status: .none, badge: badge, enabled: enabled, selection: .none, editing: ContactsPeerItemEditing(editable: false, editing: false, revealed: false), index: nil, header: header, action: { contactPeer in + return ContactsPeerItem(presentationData: ItemListPresentationData(presentationData), sortOrder: nameSortOrder, displayOrder: nameDisplayOrder, context: context, peerMode: .generalSearch, peer: .peer(peer: EnginePeer(primaryPeer), chatPeer: chatPeer.flatMap(EnginePeer.init)), status: .none, badge: badge, enabled: enabled, selection: .none, editing: ContactsPeerItemEditing(editable: false, editing: false, revealed: false), index: nil, header: header, action: { contactPeer in if case let .peer(maybePeer, maybeChatPeer) = contactPeer, let peer = maybePeer, let chatPeer = maybeChatPeer { - interaction.peerSelected(chatPeer, peer, nil) + interaction.peerSelected(chatPeer._asPeer(), peer._asPeer(), nil) } else { interaction.peerSelected(peer, nil, nil) } @@ -508,7 +508,7 @@ public enum ChatListSearchEntry: Comparable, Identifiable { }) } - return ContactsPeerItem(presentationData: ItemListPresentationData(presentationData), sortOrder: nameSortOrder, displayOrder: nameDisplayOrder, context: context, peerMode: .generalSearch, peer: .peer(peer: peer.peer, chatPeer: peer.peer), status: .addressName(suffixString), badge: badge, enabled: enabled, selection: .none, editing: ContactsPeerItemEditing(editable: false, editing: false, revealed: false), index: nil, header: header, action: { _ in + return ContactsPeerItem(presentationData: ItemListPresentationData(presentationData), sortOrder: nameSortOrder, displayOrder: nameDisplayOrder, context: context, peerMode: .generalSearch, peer: .peer(peer: EnginePeer(peer.peer), chatPeer: EnginePeer(peer.peer)), status: .addressName(suffixString), badge: badge, enabled: enabled, selection: .none, editing: ContactsPeerItemEditing(editable: false, editing: false, revealed: false), index: nil, header: header, action: { _ in interaction.peerSelected(peer.peer, nil, nil) }, contextAction: peerContextAction.flatMap { peerContextAction in return { node, gesture in diff --git a/submodules/ChatListUI/Sources/Node/ChatListItem.swift b/submodules/ChatListUI/Sources/Node/ChatListItem.swift index 1fb071c560..b761a7d3f5 100644 --- a/submodules/ChatListUI/Sources/Node/ChatListItem.swift +++ b/submodules/ChatListUI/Sources/Node/ChatListItem.swift @@ -492,7 +492,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode { if item.context.account.peerId == chatMainPeer.id { result += item.presentationData.strings.DialogList_SavedMessages } else { - result += chatMainPeer.displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder) + result += EnginePeer(chatMainPeer).displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder) } if let combinedReadState = combinedReadState, combinedReadState.count > 0 { result += "\n\(item.presentationData.strings.VoiceOver_Chat_UnreadMessages(combinedReadState.count))" @@ -520,7 +520,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode { } let (_, initialHideAuthor, messageText) = chatListItemStrings(strings: item.presentationData.strings, nameDisplayOrder: item.presentationData.nameDisplayOrder, dateTimeFormat: item.presentationData.dateTimeFormat, messages: messages, chatPeer: peer, accountPeerId: item.context.account.peerId, isPeerGroup: false) if message.flags.contains(.Incoming), !initialHideAuthor, let author = message.author, author is TelegramUser { - result += "\n\(item.presentationData.strings.VoiceOver_ChatList_MessageFrom(author.displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder)).string)" + result += "\n\(item.presentationData.strings.VoiceOver_ChatList_MessageFrom(EnginePeer(author).displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder)).string)" } result += "\n\(messageText)" return result @@ -529,7 +529,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode { var isFirst = true for peer in peers { if let chatMainPeer = peer.peer.chatMainPeer { - let peerTitle = chatMainPeer.compactDisplayTitle + let peerTitle = EnginePeer(chatMainPeer).compactDisplayTitle if !peerTitle.isEmpty { if isFirst { isFirst = false @@ -554,7 +554,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode { } let (_, initialHideAuthor, messageText) = chatListItemStrings(strings: item.presentationData.strings, nameDisplayOrder: item.presentationData.nameDisplayOrder, dateTimeFormat: item.presentationData.dateTimeFormat, messages: messages, chatPeer: peer, accountPeerId: item.context.account.peerId, isPeerGroup: false) if message.flags.contains(.Incoming), !initialHideAuthor, let author = message.author, author is TelegramUser { - result += "\n\(item.presentationData.strings.VoiceOver_ChatList_MessageFrom(author.displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder)).string)" + result += "\n\(item.presentationData.strings.VoiceOver_ChatList_MessageFrom(EnginePeer(author).displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder)).string)" } if !message.flags.contains(.Incoming), let combinedReadState = combinedReadState, combinedReadState.isOutgoingMessageIndexRead(message.index) { result += "\n\(item.presentationData.strings.VoiceOver_ChatList_MessageRead)" @@ -981,7 +981,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode { if author.id == item.context.account.peerId { inlineAuthorPrefix = item.presentationData.strings.DialogList_You } else if messages.last?.id.peerId.namespace != Namespaces.Peer.CloudUser && messages.last?.id.peerId.namespace != Namespaces.Peer.SecretChat { - inlineAuthorPrefix = author.compactDisplayTitle + inlineAuthorPrefix = EnginePeer(author).compactDisplayTitle } } } @@ -1000,7 +1000,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode { var peerText: String? if case .groupReference = item.content { if let messagePeer = itemPeer.chatMainPeer { - peerText = messagePeer.displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder) + peerText = EnginePeer(messagePeer).displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder) } } else if let message = messages.last, let author = message.author as? TelegramUser, let peer = itemPeer.chatMainPeer, !(peer is TelegramUser) { if let peer = peer as? TelegramChannel, case .broadcast = peer.info { @@ -1008,7 +1008,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode { if let forwardInfo = message.forwardInfo, forwardInfo.flags.contains(.isImported), let authorSignature = forwardInfo.authorSignature { peerText = authorSignature } else { - peerText = author.id == account.peerId ? item.presentationData.strings.DialogList_You : author.displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder) + peerText = author.id == account.peerId ? item.presentationData.strings.DialogList_You : EnginePeer(author).displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder) } } } @@ -1137,7 +1137,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode { var peerText: String? if case .groupReference = item.content { if let messagePeer = itemPeer.chatMainPeer { - peerText = messagePeer.displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder) + peerText = EnginePeer(messagePeer).displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder) } } @@ -1150,7 +1150,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode { var isFirst = true for peer in peers { if let chatMainPeer = peer.peer.chatMainPeer { - let peerTitle = chatMainPeer.compactDisplayTitle + let peerTitle = EnginePeer(chatMainPeer).compactDisplayTitle if !peerTitle.isEmpty { if isFirst { isFirst = false @@ -1177,14 +1177,14 @@ class ChatListItemNode: ItemListRevealOptionsItemNode { switch contentData { case let .chat(itemPeer, _, _, _): if let message = messages.last, let author = message.author as? TelegramUser, displayAsMessage { - titleAttributedString = NSAttributedString(string: author.id == account.peerId ? item.presentationData.strings.DialogList_You : author.displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder), font: titleFont, textColor: theme.titleColor) + titleAttributedString = NSAttributedString(string: author.id == account.peerId ? item.presentationData.strings.DialogList_You : EnginePeer(author).displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder), font: titleFont, textColor: theme.titleColor) } else if isPeerGroup { titleAttributedString = NSAttributedString(string: item.presentationData.strings.ChatList_ArchivedChatsTitle, font: titleFont, textColor: theme.titleColor) } else if itemPeer.chatMainPeer?.id == item.context.account.peerId { titleAttributedString = NSAttributedString(string: item.presentationData.strings.DialogList_SavedMessages, font: titleFont, textColor: theme.titleColor) } else if let id = itemPeer.chatMainPeer?.id, id.isReplies { titleAttributedString = NSAttributedString(string: item.presentationData.strings.DialogList_Replies, font: titleFont, textColor: theme.titleColor) - } else if let displayTitle = itemPeer.chatMainPeer?.displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder) { + } else if let displayTitle = itemPeer.chatMainPeer.flatMap(EnginePeer.init)?.displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder) { titleAttributedString = NSAttributedString(string: displayTitle, font: titleFont, textColor: item.index.messageIndex.id.peerId.namespace == Namespaces.Peer.SecretChat ? theme.secretTitleColor : theme.titleColor) } case .group: @@ -1865,7 +1865,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode { strongSelf.highlightedBackgroundNode.frame = CGRect(origin: CGPoint(x: 0.0, y: layoutOffset - separatorHeight - topNegativeInset), size: CGSize(width: layout.contentSize.width, height: layout.contentSize.height + separatorHeight + topNegativeInset)) if let peerPresence = peerPresence as? TelegramUserPresence { - strongSelf.peerPresenceManager?.reset(presence: TelegramUserPresence(status: peerPresence.status, lastActivity: 0), isOnline: online) + strongSelf.peerPresenceManager?.reset(presence: EnginePeer.Presence(TelegramUserPresence(status: peerPresence.status, lastActivity: 0)), isOnline: online) } strongSelf.updateLayout(size: layout.contentSize, leftInset: params.leftInset, rightInset: params.rightInset) diff --git a/submodules/ChatListUI/Sources/Node/ChatListItemStrings.swift b/submodules/ChatListUI/Sources/Node/ChatListItemStrings.swift index 8cf12f0f1a..c55ebd95b6 100644 --- a/submodules/ChatListUI/Sources/Node/ChatListItemStrings.swift +++ b/submodules/ChatListUI/Sources/Node/ChatListItemStrings.swift @@ -287,16 +287,16 @@ public func chatListItemStrings(strings: PresentationStrings, nameDisplayOrder: case .active: switch secretChat.role { case .creator: - messageText = strings.DialogList_EncryptedChatStartedOutgoing(peer?.compactDisplayTitle ?? "").string + messageText = strings.DialogList_EncryptedChatStartedOutgoing(peer.flatMap(EnginePeer.init)?.compactDisplayTitle ?? "").string case .participant: - messageText = strings.DialogList_EncryptedChatStartedIncoming(peer?.compactDisplayTitle ?? "").string + messageText = strings.DialogList_EncryptedChatStartedIncoming(peer.flatMap(EnginePeer.init)?.compactDisplayTitle ?? "").string } case .terminated: messageText = strings.DialogList_EncryptionRejected case .handshake: switch secretChat.role { case .creator: - messageText = strings.DialogList_AwaitingEncryption(peer?.compactDisplayTitle ?? "").string + messageText = strings.DialogList_AwaitingEncryption(peer.flatMap(EnginePeer.init)?.compactDisplayTitle ?? "").string case .participant: messageText = strings.DialogList_EncryptionProcessing } diff --git a/submodules/ChatListUI/Sources/Node/ChatListNode.swift b/submodules/ChatListUI/Sources/Node/ChatListNode.swift index 6121b32cb9..2a22b370ed 100644 --- a/submodules/ChatListUI/Sources/Node/ChatListNode.swift +++ b/submodules/ChatListUI/Sources/Node/ChatListNode.swift @@ -309,7 +309,7 @@ private func mappedInsertEntries(context: AccountContext, nodeInteraction: ChatL } } - return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: ContactsPeerItem(presentationData: ItemListPresentationData(theme: presentationData.theme, fontSize: presentationData.fontSize, strings: presentationData.strings), sortOrder: presentationData.nameSortOrder, displayOrder: presentationData.nameDisplayOrder, context: context, peerMode: .generalSearch, peer: .peer(peer: itemPeer, chatPeer: chatPeer), status: status, enabled: enabled, selection: editing ? .selectable(selected: selected) : .none, editing: ContactsPeerItemEditing(editable: false, editing: false, revealed: false), index: nil, header: header, action: { _ in + return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: ContactsPeerItem(presentationData: ItemListPresentationData(theme: presentationData.theme, fontSize: presentationData.fontSize, strings: presentationData.strings), sortOrder: presentationData.nameSortOrder, displayOrder: presentationData.nameDisplayOrder, context: context, peerMode: .generalSearch, peer: .peer(peer: itemPeer.flatMap(EnginePeer.init), chatPeer: chatPeer.flatMap(EnginePeer.init)), status: status, enabled: enabled, selection: editing ? .selectable(selected: selected) : .none, editing: ContactsPeerItemEditing(editable: false, editing: false, revealed: false), index: nil, header: header, action: { _ in if let chatPeer = chatPeer { if editing { nodeInteraction.togglePeerSelected(chatPeer) @@ -390,7 +390,7 @@ private func mappedUpdateEntries(context: AccountContext, nodeInteraction: ChatL } } - return ListViewUpdateItem(index: entry.index, previousIndex: entry.previousIndex, item: ContactsPeerItem(presentationData: ItemListPresentationData(theme: presentationData.theme, fontSize: presentationData.fontSize, strings: presentationData.strings), sortOrder: presentationData.nameSortOrder, displayOrder: presentationData.nameDisplayOrder, context: context, peerMode: .generalSearch, peer: .peer(peer: itemPeer, chatPeer: chatPeer), status: status, enabled: enabled, selection: editing ? .selectable(selected: selected) : .none, editing: ContactsPeerItemEditing(editable: false, editing: false, revealed: false), index: nil, header: header, action: { _ in + return ListViewUpdateItem(index: entry.index, previousIndex: entry.previousIndex, item: ContactsPeerItem(presentationData: ItemListPresentationData(theme: presentationData.theme, fontSize: presentationData.fontSize, strings: presentationData.strings), sortOrder: presentationData.nameSortOrder, displayOrder: presentationData.nameDisplayOrder, context: context, peerMode: .generalSearch, peer: .peer(peer: itemPeer.flatMap(EnginePeer.init), chatPeer: chatPeer.flatMap(EnginePeer.init)), status: status, enabled: enabled, selection: editing ? .selectable(selected: selected) : .none, editing: ContactsPeerItemEditing(editable: false, editing: false, revealed: false), index: nil, header: header, action: { _ in if let chatPeer = chatPeer { if editing { nodeInteraction.togglePeerSelected(chatPeer) diff --git a/submodules/ChatListUI/Sources/Node/ChatListTypingNode.swift b/submodules/ChatListUI/Sources/Node/ChatListTypingNode.swift index e2669b386b..bed127d2e5 100644 --- a/submodules/ChatListUI/Sources/Node/ChatListTypingNode.swift +++ b/submodules/ChatListUI/Sources/Node/ChatListTypingNode.swift @@ -87,7 +87,7 @@ final class ChatListInputActivitiesNode: ASDisplayNode { } else { let text: String if let _ = commonKey { - let peerTitle = activities[0].0.compactDisplayTitle + let peerTitle = EnginePeer(activities[0].0).compactDisplayTitle switch activities[0].1 { case .uploadingVideo: text = strings.DialogList_SingleUploadingVideoSuffix(peerTitle).string @@ -111,7 +111,7 @@ final class ChatListInputActivitiesNode: ASDisplayNode { text = "" } } else { - text = activities[0].0.compactDisplayTitle + text = EnginePeer(activities[0].0).compactDisplayTitle } let string = NSAttributedString(string: text, font: textFont, textColor: color) @@ -137,9 +137,9 @@ final class ChatListInputActivitiesNode: ASDisplayNode { } else { let string: NSAttributedString if activities.count > 1 { - let peerTitle = activities[0].0.compactDisplayTitle + let peerTitle = EnginePeer(activities[0].0).compactDisplayTitle if activities.count == 2 { - let secondPeerTitle = activities[1].0.compactDisplayTitle + let secondPeerTitle = EnginePeer(activities[1].0).compactDisplayTitle string = NSAttributedString(string: strings.DialogList_MultipleTypingPair(peerTitle, secondPeerTitle).string, font: textFont, textColor: color) } else { string = NSAttributedString(string: strings.DialogList_MultipleTyping(peerTitle, strings.DialogList_MultipleTypingSuffix(activities.count - 1).string).string, font: textFont, textColor: color) diff --git a/submodules/ComposePollUI/BUILD b/submodules/ComposePollUI/BUILD index f076121bd0..ca1caad8ed 100644 --- a/submodules/ComposePollUI/BUILD +++ b/submodules/ComposePollUI/BUILD @@ -12,7 +12,6 @@ swift_library( deps = [ "//submodules/AsyncDisplayKit:AsyncDisplayKit", "//submodules/Display:Display", - "//submodules/Postbox:Postbox", "//submodules/TelegramCore:TelegramCore", "//submodules/TelegramPresentationData:TelegramPresentationData", "//submodules/ItemListUI:ItemListUI", diff --git a/submodules/ComposePollUI/Sources/CreatePollController.swift b/submodules/ComposePollUI/Sources/CreatePollController.swift index e55e09d5b4..d46d52bc90 100644 --- a/submodules/ComposePollUI/Sources/CreatePollController.swift +++ b/submodules/ComposePollUI/Sources/CreatePollController.swift @@ -10,7 +10,6 @@ import AccountContext import AlertUI import PresentationDataUtils import TextFormat -import Postbox private struct OrderedLinkedListItemOrderingId: RawRepresentable, Hashable { var rawValue: Int @@ -483,7 +482,36 @@ private func createPollControllerEntries(presentationData: PresentationData, pee return entries } -public func createPollController(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal)? = nil, peer: EnginePeer, isQuiz: Bool? = nil, completion: @escaping (EnqueueMessage) -> Void) -> ViewController { +public final class ComposedPoll { + public let publicity: TelegramMediaPollPublicity + public let kind: TelegramMediaPollKind + + public let text: String + public let options: [TelegramMediaPollOption] + public let correctAnswers: [Data]? + public let results: TelegramMediaPollResults + public let deadlineTimeout: Int32? + + public init( + publicity: TelegramMediaPollPublicity, + kind: TelegramMediaPollKind, + text: String, + options: [TelegramMediaPollOption], + correctAnswers: [Data]?, + results: TelegramMediaPollResults, + deadlineTimeout: Int32? + ) { + self.publicity = publicity + self.kind = kind + self.text = text + self.options = options + self.correctAnswers = correctAnswers + self.results = results + self.deadlineTimeout = deadlineTimeout + } +} + +public func createPollController(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal)? = nil, peer: EnginePeer, isQuiz: Bool? = nil, completion: @escaping (ComposedPoll) -> Void) -> ViewController { var initialState = CreatePollControllerState() if let isQuiz = isQuiz { initialState.isQuiz = isQuiz @@ -819,14 +847,19 @@ public func createPollController(context: AccountContext, updatedPresentationDat kind = .poll(multipleAnswers: state.isMultipleChoice) } - var deadlineTimeout: Int32? - #if DEBUG - deadlineTimeout = 65 - #endif + let deadlineTimeout: Int32? = nil dismissImpl?() - completion(.message(text: "", attributes: [], mediaReference: .standalone(media: TelegramMediaPoll(pollId: MediaId(namespace: Namespaces.Media.LocalPoll, id: Int64.random(in: Int64.min ... Int64.max)), publicity: publicity, kind: kind, text: processPollText(state.text), options: options, correctAnswers: correctAnswers, results: TelegramMediaPollResults(voters: nil, totalVoters: nil, recentVoters: [], solution: resolvedSolution), isClosed: false, deadlineTimeout: deadlineTimeout)), replyToMessageId: nil, localGroupingKey: nil, correlationId: nil)) + completion(ComposedPoll( + publicity: publicity, + kind: kind, + text: processPollText(state.text), + options: options, + correctAnswers: correctAnswers, + results: TelegramMediaPollResults(voters: nil, totalVoters: nil, recentVoters: [], solution: resolvedSolution), + deadlineTimeout: deadlineTimeout + )) }) let leftNavigationButton = ItemListNavigationButton(content: .text(presentationData.strings.Common_Cancel), style: .regular, enabled: true, action: { diff --git a/submodules/ContactListUI/Sources/ContactListNode.swift b/submodules/ContactListUI/Sources/ContactListNode.swift index fada4dc91a..840d7b4412 100644 --- a/submodules/ContactListUI/Sources/ContactListNode.swift +++ b/submodules/ContactListUI/Sources/ContactListNode.swift @@ -187,7 +187,7 @@ private enum ContactListNodeEntry: Comparable, Identifiable { } else { if let _ = peer as? TelegramUser { let presence = presence ?? TelegramUserPresence(status: .none, lastActivity: 0) - status = .presence(presence, dateTimeFormat) + status = .presence(EnginePeer.Presence(presence), dateTimeFormat) } else if let group = peer as? TelegramGroup { status = .custom(string: strings.Conversation_StatusMembers(Int32(group.participantCount)), multiline: false) } else if let channel = peer as? TelegramChannel { @@ -208,7 +208,7 @@ private enum ContactListNodeEntry: Comparable, Identifiable { status = .none } } - itemPeer = .peer(peer: peer, chatPeer: peer) + itemPeer = .peer(peer: EnginePeer(peer), chatPeer: EnginePeer(peer)) case let .deviceContact(id, contact): status = .none itemPeer = .deviceContact(stableId: id, contact: contact) @@ -222,7 +222,7 @@ private enum ContactListNodeEntry: Comparable, Identifiable { switch itemPeer { case let .peer(peer, _): if let peer = peer { - contextAction(peer, node, gesture) + contextAction(peer._asPeer(), node, gesture) } case .deviceContact: break diff --git a/submodules/ContactListUI/Sources/ContactsSearchContainerNode.swift b/submodules/ContactListUI/Sources/ContactsSearchContainerNode.swift index 2cd4300906..9acad949d1 100644 --- a/submodules/ContactListUI/Sources/ContactsSearchContainerNode.swift +++ b/submodules/ContactListUI/Sources/ContactsSearchContainerNode.swift @@ -135,7 +135,7 @@ private enum ContactListSearchEntry: Comparable, Identifiable { case .contacts: header = ChatListSearchItemHeader(type: .contacts, theme: theme, strings: strings, actionTitle: nil, action: nil) if let presence = presence { - status = .presence(presence, timeFormat) + status = .presence(EnginePeer.Presence(presence), timeFormat) } else { status = .none } @@ -154,7 +154,7 @@ private enum ContactListSearchEntry: Comparable, Identifiable { let peerItem: ContactsPeerItemPeer switch peer { case let .peer(peer, _, _): - peerItem = .peer(peer: peer, chatPeer: peer) + peerItem = .peer(peer: EnginePeer(peer), chatPeer: EnginePeer(peer)) nativePeer = peer case let .deviceContact(stableId, contact): peerItem = .deviceContact(stableId: stableId, contact: contact) diff --git a/submodules/ContactListUI/Sources/InviteContactsControllerNode.swift b/submodules/ContactListUI/Sources/InviteContactsControllerNode.swift index 13c1fc2757..8d64b61cff 100644 --- a/submodules/ContactListUI/Sources/InviteContactsControllerNode.swift +++ b/submodules/ContactListUI/Sources/InviteContactsControllerNode.swift @@ -58,7 +58,7 @@ private enum InviteContactsEntry: Comparable, Identifiable { status = .none } let peer = TelegramUser(id: PeerId(namespace: .max, id: PeerId.Id._internalFromInt64Value(0)), accessHash: nil, firstName: contact.firstName, lastName: contact.lastName, username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: []) - return ContactsPeerItem(presentationData: ItemListPresentationData(presentationData), sortOrder: nameSortOrder, displayOrder: nameDisplayOrder, context: context, peerMode: .peer, peer: .peer(peer: peer, chatPeer: peer), status: status, enabled: true, selection: selection, editing: ContactsPeerItemEditing(editable: false, editing: false, revealed: false), index: nil, header: ChatListSearchItemHeader(type: .contacts, theme: theme, strings: strings, actionTitle: nil, action: nil), action: { _ in + return ContactsPeerItem(presentationData: ItemListPresentationData(presentationData), sortOrder: nameSortOrder, displayOrder: nameDisplayOrder, context: context, peerMode: .peer, peer: .peer(peer: EnginePeer(peer), chatPeer: EnginePeer(peer)), status: status, enabled: true, selection: selection, editing: ContactsPeerItemEditing(editable: false, editing: false, revealed: false), index: nil, header: ChatListSearchItemHeader(type: .contacts, theme: theme, strings: strings, actionTitle: nil, action: nil), action: { _ in interaction.toggleContact(id) }) } diff --git a/submodules/ContactsPeerItem/BUILD b/submodules/ContactsPeerItem/BUILD index fd0f757c66..af0de6ee9a 100644 --- a/submodules/ContactsPeerItem/BUILD +++ b/submodules/ContactsPeerItem/BUILD @@ -13,7 +13,6 @@ swift_library( "//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit", "//submodules/AsyncDisplayKit:AsyncDisplayKit", "//submodules/Display:Display", - "//submodules/Postbox:Postbox", "//submodules/TelegramCore:TelegramCore", "//submodules/AccountContext:AccountContext", "//submodules/AvatarNode:AvatarNode", diff --git a/submodules/ContactsPeerItem/Sources/ContactsPeerItem.swift b/submodules/ContactsPeerItem/Sources/ContactsPeerItem.swift index 6b619c9599..dcb8c8e25f 100644 --- a/submodules/ContactsPeerItem/Sources/ContactsPeerItem.swift +++ b/submodules/ContactsPeerItem/Sources/ContactsPeerItem.swift @@ -1,7 +1,6 @@ import Foundation import UIKit import AsyncDisplayKit -import Postbox import Display import SwiftSignalKit import TelegramCore @@ -29,7 +28,7 @@ public final class ContactItemHighlighting { public enum ContactsPeerItemStatus { case none - case presence(PeerPresence, PresentationDateTimeFormat) + case presence(EnginePeer.Presence, PresentationDateTimeFormat) case addressName(String) case custom(string: String, multiline: Bool) } @@ -94,17 +93,17 @@ public struct ContactsPeerItemAction { } public enum ContactsPeerItemPeer: Equatable { - case peer(peer: Peer?, chatPeer: Peer?) + case peer(peer: EnginePeer?, chatPeer: EnginePeer?) case deviceContact(stableId: DeviceContactStableId, contact: DeviceContactBasicData) public static func ==(lhs: ContactsPeerItemPeer, rhs: ContactsPeerItemPeer) -> Bool { switch lhs { case let .peer(lhsPeer, lhsChatPeer): if case let .peer(rhsPeer, rhsChatPeer) = rhs { - if !arePeersEqual(lhsPeer, rhsPeer) { + if lhsPeer != rhsPeer { return false } - if !arePeersEqual(lhsChatPeer, rhsChatPeer) { + if lhsChatPeer != rhsChatPeer { return false } return true @@ -122,6 +121,11 @@ public enum ContactsPeerItemPeer: Equatable { } public class ContactsPeerItem: ItemListItem, ListViewItemWithHeader { + public enum SortIndex { + case firstNameFirst + case lastNameFirst + } + let presentationData: ItemListPresentationData let style: ItemListStyle public let sectionId: ItemListSectionId @@ -141,8 +145,8 @@ public class ContactsPeerItem: ItemListItem, ListViewItemWithHeader { let actionIcon: ContactsPeerItemActionIcon let action: (ContactsPeerItemPeer) -> Void let disabledAction: ((ContactsPeerItemPeer) -> Void)? - let setPeerIdWithRevealedOptions: ((PeerId?, PeerId?) -> Void)? - let deletePeer: ((PeerId) -> Void)? + let setPeerIdWithRevealedOptions: ((EnginePeer.Id?, EnginePeer.Id?) -> Void)? + let deletePeer: ((EnginePeer.Id) -> Void)? let itemHighlighting: ContactItemHighlighting? let contextAction: ((ASDisplayNode, ContextGesture?) -> Void)? let arrowAction: (() -> Void)? @@ -153,7 +157,7 @@ public class ContactsPeerItem: ItemListItem, ListViewItemWithHeader { public let header: ListViewItemHeader? - public init(presentationData: ItemListPresentationData, style: ItemListStyle = .plain, sectionId: ItemListSectionId = 0, sortOrder: PresentationPersonNameOrder, displayOrder: PresentationPersonNameOrder, context: AccountContext, peerMode: ContactsPeerItemPeerMode, peer: ContactsPeerItemPeer, status: ContactsPeerItemStatus, badge: ContactsPeerItemBadge? = nil, enabled: Bool, selection: ContactsPeerItemSelection, selectionPosition: ContactsPeerItemSelectionPosition = .right, editing: ContactsPeerItemEditing, options: [ItemListPeerItemRevealOption] = [], additionalActions: [ContactsPeerItemAction] = [], actionIcon: ContactsPeerItemActionIcon = .none, index: PeerNameIndex?, header: ListViewItemHeader?, action: @escaping (ContactsPeerItemPeer) -> Void, disabledAction: ((ContactsPeerItemPeer) -> Void)? = nil, setPeerIdWithRevealedOptions: ((PeerId?, PeerId?) -> Void)? = nil, deletePeer: ((PeerId) -> Void)? = nil, itemHighlighting: ContactItemHighlighting? = nil, contextAction: ((ASDisplayNode, ContextGesture?) -> Void)? = nil, arrowAction: (() -> Void)? = nil) { + public init(presentationData: ItemListPresentationData, style: ItemListStyle = .plain, sectionId: ItemListSectionId = 0, sortOrder: PresentationPersonNameOrder, displayOrder: PresentationPersonNameOrder, context: AccountContext, peerMode: ContactsPeerItemPeerMode, peer: ContactsPeerItemPeer, status: ContactsPeerItemStatus, badge: ContactsPeerItemBadge? = nil, enabled: Bool, selection: ContactsPeerItemSelection, selectionPosition: ContactsPeerItemSelectionPosition = .right, editing: ContactsPeerItemEditing, options: [ItemListPeerItemRevealOption] = [], additionalActions: [ContactsPeerItemAction] = [], actionIcon: ContactsPeerItemActionIcon = .none, index: SortIndex?, header: ListViewItemHeader?, action: @escaping (ContactsPeerItemPeer) -> Void, disabledAction: ((ContactsPeerItemPeer) -> Void)? = nil, setPeerIdWithRevealedOptions: ((EnginePeer.Id?, EnginePeer.Id?) -> Void)? = nil, deletePeer: ((EnginePeer.Id) -> Void)? = nil, itemHighlighting: ContactItemHighlighting? = nil, contextAction: ((ASDisplayNode, ContextGesture?) -> Void)? = nil, arrowAction: (() -> Void)? = nil) { self.presentationData = presentationData self.style = style self.sectionId = sectionId @@ -185,7 +189,7 @@ public class ContactsPeerItem: ItemListItem, ListViewItemWithHeader { var letter: String = "#" switch peer { case let .peer(peer, _): - if let user = peer as? TelegramUser { + if case let .user(user) = peer { switch index { case .firstNameFirst: if let firstName = user.firstName, !firstName.isEmpty { @@ -200,11 +204,11 @@ public class ContactsPeerItem: ItemListItem, ListViewItemWithHeader { letter = String(firstName.prefix(1)).uppercased() } } - } else if let group = peer as? TelegramGroup { + } else if case let .legacyGroup(group) = peer { if !group.title.isEmpty { letter = String(group.title.prefix(1)).uppercased() } - } else if let channel = peer as? TelegramChannel { + } else if case let .channel(channel) = peer { if !channel.title.isEmpty { letter = String(channel.title.prefix(1)).uppercased() } @@ -340,7 +344,7 @@ public class ContactsPeerItemNode: ItemListRevealOptionsItemNode { private var peerPresenceManager: PeerPresenceStatusManager? private var layoutParams: (ContactsPeerItem, ListViewItemLayoutParams, Bool, Bool, Bool, ItemListNeighbors)? - public var chatPeer: Peer? { + public var chatPeer: EnginePeer? { if let peer = self.layoutParams?.0.peer { switch peer { case let .peer(peer, chatPeer): @@ -598,18 +602,18 @@ public class ContactsPeerItemNode: ItemListRevealOptionsItemNode { var titleAttributedString: NSAttributedString? var statusAttributedString: NSAttributedString? var multilineStatus: Bool = false - var userPresence: TelegramUserPresence? + var userPresence: EnginePeer.Presence? switch item.peer { case let .peer(peer, chatPeer): if let peer = peer { let textColor: UIColor - if let _ = chatPeer as? TelegramSecretChat { + if case .secretChat = chatPeer { textColor = item.presentationData.theme.chatList.secretTitleColor } else { textColor = item.presentationData.theme.list.itemPrimaryTextColor } - if let user = peer as? TelegramUser { + if case let .user(user) = peer { if peer.id == item.context.account.peerId, case .generalSearch = item.peerMode { titleAttributedString = NSAttributedString(string: item.presentationData.strings.DialogList_SavedMessages, font: titleBoldFont, textColor: textColor) } else if peer.id.isReplies { @@ -634,9 +638,9 @@ public class ContactsPeerItemNode: ItemListRevealOptionsItemNode { } else { titleAttributedString = NSAttributedString(string: item.presentationData.strings.User_DeletedAccount, font: titleBoldFont, textColor: textColor) } - } else if let group = peer as? TelegramGroup { + } else if case let .legacyGroup(group) = peer { titleAttributedString = NSAttributedString(string: group.title, font: titleBoldFont, textColor: item.presentationData.theme.list.itemPrimaryTextColor) - } else if let channel = peer as? TelegramChannel { + } else if case let .channel(channel) = peer { titleAttributedString = NSAttributedString(string: channel.title, font: titleBoldFont, textColor: item.presentationData.theme.list.itemPrimaryTextColor) } @@ -644,7 +648,6 @@ public class ContactsPeerItemNode: ItemListRevealOptionsItemNode { case .none: break case let .presence(presence, dateTimeFormat): - let presence = (presence as? TelegramUserPresence) ?? TelegramUserPresence(status: .none, lastActivity: 0) userPresence = presence let timestamp = CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970 let (string, activity) = stringAndActivityForUserPresence(strings: item.presentationData.strings, dateTimeFormat: dateTimeFormat, presence: presence, relativeTo: Int32(timestamp)) @@ -825,7 +828,7 @@ public class ContactsPeerItemNode: ItemListRevealOptionsItemNode { } else if peer.isDeleted { overrideImage = .deletedIcon } - strongSelf.avatarNode.setPeer(context: item.context, theme: item.presentationData.theme, peer: EnginePeer(peer), overrideImage: overrideImage, emptyColor: item.presentationData.theme.list.mediaPlaceholderColor, synchronousLoad: synchronousLoads) + strongSelf.avatarNode.setPeer(context: item.context, theme: item.presentationData.theme, peer: peer, overrideImage: overrideImage, emptyColor: item.presentationData.theme.list.mediaPlaceholderColor, synchronousLoad: synchronousLoads) } case let .deviceContact(_, contact): let letters: [String] diff --git a/submodules/DeleteChatPeerActionSheetItem/BUILD b/submodules/DeleteChatPeerActionSheetItem/BUILD index da28adac66..ca2b91ed1b 100644 --- a/submodules/DeleteChatPeerActionSheetItem/BUILD +++ b/submodules/DeleteChatPeerActionSheetItem/BUILD @@ -12,7 +12,6 @@ swift_library( deps = [ "//submodules/AsyncDisplayKit:AsyncDisplayKit", "//submodules/Display:Display", - "//submodules/Postbox:Postbox", "//submodules/TelegramCore:TelegramCore", "//submodules/AccountContext:AccountContext", "//submodules/AvatarNode:AvatarNode", diff --git a/submodules/GalleryUI/Sources/ChatItemGalleryFooterContentNode.swift b/submodules/GalleryUI/Sources/ChatItemGalleryFooterContentNode.swift index 208f1af5e9..5d62e2242b 100644 --- a/submodules/GalleryUI/Sources/ChatItemGalleryFooterContentNode.swift +++ b/submodules/GalleryUI/Sources/ChatItemGalleryFooterContentNode.swift @@ -635,9 +635,9 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll if let forwardInfo = message.forwardInfo, forwardInfo.flags.contains(.isImported), let authorSignature = forwardInfo.authorSignature { authorNameText = authorSignature } else if let author = message.effectiveAuthor { - authorNameText = author.displayTitle(strings: self.strings, displayOrder: self.nameOrder) + authorNameText = EnginePeer(author).displayTitle(strings: self.strings, displayOrder: self.nameOrder) } else if let peer = message.peers[message.id.peerId] { - authorNameText = peer.displayTitle(strings: self.strings, displayOrder: self.nameOrder) + authorNameText = EnginePeer(peer).displayTitle(strings: self.strings, displayOrder: self.nameOrder) } var dateText = humanReadableStringForTimestamp(strings: self.strings, dateTimeFormat: self.dateTimeFormat, timestamp: message.timestamp).string @@ -1028,7 +1028,7 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll var isChannel = false let peerId: PeerId = messages[0].id.peerId if let user = messages[0].peers[messages[0].id.peerId] as? TelegramUser { - personalPeerName = user.compactDisplayTitle + personalPeerName = EnginePeer(user).compactDisplayTitle } else if let channel = messages[0].peers[messages[0].id.peerId] as? TelegramChannel, case .broadcast = channel.info { isChannel = true } @@ -1211,14 +1211,14 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll savedMessages = true } else { if peers.count == 1, let peer = peers.first { - let peerName = peer.id == strongSelf.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) + let peerName = peer.id == strongSelf.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : EnginePeer(peer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) text = messages.count == 1 ? presentationData.strings.Conversation_ForwardTooltip_Chat_One(peerName).string : presentationData.strings.Conversation_ForwardTooltip_Chat_Many(peerName).string } else if peers.count == 2, let firstPeer = peers.first, let secondPeer = peers.last { - let firstPeerName = firstPeer.id == strongSelf.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : firstPeer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) - let secondPeerName = secondPeer.id == strongSelf.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : secondPeer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) + let firstPeerName = firstPeer.id == strongSelf.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : EnginePeer(firstPeer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) + let secondPeerName = secondPeer.id == strongSelf.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : EnginePeer(secondPeer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) text = messages.count == 1 ? presentationData.strings.Conversation_ForwardTooltip_TwoChats_One(firstPeerName, secondPeerName).string : presentationData.strings.Conversation_ForwardTooltip_TwoChats_Many(firstPeerName, secondPeerName).string } else if let peer = peers.first { - let peerName = peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) + let peerName = EnginePeer(peer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) text = messages.count == 1 ? presentationData.strings.Conversation_ForwardTooltip_ManyChats_One(peerName, "\(peers.count - 1)").string : presentationData.strings.Conversation_ForwardTooltip_ManyChats_Many(peerName, "\(peers.count - 1)").string } else { text = "" @@ -1275,14 +1275,14 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll savedMessages = true } else { if peers.count == 1, let peer = peers.first { - let peerName = peer.id == strongSelf.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) + let peerName = peer.id == strongSelf.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : EnginePeer(peer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) text = messages.count == 1 ? presentationData.strings.Conversation_ForwardTooltip_Chat_One(peerName).string : presentationData.strings.Conversation_ForwardTooltip_Chat_Many(peerName).string } else if peers.count == 2, let firstPeer = peers.first, let secondPeer = peers.last { - let firstPeerName = firstPeer.id == strongSelf.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : firstPeer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) - let secondPeerName = secondPeer.id == strongSelf.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : secondPeer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) + let firstPeerName = firstPeer.id == strongSelf.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : EnginePeer(firstPeer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) + let secondPeerName = secondPeer.id == strongSelf.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : EnginePeer(secondPeer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) text = messages.count == 1 ? presentationData.strings.Conversation_ForwardTooltip_TwoChats_One(firstPeerName, secondPeerName).string : presentationData.strings.Conversation_ForwardTooltip_TwoChats_Many(firstPeerName, secondPeerName).string } else if let peer = peers.first { - let peerName = peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) + let peerName = EnginePeer(peer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) text = messages.count == 1 ? presentationData.strings.Conversation_ForwardTooltip_ManyChats_One(peerName, "\(peers.count - 1)").string : presentationData.strings.Conversation_ForwardTooltip_ManyChats_Many(peerName, "\(peers.count - 1)").string } else { text = "" @@ -1400,14 +1400,14 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll savedMessages = true } else { if peers.count == 1, let peer = peers.first { - let peerName = peer.id == strongSelf.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) + let peerName = peer.id == strongSelf.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : EnginePeer(peer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) text = presentationData.strings.Conversation_ForwardTooltip_Chat_One(peerName).string } else if peers.count == 2, let firstPeer = peers.first, let secondPeer = peers.last { - let firstPeerName = firstPeer.id == strongSelf.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : firstPeer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) - let secondPeerName = secondPeer.id == strongSelf.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : secondPeer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) + let firstPeerName = firstPeer.id == strongSelf.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : EnginePeer(firstPeer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) + let secondPeerName = secondPeer.id == strongSelf.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : EnginePeer(secondPeer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) text = presentationData.strings.Conversation_ForwardTooltip_TwoChats_One(firstPeerName, secondPeerName).string } else if let peer = peers.first { - let peerName = peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) + let peerName = EnginePeer(peer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) text = presentationData.strings.Conversation_ForwardTooltip_ManyChats_One(peerName, "\(peers.count - 1)").string } else { text = "" diff --git a/submodules/GalleryUI/Sources/GalleryController.swift b/submodules/GalleryUI/Sources/GalleryController.swift index 6042c2c2e6..f1a039c794 100644 --- a/submodules/GalleryUI/Sources/GalleryController.swift +++ b/submodules/GalleryUI/Sources/GalleryController.swift @@ -177,7 +177,7 @@ public func galleryItemForEntry(context: AccountContext, presentationData: Prese } let caption = galleryCaptionStringWithAppliedEntities(text, entities: entities) - return UniversalVideoGalleryItem(context: context, presentationData: presentationData, content: content, originData: GalleryItemOriginData(title: message.effectiveAuthor?.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), timestamp: message.timestamp), indexData: location.flatMap { GalleryItemIndexData(position: Int32($0.index), totalCount: Int32($0.count)) }, contentInfo: .message(message), caption: caption, displayInfoOnTop: displayInfoOnTop, hideControls: hideControls, fromPlayingVideo: fromPlayingVideo, isSecret: isSecret, landscape: landscape, timecode: timecode, playbackRate: playbackRate, configuration: configuration, playbackCompleted: playbackCompleted, performAction: performAction, openActionOptions: openActionOptions, storeMediaPlaybackState: storeMediaPlaybackState, present: present) + return UniversalVideoGalleryItem(context: context, presentationData: presentationData, content: content, originData: GalleryItemOriginData(title: message.effectiveAuthor.flatMap(EnginePeer.init)?.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), timestamp: message.timestamp), indexData: location.flatMap { GalleryItemIndexData(position: Int32($0.index), totalCount: Int32($0.count)) }, contentInfo: .message(message), caption: caption, displayInfoOnTop: displayInfoOnTop, hideControls: hideControls, fromPlayingVideo: fromPlayingVideo, isSecret: isSecret, landscape: landscape, timecode: timecode, playbackRate: playbackRate, configuration: configuration, playbackCompleted: playbackCompleted, performAction: performAction, openActionOptions: openActionOptions, storeMediaPlaybackState: storeMediaPlaybackState, present: present) } else { if let fileName = file.fileName, (fileName as NSString).pathExtension.lowercased() == "json" { return ChatAnimationGalleryItem(context: context, presentationData: presentationData, message: message, location: location) @@ -218,7 +218,7 @@ public func galleryItemForEntry(context: AccountContext, presentationData: Prese } } if let content = content { - return UniversalVideoGalleryItem(context: context, presentationData: presentationData, content: content, originData: GalleryItemOriginData(title: message.effectiveAuthor?.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), timestamp: message.timestamp), indexData: location.flatMap { GalleryItemIndexData(position: Int32($0.index), totalCount: Int32($0.count)) }, contentInfo: .message(message), caption: NSAttributedString(string: ""), displayInfoOnTop: displayInfoOnTop, fromPlayingVideo: fromPlayingVideo, isSecret: isSecret, landscape: landscape, timecode: timecode, playbackRate: playbackRate, configuration: configuration, performAction: performAction, openActionOptions: openActionOptions, storeMediaPlaybackState: storeMediaPlaybackState, present: present) + return UniversalVideoGalleryItem(context: context, presentationData: presentationData, content: content, originData: GalleryItemOriginData(title: message.effectiveAuthor.flatMap(EnginePeer.init)?.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), timestamp: message.timestamp), indexData: location.flatMap { GalleryItemIndexData(position: Int32($0.index), totalCount: Int32($0.count)) }, contentInfo: .message(message), caption: NSAttributedString(string: ""), displayInfoOnTop: displayInfoOnTop, fromPlayingVideo: fromPlayingVideo, isSecret: isSecret, landscape: landscape, timecode: timecode, playbackRate: playbackRate, configuration: configuration, performAction: performAction, openActionOptions: openActionOptions, storeMediaPlaybackState: storeMediaPlaybackState, present: present) } else { return nil } diff --git a/submodules/GalleryUI/Sources/GalleryTitleView.swift b/submodules/GalleryUI/Sources/GalleryTitleView.swift index c61e8213b4..a85a906487 100644 --- a/submodules/GalleryUI/Sources/GalleryTitleView.swift +++ b/submodules/GalleryUI/Sources/GalleryTitleView.swift @@ -3,6 +3,7 @@ import UIKit import AsyncDisplayKit import Display import Postbox +import TelegramCore import TelegramPresentationData import TelegramStringFormatting @@ -33,7 +34,7 @@ final class GalleryTitleView: UIView, NavigationBarTitleView { } func setMessage(_ message: Message, presentationData: PresentationData, accountPeerId: PeerId) { - let authorNameText = stringForFullAuthorName(message: message, strings: presentationData.strings, nameDisplayOrder: presentationData.nameDisplayOrder, accountPeerId: accountPeerId) + let authorNameText = stringForFullAuthorName(message: EngineMessage(message), strings: presentationData.strings, nameDisplayOrder: presentationData.nameDisplayOrder, accountPeerId: accountPeerId) let dateText = humanReadableStringForTimestamp(strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat, timestamp: message.timestamp).string self.authorNameNode.attributedText = NSAttributedString(string: authorNameText, font: titleFont, textColor: .white) diff --git a/submodules/GalleryUI/Sources/SecretMediaPreviewController.swift b/submodules/GalleryUI/Sources/SecretMediaPreviewController.swift index b8d108ed4b..f0de0120e9 100644 --- a/submodules/GalleryUI/Sources/SecretMediaPreviewController.swift +++ b/submodules/GalleryUI/Sources/SecretMediaPreviewController.swift @@ -300,7 +300,7 @@ public final class SecretMediaPreviewController: ViewController { }, transition: .immediate) } else { let contentNode = SecretMediaPreviewFooterContentNode() - let peerTitle = messageMainPeer(message)?.compactDisplayTitle ?? "" + let peerTitle = messageMainPeer(message).flatMap(EnginePeer.init)?.compactDisplayTitle ?? "" let text: String if let file = media as? TelegramMediaFile { if file.isAnimated { diff --git a/submodules/GameUI/BUILD b/submodules/GameUI/BUILD index 1ea06ab121..dce9403ef6 100644 --- a/submodules/GameUI/BUILD +++ b/submodules/GameUI/BUILD @@ -13,7 +13,6 @@ swift_library( "//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit", "//submodules/AsyncDisplayKit:AsyncDisplayKit", "//submodules/Display:Display", - "//submodules/Postbox:Postbox", "//submodules/TelegramCore:TelegramCore", "//submodules/TelegramPresentationData:TelegramPresentationData", "//submodules/AccountContext:AccountContext", diff --git a/submodules/GameUI/Sources/GameController.swift b/submodules/GameUI/Sources/GameController.swift index 5472afc754..b3913f61de 100644 --- a/submodules/GameUI/Sources/GameController.swift +++ b/submodules/GameUI/Sources/GameController.swift @@ -4,7 +4,6 @@ import Display import AsyncDisplayKit import TelegramCore import SwiftSignalKit -import Postbox import TelegramPresentationData import AccountContext @@ -15,11 +14,11 @@ public final class GameController: ViewController { private let context: AccountContext private let url: String - private let message: Message + private let message: EngineMessage private var presentationData: PresentationData - public init(context: AccountContext, url: String, message: Message) { + public init(context: AccountContext, url: String, message: EngineMessage) { self.context = context self.url = url self.message = message @@ -36,10 +35,10 @@ public final class GameController: ViewController { if let game = media as? TelegramMediaGame { let titleView = GameControllerTitleView(theme: self.presentationData.theme) - var botPeer: Peer? + var botPeer: EnginePeer? inner: for attribute in message.attributes { if let attribute = attribute as? InlineBotMessageAttribute, let peerId = attribute.peerId { - botPeer = message.peers[peerId] + botPeer = message.peers[peerId].flatMap(EnginePeer.init) break inner } } diff --git a/submodules/GameUI/Sources/GameControllerNode.swift b/submodules/GameUI/Sources/GameControllerNode.swift index 5a7a17d15a..4471f116b3 100644 --- a/submodules/GameUI/Sources/GameControllerNode.swift +++ b/submodules/GameUI/Sources/GameControllerNode.swift @@ -4,7 +4,6 @@ import Display import AsyncDisplayKit import WebKit import TelegramCore -import Postbox import SwiftSignalKit import TelegramPresentationData import AccountContext @@ -31,9 +30,9 @@ final class GameControllerNode: ViewControllerTracingNode { private let context: AccountContext var presentationData: PresentationData private let present: (ViewController, Any?) -> Void - private let message: Message + private let message: EngineMessage - init(context: AccountContext, presentationData: PresentationData, url: String, present: @escaping (ViewController, Any?) -> Void, message: Message) { + init(context: AccountContext, presentationData: PresentationData, url: String, present: @escaping (ViewController, Any?) -> Void, message: EngineMessage) { self.context = context self.presentationData = presentationData self.present = present @@ -107,14 +106,14 @@ final class GameControllerNode: ViewControllerTracingNode { }) } - private func shareData() -> (Peer, String)? { - var botPeer: Peer? + private func shareData() -> (EnginePeer, String)? { + var botPeer: EnginePeer? var gameName: String? for media in self.message.media { if let game = media as? TelegramMediaGame { inner: for attribute in self.message.attributes { if let attribute = attribute as? InlineBotMessageAttribute, let peerId = attribute.peerId { - botPeer = self.message.peers[peerId] + botPeer = self.message.peers[peerId].flatMap(EnginePeer.init) break inner } } diff --git a/submodules/GameUI/Sources/GameControllerTitleView.swift b/submodules/GameUI/Sources/GameControllerTitleView.swift index eec1b30b07..df8641aa83 100644 --- a/submodules/GameUI/Sources/GameControllerTitleView.swift +++ b/submodules/GameUI/Sources/GameControllerTitleView.swift @@ -2,7 +2,6 @@ import Foundation import UIKit import AsyncDisplayKit import Display -import Postbox import TelegramCore import SwiftSignalKit import TelegramPresentationData diff --git a/submodules/GraphUI/BUILD b/submodules/GraphUI/BUILD index fc10bc1cb3..48670e81ce 100644 --- a/submodules/GraphUI/BUILD +++ b/submodules/GraphUI/BUILD @@ -13,7 +13,6 @@ swift_library( "//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit", "//submodules/AsyncDisplayKit:AsyncDisplayKit", "//submodules/Display:Display", - "//submodules/Postbox:Postbox", "//submodules/TelegramCore:TelegramCore", "//submodules/TelegramPresentationData:TelegramPresentationData", "//submodules/TelegramUIPreferences:TelegramUIPreferences", diff --git a/submodules/HashtagSearchUI/Sources/HashtagSearchControllerNode.swift b/submodules/HashtagSearchUI/Sources/HashtagSearchControllerNode.swift index 477a463690..b0633b30fa 100644 --- a/submodules/HashtagSearchUI/Sources/HashtagSearchControllerNode.swift +++ b/submodules/HashtagSearchUI/Sources/HashtagSearchControllerNode.swift @@ -48,7 +48,7 @@ final class HashtagSearchControllerNode: ASDisplayNode { } else if let id = peer?.id, id.isReplies { items.append(presentationData.strings.DialogList_Replies) } else { - items.append(peer?.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) ?? "") + items.append(peer.flatMap(EnginePeer.init)?.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) ?? "") } items.append(strings.HashtagSearch_AllChats) self.segmentedControlNode = SegmentedControlNode(theme: SegmentedControlTheme(theme: theme), items: items.map { SegmentedControlItem(title: $0) }, selectedIndex: 0) diff --git a/submodules/InstantPageUI/Sources/InstantPagePeerReferenceNode.swift b/submodules/InstantPageUI/Sources/InstantPagePeerReferenceNode.swift index 93ab63ca74..d69acf174f 100644 --- a/submodules/InstantPageUI/Sources/InstantPagePeerReferenceNode.swift +++ b/submodules/InstantPageUI/Sources/InstantPagePeerReferenceNode.swift @@ -210,7 +210,7 @@ final class InstantPagePeerReferenceNode: ASDisplayNode, InstantPageNode { private func applyThemeAndStrings(themeUpdated: Bool) { if let peer = self.peer { let textColor = self.transparent ? UIColor.white : self.theme.panelPrimaryColor - self.nameNode.attributedText = NSAttributedString(string: peer.displayTitle(strings: self.strings, displayOrder: self.nameDisplayOrder), font: Font.medium(17.0), textColor: textColor) + self.nameNode.attributedText = NSAttributedString(string: EnginePeer(peer).displayTitle(strings: self.strings, displayOrder: self.nameDisplayOrder), font: Font.medium(17.0), textColor: textColor) } let accentColor = self.transparent ? UIColor.white : self.theme.panelAccentColor self.joinNode.setAttributedTitle(NSAttributedString(string: self.strings.Channel_JoinChannel, font: Font.medium(17.0), textColor: accentColor), for: []) diff --git a/submodules/InviteLinksUI/Sources/InviteLinkListController.swift b/submodules/InviteLinksUI/Sources/InviteLinkListController.swift index 06303b08db..765e509835 100644 --- a/submodules/InviteLinksUI/Sources/InviteLinkListController.swift +++ b/submodules/InviteLinksUI/Sources/InviteLinkListController.swift @@ -261,7 +261,7 @@ private enum InviteLinksListEntry: ItemListNodeEntry { case let .adminsHeader(_, text): return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section) case let .admin(_, _, creator): - return ItemListPeerItem(presentationData: presentationData, dateTimeFormat: PresentationDateTimeFormat(), nameDisplayOrder: .firstLast, context: arguments.context, peer: creator.peer.peer!, height: .peerList, aliasHandling: .standard, nameColor: .primary, nameStyle: .plain, presence: nil, text: .none, label: creator.count > 1 ? .disclosure("\(creator.count)") : .none, editing: ItemListPeerItemEditing(editable: false, editing: false, revealed: nil), revealOptions: nil, switchValue: nil, enabled: true, highlighted: false, selectable: true, sectionId: self.section, action: { + return ItemListPeerItem(presentationData: presentationData, dateTimeFormat: PresentationDateTimeFormat(), nameDisplayOrder: .firstLast, context: arguments.context, peer: EnginePeer(creator.peer.peer!), height: .peerList, aliasHandling: .standard, nameColor: .primary, nameStyle: .plain, presence: nil, text: .none, label: creator.count > 1 ? .disclosure("\(creator.count)") : .none, editing: ItemListPeerItemEditing(editable: false, editing: false, revealed: nil), revealOptions: nil, switchValue: nil, enabled: true, highlighted: false, selectable: true, sectionId: self.section, action: { arguments.openAdmin(creator) }, setPeerIdWithRevealedOptions: { _, _ in }, removePeer: { _ in }, toggleUpdated: nil, contextAction: nil) } @@ -309,7 +309,7 @@ private func inviteLinkListControllerEntries(presentationData: PresentationData, entries.append(.mainLink(presentationData.theme, mainInvite, importers?.importers.prefix(3).compactMap { $0.peer.peer } ?? [], importersCount, isPublic)) if let adminPeer = admin?.peer.peer, let peer = peerViewMainPeer(view) { - let string = presentationData.strings.InviteLink_OtherPermanentLinkInfo(adminPeer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)) + let string = presentationData.strings.InviteLink_OtherPermanentLinkInfo(EnginePeer(adminPeer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), EnginePeer(peer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)) entries.append(.mainLinkOtherInfo(presentationData.theme, string.string)) } @@ -814,7 +814,7 @@ public func inviteLinkListController(context: AccountContext, updatedPresentatio let title: ItemListControllerTitle if let admin = admin, let peer = admin.peer.peer { - title = .textWithSubtitle(peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), presentationData.strings.InviteLink_InviteLinks(admin.count)) + title = .textWithSubtitle(EnginePeer(peer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), presentationData.strings.InviteLink_InviteLinks(admin.count)) } else { title = .text(presentationData.strings.InviteLink_Title) } diff --git a/submodules/InviteLinksUI/Sources/InviteLinkViewController.swift b/submodules/InviteLinksUI/Sources/InviteLinkViewController.swift index 818b16a77a..dd42de62c0 100644 --- a/submodules/InviteLinksUI/Sources/InviteLinkViewController.swift +++ b/submodules/InviteLinksUI/Sources/InviteLinkViewController.swift @@ -172,7 +172,7 @@ private enum InviteLinkViewEntry: Comparable, Identifiable { return SectionHeaderItem(presentationData: ItemListPresentationData(presentationData), title: title) case let .creator(_, dateTimeFormat, peer, date): let dateString = stringForFullDate(timestamp: date, strings: presentationData.strings, dateTimeFormat: dateTimeFormat) - return ItemListPeerItem(presentationData: ItemListPresentationData(presentationData), dateTimeFormat: dateTimeFormat, nameDisplayOrder: presentationData.nameDisplayOrder, context: interaction.context, peer: peer, height: .generic, nameStyle: .distinctBold, presence: nil, text: .text(dateString, .secondary), label: .none, editing: ItemListPeerItemEditing(editable: false, editing: false, revealed: false), revealOptions: nil, switchValue: nil, enabled: true, selectable: peer.id != account.peerId, sectionId: 0, action: { + return ItemListPeerItem(presentationData: ItemListPresentationData(presentationData), dateTimeFormat: dateTimeFormat, nameDisplayOrder: presentationData.nameDisplayOrder, context: interaction.context, peer: EnginePeer(peer), height: .generic, nameStyle: .distinctBold, presence: nil, text: .text(dateString, .secondary), label: .none, editing: ItemListPeerItemEditing(editable: false, editing: false, revealed: false), revealOptions: nil, switchValue: nil, enabled: true, selectable: peer.id != account.peerId, sectionId: 0, action: { interaction.openPeer(peer.id) }, setPeerIdWithRevealedOptions: { _, _ in }, removePeer: { _ in }, hasTopStripe: false, noInsets: true, tag: nil) case let .importerHeader(_, title, subtitle, expired): @@ -189,7 +189,7 @@ private enum InviteLinkViewEntry: Comparable, Identifiable { return SectionHeaderItem(presentationData: ItemListPresentationData(presentationData), title: title, additionalText: additionalText) case let .importer(_, _, dateTimeFormat, peer, date, loading): let dateString = stringForFullDate(timestamp: date, strings: presentationData.strings, dateTimeFormat: dateTimeFormat) - return ItemListPeerItem(presentationData: ItemListPresentationData(presentationData), dateTimeFormat: dateTimeFormat, nameDisplayOrder: presentationData.nameDisplayOrder, context: interaction.context, peer: peer, height: .generic, nameStyle: .distinctBold, presence: nil, text: .text(dateString, .secondary), label: .none, editing: ItemListPeerItemEditing(editable: false, editing: false, revealed: false), revealOptions: nil, switchValue: nil, enabled: true, selectable: peer.id != account.peerId, sectionId: 0, action: { + return ItemListPeerItem(presentationData: ItemListPresentationData(presentationData), dateTimeFormat: dateTimeFormat, nameDisplayOrder: presentationData.nameDisplayOrder, context: interaction.context, peer: EnginePeer(peer), height: .generic, nameStyle: .distinctBold, presence: nil, text: .text(dateString, .secondary), label: .none, editing: ItemListPeerItemEditing(editable: false, editing: false, revealed: false), revealOptions: nil, switchValue: nil, enabled: true, selectable: peer.id != account.peerId, sectionId: 0, action: { interaction.openPeer(peer.id) }, setPeerIdWithRevealedOptions: { _, _ in }, removePeer: { _ in }, hasTopStripe: false, noInsets: true, tag: nil, shimmering: loading ? ItemListPeerItemShimmering(alternationIndex: 0) : nil) } diff --git a/submodules/ItemListAvatarAndNameInfoItem/BUILD b/submodules/ItemListAvatarAndNameInfoItem/BUILD index dbf1c6e68d..e24785c855 100644 --- a/submodules/ItemListAvatarAndNameInfoItem/BUILD +++ b/submodules/ItemListAvatarAndNameInfoItem/BUILD @@ -13,7 +13,6 @@ swift_library( "//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit", "//submodules/AsyncDisplayKit:AsyncDisplayKit", "//submodules/Display:Display", - "//submodules/Postbox:Postbox", "//submodules/TelegramCore:TelegramCore", "//submodules/TelegramPresentationData:TelegramPresentationData", "//submodules/PeerPresenceStatusManager:PeerPresenceStatusManager", diff --git a/submodules/ItemListAvatarAndNameInfoItem/Sources/ItemListAvatarAndNameItem.swift b/submodules/ItemListAvatarAndNameInfoItem/Sources/ItemListAvatarAndNameItem.swift index daff7c21dd..850998868f 100644 --- a/submodules/ItemListAvatarAndNameInfoItem/Sources/ItemListAvatarAndNameItem.swift +++ b/submodules/ItemListAvatarAndNameInfoItem/Sources/ItemListAvatarAndNameItem.swift @@ -2,7 +2,6 @@ import Foundation import UIKit import Display import AsyncDisplayKit -import Postbox import TelegramCore import SwiftSignalKit import TelegramPresentationData @@ -31,13 +30,13 @@ public enum ItemListAvatarAndNameInfoItemName: Equatable { case personName(firstName: String, lastName: String, phone: String) case title(title: String, type: ItemListAvatarAndNameInfoItemTitleType) - public init(_ peer: Peer) { + public init(_ peer: EnginePeer) { switch peer.indexName { case let .personName(first, last, _, phone): self = .personName(firstName: first, lastName: last, phone: phone ?? "") case let .title(title, _): let type: ItemListAvatarAndNameInfoItemTitleType - if let peer = peer as? TelegramChannel, case .broadcast = peer.info { + if case let .channel(peer) = peer, case .broadcast = peer.info { type = .channel } else { type = .group @@ -132,10 +131,10 @@ public class ItemListAvatarAndNameInfoItem: ListViewItem, ItemListItem { let presentationData: ItemListPresentationData let dateTimeFormat: PresentationDateTimeFormat let mode: ItemListAvatarAndNameInfoItemMode - let peer: Peer? - let presence: PeerPresence? + let peer: EnginePeer? + let presence: EnginePeer.Presence? let label: String? - let cachedData: CachedPeerData? + let memberCount: Int? let state: ItemListAvatarAndNameInfoItemState public let sectionId: ItemListSectionId let style: ItemListAvatarAndNameInfoItemStyle @@ -151,7 +150,7 @@ public class ItemListAvatarAndNameInfoItem: ListViewItem, ItemListItem { public let selectable: Bool - public init(accountContext: AccountContext, presentationData: ItemListPresentationData, dateTimeFormat: PresentationDateTimeFormat, mode: ItemListAvatarAndNameInfoItemMode, peer: Peer?, presence: PeerPresence?, label: String? = nil, cachedData: CachedPeerData?, state: ItemListAvatarAndNameInfoItemState, sectionId: ItemListSectionId, style: ItemListAvatarAndNameInfoItemStyle, editingNameUpdated: @escaping (ItemListAvatarAndNameInfoItemName) -> Void, editingNameCompleted: @escaping () -> Void = {}, avatarTapped: @escaping () -> Void, context: ItemListAvatarAndNameInfoItemContext? = nil, updatingImage: ItemListAvatarAndNameInfoItemUpdatingAvatar? = nil, call: (() -> Void)? = nil, action: (() -> Void)? = nil, longTapAction: (() -> Void)? = nil, tag: ItemListItemTag? = nil) { + public init(accountContext: AccountContext, presentationData: ItemListPresentationData, dateTimeFormat: PresentationDateTimeFormat, mode: ItemListAvatarAndNameInfoItemMode, peer: EnginePeer?, presence: EnginePeer.Presence?, label: String? = nil, memberCount: Int?, state: ItemListAvatarAndNameInfoItemState, sectionId: ItemListSectionId, style: ItemListAvatarAndNameInfoItemStyle, editingNameUpdated: @escaping (ItemListAvatarAndNameInfoItemName) -> Void, editingNameCompleted: @escaping () -> Void = {}, avatarTapped: @escaping () -> Void, context: ItemListAvatarAndNameInfoItemContext? = nil, updatingImage: ItemListAvatarAndNameInfoItemUpdatingAvatar? = nil, call: (() -> Void)? = nil, action: (() -> Void)? = nil, longTapAction: (() -> Void)? = nil, tag: ItemListItemTag? = nil) { self.accountContext = accountContext self.presentationData = presentationData self.dateTimeFormat = dateTimeFormat @@ -159,7 +158,7 @@ public class ItemListAvatarAndNameInfoItem: ListViewItem, ItemListItem { self.peer = peer self.presence = presence self.label = label - self.cachedData = cachedData + self.memberCount = memberCount self.state = state self.sectionId = sectionId self.style = style @@ -396,7 +395,7 @@ public class ItemListAvatarAndNameInfoItemNode: ListViewItemNode, ItemListItemNo var statusText: String = "" let statusColor: UIColor - if let peer = item.peer as? TelegramUser { + if case let .user(peer) = item.peer { let servicePeer = isServicePeer(peer) switch item.mode { case .settings: @@ -423,8 +422,7 @@ public class ItemListAvatarAndNameInfoItemNode: ListViewItemNode, ItemListItemNo } else if let _ = peer.botInfo { statusText = item.presentationData.strings.Bot_GenericBotStatus statusColor = item.presentationData.theme.list.itemSecondaryTextColor - } else if case .generic = item.mode, !servicePeer { - let presence = (item.presence as? TelegramUserPresence) ?? TelegramUserPresence(status: .none, lastActivity: 0) + } else if case .generic = item.mode, !servicePeer, let presence = item.presence { let timestamp = CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970 let (string, activity) = stringAndActivityForUserPresence(strings: item.presentationData.strings, dateTimeFormat: item.dateTimeFormat, presence: presence, relativeTo: Int32(timestamp), expanded: true) statusText = string @@ -438,19 +436,19 @@ public class ItemListAvatarAndNameInfoItemNode: ListViewItemNode, ItemListItemNo statusColor = item.presentationData.theme.list.itemPrimaryTextColor } } - } else if let channel = item.peer as? TelegramChannel { - if let cachedChannelData = item.cachedData as? CachedChannelData, let memberCount = cachedChannelData.participantsSummary.memberCount { + } else if case let .channel(channel) = item.peer { + if let memberCount = item.memberCount { if case .group = channel.info { if memberCount == 0 { statusText = item.presentationData.strings.Group_Status } else { - statusText = item.presentationData.strings.Conversation_StatusMembers(memberCount) + statusText = item.presentationData.strings.Conversation_StatusMembers(Int32(memberCount)) } } else { if memberCount == 0 { statusText = item.presentationData.strings.Channel_Status } else { - statusText = item.presentationData.strings.Conversation_StatusSubscribers(memberCount) + statusText = item.presentationData.strings.Conversation_StatusSubscribers(Int32(memberCount)) } } statusColor = item.presentationData.theme.list.itemSecondaryTextColor @@ -464,7 +462,7 @@ public class ItemListAvatarAndNameInfoItemNode: ListViewItemNode, ItemListItemNo statusColor = item.presentationData.theme.list.itemSecondaryTextColor } } - } else if let group = item.peer as? TelegramGroup { + } else if case let .legacyGroup(group) = item.peer { statusText = item.presentationData.strings.GroupInfo_ParticipantCount(Int32(group.participantCount)) statusColor = item.presentationData.theme.list.itemSecondaryTextColor } else { @@ -666,7 +664,7 @@ public class ItemListAvatarAndNameInfoItemNode: ListViewItemNode, ItemListItemNo overrideImage = .deletedIcon } - strongSelf.avatarNode.setPeer(context: item.accountContext, theme: item.presentationData.theme, peer: EnginePeer(peer), overrideImage: overrideImage, emptyColor: ignoreEmpty ? nil : item.presentationData.theme.list.mediaPlaceholderColor, synchronousLoad: synchronousLoads) + strongSelf.avatarNode.setPeer(context: item.accountContext, theme: item.presentationData.theme, peer: peer, overrideImage: overrideImage, emptyColor: ignoreEmpty ? nil : item.presentationData.theme.list.mediaPlaceholderColor, synchronousLoad: synchronousLoads) } let avatarFrame = CGRect(origin: CGPoint(x: params.leftInset + 15.0, y: floor((layout.contentSize.height - 66.0) / 2.0)), size: CGSize(width: 66.0, height: 66.0)) @@ -950,7 +948,7 @@ public class ItemListAvatarAndNameInfoItemNode: ListViewItemNode, ItemListItemNo strongSelf.credibilityIconNode?.alpha = 1.0 } } - if let presence = item.presence as? TelegramUserPresence { + if let presence = item.presence { strongSelf.peerPresenceManager?.reset(presence: presence) } diff --git a/submodules/ItemListPeerItem/BUILD b/submodules/ItemListPeerItem/BUILD index 82417c0e2f..190e248dea 100644 --- a/submodules/ItemListPeerItem/BUILD +++ b/submodules/ItemListPeerItem/BUILD @@ -13,7 +13,6 @@ swift_library( "//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit", "//submodules/AsyncDisplayKit:AsyncDisplayKit", "//submodules/Display:Display", - "//submodules/Postbox:Postbox", "//submodules/TelegramCore:TelegramCore", "//submodules/AvatarNode:AvatarNode", "//submodules/TelegramPresentationData:TelegramPresentationData", diff --git a/submodules/ItemListPeerItem/Sources/ItemListPeerItem.swift b/submodules/ItemListPeerItem/Sources/ItemListPeerItem.swift index 477e89f4ce..c697a5cd8d 100644 --- a/submodules/ItemListPeerItem/Sources/ItemListPeerItem.swift +++ b/submodules/ItemListPeerItem/Sources/ItemListPeerItem.swift @@ -3,7 +3,6 @@ import UIKit import Display import AsyncDisplayKit import SwiftSignalKit -import Postbox import TelegramCore import TelegramPresentationData import TelegramUIPreferences @@ -317,12 +316,12 @@ public final class ItemListPeerItem: ListViewItem, ItemListItem { let dateTimeFormat: PresentationDateTimeFormat let nameDisplayOrder: PresentationPersonNameOrder let context: AccountContext - let peer: Peer + let peer: EnginePeer let height: ItemListPeerItemHeight let aliasHandling: ItemListPeerItemAliasHandling let nameColor: ItemListPeerItemNameColor let nameStyle: ItemListPeerItemNameStyle - let presence: PeerPresence? + let presence: EnginePeer.Presence? let text: ItemListPeerItemText let label: ItemListPeerItemLabel let editing: ItemListPeerItemEditing @@ -333,8 +332,8 @@ public final class ItemListPeerItem: ListViewItem, ItemListItem { public let selectable: Bool public let sectionId: ItemListSectionId let action: (() -> Void)? - let setPeerIdWithRevealedOptions: (PeerId?, PeerId?) -> Void - let removePeer: (PeerId) -> Void + let setPeerIdWithRevealedOptions: (EnginePeer.Id?, EnginePeer.Id?) -> Void + let removePeer: (EnginePeer.Id) -> Void let toggleUpdated: ((Bool) -> Void)? let contextAction: ((ASDisplayNode, ContextGesture?) -> Void)? let hasTopStripe: Bool @@ -346,7 +345,7 @@ public final class ItemListPeerItem: ListViewItem, ItemListItem { let displayDecorations: Bool let disableInteractiveTransitionIfNecessary: Bool - public init(presentationData: ItemListPresentationData, dateTimeFormat: PresentationDateTimeFormat, nameDisplayOrder: PresentationPersonNameOrder, context: AccountContext, peer: Peer, height: ItemListPeerItemHeight = .peerList, aliasHandling: ItemListPeerItemAliasHandling = .standard, nameColor: ItemListPeerItemNameColor = .primary, nameStyle: ItemListPeerItemNameStyle = .distinctBold, presence: PeerPresence?, text: ItemListPeerItemText, label: ItemListPeerItemLabel, editing: ItemListPeerItemEditing, revealOptions: ItemListPeerItemRevealOptions? = nil, switchValue: ItemListPeerItemSwitch?, enabled: Bool, highlighted: Bool = false, selectable: Bool, sectionId: ItemListSectionId, action: (() -> Void)?, setPeerIdWithRevealedOptions: @escaping (PeerId?, PeerId?) -> Void, removePeer: @escaping (PeerId) -> Void, toggleUpdated: ((Bool) -> Void)? = nil, contextAction: ((ASDisplayNode, ContextGesture?) -> Void)? = nil, hasTopStripe: Bool = true, hasTopGroupInset: Bool = true, noInsets: Bool = false, tag: ItemListItemTag? = nil, header: ListViewItemHeader? = nil, shimmering: ItemListPeerItemShimmering? = nil, displayDecorations: Bool = true, disableInteractiveTransitionIfNecessary: Bool = false) { + public init(presentationData: ItemListPresentationData, dateTimeFormat: PresentationDateTimeFormat, nameDisplayOrder: PresentationPersonNameOrder, context: AccountContext, peer: EnginePeer, height: ItemListPeerItemHeight = .peerList, aliasHandling: ItemListPeerItemAliasHandling = .standard, nameColor: ItemListPeerItemNameColor = .primary, nameStyle: ItemListPeerItemNameStyle = .distinctBold, presence: EnginePeer.Presence?, text: ItemListPeerItemText, label: ItemListPeerItemLabel, editing: ItemListPeerItemEditing, revealOptions: ItemListPeerItemRevealOptions? = nil, switchValue: ItemListPeerItemSwitch?, enabled: Bool, highlighted: Bool = false, selectable: Bool, sectionId: ItemListSectionId, action: (() -> Void)?, setPeerIdWithRevealedOptions: @escaping (EnginePeer.Id?, EnginePeer.Id?) -> Void, removePeer: @escaping (EnginePeer.Id) -> Void, toggleUpdated: ((Bool) -> Void)? = nil, contextAction: ((ASDisplayNode, ContextGesture?) -> Void)? = nil, hasTopStripe: Bool = true, hasTopGroupInset: Bool = true, noInsets: Bool = false, tag: ItemListItemTag? = nil, header: ListViewItemHeader? = nil, shimmering: ItemListPeerItemShimmering? = nil, displayDecorations: Bool = true, disableInteractiveTransitionIfNecessary: Bool = false) { self.presentationData = presentationData self.dateTimeFormat = dateTimeFormat self.nameDisplayOrder = nameDisplayOrder @@ -694,7 +693,7 @@ public class ItemListPeerItemNode: ItemListRevealOptionsItemNode, ItemListItemNo titleAttributedString = NSAttributedString(string: item.presentationData.strings.DialogList_SavedMessages, font: currentBoldFont, textColor: titleColor) } else if item.peer.id.isReplies { titleAttributedString = NSAttributedString(string: item.presentationData.strings.DialogList_Replies, font: currentBoldFont, textColor: titleColor) - } else if let user = item.peer as? TelegramUser { + } else if case let .user(user) = item.peer { if let firstName = user.firstName, let lastName = user.lastName, !firstName.isEmpty, !lastName.isEmpty { let string = NSMutableAttributedString() switch item.nameDisplayOrder { @@ -715,15 +714,15 @@ public class ItemListPeerItemNode: ItemListRevealOptionsItemNode, ItemListItemNo } else { titleAttributedString = NSAttributedString(string: item.presentationData.strings.User_DeletedAccount, font: currentBoldFont, textColor: titleColor) } - } else if let group = item.peer as? TelegramGroup { + } else if case let .legacyGroup(group) = item.peer { titleAttributedString = NSAttributedString(string: group.title, font: currentBoldFont, textColor: titleColor) - } else if let channel = item.peer as? TelegramChannel { + } else if case let .channel(channel) = item.peer { titleAttributedString = NSAttributedString(string: channel.title, font: currentBoldFont, textColor: titleColor) } switch item.text { case .presence: - if let user = item.peer as? TelegramUser, let botInfo = user.botInfo { + if case let .user(user) = item.peer, let botInfo = user.botInfo { let botStatus: String if botInfo.flags.contains(.hasAccessToChatHistory) { botStatus = item.presentationData.strings.Bot_GroupStatusReadsHistory @@ -731,7 +730,7 @@ public class ItemListPeerItemNode: ItemListRevealOptionsItemNode, ItemListItemNo botStatus = item.presentationData.strings.Bot_GroupStatusDoesNotReadHistory } statusAttributedString = NSAttributedString(string: botStatus, font: statusFont, textColor: item.presentationData.theme.list.itemSecondaryTextColor) - } else if let presence = item.presence as? TelegramUserPresence { + } else if let presence = item.presence { let timestamp = CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970 let (string, activity) = stringAndActivityForUserPresence(strings: item.presentationData.strings, dateTimeFormat: item.dateTimeFormat, presence: presence, relativeTo: Int32(timestamp)) statusAttributedString = NSAttributedString(string: string, font: statusFont, textColor: activity ? item.presentationData.theme.list.itemAccentColor : item.presentationData.theme.list.itemSecondaryTextColor) @@ -1106,20 +1105,20 @@ public class ItemListPeerItemNode: ItemListRevealOptionsItemNode, ItemListItemNo transition.updateFrame(node: strongSelf.avatarNode, frame: avatarFrame) if item.peer.id == item.context.account.peerId, case .threatSelfAsSaved = item.aliasHandling { - strongSelf.avatarNode.setPeer(context: item.context, theme: item.presentationData.theme, peer: EnginePeer(item.peer), overrideImage: .savedMessagesIcon, emptyColor: item.presentationData.theme.list.mediaPlaceholderColor, synchronousLoad: synchronousLoad) + strongSelf.avatarNode.setPeer(context: item.context, theme: item.presentationData.theme, peer: item.peer, overrideImage: .savedMessagesIcon, emptyColor: item.presentationData.theme.list.mediaPlaceholderColor, synchronousLoad: synchronousLoad) } else if item.peer.id.isReplies { - strongSelf.avatarNode.setPeer(context: item.context, theme: item.presentationData.theme, peer: EnginePeer(item.peer), overrideImage: .repliesIcon, emptyColor: item.presentationData.theme.list.mediaPlaceholderColor, synchronousLoad: synchronousLoad) + strongSelf.avatarNode.setPeer(context: item.context, theme: item.presentationData.theme, peer: item.peer, overrideImage: .repliesIcon, emptyColor: item.presentationData.theme.list.mediaPlaceholderColor, synchronousLoad: synchronousLoad) } else { var overrideImage: AvatarNodeImageOverride? if item.peer.isDeleted { overrideImage = .deletedIcon } - strongSelf.avatarNode.setPeer(context: item.context, theme: item.presentationData.theme, peer: EnginePeer(item.peer), overrideImage: overrideImage, emptyColor: item.presentationData.theme.list.mediaPlaceholderColor, synchronousLoad: synchronousLoad) + strongSelf.avatarNode.setPeer(context: item.context, theme: item.presentationData.theme, peer: item.peer, overrideImage: overrideImage, emptyColor: item.presentationData.theme.list.mediaPlaceholderColor, synchronousLoad: synchronousLoad) } strongSelf.highlightedBackgroundNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -UIScreenPixel), size: CGSize(width: params.width, height: layout.contentSize.height + UIScreenPixel + UIScreenPixel)) - if let presence = item.presence as? TelegramUserPresence { + if let presence = item.presence { strongSelf.peerPresenceManager?.reset(presence: presence) } diff --git a/submodules/LanguageLinkPreviewUI/BUILD b/submodules/LanguageLinkPreviewUI/BUILD index 7dbed7278d..6d40c1c244 100644 --- a/submodules/LanguageLinkPreviewUI/BUILD +++ b/submodules/LanguageLinkPreviewUI/BUILD @@ -13,7 +13,6 @@ swift_library( "//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit", "//submodules/AsyncDisplayKit:AsyncDisplayKit", "//submodules/Display:Display", - "//submodules/Postbox:Postbox", "//submodules/TelegramCore:TelegramCore", "//submodules/TelegramPresentationData:TelegramPresentationData", "//submodules/AccountContext:AccountContext", diff --git a/submodules/LanguageLinkPreviewUI/Sources/LanguageLinkPreviewContentNode.swift b/submodules/LanguageLinkPreviewUI/Sources/LanguageLinkPreviewContentNode.swift index 15b8006cb9..5321d1ac70 100644 --- a/submodules/LanguageLinkPreviewUI/Sources/LanguageLinkPreviewContentNode.swift +++ b/submodules/LanguageLinkPreviewUI/Sources/LanguageLinkPreviewContentNode.swift @@ -2,7 +2,6 @@ import Foundation import UIKit import AsyncDisplayKit import Display -import Postbox import TelegramCore import TelegramPresentationData import TextFormat @@ -76,7 +75,7 @@ final class LanguageLinkPreviewContentNode: ASDisplayNode, ShareContentContainer func deactivate() { } - func setEnsurePeerVisibleOnLayout(_ peerId: PeerId?) { + func setEnsurePeerVisibleOnLayout(_ peerId: EnginePeer.Id?) { } func setContentOffsetUpdated(_ f: ((CGFloat, ContainedViewLayoutTransition) -> Void)?) { diff --git a/submodules/LanguageLinkPreviewUI/Sources/LanguageLinkPreviewController.swift b/submodules/LanguageLinkPreviewUI/Sources/LanguageLinkPreviewController.swift index 7b324a3380..953120f3c9 100644 --- a/submodules/LanguageLinkPreviewUI/Sources/LanguageLinkPreviewController.swift +++ b/submodules/LanguageLinkPreviewUI/Sources/LanguageLinkPreviewController.swift @@ -2,7 +2,6 @@ import Foundation import UIKit import Display import AsyncDisplayKit -import Postbox import TelegramCore import SwiftSignalKit import TelegramPresentationData diff --git a/submodules/LanguageLinkPreviewUI/Sources/LanguageLinkPreviewControllerNode.swift b/submodules/LanguageLinkPreviewUI/Sources/LanguageLinkPreviewControllerNode.swift index c00b384e56..fbbe55e444 100644 --- a/submodules/LanguageLinkPreviewUI/Sources/LanguageLinkPreviewControllerNode.swift +++ b/submodules/LanguageLinkPreviewUI/Sources/LanguageLinkPreviewControllerNode.swift @@ -3,7 +3,6 @@ import UIKit import Display import AsyncDisplayKit import SwiftSignalKit -import Postbox import TelegramCore import TelegramPresentationData import ActivityIndicator diff --git a/submodules/LegacyMediaPickerUI/Sources/LegacyAttachmentMenu.swift b/submodules/LegacyMediaPickerUI/Sources/LegacyAttachmentMenu.swift index c889b3f048..260cd02cd3 100644 --- a/submodules/LegacyMediaPickerUI/Sources/LegacyAttachmentMenu.swift +++ b/submodules/LegacyMediaPickerUI/Sources/LegacyAttachmentMenu.swift @@ -82,7 +82,7 @@ public func legacyMediaEditor(context: AccountContext, peer: Peer, media: AnyMed } let presentationData = context.sharedContext.currentPresentationData.with { $0 } - let recipientName = peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) + let recipientName = EnginePeer(peer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) let legacyController = LegacyController(presentation: .custom, theme: presentationData.theme, initialLayout: nil) legacyController.blocksBackgroundWhenInOverlay = true @@ -182,7 +182,7 @@ public func legacyAttachmentMenu(context: AccountContext, peer: Peer, chatLocati carouselItemView = carouselItem carouselItem.stickersContext = paintStickersContext carouselItem.suggestionContext = legacySuggestionContext(context: context, peerId: peer.id, chatLocation: chatLocation) - carouselItem.recipientName = peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) + carouselItem.recipientName = EnginePeer(peer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) var openedCamera = false controller.willDismiss = { [weak carouselItem] _ in if let carouselItem = carouselItem, !openedCamera { @@ -315,7 +315,7 @@ public func legacyAttachmentMenu(context: AccountContext, peer: Peer, chatLocati navigationController.setNavigationBarHidden(true, animated: false) legacyController.bind(controller: navigationController) - let recipientName = peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) + let recipientName = EnginePeer(peer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) legacyController.enableSizeClassSignal = true @@ -439,7 +439,7 @@ public func presentLegacyPasteMenu(context: AccountContext, peer: Peer, chatLoca } hasSilentPosting = true } - let recipientName = peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) + let recipientName = EnginePeer(peer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) legacyController.enableSizeClassSignal = true diff --git a/submodules/LegacyMediaPickerUI/Sources/LegacyMediaPickers.swift b/submodules/LegacyMediaPickerUI/Sources/LegacyMediaPickers.swift index ac2e9e55b6..fa7fa8697a 100644 --- a/submodules/LegacyMediaPickerUI/Sources/LegacyMediaPickers.swift +++ b/submodules/LegacyMediaPickerUI/Sources/LegacyMediaPickers.swift @@ -84,7 +84,7 @@ public func legacyAssetPicker(context: AccountContext, presentationData: Present } else { Queue.mainQueue().async { subscriber.putNext({ context in - let controller = TGMediaAssetsController(context: context, assetGroup: group, intent: intent, recipientName: peer?.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), saveEditedPhotos: !isSecretChat && saveEditedPhotos, allowGrouping: allowGrouping, inhibitSelection: editingMedia, selectionLimit: Int32(selectionLimit)) + let controller = TGMediaAssetsController(context: context, assetGroup: group, intent: intent, recipientName: peer.flatMap(EnginePeer.init)?.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), saveEditedPhotos: !isSecretChat && saveEditedPhotos, allowGrouping: allowGrouping, inhibitSelection: editingMedia, selectionLimit: Int32(selectionLimit)) return controller! }) subscriber.putCompletion() @@ -93,7 +93,7 @@ public func legacyAssetPicker(context: AccountContext, presentationData: Present }) } else { subscriber.putNext({ context in - let controller = TGMediaAssetsController(context: context, assetGroup: nil, intent: intent, recipientName: peer?.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), saveEditedPhotos: !isSecretChat && saveEditedPhotos, allowGrouping: allowGrouping, inhibitSelection: editingMedia, selectionLimit: Int32(selectionLimit)) + let controller = TGMediaAssetsController(context: context, assetGroup: nil, intent: intent, recipientName: peer.flatMap(EnginePeer.init)?.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), saveEditedPhotos: !isSecretChat && saveEditedPhotos, allowGrouping: allowGrouping, inhibitSelection: editingMedia, selectionLimit: Int32(selectionLimit)) return controller! }) subscriber.putCompletion() diff --git a/submodules/ListMessageItem/Sources/ListMessageFileItemNode.swift b/submodules/ListMessageItem/Sources/ListMessageFileItemNode.swift index e1cd8a7656..9a8308574b 100644 --- a/submodules/ListMessageItem/Sources/ListMessageFileItemNode.swift +++ b/submodules/ListMessageItem/Sources/ListMessageFileItemNode.swift @@ -425,7 +425,7 @@ public final class ListMessageFileItemNode: ListMessageNode { } if item.isGlobalSearchResult { - let authorString = stringForFullAuthorName(message: item.message, strings: item.presentationData.strings, nameDisplayOrder: item.presentationData.nameDisplayOrder, accountPeerId: item.context.account.peerId) + let authorString = stringForFullAuthorName(message: EngineMessage(item.message), strings: item.presentationData.strings, nameDisplayOrder: item.presentationData.nameDisplayOrder, accountPeerId: item.context.account.peerId) if descriptionString.isEmpty { descriptionString = authorString } else { @@ -443,7 +443,7 @@ public final class ListMessageFileItemNode: ListMessageNode { } } else { titleText = NSAttributedString(string: " ", font: audioTitleFont, textColor: item.presentationData.theme.theme.list.itemPrimaryTextColor) - descriptionText = NSAttributedString(string: item.message.author?.displayTitle(strings: item.presentationData.strings, displayOrder: .firstLast) ?? " ", font: descriptionFont, textColor: item.presentationData.theme.theme.list.itemSecondaryTextColor) + descriptionText = NSAttributedString(string: item.message.author.flatMap(EnginePeer.init)?.displayTitle(strings: item.presentationData.strings, displayOrder: .firstLast) ?? " ", font: descriptionFont, textColor: item.presentationData.theme.theme.list.itemSecondaryTextColor) } } } @@ -454,7 +454,7 @@ public final class ListMessageFileItemNode: ListMessageNode { if author.id == item.context.account.peerId { authorName = item.presentationData.strings.DialogList_You } else { - authorName = author.displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder) + authorName = EnginePeer(author).displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder) } } else if let signature = message.forwardInfo?.authorSignature { authorName = signature @@ -462,14 +462,14 @@ public final class ListMessageFileItemNode: ListMessageNode { if author.id == item.context.account.peerId { authorName = item.presentationData.strings.DialogList_You } else { - authorName = author.displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder) + authorName = EnginePeer(author).displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder) } } else { authorName = " " } if item.isGlobalSearchResult { - authorName = stringForFullAuthorName(message: item.message, strings: item.presentationData.strings, nameDisplayOrder: item.presentationData.nameDisplayOrder, accountPeerId: item.context.account.peerId) + authorName = stringForFullAuthorName(message: EngineMessage(item.message), strings: item.presentationData.strings, nameDisplayOrder: item.presentationData.nameDisplayOrder, accountPeerId: item.context.account.peerId) } titleText = NSAttributedString(string: authorName, font: audioTitleFont, textColor: item.presentationData.theme.theme.list.itemPrimaryTextColor) @@ -522,7 +522,7 @@ public final class ListMessageFileItemNode: ListMessageNode { } if item.isGlobalSearchResult { - let authorString = stringForFullAuthorName(message: item.message, strings: item.presentationData.strings, nameDisplayOrder: item.presentationData.nameDisplayOrder, accountPeerId: item.context.account.peerId) + let authorString = stringForFullAuthorName(message: EngineMessage(item.message), strings: item.presentationData.strings, nameDisplayOrder: item.presentationData.nameDisplayOrder, accountPeerId: item.context.account.peerId) if descriptionString.isEmpty { descriptionString = authorString } else { diff --git a/submodules/ListMessageItem/Sources/ListMessageSnippetItemNode.swift b/submodules/ListMessageItem/Sources/ListMessageSnippetItemNode.swift index 6cc80b5d17..09615cee7e 100644 --- a/submodules/ListMessageItem/Sources/ListMessageSnippetItemNode.swift +++ b/submodules/ListMessageItem/Sources/ListMessageSnippetItemNode.swift @@ -537,7 +537,7 @@ public final class ListMessageSnippetItemNode: ListMessageNode { var authorString = "" if item.isGlobalSearchResult { - authorString = stringForFullAuthorName(message: item.message, strings: item.presentationData.strings, nameDisplayOrder: item.presentationData.nameDisplayOrder, accountPeerId: item.context.account.peerId) + authorString = stringForFullAuthorName(message: EngineMessage(item.message), strings: item.presentationData.strings, nameDisplayOrder: item.presentationData.nameDisplayOrder, accountPeerId: item.context.account.peerId) } let authorText = NSAttributedString(string: authorString, font: authorFont, textColor: item.presentationData.theme.theme.list.itemSecondaryTextColor) diff --git a/submodules/LiveLocationManager/BUILD b/submodules/LiveLocationManager/BUILD index 9af918155c..47b328632a 100644 --- a/submodules/LiveLocationManager/BUILD +++ b/submodules/LiveLocationManager/BUILD @@ -12,7 +12,6 @@ swift_library( deps = [ "//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit", "//submodules/TelegramCore:TelegramCore", - "//submodules/Postbox:Postbox", "//submodules/DeviceLocationManager:DeviceLocationManager", "//submodules/AccountContext:AccountContext", ], diff --git a/submodules/LiveLocationManager/Sources/LiveLocationManager.swift b/submodules/LiveLocationManager/Sources/LiveLocationManager.swift index bc7be66cb0..b78f60a1cd 100644 --- a/submodules/LiveLocationManager/Sources/LiveLocationManager.swift +++ b/submodules/LiveLocationManager/Sources/LiveLocationManager.swift @@ -1,6 +1,5 @@ import Foundation import TelegramCore -import Postbox import SwiftSignalKit import CoreLocation import DeviceLocationManager @@ -9,7 +8,7 @@ import AccountContext public final class LiveLocationManagerImpl: LiveLocationManager { private let queue = Queue.mainQueue() - private let account: Account + private let engine: TelegramEngine private let locationManager: DeviceLocationManager private let summaryManagerImpl: LiveLocationSummaryManagerImpl @@ -36,51 +35,48 @@ public final class LiveLocationManagerImpl: LiveLocationManager { private var deviceLocationPromise = Promise<(CLLocation, Double?)>() - private var broadcastToMessageIds: [MessageId: Int32] = [:] - private var stopMessageIds = Set() + private var broadcastToMessageIds: [EngineMessage.Id: Int32] = [:] + private var stopMessageIds = Set() - private let editMessageDisposables = DisposableDict() + private let editMessageDisposables = DisposableDict() private var invalidationTimer: (SwiftSignalKit.Timer, Int32)? - public init(engine: TelegramEngine, account: Account, locationManager: DeviceLocationManager, inForeground: Signal) { - self.account = account + public init(engine: TelegramEngine, locationManager: DeviceLocationManager, inForeground: Signal) { + self.engine = engine self.locationManager = locationManager - self.summaryManagerImpl = LiveLocationSummaryManagerImpl(queue: self.queue, engine: engine, postbox: account.postbox, accountPeerId: account.peerId, viewTracker: account.viewTracker) - - let viewKey: PostboxViewKey = .localMessageTag(.OutgoingLiveLocation) - self.messagesDisposable = (account.postbox.combinedView(keys: [viewKey]) - |> deliverOn(self.queue)).start(next: { [weak self] view in + self.summaryManagerImpl = LiveLocationSummaryManagerImpl(queue: self.queue, engine: engine, accountPeerId: engine.account.peerId) + + self.messagesDisposable = (self.engine.messages.activeLiveLocationMessages() + |> deliverOn(self.queue)).start(next: { [weak self] message in if let strongSelf = self { let timestamp = Int32(CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970) - var broadcastToMessageIds: [MessageId: Int32] = [:] - var stopMessageIds = Set() - - if let view = view.views[viewKey] as? LocalMessageTagsView { - for message in view.messages.values { - if !message.flags.contains(.Incoming) { - if message.flags.intersection([.Failed, .Unsent]).isEmpty { - var activeLiveBroadcastingTimeout: Int32? - for media in message.media { - if let telegramMap = media as? TelegramMediaMap { - if let liveBroadcastingTimeout = telegramMap.liveBroadcastingTimeout { - if message.timestamp + liveBroadcastingTimeout > timestamp { - activeLiveBroadcastingTimeout = liveBroadcastingTimeout - } + var broadcastToMessageIds: [EngineMessage.Id: Int32] = [:] + var stopMessageIds = Set() + + for message in message { + if !message.flags.contains(.Incoming) { + if message.flags.intersection([.Failed, .Unsent]).isEmpty { + var activeLiveBroadcastingTimeout: Int32? + for media in message.media { + if let telegramMap = media as? TelegramMediaMap { + if let liveBroadcastingTimeout = telegramMap.liveBroadcastingTimeout { + if message.timestamp + liveBroadcastingTimeout > timestamp { + activeLiveBroadcastingTimeout = liveBroadcastingTimeout } } } - if let activeLiveBroadcastingTimeout = activeLiveBroadcastingTimeout { - broadcastToMessageIds[message.id] = message.timestamp + activeLiveBroadcastingTimeout - } else { - stopMessageIds.insert(message.id) - } } - } else { - assertionFailure() + if let activeLiveBroadcastingTimeout = activeLiveBroadcastingTimeout { + broadcastToMessageIds[message.id] = message.timestamp + activeLiveBroadcastingTimeout + } else { + stopMessageIds.insert(message.id) + } } + } else { + assertionFailure() } } @@ -139,7 +135,7 @@ public final class LiveLocationManagerImpl: LiveLocationManager { self.invalidationTimer?.0.invalidate() } - private func update(broadcastToMessageIds: [MessageId: Int32], stopMessageIds: Set) { + private func update(broadcastToMessageIds: [EngineMessage.Id: Int32], stopMessageIds: Set) { assert(self.queue.isCurrent()) if self.broadcastToMessageIds == broadcastToMessageIds && self.stopMessageIds == stopMessageIds { @@ -170,7 +166,7 @@ public final class LiveLocationManagerImpl: LiveLocationManager { let addedStopped = stopMessageIds.subtracting(self.stopMessageIds) self.stopMessageIds = stopMessageIds for id in addedStopped { - self.editMessageDisposables.set((TelegramEngine(account: self.account).messages.requestEditLiveLocation(messageId: id, stop: true, coordinate: nil, heading: nil, proximityNotificationRadius: nil) + self.editMessageDisposables.set((self.engine.messages.requestEditLiveLocation(messageId: id, stop: true, coordinate: nil, heading: nil, proximityNotificationRadius: nil) |> deliverOn(self.queue)).start(completed: { [weak self] in if let strongSelf = self { strongSelf.editMessageDisposables.set(nil, forKey: id) @@ -187,7 +183,7 @@ public final class LiveLocationManagerImpl: LiveLocationManager { var updatedBroadcastToMessageIds = self.broadcastToMessageIds var updatedStopMessageIds = self.stopMessageIds - var earliestCancelIdAndTimestamp: (MessageId, Int32)? + var earliestCancelIdAndTimestamp: (EngineMessage.Id, Int32)? for (id, timestamp) in self.broadcastToMessageIds { if currentTimestamp >= timestamp { updatedBroadcastToMessageIds.removeValue(forKey: id) @@ -223,9 +219,9 @@ public final class LiveLocationManagerImpl: LiveLocationManager { assert(self.queue.isCurrent()) let ids = self.broadcastToMessageIds - let remainingIds = Atomic>(value: Set(ids.keys)) + let remainingIds = Atomic>(value: Set(ids.keys)) for id in ids.keys { - self.editMessageDisposables.set((TelegramEngine(account: self.account).messages.requestEditLiveLocation(messageId: id, stop: false, coordinate: (latitude: coordinate.latitude, longitude: coordinate.longitude, accuracyRadius: Int32(accuracyRadius)), heading: heading.flatMap { Int32($0) }, proximityNotificationRadius: nil) + self.editMessageDisposables.set((self.engine.messages.requestEditLiveLocation(messageId: id, stop: false, coordinate: (latitude: coordinate.latitude, longitude: coordinate.longitude, accuracyRadius: Int32(accuracyRadius)), heading: heading.flatMap { Int32($0) }, proximityNotificationRadius: nil) |> deliverOn(self.queue)).start(completed: { [weak self] in if let strongSelf = self { strongSelf.editMessageDisposables.set(nil, forKey: id) @@ -243,29 +239,12 @@ public final class LiveLocationManagerImpl: LiveLocationManager { } } - public func cancelLiveLocation(peerId: PeerId) { + public func cancelLiveLocation(peerId: EnginePeer.Id) { assert(self.queue.isCurrent()) let ids = self.broadcastToMessageIds.keys.filter({ $0.peerId == peerId }) if !ids.isEmpty { - let _ = self.account.postbox.transaction({ transaction -> Void in - for id in ids { - transaction.updateMessage(id, update: { currentMessage in - var storeForwardInfo: StoreMessageForwardInfo? - if let forwardInfo = currentMessage.forwardInfo { - storeForwardInfo = StoreMessageForwardInfo(authorId: forwardInfo.author?.id, sourceId: forwardInfo.source?.id, sourceMessageId: forwardInfo.sourceMessageId, date: forwardInfo.date, authorSignature: forwardInfo.authorSignature, psaType: forwardInfo.psaType, flags: forwardInfo.flags) - } - var updatedMedia = currentMessage.media - let timestamp = Int32(CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970) - for i in 0 ..< updatedMedia.count { - if let media = updatedMedia[i] as? TelegramMediaMap, let _ = media.liveBroadcastingTimeout { - updatedMedia[i] = TelegramMediaMap(latitude: media.latitude, longitude: media.longitude, heading: media.heading, accuracyRadius: media.accuracyRadius, geoPlace: media.geoPlace, venue: media.venue, liveBroadcastingTimeout: max(0, timestamp - currentMessage.timestamp - 1), liveProximityNotificationRadius: nil) - } - } - return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: currentMessage.attributes, media: updatedMedia)) - }) - } - }).start() + let _ = self.engine.messages.requestCancelLiveLocation(ids: ids).start() } } @@ -275,7 +254,7 @@ public final class LiveLocationManagerImpl: LiveLocationManager { } } - public func internalMessageForPeerId(_ peerId: PeerId) -> MessageId? { + public func internalMessageForPeerId(_ peerId: EnginePeer.Id) -> EngineMessage.Id? { for id in self.broadcastToMessageIds.keys { if id.peerId == peerId { return id diff --git a/submodules/LiveLocationManager/Sources/LiveLocationSummaryManager.swift b/submodules/LiveLocationManager/Sources/LiveLocationSummaryManager.swift index 401833b4e9..ce767dadd3 100644 --- a/submodules/LiveLocationManager/Sources/LiveLocationSummaryManager.swift +++ b/submodules/LiveLocationManager/Sources/LiveLocationSummaryManager.swift @@ -1,15 +1,14 @@ import Foundation -import Postbox import TelegramCore import SwiftSignalKit import AccountContext private final class LiveLocationSummaryContext { private let queue: Queue - private let postbox: Postbox - private var subscribers = Bag<([MessageId: Message]) -> Void>() + private let engine: TelegramEngine + private var subscribers = Bag<([EngineMessage.Id: EngineMessage]) -> Void>() - var messageIds = Set() { + var messageIds = Set() { didSet { assert(self.queue.isCurrent()) @@ -18,10 +17,12 @@ private final class LiveLocationSummaryContext { self.disposable.set(nil) self.messages = [:] } else { - let key = PostboxViewKey.messages(self.messageIds) - self.disposable.set((self.postbox.combinedView(keys: [key]) |> deliverOn(self.queue)).start(next: { [weak self] view in + self.disposable.set((self.engine.data.subscribe( + TelegramEngine.EngineData.Item.Messages.Messages(ids: self.messageIds) + ) + |> deliverOn(self.queue)).start(next: { [weak self] messages in if let strongSelf = self { - strongSelf.messages = (view.views[key] as? MessagesView)?.messages ?? [:] + strongSelf.messages = messages } })) } @@ -29,7 +30,7 @@ private final class LiveLocationSummaryContext { } } - private var messages: [MessageId: Message] = [:] { + private var messages: [EngineMessage.Id: EngineMessage] = [:] { didSet { assert(self.queue.isCurrent()) @@ -41,16 +42,16 @@ private final class LiveLocationSummaryContext { private let disposable = MetaDisposable() - init(queue: Queue, postbox: Postbox) { + init(queue: Queue, engine: TelegramEngine) { self.queue = queue - self.postbox = postbox + self.engine = engine } deinit { self.disposable.dispose() } - func subscribe() -> Signal<[MessageId: Message], NoError> { + func subscribe() -> Signal<[EngineMessage.Id: EngineMessage], NoError> { let queue = self.queue return Signal { [weak self] subscriber in let disposable = MetaDisposable() @@ -79,12 +80,11 @@ private final class LiveLocationSummaryContext { private final class LiveLocationPeerSummaryContext { private let queue: Queue private let engine: TelegramEngine - private let accountPeerId: PeerId - private let viewTracker: AccountViewTracker - private let peerId: PeerId + private let accountPeerId: EnginePeer.Id + private let peerId: EnginePeer.Id private let becameEmpty: () -> Void - private var peersAndMessages: [(Peer, Message)]? = nil { + private var peersAndMessages: [(EnginePeer, EngineMessage)]? = nil { didSet { assert(self.queue.isCurrent()) @@ -108,7 +108,7 @@ private final class LiveLocationPeerSummaryContext { } } } - private var subscribers = Bag<([(Peer, Message)]?) -> Void>() + private var subscribers = Bag<([(EnginePeer, EngineMessage)]?) -> Void>() var isEmpty: Bool { return !self.isActive && self.subscribers.isEmpty @@ -116,11 +116,10 @@ private final class LiveLocationPeerSummaryContext { private let peerDisposable = MetaDisposable() - init(queue: Queue, engine: TelegramEngine, accountPeerId: PeerId, viewTracker: AccountViewTracker, peerId: PeerId, becameEmpty: @escaping () -> Void) { + init(queue: Queue, engine: TelegramEngine, accountPeerId: EnginePeer.Id, peerId: EnginePeer.Id, becameEmpty: @escaping () -> Void) { self.queue = queue self.engine = engine self.accountPeerId = accountPeerId - self.viewTracker = viewTracker self.peerId = peerId self.becameEmpty = becameEmpty } @@ -129,7 +128,7 @@ private final class LiveLocationPeerSummaryContext { self.peerDisposable.dispose() } - func subscribe(_ f: @escaping ([(Peer, Message)]?) -> Void) -> Disposable { + func subscribe(_ f: @escaping ([(EnginePeer, EngineMessage)]?) -> Void) -> Disposable { let wasEmpty = self.subscribers.isEmpty let index = self.subscribers.add({ next in f(next) @@ -164,11 +163,11 @@ private final class LiveLocationPeerSummaryContext { self.peerDisposable.set((self.engine.messages.topPeerActiveLiveLocationMessages(peerId: self.peerId) |> deliverOn(self.queue)).start(next: { [weak self] accountPeer, messages in if let strongSelf = self { - var peersAndMessages: [(Peer, Message)] = [] + var peersAndMessages: [(EnginePeer, EngineMessage)] = [] for message in messages { if let author = message.author { if author.id != strongSelf.accountPeerId && message.flags.contains(.Incoming) { - peersAndMessages.append((author, message)) + peersAndMessages.append((EnginePeer(author), EngineMessage(message))) } } } @@ -189,33 +188,29 @@ private final class LiveLocationPeerSummaryContext { public final class LiveLocationSummaryManagerImpl: LiveLocationSummaryManager { private let queue: Queue private let engine: TelegramEngine - private let postbox: Postbox - private let accountPeerId: PeerId - private let viewTracker: AccountViewTracker + private let accountPeerId: EnginePeer.Id private let globalContext: LiveLocationSummaryContext - private var peerContexts: [PeerId: LiveLocationPeerSummaryContext] = [:] + private var peerContexts: [EnginePeer.Id: LiveLocationPeerSummaryContext] = [:] - init(queue: Queue, engine: TelegramEngine, postbox: Postbox, accountPeerId: PeerId, viewTracker: AccountViewTracker) { + init(queue: Queue, engine: TelegramEngine, accountPeerId: EnginePeer.Id) { assert(queue.isCurrent()) self.queue = queue self.engine = engine - self.postbox = postbox self.accountPeerId = accountPeerId - self.viewTracker = viewTracker - self.globalContext = LiveLocationSummaryContext(queue: queue, postbox: postbox) + self.globalContext = LiveLocationSummaryContext(queue: queue, engine: engine) } - func update(messageIds: Set) { - var peerIds = Set() + func update(messageIds: Set) { + var peerIds = Set() for id in messageIds { peerIds.insert(id.peerId) } for peerId in peerIds { if self.peerContexts[peerId] == nil { - let context = LiveLocationPeerSummaryContext(queue: self.queue, engine: self.engine, accountPeerId: self.accountPeerId, viewTracker: self.viewTracker, peerId: peerId, becameEmpty: { [weak self] in + let context = LiveLocationPeerSummaryContext(queue: self.queue, engine: self.engine, accountPeerId: self.accountPeerId, peerId: peerId, becameEmpty: { [weak self] in if let strongSelf = self, let context = strongSelf.peerContexts[peerId], context.isEmpty { strongSelf.peerContexts.removeValue(forKey: peerId) } @@ -231,11 +226,11 @@ public final class LiveLocationSummaryManagerImpl: LiveLocationSummaryManager { self.globalContext.messageIds = messageIds } - public func broadcastingToMessages() -> Signal<[MessageId: Message], NoError> { + public func broadcastingToMessages() -> Signal<[EngineMessage.Id: EngineMessage], NoError> { return self.globalContext.subscribe() } - public func peersBroadcastingTo(peerId: PeerId) -> Signal<[(Peer, Message)]?, NoError> { + public func peersBroadcastingTo(peerId: EnginePeer.Id) -> Signal<[(EnginePeer, EngineMessage)]?, NoError> { let queue = self.queue return Signal { [weak self] subscriber in let disposable = MetaDisposable() @@ -245,7 +240,7 @@ public final class LiveLocationSummaryManagerImpl: LiveLocationSummaryManager { if let current = strongSelf.peerContexts[peerId] { context = current } else { - context = LiveLocationPeerSummaryContext(queue: strongSelf.queue, engine: strongSelf.engine, accountPeerId: strongSelf.accountPeerId, viewTracker: strongSelf.viewTracker, peerId: peerId, becameEmpty: { + context = LiveLocationPeerSummaryContext(queue: strongSelf.queue, engine: strongSelf.engine, accountPeerId: strongSelf.accountPeerId, peerId: peerId, becameEmpty: { if let strongSelf = self, let context = strongSelf.peerContexts[peerId], context.isEmpty { strongSelf.peerContexts.removeValue(forKey: peerId) } diff --git a/submodules/LiveLocationPositionNode/BUILD b/submodules/LiveLocationPositionNode/BUILD index a962112384..b57e84dcfb 100644 --- a/submodules/LiveLocationPositionNode/BUILD +++ b/submodules/LiveLocationPositionNode/BUILD @@ -12,7 +12,6 @@ swift_library( deps = [ "//submodules/AsyncDisplayKit:AsyncDisplayKit", "//submodules/Display:Display", - "//submodules/Postbox:Postbox", "//submodules/TelegramCore:TelegramCore", "//submodules/TelegramPresentationData:TelegramPresentationData", "//submodules/AvatarNode:AvatarNode", diff --git a/submodules/LocalizedPeerData/BUILD b/submodules/LocalizedPeerData/BUILD index 4ab6122d50..7fe29f6078 100644 --- a/submodules/LocalizedPeerData/BUILD +++ b/submodules/LocalizedPeerData/BUILD @@ -11,7 +11,6 @@ swift_library( ], deps = [ "//submodules/TelegramCore:TelegramCore", - "//submodules/Postbox:Postbox", "//submodules/TelegramPresentationData:TelegramPresentationData", "//submodules/TelegramUIPreferences:TelegramUIPreferences", "//submodules/PhoneNumberFormat:PhoneNumberFormat", diff --git a/submodules/LocalizedPeerData/Sources/PeerTitle.swift b/submodules/LocalizedPeerData/Sources/PeerTitle.swift index 29578b4a0e..0ada467530 100644 --- a/submodules/LocalizedPeerData/Sources/PeerTitle.swift +++ b/submodules/LocalizedPeerData/Sources/PeerTitle.swift @@ -1,14 +1,13 @@ import Foundation import TelegramCore -import Postbox import TelegramPresentationData import TelegramUIPreferences import PhoneNumberFormat -public extension Peer { +public extension EnginePeer { var compactDisplayTitle: String { switch self { - case let user as TelegramUser: + case let .user(user): if let firstName = user.firstName, !firstName.isEmpty { return firstName } else if let lastName = user.lastName, !lastName.isEmpty { @@ -18,18 +17,18 @@ public extension Peer { } else { return "" } - case let group as TelegramGroup: + case let .legacyGroup(group): return group.title - case let channel as TelegramChannel: + case let .channel(channel): return channel.title - default: + case .secretChat: return "" } } - + func displayTitle(strings: PresentationStrings, displayOrder: PresentationPersonNameOrder) -> String { switch self { - case let user as TelegramUser: + case let .user(user): if user.id.isReplies { return strings.DialogList_Replies } @@ -51,22 +50,12 @@ public extension Peer { } else { return strings.User_DeletedAccount } - case let group as TelegramGroup: + case let .legacyGroup(group): return group.title - case let channel as TelegramChannel: + case let .channel(channel): return channel.title - default: + case .secretChat: return "" } } } - -public extension EnginePeer { - var compactDisplayTitle: String { - return self._asPeer().compactDisplayTitle - } - - func displayTitle(strings: PresentationStrings, displayOrder: PresentationPersonNameOrder) -> String { - return self._asPeer().displayTitle(strings: strings, displayOrder: displayOrder) - } -} diff --git a/submodules/LocationUI/Sources/LocationLiveListItem.swift b/submodules/LocationUI/Sources/LocationLiveListItem.swift index e6ef55b5d8..22c561d19e 100644 --- a/submodules/LocationUI/Sources/LocationLiveListItem.swift +++ b/submodules/LocationUI/Sources/LocationLiveListItem.swift @@ -159,7 +159,7 @@ final class LocationLiveListItemNode: ListViewItemNode { var title: String = "" if let author = item.message.author { - title = author.displayTitle(strings: item.presentationData.strings, displayOrder: item.nameDisplayOrder) + title = EnginePeer(author).displayTitle(strings: item.presentationData.strings, displayOrder: item.nameDisplayOrder) } let titleAttributedString = NSAttributedString(string: title, font: titleFont, textColor: item.presentationData.theme.list.itemPrimaryTextColor) let (titleLayout, titleApply) = makeTitleLayout(TextNodeLayoutArguments(attributedString: titleAttributedString, backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width - leftInset - rightInset - 54.0, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets())) diff --git a/submodules/LocationUI/Sources/LocationPickerController.swift b/submodules/LocationUI/Sources/LocationPickerController.swift index 39903fde4e..6b77ceb5e6 100644 --- a/submodules/LocationUI/Sources/LocationPickerController.swift +++ b/submodules/LocationUI/Sources/LocationPickerController.swift @@ -126,7 +126,7 @@ public final class LocationPickerController: ViewController { let controller = ActionSheetController(presentationData: strongSelf.presentationData) var title = strongSelf.presentationData.strings.Map_LiveLocationGroupDescription if case let .share(peer, _, _) = strongSelf.mode, let receiver = peer as? TelegramUser { - title = strongSelf.presentationData.strings.Map_LiveLocationPrivateDescription(receiver.compactDisplayTitle).string + title = strongSelf.presentationData.strings.Map_LiveLocationPrivateDescription(EnginePeer(receiver).compactDisplayTitle).string } controller.setItemGroups([ ActionSheetItemGroup(items: [ diff --git a/submodules/LocationUI/Sources/LocationViewController.swift b/submodules/LocationUI/Sources/LocationViewController.swift index a8d84d43be..758dbe9cf7 100644 --- a/submodules/LocationUI/Sources/LocationViewController.swift +++ b/submodules/LocationUI/Sources/LocationViewController.swift @@ -240,7 +240,7 @@ public final class LocationViewController: ViewController { var compactDisplayTitle: String? if let peer = peer as? TelegramUser { - compactDisplayTitle = peer.compactDisplayTitle + compactDisplayTitle = EnginePeer(peer).compactDisplayTitle } let controller = LocationDistancePickerScreen(context: context, style: .default, compactDisplayTitle: compactDisplayTitle, distances: strongSelf.controllerNode.headerNode.mapNode.distancesToAllAnnotations, updated: { [weak self] distance in @@ -345,7 +345,7 @@ public final class LocationViewController: ViewController { var compactDisplayTitle: String? if let peer = peer as? TelegramUser { - compactDisplayTitle = peer.compactDisplayTitle + compactDisplayTitle = EnginePeer(peer).compactDisplayTitle } var text: String @@ -379,7 +379,7 @@ public final class LocationViewController: ViewController { let controller = ActionSheetController(presentationData: strongSelf.presentationData) var title = strongSelf.presentationData.strings.Map_LiveLocationGroupDescription if let user = peer as? TelegramUser { - title = strongSelf.presentationData.strings.Map_LiveLocationPrivateDescription(user.compactDisplayTitle).string + title = strongSelf.presentationData.strings.Map_LiveLocationPrivateDescription(EnginePeer(user).compactDisplayTitle).string } let sendLiveLocationImpl: (Int32) -> Void = { [weak controller] period in diff --git a/submodules/LocationUI/Sources/LocationViewControllerNode.swift b/submodules/LocationUI/Sources/LocationViewControllerNode.swift index 4671b10bcd..8240717de2 100644 --- a/submodules/LocationUI/Sources/LocationViewControllerNode.swift +++ b/submodules/LocationUI/Sources/LocationViewControllerNode.swift @@ -720,7 +720,7 @@ final class LocationViewControllerNode: ViewControllerTracingNode, CLLocationMan var text: String = strongSelf.presentationData.strings.Location_ProximityGroupTip if peer.id.namespace == Namespaces.Peer.CloudUser { - text = strongSelf.presentationData.strings.Location_ProximityTip(peer.compactDisplayTitle).string + text = strongSelf.presentationData.strings.Location_ProximityTip(EnginePeer(peer).compactDisplayTitle).string } strongSelf.interaction.present(TooltipScreen(account: strongSelf.context.account, text: text, icon: nil, location: .point(location.offsetBy(dx: -9.0, dy: 0.0), .right), displayDuration: .custom(3.0), shouldDismissOnTouch: { _ in diff --git a/submodules/NotificationMuteSettingsUI/Sources/NotificationMuteSettingsController.swift b/submodules/NotificationMuteSettingsUI/Sources/NotificationMuteSettingsController.swift index 9de968b3a3..d9346c9003 100644 --- a/submodules/NotificationMuteSettingsUI/Sources/NotificationMuteSettingsController.swift +++ b/submodules/NotificationMuteSettingsUI/Sources/NotificationMuteSettingsController.swift @@ -2,7 +2,6 @@ import Foundation import UIKit import Display import TelegramCore -import Postbox import TelegramPresentationData import TelegramStringFormatting diff --git a/submodules/NotificationSoundSelectionUI/Sources/NotificationSoundSelection.swift b/submodules/NotificationSoundSelectionUI/Sources/NotificationSoundSelection.swift index dba477ec7e..0be8217d1e 100644 --- a/submodules/NotificationSoundSelectionUI/Sources/NotificationSoundSelection.swift +++ b/submodules/NotificationSoundSelectionUI/Sources/NotificationSoundSelection.swift @@ -2,7 +2,6 @@ import Foundation import UIKit import Display import SwiftSignalKit -import Postbox import TelegramCore import AVFoundation import TelegramPresentationData diff --git a/submodules/PassportUI/Sources/SecureIdAuthFormContentNode.swift b/submodules/PassportUI/Sources/SecureIdAuthFormContentNode.swift index ca0acecdc2..3b1f79e9fd 100644 --- a/submodules/PassportUI/Sources/SecureIdAuthFormContentNode.swift +++ b/submodules/PassportUI/Sources/SecureIdAuthFormContentNode.swift @@ -57,13 +57,13 @@ final class SecureIdAuthFormContentNode: ASDisplayNode, SecureIdAuthContentNode, let privacyPolicyAttributes = MarkdownAttributeSet(font: infoFont, textColor: theme.list.freeTextColor) let privacyPolicyLinkAttributes = MarkdownAttributeSet(font: infoFont, textColor: theme.list.itemAccentColor, additionalAttributes: [NSAttributedString.Key.underlineStyle.rawValue: NSUnderlineStyle.single.rawValue as NSNumber, TelegramTextAttributes.URL: privacyPolicyUrl]) - text = parseMarkdownIntoAttributedString(strings.Passport_PrivacyPolicy(peer.displayTitle(strings: strings, displayOrder: nameDisplayOrder), (peer.addressName ?? "")).string.replacingOccurrences(of: "]", with: "]()"), attributes: MarkdownAttributes(body: privacyPolicyAttributes, bold: privacyPolicyAttributes, link: privacyPolicyLinkAttributes, linkAttribute: { _ in + text = parseMarkdownIntoAttributedString(strings.Passport_PrivacyPolicy(EnginePeer(peer).displayTitle(strings: strings, displayOrder: nameDisplayOrder), (EnginePeer(peer).addressName ?? "")).string.replacingOccurrences(of: "]", with: "]()"), attributes: MarkdownAttributes(body: privacyPolicyAttributes, bold: privacyPolicyAttributes, link: privacyPolicyLinkAttributes, linkAttribute: { _ in return nil }), textAlignment: .center) } else { - text = NSAttributedString(string: strings.Passport_AcceptHelp(peer.displayTitle(strings: strings, displayOrder: nameDisplayOrder), (peer.addressName ?? "")).string, font: infoFont, textColor: theme.list.freeTextColor, paragraphAlignment: .left) + text = NSAttributedString(string: strings.Passport_AcceptHelp(EnginePeer(peer).displayTitle(strings: strings, displayOrder: nameDisplayOrder), (peer.addressName ?? "")).string, font: infoFont, textColor: theme.list.freeTextColor, paragraphAlignment: .left) } self.textNode.attributedText = text diff --git a/submodules/PassportUI/Sources/SecureIdAuthHeaderNode.swift b/submodules/PassportUI/Sources/SecureIdAuthHeaderNode.swift index 9cd9360036..0312848ef9 100644 --- a/submodules/PassportUI/Sources/SecureIdAuthHeaderNode.swift +++ b/submodules/PassportUI/Sources/SecureIdAuthHeaderNode.swift @@ -54,7 +54,7 @@ final class SecureIdAuthHeaderNode: ASDisplayNode { func updateState(formData: SecureIdEncryptedFormData?, verificationState: SecureIdAuthControllerVerificationState) { if let formData = formData { self.serviceAvatarNode.setPeer(context: self.context, theme: self.theme, peer: EnginePeer(formData.servicePeer)) - let titleData = self.strings.Passport_RequestHeader(formData.servicePeer.displayTitle(strings: self.strings, displayOrder: self.nameDisplayOrder)) + let titleData = self.strings.Passport_RequestHeader(EnginePeer(formData.servicePeer).displayTitle(strings: self.strings, displayOrder: self.nameDisplayOrder)) let titleString = NSMutableAttributedString() titleString.append(NSAttributedString(string: titleData.string, font: textFont, textColor: self.theme.list.freeTextColor)) diff --git a/submodules/PeerAvatarGalleryUI/Sources/AvatarGalleryItemFooterContentNode.swift b/submodules/PeerAvatarGalleryUI/Sources/AvatarGalleryItemFooterContentNode.swift index aedbe340bb..c75cba79f5 100644 --- a/submodules/PeerAvatarGalleryUI/Sources/AvatarGalleryItemFooterContentNode.swift +++ b/submodules/PeerAvatarGalleryUI/Sources/AvatarGalleryItemFooterContentNode.swift @@ -107,7 +107,7 @@ final class AvatarGalleryItemFooterContentNode: GalleryFooterContentNode { var buttonText: String? switch entry { case let .image(_, _, _, videoRepresentations, peer, date, _, _, _, _): - nameText = peer?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? "" + nameText = peer.flatMap(EnginePeer.init)?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? "" if let date = date { dateText = humanReadableStringForTimestamp(strings: self.strings, dateTimeFormat: self.dateTimeFormat, timestamp: date).string } diff --git a/submodules/PeerInfoUI/Sources/ChannelAdminController.swift b/submodules/PeerInfoUI/Sources/ChannelAdminController.swift index d2a480debb..21d8807251 100644 --- a/submodules/PeerInfoUI/Sources/ChannelAdminController.swift +++ b/submodules/PeerInfoUI/Sources/ChannelAdminController.swift @@ -286,7 +286,7 @@ private enum ChannelAdminEntry: ItemListNodeEntry { let arguments = arguments as! ChannelAdminControllerArguments switch self { case let .info(_, _, dateTimeFormat, peer, presence): - return ItemListAvatarAndNameInfoItem(accountContext: arguments.context, presentationData: presentationData, dateTimeFormat: dateTimeFormat, mode: .generic, peer: peer, presence: presence, cachedData: nil, state: ItemListAvatarAndNameInfoItemState(), sectionId: self.section, style: .blocks(withTopInset: true, withExtendedBottomInset: false), editingNameUpdated: { _ in + return ItemListAvatarAndNameInfoItem(accountContext: arguments.context, presentationData: presentationData, dateTimeFormat: dateTimeFormat, mode: .generic, peer: EnginePeer(peer), presence: presence.flatMap(EnginePeer.Presence.init), memberCount: nil, state: ItemListAvatarAndNameInfoItemState(), sectionId: self.section, style: .blocks(withTopInset: true, withExtendedBottomInset: false), editingNameUpdated: { _ in }, avatarTapped: { }) case let .rankTitle(_, text, count, limit): @@ -987,9 +987,9 @@ public func channelAdminController(context: AccountContext, updatedPresentationD if let admin = adminView.peers[adminView.peerId] { switch channel.info { case .broadcast: - text = presentationData.strings.Privacy_GroupsAndChannels_InviteToChannelError(admin.compactDisplayTitle, admin.compactDisplayTitle).string + text = presentationData.strings.Privacy_GroupsAndChannels_InviteToChannelError(EnginePeer(admin).compactDisplayTitle, EnginePeer(admin).compactDisplayTitle).string case .group: - text = presentationData.strings.Privacy_GroupsAndChannels_InviteToGroupError(admin.compactDisplayTitle, admin.compactDisplayTitle).string + text = presentationData.strings.Privacy_GroupsAndChannels_InviteToGroupError(EnginePeer(admin).compactDisplayTitle, EnginePeer(admin).compactDisplayTitle).string } } case .notMutualContact: @@ -1071,9 +1071,9 @@ public func channelAdminController(context: AccountContext, updatedPresentationD case .restricted: switch channel.info { case .broadcast: - text = presentationData.strings.Privacy_GroupsAndChannels_InviteToChannelError(admin.compactDisplayTitle, admin.compactDisplayTitle).string + text = presentationData.strings.Privacy_GroupsAndChannels_InviteToChannelError(EnginePeer(admin).compactDisplayTitle, EnginePeer(admin).compactDisplayTitle).string case .group: - text = presentationData.strings.Privacy_GroupsAndChannels_InviteToGroupError(admin.compactDisplayTitle, admin.compactDisplayTitle).string + text = presentationData.strings.Privacy_GroupsAndChannels_InviteToGroupError(EnginePeer(admin).compactDisplayTitle, EnginePeer(admin).compactDisplayTitle).string } case .notMutualContact: if case .broadcast = channel.info { @@ -1132,7 +1132,7 @@ public func channelAdminController(context: AccountContext, updatedPresentationD updateRightsDisposable.set((context.engine.peers.addGroupAdmin(peerId: peerId, adminId: adminId) |> deliverOnMainQueue).start(error: { error in if case let .addMemberError(error) = error, case .privacy = error, let admin = adminView.peers[adminView.peerId] { - presentControllerImpl?(textAlertController(context: context, updatedPresentationData: updatedPresentationData, title: nil, text: presentationData.strings.Privacy_GroupsAndChannels_InviteToGroupError(admin.compactDisplayTitle, admin.compactDisplayTitle).string, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), nil) + presentControllerImpl?(textAlertController(context: context, updatedPresentationData: updatedPresentationData, title: nil, text: presentationData.strings.Privacy_GroupsAndChannels_InviteToGroupError(EnginePeer(admin).compactDisplayTitle, EnginePeer(admin).compactDisplayTitle).string, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), nil) } else if case .adminsTooMuch = error { presentControllerImpl?(textAlertController(context: context, updatedPresentationData: updatedPresentationData, title: nil, text: presentationData.strings.Group_ErrorAdminsTooMuch, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), nil) } @@ -1192,7 +1192,7 @@ public func channelAdminController(context: AccountContext, updatedPresentationD if case let .addMemberError(error) = error { var text = presentationData.strings.Login_UnknownError if case .restricted = error, let admin = adminView.peers[adminView.peerId] { - text = presentationData.strings.Privacy_GroupsAndChannels_InviteToGroupError(admin.compactDisplayTitle, admin.compactDisplayTitle).string + text = presentationData.strings.Privacy_GroupsAndChannels_InviteToGroupError(EnginePeer(admin).compactDisplayTitle, EnginePeer(admin).compactDisplayTitle).string } else if case .tooMuchJoined = error { text = presentationData.strings.Invite_ChannelsTooMuch } diff --git a/submodules/PeerInfoUI/Sources/ChannelAdminsController.swift b/submodules/PeerInfoUI/Sources/ChannelAdminsController.swift index ce06586fff..c700fe1955 100644 --- a/submodules/PeerInfoUI/Sources/ChannelAdminsController.swift +++ b/submodules/PeerInfoUI/Sources/ChannelAdminsController.swift @@ -195,7 +195,7 @@ private enum ChannelAdminsEntry: ItemListNodeEntry { if peer.id == participant.peer.id { peerText = strings.Channel_Management_LabelAdministrator } else { - peerText = strings.Channel_Management_PromotedBy(peer.displayTitle(strings: strings, displayOrder: nameDisplayOrder)).string + peerText = strings.Channel_Management_PromotedBy(EnginePeer(peer).displayTitle(strings: strings, displayOrder: nameDisplayOrder)).string } } else { peerText = "" @@ -209,7 +209,7 @@ private enum ChannelAdminsEntry: ItemListNodeEntry { arguments.openAdmin(participant.participant) } } - return ItemListPeerItem(presentationData: presentationData, dateTimeFormat: dateTimeFormat, nameDisplayOrder: nameDisplayOrder, context: arguments.context, peer: participant.peer, presence: nil, text: .text(peerText, .secondary), label: .none, editing: editing, switchValue: nil, enabled: enabled, selectable: true, sectionId: self.section, action: action, setPeerIdWithRevealedOptions: { previousId, id in + return ItemListPeerItem(presentationData: presentationData, dateTimeFormat: dateTimeFormat, nameDisplayOrder: nameDisplayOrder, context: arguments.context, peer: EnginePeer(participant.peer), presence: nil, text: .text(peerText, .secondary), label: .none, editing: editing, switchValue: nil, enabled: enabled, selectable: true, sectionId: self.section, action: action, setPeerIdWithRevealedOptions: { previousId, id in arguments.setPeerIdWithRevealedOptions(previousId, id) }, removePeer: { peerId in arguments.removeAdmin(peerId) @@ -516,7 +516,7 @@ public func channelAdminsController(context: AccountContext, updatedPresentation guard let peer = peer, let user = user else { return } - presentControllerImpl?(UndoOverlayController(presentationData: context.sharedContext.currentPresentationData.with { $0 }, content: .succeed(text: presentationData.strings.Channel_OwnershipTransfer_TransferCompleted(user.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)).string), elevatedLayout: false, action: { _ in return false }), nil) + presentControllerImpl?(UndoOverlayController(presentationData: context.sharedContext.currentPresentationData.with { $0 }, content: .succeed(text: presentationData.strings.Channel_OwnershipTransfer_TransferCompleted(EnginePeer(user).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), EnginePeer(peer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)).string), elevatedLayout: false, action: { _ in return false }), nil) }) } diff --git a/submodules/PeerInfoUI/Sources/ChannelBannedMemberController.swift b/submodules/PeerInfoUI/Sources/ChannelBannedMemberController.swift index fc31836b57..92df566a89 100644 --- a/submodules/PeerInfoUI/Sources/ChannelBannedMemberController.swift +++ b/submodules/PeerInfoUI/Sources/ChannelBannedMemberController.swift @@ -207,7 +207,7 @@ private enum ChannelBannedMemberEntry: ItemListNodeEntry { let arguments = arguments as! ChannelBannedMemberControllerArguments switch self { case let .info(_, _, dateTimeFormat, peer, presence): - return ItemListAvatarAndNameInfoItem(accountContext: arguments.context, presentationData: presentationData, dateTimeFormat: dateTimeFormat, mode: .generic, peer: peer, presence: presence, cachedData: nil, state: ItemListAvatarAndNameInfoItemState(), sectionId: self.section, style: .blocks(withTopInset: true, withExtendedBottomInset: false), editingNameUpdated: { _ in + return ItemListAvatarAndNameInfoItem(accountContext: arguments.context, presentationData: presentationData, dateTimeFormat: dateTimeFormat, mode: .generic, peer: EnginePeer(peer), presence: presence.flatMap(EnginePeer.Presence.init), memberCount: nil, state: ItemListAvatarAndNameInfoItemState(), sectionId: self.section, style: .blocks(withTopInset: true, withExtendedBottomInset: false), editingNameUpdated: { _ in }, avatarTapped: { }) case let .rightsHeader(_, text): @@ -300,7 +300,7 @@ private func channelBannedMemberControllerEntries(presentationData: Presentation entries.append(.timeout(presentationData.theme, presentationData.strings.GroupPermission_Duration, currentTimeoutString)) if let initialParticipant = initialParticipant, case let .member(_, _, _, banInfo?, _) = initialParticipant, let initialBannedBy = initialBannedBy { - entries.append(.exceptionInfo(presentationData.theme, presentationData.strings.GroupPermission_AddedInfo(initialBannedBy.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), stringForRelativeSymbolicTimestamp(strings: presentationData.strings, relativeTimestamp: banInfo.timestamp, relativeTo: state.referenceTimestamp, dateTimeFormat: presentationData.dateTimeFormat)).string)) + entries.append(.exceptionInfo(presentationData.theme, presentationData.strings.GroupPermission_AddedInfo(EnginePeer(initialBannedBy).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), stringForRelativeSymbolicTimestamp(strings: presentationData.strings, relativeTimestamp: banInfo.timestamp, relativeTo: state.referenceTimestamp, dateTimeFormat: presentationData.dateTimeFormat)).string)) entries.append(.delete(presentationData.theme, presentationData.strings.GroupPermission_Delete)) } } else if let group = channelView.peers[channelView.peerId] as? TelegramGroup, let member = memberView.peers[memberView.peerId] { @@ -346,7 +346,7 @@ private func channelBannedMemberControllerEntries(presentationData: Presentation entries.append(.timeout(presentationData.theme, presentationData.strings.GroupPermission_Duration, currentTimeoutString)) if let initialParticipant = initialParticipant, case let .member(_, _, _, banInfo?, _) = initialParticipant, let initialBannedBy = initialBannedBy { - entries.append(.exceptionInfo(presentationData.theme, presentationData.strings.GroupPermission_AddedInfo(initialBannedBy.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), stringForRelativeSymbolicTimestamp(strings: presentationData.strings, relativeTimestamp: banInfo.timestamp, relativeTo: state.referenceTimestamp, dateTimeFormat: presentationData.dateTimeFormat)).string)) + entries.append(.exceptionInfo(presentationData.theme, presentationData.strings.GroupPermission_AddedInfo(EnginePeer(initialBannedBy).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), stringForRelativeSymbolicTimestamp(strings: presentationData.strings, relativeTimestamp: banInfo.timestamp, relativeTo: state.referenceTimestamp, dateTimeFormat: presentationData.dateTimeFormat)).string)) entries.append(.delete(presentationData.theme, presentationData.strings.GroupPermission_Delete)) } } @@ -695,7 +695,7 @@ public func channelBannedMemberController(context: AccountContext, updatedPresen let presentationData = updatedPresentationData?.initial ?? context.sharedContext.currentPresentationData.with { $0 } let actionSheet = ActionSheetController(presentationData: presentationData) var items: [ActionSheetItem] = [] - items.append(ActionSheetTextItem(title: presentationData.strings.GroupPermission_ApplyAlertText(peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)).string)) + items.append(ActionSheetTextItem(title: presentationData.strings.GroupPermission_ApplyAlertText(EnginePeer(peer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)).string)) items.append(ActionSheetButtonItem(title: presentationData.strings.GroupPermission_ApplyAlertAction, color: .accent, font: .default, enabled: true, action: { [weak actionSheet] in actionSheet?.dismissAnimated() applyRights() diff --git a/submodules/PeerInfoUI/Sources/ChannelBlacklistController.swift b/submodules/PeerInfoUI/Sources/ChannelBlacklistController.swift index 18e12f9ab4..71f351c140 100644 --- a/submodules/PeerInfoUI/Sources/ChannelBlacklistController.swift +++ b/submodules/PeerInfoUI/Sources/ChannelBlacklistController.swift @@ -163,12 +163,12 @@ private enum ChannelBlacklistEntry: ItemListNodeEntry { switch participant.participant { case let .member(_, _, _, banInfo, _): if let banInfo = banInfo, let peer = participant.peers[banInfo.restrictedBy] { - text = .text(strings.Channel_Management_RemovedBy(peer.displayTitle(strings: strings, displayOrder: nameDisplayOrder)).string, .secondary) + text = .text(strings.Channel_Management_RemovedBy(EnginePeer(peer).displayTitle(strings: strings, displayOrder: nameDisplayOrder)).string, .secondary) } default: break } - return ItemListPeerItem(presentationData: presentationData, dateTimeFormat: dateTimeFormat, nameDisplayOrder: nameDisplayOrder, context: arguments.context, peer: participant.peer, presence: nil, text: text, label: .none, editing: editing, switchValue: nil, enabled: enabled, selectable: true, sectionId: self.section, action: { + return ItemListPeerItem(presentationData: presentationData, dateTimeFormat: dateTimeFormat, nameDisplayOrder: nameDisplayOrder, context: arguments.context, peer: EnginePeer(participant.peer), presence: nil, text: text, label: .none, editing: editing, switchValue: nil, enabled: enabled, selectable: true, sectionId: self.section, action: { arguments.openPeer(participant) }, setPeerIdWithRevealedOptions: { previousId, id in arguments.setPeerIdWithRevealedOptions(previousId, id) @@ -356,8 +356,8 @@ public func channelBlacklistController(context: AccountContext, updatedPresentat let presentationData = context.sharedContext.currentPresentationData.with { $0 } let actionSheet = ActionSheetController(presentationData: presentationData) var items: [ActionSheetItem] = [] - if !participant.peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder).isEmpty { - items.append(ActionSheetTextItem(title: participant.peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder))) + if !EnginePeer(participant.peer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder).isEmpty { + items.append(ActionSheetTextItem(title: EnginePeer(participant.peer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder))) } let viewInfoTitle: String if participant.peer is TelegramChannel { diff --git a/submodules/PeerInfoUI/Sources/ChannelDiscussionGroupActionSheetItem.swift b/submodules/PeerInfoUI/Sources/ChannelDiscussionGroupActionSheetItem.swift index 10eb8591c4..2418f972f1 100644 --- a/submodules/PeerInfoUI/Sources/ChannelDiscussionGroupActionSheetItem.swift +++ b/submodules/PeerInfoUI/Sources/ChannelDiscussionGroupActionSheetItem.swift @@ -70,9 +70,9 @@ private final class ChannelDiscussionGroupActionSheetItemNode: ActionSheetItemNo let text: PresentationStrings.FormattedString if let channelPeer = channelPeer as? TelegramChannel, let addressName = channelPeer.addressName, !addressName.isEmpty { - text = strings.Channel_DiscussionGroup_PublicChannelLink(groupPeer.displayTitle(strings: strings, displayOrder: nameDisplayOrder), channelPeer.displayTitle(strings: strings, displayOrder: nameDisplayOrder)) + text = strings.Channel_DiscussionGroup_PublicChannelLink(EnginePeer(groupPeer).displayTitle(strings: strings, displayOrder: nameDisplayOrder), EnginePeer(channelPeer).displayTitle(strings: strings, displayOrder: nameDisplayOrder)) } else { - text = strings.Channel_DiscussionGroup_PrivateChannelLink(groupPeer.displayTitle(strings: strings, displayOrder: nameDisplayOrder), channelPeer.displayTitle(strings: strings, displayOrder: nameDisplayOrder)) + text = strings.Channel_DiscussionGroup_PrivateChannelLink(EnginePeer(groupPeer).displayTitle(strings: strings, displayOrder: nameDisplayOrder), EnginePeer(channelPeer).displayTitle(strings: strings, displayOrder: nameDisplayOrder)) } let textFont = Font.regular(floor(theme.baseFontSize * 14.0 / 17.0)) diff --git a/submodules/PeerInfoUI/Sources/ChannelDiscussionGroupSearchContainerNode.swift b/submodules/PeerInfoUI/Sources/ChannelDiscussionGroupSearchContainerNode.swift index 1f93629c74..ff3bb6b05f 100644 --- a/submodules/PeerInfoUI/Sources/ChannelDiscussionGroupSearchContainerNode.swift +++ b/submodules/PeerInfoUI/Sources/ChannelDiscussionGroupSearchContainerNode.swift @@ -71,7 +71,7 @@ private final class ChannelDiscussionGroupSearchEntry: Comparable, Identifiable func item(context: AccountContext, presentationData: PresentationData, interaction: ChannelDiscussionGroupSearchInteraction) -> ListViewItem { switch self.content { case let .peer(peer): - return ContactsPeerItem(presentationData: ItemListPresentationData(presentationData), sortOrder: .firstLast, displayOrder: .firstLast, context: context, peerMode: .peer, peer: .peer(peer: peer, chatPeer: peer), status: .none, enabled: true, selection: .none, editing: ContactsPeerItemEditing(editable: false, editing: false, revealed: false), index: nil, header: nil, action: { _ in + return ContactsPeerItem(presentationData: ItemListPresentationData(presentationData), sortOrder: .firstLast, displayOrder: .firstLast, context: context, peerMode: .peer, peer: .peer(peer: EnginePeer(peer), chatPeer: EnginePeer(peer)), status: .none, enabled: true, selection: .none, editing: ContactsPeerItemEditing(editable: false, editing: false, revealed: false), index: nil, header: nil, action: { _ in interaction.peerSelected(peer) }) } diff --git a/submodules/PeerInfoUI/Sources/ChannelDiscussionGroupSetupController.swift b/submodules/PeerInfoUI/Sources/ChannelDiscussionGroupSetupController.swift index d0c546daef..1472a72073 100644 --- a/submodules/PeerInfoUI/Sources/ChannelDiscussionGroupSetupController.swift +++ b/submodules/PeerInfoUI/Sources/ChannelDiscussionGroupSetupController.swift @@ -156,7 +156,7 @@ private enum ChannelDiscussionGroupSetupControllerEntry: ItemListNodeEntry { } else { text = strings.Channel_DiscussionGroup_PrivateChannel } - return ItemListPeerItem(presentationData: presentationData, dateTimeFormat: PresentationDateTimeFormat(), nameDisplayOrder: nameOrder, context: arguments.context, peer: peer, aliasHandling: .standard, nameStyle: .plain, presence: nil, text: .text(text, .secondary), label: .none, editing: ItemListPeerItemEditing(editable: false, editing: false, revealed: false), revealOptions: nil, switchValue: nil, enabled: true, selectable: true, sectionId: self.section, action: { + return ItemListPeerItem(presentationData: presentationData, dateTimeFormat: PresentationDateTimeFormat(), nameDisplayOrder: nameOrder, context: arguments.context, peer: EnginePeer(peer), aliasHandling: .standard, nameStyle: .plain, presence: nil, text: .text(text, .secondary), label: .none, editing: ItemListPeerItemEditing(editable: false, editing: false, revealed: false), revealOptions: nil, switchValue: nil, enabled: true, selectable: true, sectionId: self.section, action: { arguments.selectGroup(peer.id) }, setPeerIdWithRevealedOptions: { _, _ in }, removePeer: { _ in }) case let .groupsInfo(_, title): @@ -181,9 +181,9 @@ private func channelDiscussionGroupSetupControllerEntries(presentationData: Pres if case let .known(maybeLinkedDiscussionPeerId) = cachedData.linkedDiscussionPeerId, let linkedDiscussionPeerId = maybeLinkedDiscussionPeerId { if let group = view.peers[linkedDiscussionPeerId] { if case .group = peer.info { - entries.append(.header(presentationData.theme, presentationData.strings, group.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), true, presentationData.strings.Channel_DiscussionGroup_HeaderLabel)) + entries.append(.header(presentationData.theme, presentationData.strings, EnginePeer(group).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), true, presentationData.strings.Channel_DiscussionGroup_HeaderLabel)) } else { - entries.append(.header(presentationData.theme, presentationData.strings, group.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), false, presentationData.strings.Channel_DiscussionGroup_HeaderLabel)) + entries.append(.header(presentationData.theme, presentationData.strings, EnginePeer(group).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), false, presentationData.strings.Channel_DiscussionGroup_HeaderLabel)) } entries.append(.group(0, presentationData.theme, presentationData.strings, group, presentationData.nameDisplayOrder)) @@ -258,7 +258,7 @@ public func channelDiscussionGroupSetupController(context: AccountContext, updat return } let presentationData = context.sharedContext.currentPresentationData.with { $0 } - pushControllerImpl?(context.sharedContext.makeCreateGroupController(context: context, peerIds: [], initialTitle: peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) + " Chat", mode: .supergroup, completion: { groupId, dismiss in + pushControllerImpl?(context.sharedContext.makeCreateGroupController(context: context, peerIds: [], initialTitle: EnginePeer(peer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) + " Chat", mode: .supergroup, completion: { groupId, dismiss in var applySignal = context.engine.peers.updateGroupDiscussionForChannel(channelId: peerId, groupId: groupId) var cancelImpl: (() -> Void)? let progressSignal = Signal { subscriber in diff --git a/submodules/PeerInfoUI/Sources/ChannelInfoController.swift b/submodules/PeerInfoUI/Sources/ChannelInfoController.swift index 917209a4f7..3d4acfa6ca 100644 --- a/submodules/PeerInfoUI/Sources/ChannelInfoController.swift +++ b/submodules/PeerInfoUI/Sources/ChannelInfoController.swift @@ -327,7 +327,7 @@ private enum ChannelInfoEntry: ItemListNodeEntry { let arguments = arguments as! ChannelInfoControllerArguments switch self { case let .info(_, _, dateTimeFormat, peer, cachedData, state, updatingAvatar): - return ItemListAvatarAndNameInfoItem(accountContext: arguments.context, presentationData: presentationData, dateTimeFormat: dateTimeFormat, mode: .generic, peer: peer, presence: nil, cachedData: cachedData, state: state, sectionId: self.section, style: .plain, editingNameUpdated: { editingName in + return ItemListAvatarAndNameInfoItem(accountContext: arguments.context, presentationData: presentationData, dateTimeFormat: dateTimeFormat, mode: .generic, peer: peer.flatMap(EnginePeer.init), presence: nil, memberCount: (cachedData as? CachedChannelData)?.participantsSummary.memberCount.flatMap(Int.init), state: state, sectionId: self.section, style: .plain, editingNameUpdated: { editingName in arguments.updateEditingName(editingName) }, avatarTapped: { arguments.tapAvatarAction() @@ -500,7 +500,7 @@ private func channelInfoEntries(account: Account, presentationData: Presentation if let addressName = peer.addressName, !addressName.isEmpty { discussionGroupTitle = "@\(addressName)" } else { - discussionGroupTitle = peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) + discussionGroupTitle = EnginePeer(peer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) } } else { discussionGroupTitle = presentationData.strings.Channel_DiscussionGroupAdd @@ -535,7 +535,7 @@ private func channelInfoEntries(account: Account, presentationData: Presentation if let addressName = peer.addressName, !addressName.isEmpty { discussionGroupTitle = "@\(addressName)" } else { - discussionGroupTitle = peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) + discussionGroupTitle = EnginePeer(peer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) } } else if canEditChannel { discussionGroupTitle = presentationData.strings.Channel_DiscussionGroupAdd @@ -756,7 +756,7 @@ public func channelInfoController(context: AccountContext, peerId: PeerId) -> Vi let mixin = TGMediaAvatarMenuMixin(context: legacyController.context, parentController: emptyController, hasSearchButton: true, hasDeleteButton: hasPhotos, hasViewButton: false, personalPhoto: false, isVideo: false, saveEditedPhotos: false, saveCapturedMedia: false, signup: true)! let _ = currentAvatarMixin.swap(mixin) mixin.requestSearchController = { assetsController in - let controller = WebSearchController(context: context, peer: peer, chatLocation: nil, configuration: searchBotsConfiguration, mode: .avatar(initialQuery: peer?.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), completion: { result in + let controller = WebSearchController(context: context, peer: peer, chatLocation: nil, configuration: searchBotsConfiguration, mode: .avatar(initialQuery: peer.flatMap(EnginePeer.init)?.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), completion: { result in assetsController?.dismiss() completedImpl(result) })) @@ -1027,7 +1027,7 @@ public func channelInfoController(context: AccountContext, peerId: PeerId) -> Vi text = about } updateState { state in - return state.withUpdatedEditingState(ChannelInfoEditingState(editingName: ItemListAvatarAndNameInfoItemName(channel), editingDescriptionText: text)) + return state.withUpdatedEditingState(ChannelInfoEditingState(editingName: ItemListAvatarAndNameInfoItemName(EnginePeer(channel)), editingDescriptionText: text)) } } }) diff --git a/submodules/PeerInfoUI/Sources/ChannelMembersController.swift b/submodules/PeerInfoUI/Sources/ChannelMembersController.swift index 2276f0b775..f52fb48cdb 100644 --- a/submodules/PeerInfoUI/Sources/ChannelMembersController.swift +++ b/submodules/PeerInfoUI/Sources/ChannelMembersController.swift @@ -172,7 +172,7 @@ private enum ChannelMembersEntry: ItemListNodeEntry { } else { text = .presence } - return ItemListPeerItem(presentationData: presentationData, dateTimeFormat: dateTimeFormat, nameDisplayOrder: nameDisplayOrder, context: arguments.context, peer: participant.peer, presence: participant.presences[participant.peer.id], text: text, label: .none, editing: editing, switchValue: nil, enabled: enabled, selectable: participant.peer.id != arguments.context.account.peerId, sectionId: self.section, action: { + return ItemListPeerItem(presentationData: presentationData, dateTimeFormat: dateTimeFormat, nameDisplayOrder: nameDisplayOrder, context: arguments.context, peer: EnginePeer(participant.peer), presence: participant.presences[participant.peer.id].flatMap(EnginePeer.Presence.init), text: text, label: .none, editing: editing, switchValue: nil, enabled: enabled, selectable: participant.peer.id != arguments.context.account.peerId, sectionId: self.section, action: { arguments.openPeer(participant.peer) }, setPeerIdWithRevealedOptions: { previousId, id in arguments.setPeerIdWithRevealedOptions(previousId, id) diff --git a/submodules/PeerInfoUI/Sources/ChannelMembersSearchContainerNode.swift b/submodules/PeerInfoUI/Sources/ChannelMembersSearchContainerNode.swift index 412bd2d7df..42738eb394 100644 --- a/submodules/PeerInfoUI/Sources/ChannelMembersSearchContainerNode.swift +++ b/submodules/PeerInfoUI/Sources/ChannelMembersSearchContainerNode.swift @@ -153,7 +153,7 @@ private final class ChannelMembersSearchEntry: Comparable, Identifiable { func item(context: AccountContext, presentationData: PresentationData, nameSortOrder: PresentationPersonNameOrder, nameDisplayOrder: PresentationPersonNameOrder, interaction: ChannelMembersSearchContainerInteraction) -> ListViewItem { switch self.content { case let .peer(peer): - return ContactsPeerItem(presentationData: ItemListPresentationData(presentationData), sortOrder: nameSortOrder, displayOrder: nameDisplayOrder, context: context, peerMode: .peer, peer: .peer(peer: peer, chatPeer: peer), status: .none, enabled: true, selection: .none, editing: ContactsPeerItemEditing(editable: false, editing: false, revealed: false), index: nil, header: self.section.chatListHeaderType.flatMap({ ChatListSearchItemHeader(type: $0, theme: presentationData.theme, strings: presentationData.strings, actionTitle: nil, action: nil) }), action: { _ in + return ContactsPeerItem(presentationData: ItemListPresentationData(presentationData), sortOrder: nameSortOrder, displayOrder: nameDisplayOrder, context: context, peerMode: .peer, peer: .peer(peer: EnginePeer(peer), chatPeer: EnginePeer(peer)), status: .none, enabled: true, selection: .none, editing: ContactsPeerItemEditing(editable: false, editing: false, revealed: false), index: nil, header: self.section.chatListHeaderType.flatMap({ ChatListSearchItemHeader(type: $0, theme: presentationData.theme, strings: presentationData.strings, actionTitle: nil, action: nil) }), action: { _ in interaction.peerSelected(peer, nil) }) case let .participant(participant, label, revealActions, revealed, enabled): @@ -161,7 +161,7 @@ private final class ChannelMembersSearchEntry: Comparable, Identifiable { if let label = label { status = .custom(string: label, multiline: false) } else if let presence = participant.presences[participant.peer.id], self.addIcon { - status = .presence(presence, dateTimeFormat) + status = .presence(EnginePeer.Presence(presence), dateTimeFormat) } else { status = .none } @@ -187,7 +187,7 @@ private final class ChannelMembersSearchEntry: Comparable, Identifiable { actionIcon = .add } - return ContactsPeerItem(presentationData: ItemListPresentationData(presentationData), sortOrder: nameSortOrder, displayOrder: nameDisplayOrder, context: context, peerMode: .peer, peer: .peer(peer: participant.peer, chatPeer: participant.peer), status: status, enabled: enabled, selection: .none, editing: ContactsPeerItemEditing(editable: false, editing: false, revealed: revealed), options: options, actionIcon: actionIcon, index: nil, header: self.section.chatListHeaderType.flatMap({ ChatListSearchItemHeader(type: $0, theme: presentationData.theme, strings: presentationData.strings, actionTitle: nil, action: nil) }), action: { _ in + return ContactsPeerItem(presentationData: ItemListPresentationData(presentationData), sortOrder: nameSortOrder, displayOrder: nameDisplayOrder, context: context, peerMode: .peer, peer: .peer(peer: EnginePeer(participant.peer), chatPeer: EnginePeer(participant.peer)), status: status, enabled: enabled, selection: .none, editing: ContactsPeerItemEditing(editable: false, editing: false, revealed: revealed), options: options, actionIcon: actionIcon, index: nil, header: self.section.chatListHeaderType.flatMap({ ChatListSearchItemHeader(type: $0, theme: presentationData.theme, strings: presentationData.strings, actionTitle: nil, action: nil) }), action: { _ in interaction.peerSelected(participant.peer, participant) }, setPeerIdWithRevealedOptions: { peerId, fromPeerId in interaction.setPeerIdWithRevealedOptions(RevealedPeerId(peerId: participant.peer.id, section: self.section), fromPeerId.flatMap({ RevealedPeerId(peerId: $0, section: self.section) })) @@ -816,7 +816,7 @@ public final class ChannelMembersSearchContainerNode: SearchDisplayControllerCon if peer.id == participant.peer.id { label = presentationData.strings.Channel_Management_LabelAdministrator } else { - label = presentationData.strings.Channel_Management_PromotedBy(peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)).string + label = presentationData.strings.Channel_Management_PromotedBy(EnginePeer(peer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)).string } } } @@ -843,7 +843,7 @@ public final class ChannelMembersSearchContainerNode: SearchDisplayControllerCon switch participant.participant { case let .member(_, _, _, banInfo, _): if let banInfo = banInfo, let peer = participant.peers[banInfo.restrictedBy] { - label = presentationData.strings.Channel_Management_RemovedBy(peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)).string + label = presentationData.strings.Channel_Management_RemovedBy(EnginePeer(peer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)).string } default: break @@ -1076,7 +1076,7 @@ public final class ChannelMembersSearchContainerNode: SearchDisplayControllerCon if peer.id == participant.peer.id { label = presentationData.strings.Channel_Management_LabelAdministrator } else { - label = presentationData.strings.Channel_Management_PromotedBy(peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)).string + label = presentationData.strings.Channel_Management_PromotedBy(EnginePeer(peer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)).string } } } @@ -1103,7 +1103,7 @@ public final class ChannelMembersSearchContainerNode: SearchDisplayControllerCon switch participant.participant { case let .member(_, _, _, banInfo, _): if let banInfo = banInfo, let peer = participant.peers[banInfo.restrictedBy] { - label = presentationData.strings.Channel_Management_RemovedBy(peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)).string + label = presentationData.strings.Channel_Management_RemovedBy(EnginePeer(peer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)).string } default: break diff --git a/submodules/PeerInfoUI/Sources/ChannelMembersSearchControllerNode.swift b/submodules/PeerInfoUI/Sources/ChannelMembersSearchControllerNode.swift index c39a065c98..e55cb6ead0 100644 --- a/submodules/PeerInfoUI/Sources/ChannelMembersSearchControllerNode.swift +++ b/submodules/PeerInfoUI/Sources/ChannelMembersSearchControllerNode.swift @@ -133,23 +133,23 @@ private enum ChannelMembersSearchEntry: Comparable, Identifiable { status = .custom(string: label, multiline: false) } else if participant.peer.id != context.account.peerId { let presence = participant.presences[participant.peer.id] ?? TelegramUserPresence(status: .none, lastActivity: 0) - status = .presence(presence, presentationData.dateTimeFormat) + status = .presence(EnginePeer.Presence(presence), presentationData.dateTimeFormat) } else { status = .none } - return ContactsPeerItem(presentationData: ItemListPresentationData(presentationData), sortOrder: nameSortOrder, displayOrder: nameDisplayOrder, context: context, peerMode: .peer, peer: .peer(peer: participant.peer, chatPeer: nil), status: status, enabled: enabled, selection: .none, editing: editing, index: nil, header: ChatListSearchItemHeader(type: .groupMembers, theme: presentationData.theme, strings: presentationData.strings), action: { _ in + return ContactsPeerItem(presentationData: ItemListPresentationData(presentationData), sortOrder: nameSortOrder, displayOrder: nameDisplayOrder, context: context, peerMode: .peer, peer: .peer(peer: EnginePeer(participant.peer), chatPeer: nil), status: status, enabled: enabled, selection: .none, editing: editing, index: nil, header: ChatListSearchItemHeader(type: .groupMembers, theme: presentationData.theme, strings: presentationData.strings), action: { _ in interaction.openPeer(participant.peer, participant) }) case let .contact(_, peer, presence): let status: ContactsPeerItemStatus if peer.id != context.account.peerId, let presence = presence { - status = .presence(presence, presentationData.dateTimeFormat) + status = .presence(EnginePeer.Presence(presence), presentationData.dateTimeFormat) } else { status = .none } - return ContactsPeerItem(presentationData: ItemListPresentationData(presentationData), sortOrder: nameSortOrder, displayOrder: nameDisplayOrder, context: context, peerMode: .peer, peer: .peer(peer: peer, chatPeer: nil), status: status, enabled: true, selection: .none, editing: ContactsPeerItemEditing(editable: false, editing: false, revealed: false), index: nil, header: ChatListSearchItemHeader(type: .contacts, theme: presentationData.theme, strings: presentationData.strings), action: { _ in + return ContactsPeerItem(presentationData: ItemListPresentationData(presentationData), sortOrder: nameSortOrder, displayOrder: nameDisplayOrder, context: context, peerMode: .peer, peer: .peer(peer: EnginePeer(peer), chatPeer: nil), status: status, enabled: true, selection: .none, editing: ContactsPeerItemEditing(editable: false, editing: false, revealed: false), index: nil, header: ChatListSearchItemHeader(type: .contacts, theme: presentationData.theme, strings: presentationData.strings), action: { _ in interaction.openPeer(peer, nil) }) } diff --git a/submodules/PeerInfoUI/Sources/ChannelOwnershipTransferController.swift b/submodules/PeerInfoUI/Sources/ChannelOwnershipTransferController.swift index 61172ab3c7..9c6b04205a 100644 --- a/submodules/PeerInfoUI/Sources/ChannelOwnershipTransferController.swift +++ b/submodules/PeerInfoUI/Sources/ChannelOwnershipTransferController.swift @@ -541,10 +541,10 @@ private func confirmChannelOwnershipTransferController(context: AccountContext, var text: String if isGroup { title = presentationData.strings.Group_OwnershipTransfer_Title - text = presentationData.strings.Group_OwnershipTransfer_DescriptionInfo(peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), member.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)).string + text = presentationData.strings.Group_OwnershipTransfer_DescriptionInfo(EnginePeer(peer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), EnginePeer(member).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)).string } else { title = presentationData.strings.Channel_OwnershipTransfer_Title - text = presentationData.strings.Channel_OwnershipTransfer_DescriptionInfo(peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), member.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)).string + text = presentationData.strings.Channel_OwnershipTransfer_DescriptionInfo(EnginePeer(peer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), EnginePeer(member).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)).string } let attributedTitle = NSAttributedString(string: title, font: Font.medium(17.0), textColor: theme.primaryColor, paragraphAlignment: .center) diff --git a/submodules/PeerInfoUI/Sources/ChannelPermissionsController.swift b/submodules/PeerInfoUI/Sources/ChannelPermissionsController.swift index ff4f0e5c3a..bcbd8082a8 100644 --- a/submodules/PeerInfoUI/Sources/ChannelPermissionsController.swift +++ b/submodules/PeerInfoUI/Sources/ChannelPermissionsController.swift @@ -315,7 +315,7 @@ private enum ChannelPermissionsEntry: ItemListNodeEntry { default: break } - return ItemListPeerItem(presentationData: presentationData, dateTimeFormat: dateTimeFormat, nameDisplayOrder: nameDisplayOrder, context: arguments.context, peer: participant.peer, presence: nil, text: text, label: .none, editing: editing, switchValue: nil, enabled: enabled, selectable: true, sectionId: self.section, action: canOpen ? { + return ItemListPeerItem(presentationData: presentationData, dateTimeFormat: dateTimeFormat, nameDisplayOrder: nameDisplayOrder, context: arguments.context, peer: EnginePeer(participant.peer), presence: nil, text: text, label: .none, editing: editing, switchValue: nil, enabled: enabled, selectable: true, sectionId: self.section, action: canOpen ? { arguments.openPeer(participant.participant) } : { arguments.openPeerInfo(participant.peer) diff --git a/submodules/PeerInfoUI/Sources/ChannelVisibilityController.swift b/submodules/PeerInfoUI/Sources/ChannelVisibilityController.swift index 27b8f92b3a..6d9e63b974 100644 --- a/submodules/PeerInfoUI/Sources/ChannelVisibilityController.swift +++ b/submodules/PeerInfoUI/Sources/ChannelVisibilityController.swift @@ -350,7 +350,7 @@ private enum ChannelVisibilityEntry: ItemListNodeEntry { if let addressName = peer.addressName { label = "t.me/" + addressName } - return ItemListPeerItem(presentationData: presentationData, dateTimeFormat: dateTimeFormat, nameDisplayOrder: nameDisplayOrder, context: arguments.context, peer: peer, presence: nil, text: .text(label, .secondary), label: .none, editing: editing, switchValue: nil, enabled: enabled, selectable: true, sectionId: self.section, action: nil, setPeerIdWithRevealedOptions: { previousId, id in + return ItemListPeerItem(presentationData: presentationData, dateTimeFormat: dateTimeFormat, nameDisplayOrder: nameDisplayOrder, context: arguments.context, peer: EnginePeer(peer), presence: nil, text: .text(label, .secondary), label: .none, editing: editing, switchValue: nil, enabled: enabled, selectable: true, sectionId: self.section, action: nil, setPeerIdWithRevealedOptions: { previousId, id in arguments.setPeerIdWithRevealedOptions(previousId, id) }, removePeer: { peerId in arguments.revokePeerId(peerId) diff --git a/submodules/PeerInfoUI/Sources/DeviceContactInfoController.swift b/submodules/PeerInfoUI/Sources/DeviceContactInfoController.swift index c63e72654f..22a49b17b2 100644 --- a/submodules/PeerInfoUI/Sources/DeviceContactInfoController.swift +++ b/submodules/PeerInfoUI/Sources/DeviceContactInfoController.swift @@ -396,7 +396,7 @@ private enum DeviceContactInfoEntry: ItemListNodeEntry { let arguments = arguments as! DeviceContactInfoControllerArguments switch self { case let .info(_, _, _, dateTimeFormat, peer, state, jobSummary, _): - return ItemListAvatarAndNameInfoItem(accountContext: arguments.context, presentationData: presentationData, dateTimeFormat: dateTimeFormat, mode: .contact, peer: peer, presence: nil, label: jobSummary, cachedData: nil, state: state, sectionId: self.section, style: arguments.isPlain ? .plain : .blocks(withTopInset: false, withExtendedBottomInset: true), editingNameUpdated: { editingName in + return ItemListAvatarAndNameInfoItem(accountContext: arguments.context, presentationData: presentationData, dateTimeFormat: dateTimeFormat, mode: .contact, peer: EnginePeer(peer), presence: nil, label: jobSummary, memberCount: nil, state: state, sectionId: self.section, style: arguments.isPlain ? .plain : .blocks(withTopInset: false, withExtendedBottomInset: true), editingNameUpdated: { editingName in arguments.updateEditingName(editingName) }, avatarTapped: { }, context: nil, call: nil) @@ -685,7 +685,7 @@ private func deviceContactInfoEntries(account: Account, presentationData: Presen } else if !personName.1.isEmpty { personCompactName = personName.1 } else { - personCompactName = peer.compactDisplayTitle + personCompactName = EnginePeer(peer).compactDisplayTitle } if contactData.basicData.phoneNumbers.isEmpty { diff --git a/submodules/PeerInfoUI/Sources/OldChannelsController.swift b/submodules/PeerInfoUI/Sources/OldChannelsController.swift index 8bbd63394d..6700fdfd90 100644 --- a/submodules/PeerInfoUI/Sources/OldChannelsController.swift +++ b/submodules/PeerInfoUI/Sources/OldChannelsController.swift @@ -172,7 +172,7 @@ private enum OldChannelsEntry: ItemListNodeEntry { case let .peersHeader(title): return ItemListSectionHeaderItem(presentationData: presentationData, text: title, sectionId: self.section) case let .peer(_, peer, selected): - return ContactsPeerItem(presentationData: presentationData, style: .blocks, sectionId: self.section, sortOrder: .firstLast, displayOrder: .firstLast, context: arguments.context, peerMode: .peer, peer: .peer(peer: peer.peer, chatPeer: peer.peer), status: .custom(string: localizedOldChannelDate(peer: peer, strings: presentationData.strings), multiline: false), badge: nil, enabled: true, selection: ContactsPeerItemSelection.selectable(selected: selected), editing: ContactsPeerItemEditing(editable: false, editing: false, revealed: false), options: [], actionIcon: .none, index: nil, header: nil, action: { _ in + return ContactsPeerItem(presentationData: presentationData, style: .blocks, sectionId: self.section, sortOrder: .firstLast, displayOrder: .firstLast, context: arguments.context, peerMode: .peer, peer: .peer(peer: EnginePeer(peer.peer), chatPeer: EnginePeer(peer.peer)), status: .custom(string: localizedOldChannelDate(peer: peer, strings: presentationData.strings), multiline: false), badge: nil, enabled: true, selection: ContactsPeerItemSelection.selectable(selected: selected), editing: ContactsPeerItemEditing(editable: false, editing: false, revealed: false), options: [], actionIcon: .none, index: nil, header: nil, action: { _ in arguments.togglePeer(peer.peer.id, true) }, setPeerIdWithRevealedOptions: nil, deletePeer: nil, itemHighlighting: nil, contextAction: nil) } diff --git a/submodules/PeerInfoUI/Sources/OldChannelsSearch.swift b/submodules/PeerInfoUI/Sources/OldChannelsSearch.swift index c508d602f8..776bf8875c 100644 --- a/submodules/PeerInfoUI/Sources/OldChannelsSearch.swift +++ b/submodules/PeerInfoUI/Sources/OldChannelsSearch.swift @@ -141,7 +141,7 @@ private enum OldChannelsSearchEntry: Comparable, Identifiable { func item(context: AccountContext, presentationData: ItemListPresentationData, interaction: OldChannelsSearchInteraction) -> ListViewItem { switch self { case let .peer(_, peer, selected): - return ContactsPeerItem(presentationData: presentationData, style: .plain, sortOrder: .firstLast, displayOrder: .firstLast, context: context, peerMode: .peer, peer: .peer(peer: peer.peer, chatPeer: peer.peer), status: .custom(string: localizedOldChannelDate(peer: peer, strings: presentationData.strings), multiline: false), badge: nil, enabled: true, selection: ContactsPeerItemSelection.selectable(selected: selected), editing: ContactsPeerItemEditing(editable: false, editing: false, revealed: false), options: [], actionIcon: .none, index: nil, header: nil, action: { _ in + return ContactsPeerItem(presentationData: presentationData, style: .plain, sortOrder: .firstLast, displayOrder: .firstLast, context: context, peerMode: .peer, peer: .peer(peer: EnginePeer(peer.peer), chatPeer: EnginePeer(peer.peer)), status: .custom(string: localizedOldChannelDate(peer: peer, strings: presentationData.strings), multiline: false), badge: nil, enabled: true, selection: ContactsPeerItemSelection.selectable(selected: selected), editing: ContactsPeerItemEditing(editable: false, editing: false, revealed: false), options: [], actionIcon: .none, index: nil, header: nil, action: { _ in interaction.togglePeer(peer.peer.id) }, setPeerIdWithRevealedOptions: nil, deletePeer: nil, itemHighlighting: nil, contextAction: nil) } diff --git a/submodules/PeerInfoUI/Sources/SecretChatKeyControllerNode.swift b/submodules/PeerInfoUI/Sources/SecretChatKeyControllerNode.swift index f69303f09f..ac7cb5d653 100644 --- a/submodules/PeerInfoUI/Sources/SecretChatKeyControllerNode.swift +++ b/submodules/PeerInfoUI/Sources/SecretChatKeyControllerNode.swift @@ -118,7 +118,7 @@ final class SecretChatKeyControllerNode: ViewControllerTracingNode { let (keyTextLayout, keyTextApply) = makeKeyTextLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: text, font: Font.semiboldMonospace(15.0), textColor: self.presentationData.theme.list.itemPrimaryTextColor), backgroundColor: nil, maximumNumberOfLines: 0, truncationType: .end, constrainedSize: CGSize(width: layout.size.width - sideInset * 2.0, height: CGFloat.greatestFiniteMagnitude), alignment: .left, lineSpacing: 0.0, cutout: nil, insets: UIEdgeInsets())) - let infoString = self.presentationData.strings.EncryptionKey_Description(self.peer.compactDisplayTitle, self.peer.compactDisplayTitle) + let infoString = self.presentationData.strings.EncryptionKey_Description(EnginePeer(self.peer).compactDisplayTitle, EnginePeer(self.peer).compactDisplayTitle) let infoText = NSMutableAttributedString(string: infoString.string, attributes: [.font: Font.regular(14.0), .foregroundColor: self.presentationData.theme.list.itemPrimaryTextColor]) for range in infoString.ranges { diff --git a/submodules/PeerInfoUI/Sources/UserInfoController.swift b/submodules/PeerInfoUI/Sources/UserInfoController.swift index 15e9e67a66..38df784c36 100644 --- a/submodules/PeerInfoUI/Sources/UserInfoController.swift +++ b/submodules/PeerInfoUI/Sources/UserInfoController.swift @@ -61,7 +61,7 @@ public func openAddPersonContactImpl(context: AccountContext, updatedPresentatio } let presentationData = context.sharedContext.currentPresentationData.with { $0 } - present(OverlayStatusController(theme: presentationData.theme, type: .genericSuccess(presentationData.strings.AddContact_StatusSuccess(peer.compactDisplayTitle).string, true)), nil) + present(OverlayStatusController(theme: presentationData.theme, type: .genericSuccess(presentationData.strings.AddContact_StatusSuccess(EnginePeer(peer).compactDisplayTitle).string, true)), nil) } }), completed: nil, cancelled: nil)) }) diff --git a/submodules/PeerPresenceStatusManager/BUILD b/submodules/PeerPresenceStatusManager/BUILD index f82042b8dd..e5b366749f 100644 --- a/submodules/PeerPresenceStatusManager/BUILD +++ b/submodules/PeerPresenceStatusManager/BUILD @@ -11,7 +11,6 @@ swift_library( ], deps = [ "//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit", - "//submodules/Postbox:Postbox", "//submodules/TelegramCore:TelegramCore", ], visibility = [ diff --git a/submodules/PeerPresenceStatusManager/Sources/PeerPresenceStatusManager.swift b/submodules/PeerPresenceStatusManager/Sources/PeerPresenceStatusManager.swift index c846cc22cd..e173f2f2f4 100644 --- a/submodules/PeerPresenceStatusManager/Sources/PeerPresenceStatusManager.swift +++ b/submodules/PeerPresenceStatusManager/Sources/PeerPresenceStatusManager.swift @@ -2,7 +2,7 @@ import Foundation import SwiftSignalKit import TelegramCore -private func suggestedUserPresenceStringRefreshTimeout(_ presence: TelegramUserPresence, relativeTo timestamp: Int32, isOnline: Bool?) -> Double { +private func suggestedUserPresenceStringRefreshTimeout(_ presence: EnginePeer.Presence, relativeTo timestamp: Int32, isOnline: Bool?) -> Double { switch presence.status { case let .present(statusTimestamp): if statusTimestamp >= timestamp { @@ -28,7 +28,7 @@ private func suggestedUserPresenceStringRefreshTimeout(_ presence: TelegramUserP } else { return Double.infinity } - case .none, .lastWeek, .lastMonth: + case .longTimeAgo, .lastWeek, .lastMonth: return Double.infinity } } @@ -45,7 +45,7 @@ public final class PeerPresenceStatusManager { self.timer?.invalidate() } - public func reset(presence: TelegramUserPresence, isOnline: Bool? = nil) { + public func reset(presence: EnginePeer.Presence, isOnline: Bool? = nil) { self.timer?.invalidate() self.timer = nil diff --git a/submodules/PeersNearbyUI/Sources/PeersNearbyController.swift b/submodules/PeersNearbyUI/Sources/PeersNearbyController.swift index 8f3aff66bb..f89a075977 100644 --- a/submodules/PeersNearbyUI/Sources/PeersNearbyController.swift +++ b/submodules/PeersNearbyUI/Sources/PeersNearbyController.swift @@ -230,7 +230,7 @@ private enum PeersNearbyEntry: ItemListNodeEntry { if isSelfPeer { text = strings.PeopleNearby_VisibleUntil(humanReadableStringForTimestamp(strings: strings, dateTimeFormat: dateTimeFormat, timestamp: peer.expires).string).string } - return ItemListPeerItem(presentationData: presentationData, dateTimeFormat: dateTimeFormat, nameDisplayOrder: nameDisplayOrder, context: arguments.context, peer: peer.peer.0, aliasHandling: .standard, nameColor: .primary, nameStyle: .distinctBold, presence: nil, text: .text(text, .secondary), label: .none, editing: ItemListPeerItemEditing(editable: false, editing: false, revealed: false), revealOptions: nil, switchValue: nil, enabled: true, selectable: !isSelfPeer, sectionId: self.section, action: { + return ItemListPeerItem(presentationData: presentationData, dateTimeFormat: dateTimeFormat, nameDisplayOrder: nameDisplayOrder, context: arguments.context, peer: EnginePeer(peer.peer.0), aliasHandling: .standard, nameColor: .primary, nameStyle: .distinctBold, presence: nil, text: .text(text, .secondary), label: .none, editing: ItemListPeerItemEditing(editable: false, editing: false, revealed: false), revealOptions: nil, switchValue: nil, enabled: true, selectable: !isSelfPeer, sectionId: self.section, action: { if !isSelfPeer { arguments.openProfile(peer.peer.0, peer.distance) } @@ -254,7 +254,7 @@ private enum PeersNearbyEntry: ItemListNodeEntry { } else { text = .text(strings.Map_DistanceAway(shortStringForDistance(strings: strings, distance: peer.distance)).string, .secondary) } - return ItemListPeerItem(presentationData: presentationData, dateTimeFormat: dateTimeFormat, nameDisplayOrder: nameDisplayOrder, context: arguments.context, peer: peer.peer.0, aliasHandling: .standard, nameColor: .primary, nameStyle: .distinctBold, presence: nil, text: text, label: .none, editing: ItemListPeerItemEditing(editable: false, editing: false, revealed: false), revealOptions: nil, switchValue: nil, enabled: true, highlighted: highlighted, selectable: true, sectionId: self.section, action: { + return ItemListPeerItem(presentationData: presentationData, dateTimeFormat: dateTimeFormat, nameDisplayOrder: nameDisplayOrder, context: arguments.context, peer: EnginePeer(peer.peer.0), aliasHandling: .standard, nameColor: .primary, nameStyle: .distinctBold, presence: nil, text: text, label: .none, editing: ItemListPeerItemEditing(editable: false, editing: false, revealed: false), revealOptions: nil, switchValue: nil, enabled: true, highlighted: highlighted, selectable: true, sectionId: self.section, action: { arguments.openChat(peer.peer.0) }, setPeerIdWithRevealedOptions: { _, _ in }, removePeer: { _ in }, toggleUpdated: nil, contextAction: { node, gesture in arguments.contextAction(peer.peer.0, node, gesture) @@ -268,7 +268,7 @@ private enum PeersNearbyEntry: ItemListNodeEntry { } else { text = .text(strings.Map_DistanceAway(shortStringForDistance(strings: strings, distance: peer.distance)).string, .secondary) } - return ItemListPeerItem(presentationData: presentationData, dateTimeFormat: dateTimeFormat, nameDisplayOrder: nameDisplayOrder, context: arguments.context, peer: peer.peer.0, aliasHandling: .standard, nameColor: .primary, nameStyle: .distinctBold, presence: nil, text: text, label: .none, editing: ItemListPeerItemEditing(editable: false, editing: false, revealed: false), revealOptions: nil, switchValue: nil, enabled: true, highlighted: highlighted, selectable: true, sectionId: self.section, action: { + return ItemListPeerItem(presentationData: presentationData, dateTimeFormat: dateTimeFormat, nameDisplayOrder: nameDisplayOrder, context: arguments.context, peer: EnginePeer(peer.peer.0), aliasHandling: .standard, nameColor: .primary, nameStyle: .distinctBold, presence: nil, text: text, label: .none, editing: ItemListPeerItemEditing(editable: false, editing: false, revealed: false), revealOptions: nil, switchValue: nil, enabled: true, highlighted: highlighted, selectable: true, sectionId: self.section, action: { arguments.openChat(peer.peer.0) }, setPeerIdWithRevealedOptions: { _, _ in }, removePeer: { _ in }, toggleUpdated: nil, contextAction: { node, gesture in arguments.contextAction(peer.peer.0, node, gesture) diff --git a/submodules/SettingsUI/BUILD b/submodules/SettingsUI/BUILD index 90dbf66c2a..d2036f4f16 100644 --- a/submodules/SettingsUI/BUILD +++ b/submodules/SettingsUI/BUILD @@ -88,7 +88,6 @@ swift_library( "//submodules/OpenInExternalAppUI:OpenInExternalAppUI", "//submodules/AccountUtils:AccountUtils", "//submodules/AuthTransferUI:AuthTransferUI", - "//submodules/WidgetSetupScreen:WidgetSetupScreen", "//submodules/UIKitRuntimeUtils:UIKitRuntimeUtils", "//submodules/DebugSettingsUI:DebugSettingsUI", "//submodules/WallpaperBackgroundNode:WallpaperBackgroundNode", diff --git a/submodules/SettingsUI/Sources/Data and Storage/DataAndStorageSettingsController.swift b/submodules/SettingsUI/Sources/Data and Storage/DataAndStorageSettingsController.swift index 7b3b219bb9..4b6b0f8130 100644 --- a/submodules/SettingsUI/Sources/Data and Storage/DataAndStorageSettingsController.swift +++ b/submodules/SettingsUI/Sources/Data and Storage/DataAndStorageSettingsController.swift @@ -11,7 +11,6 @@ import ItemListUI import PresentationDataUtils import AccountContext import OpenInExternalAppUI -import WidgetSetupScreen private final class DataAndStorageControllerArguments { let openStorageUsage: () -> Void @@ -27,10 +26,9 @@ private final class DataAndStorageControllerArguments { let toggleDownloadInBackground: (Bool) -> Void let openBrowserSelection: () -> Void let openIntents: () -> Void - let openWidgetSettings: () -> Void let toggleEnableSensitiveContent: (Bool) -> Void - init(openStorageUsage: @escaping () -> Void, openNetworkUsage: @escaping () -> Void, openProxy: @escaping () -> Void, openAutomaticDownloadConnectionType: @escaping (AutomaticDownloadConnectionType) -> Void, resetAutomaticDownload: @escaping () -> Void, openVoiceUseLessData: @escaping () -> Void, openSaveIncomingPhotos: @escaping () -> Void, toggleSaveEditedPhotos: @escaping (Bool) -> Void, toggleAutoplayGifs: @escaping (Bool) -> Void, toggleAutoplayVideos: @escaping (Bool) -> Void, toggleDownloadInBackground: @escaping (Bool) -> Void, openBrowserSelection: @escaping () -> Void, openIntents: @escaping () -> Void, openWidgetSettings: @escaping () -> Void, toggleEnableSensitiveContent: @escaping (Bool) -> Void) { + init(openStorageUsage: @escaping () -> Void, openNetworkUsage: @escaping () -> Void, openProxy: @escaping () -> Void, openAutomaticDownloadConnectionType: @escaping (AutomaticDownloadConnectionType) -> Void, resetAutomaticDownload: @escaping () -> Void, openVoiceUseLessData: @escaping () -> Void, openSaveIncomingPhotos: @escaping () -> Void, toggleSaveEditedPhotos: @escaping (Bool) -> Void, toggleAutoplayGifs: @escaping (Bool) -> Void, toggleAutoplayVideos: @escaping (Bool) -> Void, toggleDownloadInBackground: @escaping (Bool) -> Void, openBrowserSelection: @escaping () -> Void, openIntents: @escaping () -> Void, toggleEnableSensitiveContent: @escaping (Bool) -> Void) { self.openStorageUsage = openStorageUsage self.openNetworkUsage = openNetworkUsage self.openProxy = openProxy @@ -44,7 +42,6 @@ private final class DataAndStorageControllerArguments { self.toggleDownloadInBackground = toggleDownloadInBackground self.openBrowserSelection = openBrowserSelection self.openIntents = openIntents - self.openWidgetSettings = openWidgetSettings self.toggleEnableSensitiveContent = toggleEnableSensitiveContent } } @@ -89,7 +86,6 @@ private enum DataAndStorageEntry: ItemListNodeEntry { case useLessVoiceData(PresentationTheme, String, String) case otherHeader(PresentationTheme, String) case shareSheet(PresentationTheme, String) - case widgetSettings(String) case saveIncomingPhotos(PresentationTheme, String) case saveEditedPhotos(PresentationTheme, String, Bool) case openLinksIn(PresentationTheme, String, String) @@ -109,7 +105,7 @@ private enum DataAndStorageEntry: ItemListNodeEntry { return DataAndStorageSection.autoPlay.rawValue case .voiceCallsHeader, .useLessVoiceData: return DataAndStorageSection.voiceCalls.rawValue - case .otherHeader, .shareSheet, .widgetSettings, .saveIncomingPhotos, .saveEditedPhotos, .openLinksIn, .downloadInBackground, .downloadInBackgroundInfo: + case .otherHeader, .shareSheet, .saveIncomingPhotos, .saveEditedPhotos, .openLinksIn, .downloadInBackground, .downloadInBackgroundInfo: return DataAndStorageSection.other.rawValue case .connectionHeader, .connectionProxy: return DataAndStorageSection.connection.rawValue @@ -146,8 +142,6 @@ private enum DataAndStorageEntry: ItemListNodeEntry { return 11 case .shareSheet: return 12 - case .widgetSettings: - return 13 case .saveIncomingPhotos: return 14 case .saveEditedPhotos: @@ -247,12 +241,6 @@ private enum DataAndStorageEntry: ItemListNodeEntry { } else { return false } - case let .widgetSettings(text): - if case .widgetSettings(text) = rhs { - return true - } else { - return false - } case let .saveIncomingPhotos(lhsTheme, lhsText): if case let .saveIncomingPhotos(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText { return true @@ -357,10 +345,6 @@ private enum DataAndStorageEntry: ItemListNodeEntry { return ItemListDisclosureItem(presentationData: presentationData, title: text, label: "", sectionId: self.section, style: .blocks, action: { arguments.openIntents() }) - case let .widgetSettings(text): - return ItemListDisclosureItem(presentationData: presentationData, title: text, label: "", sectionId: self.section, style: .blocks, action: { - arguments.openWidgetSettings() - }) case let .saveIncomingPhotos(_, text): return ItemListDisclosureItem(presentationData: presentationData, title: text, label: "", sectionId: self.section, style: .blocks, action: { arguments.openSaveIncomingPhotos() @@ -504,9 +488,6 @@ private func dataAndStorageControllerEntries(state: DataAndStorageControllerStat if #available(iOSApplicationExtension 13.2, iOS 13.2, *) { entries.append(.shareSheet(presentationData.theme, presentationData.strings.ChatSettings_IntentsSettings)) } - /*if #available(iOSApplicationExtension 14.0, iOS 14.0, *) { - entries.append(.widgetSettings(presentationData.strings.ChatSettings_WidgetSettings)) - }*/ entries.append(.saveIncomingPhotos(presentationData.theme, presentationData.strings.Settings_SaveIncomingPhotos)) entries.append(.saveEditedPhotos(presentationData.theme, presentationData.strings.Settings_SaveEditedPhotos, data.generatedMediaStoreSettings.storeEditedPhotos)) entries.append(.openLinksIn(presentationData.theme, presentationData.strings.ChatSettings_OpenLinksIn, defaultWebBrowser)) @@ -659,9 +640,6 @@ public func dataAndStorageController(context: AccountContext, focusOnItemTag: Da }, openIntents: { let controller = intentsSettingsController(context: context) pushControllerImpl?(controller) - }, openWidgetSettings: { - let controller = widgetSetupScreen(context: context) - pushControllerImpl?(controller) }, toggleEnableSensitiveContent: { value in let _ = (contentSettingsConfiguration.get() |> take(1) diff --git a/submodules/SettingsUI/Sources/Data and Storage/IntentsSettingsController.swift b/submodules/SettingsUI/Sources/Data and Storage/IntentsSettingsController.swift index 200c1aa23e..1b365ce2ab 100644 --- a/submodules/SettingsUI/Sources/Data and Storage/IntentsSettingsController.swift +++ b/submodules/SettingsUI/Sources/Data and Storage/IntentsSettingsController.swift @@ -187,7 +187,7 @@ private enum IntentsSettingsControllerEntry: ItemListNodeEntry { case let .accountHeader(_, text): return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section) case let .account(_, peer, selected, _): - return ItemListPeerItem(presentationData: presentationData, dateTimeFormat: PresentationDateTimeFormat(), nameDisplayOrder: .firstLast, context: arguments.context.sharedContext.makeTempAccountContext(account: arguments.context.account), peer: peer, height: .generic, aliasHandling: .standard, nameStyle: .plain, presence: nil, text: .none, label: .none, editing: ItemListPeerItemEditing(editable: true, editing: false, revealed: false), revealOptions: nil, switchValue: ItemListPeerItemSwitch(value: selected, style: .check), enabled: true, selectable: true, sectionId: self.section, action: { + return ItemListPeerItem(presentationData: presentationData, dateTimeFormat: PresentationDateTimeFormat(), nameDisplayOrder: .firstLast, context: arguments.context.sharedContext.makeTempAccountContext(account: arguments.context.account), peer: EnginePeer(peer), height: .generic, aliasHandling: .standard, nameStyle: .plain, presence: nil, text: .none, label: .none, editing: ItemListPeerItemEditing(editable: true, editing: false, revealed: false), revealOptions: nil, switchValue: ItemListPeerItemSwitch(value: selected, style: .check), enabled: true, selectable: true, sectionId: self.section, action: { arguments.updateSettings { $0.withUpdatedAccount(peer.id) } }, setPeerIdWithRevealedOptions: { _, _ in}, removePeer: { _ in }) case let .accountInfo(_, text): diff --git a/submodules/SettingsUI/Sources/Data and Storage/StorageUsageController.swift b/submodules/SettingsUI/Sources/Data and Storage/StorageUsageController.swift index 18a0675ad9..7e84bb7ede 100644 --- a/submodules/SettingsUI/Sources/Data and Storage/StorageUsageController.swift +++ b/submodules/SettingsUI/Sources/Data and Storage/StorageUsageController.swift @@ -264,7 +264,7 @@ private enum StorageUsageEntry: ItemListNodeEntry { let options: [ItemListPeerItemRevealOption] = [ItemListPeerItemRevealOption(type: .destructive, title: strings.ClearCache_Clear, action: { arguments.clearPeerMedia(peer.id) })] - return ItemListPeerItem(presentationData: presentationData, dateTimeFormat: dateTimeFormat, nameDisplayOrder: nameDisplayOrder, context: arguments.context, peer: peer, aliasHandling: .threatSelfAsSaved, nameColor: chatPeer == nil ? .primary : .secret, presence: nil, text: .none, label: .disclosure(value), editing: ItemListPeerItemEditing(editable: true, editing: false, revealed: revealed), revealOptions: ItemListPeerItemRevealOptions(options: options), switchValue: nil, enabled: true, selectable: true, sectionId: self.section, action: { + return ItemListPeerItem(presentationData: presentationData, dateTimeFormat: dateTimeFormat, nameDisplayOrder: nameDisplayOrder, context: arguments.context, peer: EnginePeer(peer), aliasHandling: .threatSelfAsSaved, nameColor: chatPeer == nil ? .primary : .secret, presence: nil, text: .none, label: .disclosure(value), editing: ItemListPeerItemEditing(editable: true, editing: false, revealed: revealed), revealOptions: ItemListPeerItemRevealOptions(options: options), switchValue: nil, enabled: true, selectable: true, sectionId: self.section, action: { let resolvedPeer = chatPeer ?? peer arguments.openPeerMedia(resolvedPeer.id) }, setPeerIdWithRevealedOptions: { peerId, fromPeerId in diff --git a/submodules/SettingsUI/Sources/Notifications/Exceptions/NotificationExceptionControllerNode.swift b/submodules/SettingsUI/Sources/Notifications/Exceptions/NotificationExceptionControllerNode.swift index 27e56d5f88..f141af50d7 100644 --- a/submodules/SettingsUI/Sources/Notifications/Exceptions/NotificationExceptionControllerNode.swift +++ b/submodules/SettingsUI/Sources/Notifications/Exceptions/NotificationExceptionControllerNode.swift @@ -299,13 +299,13 @@ private func notificationsExceptionEntries(presentationData: PresentationData, s var index: Int = 0 for (_, value) in state.mode.settings.filter({ (_, value) in if let query = query, !query.isEmpty { - return !value.peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder).lowercased().components(separatedBy: " ").filter { $0.hasPrefix(query.lowercased())}.isEmpty + return !EnginePeer(value.peer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder).lowercased().components(separatedBy: " ").filter { $0.hasPrefix(query.lowercased())}.isEmpty } else { return true } }).sorted(by: { lhs, rhs in - let lhsName = lhs.value.peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) - let rhsName = rhs.value.peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) + let lhsName = EnginePeer(lhs.value.peer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) + let rhsName = EnginePeer(rhs.value.peer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) if let lhsDate = lhs.value.date, let rhsDate = rhs.value.date { return lhsDate > rhsDate @@ -530,7 +530,7 @@ private enum NotificationExceptionEntry : ItemListNodeEntry { arguments.selectPeer() }) case let .peer(_, peer, _, _, dateTimeFormat, nameDisplayOrder, value, _, revealed, editing, isSearching): - return ItemListPeerItem(presentationData: presentationData, dateTimeFormat: dateTimeFormat, nameDisplayOrder: nameDisplayOrder, context: arguments.context, peer: peer, presence: nil, text: .text(value, .secondary), label: .none, editing: ItemListPeerItemEditing(editable: true, editing: editing, revealed: revealed), switchValue: nil, enabled: true, selectable: true, sectionId: self.section, action: { + return ItemListPeerItem(presentationData: presentationData, dateTimeFormat: dateTimeFormat, nameDisplayOrder: nameDisplayOrder, context: arguments.context, peer: EnginePeer(peer), presence: nil, text: .text(value, .secondary), label: .none, editing: ItemListPeerItemEditing(editable: true, editing: editing, revealed: revealed), switchValue: nil, enabled: true, selectable: true, sectionId: self.section, action: { arguments.openPeer(peer) }, setPeerIdWithRevealedOptions: { peerId, fromPeerId in arguments.updateRevealedPeerId(peerId) @@ -538,7 +538,7 @@ private enum NotificationExceptionEntry : ItemListNodeEntry { arguments.deletePeer(peer) }, hasTopStripe: false, hasTopGroupInset: false, noInsets: isSearching) case let .addPeer(_, peer, theme, strings, _, nameDisplayOrder): - return ContactsPeerItem(presentationData: presentationData, sortOrder: nameDisplayOrder, displayOrder: nameDisplayOrder, context: arguments.context, peerMode: .peer, peer: .peer(peer: peer, chatPeer: peer), status: .none, enabled: true, selection: .none, editing: ContactsPeerItemEditing(editable: false, editing: false, revealed: false), options: [], actionIcon: .add, index: nil, header: ChatListSearchItemHeader(type: .addToExceptions, theme: theme, strings: strings, actionTitle: nil, action: nil), action: { _ in + return ContactsPeerItem(presentationData: presentationData, sortOrder: nameDisplayOrder, displayOrder: nameDisplayOrder, context: arguments.context, peerMode: .peer, peer: .peer(peer: EnginePeer(peer), chatPeer: EnginePeer(peer)), status: .none, enabled: true, selection: .none, editing: ContactsPeerItemEditing(editable: false, editing: false, revealed: false), options: [], actionIcon: .add, index: nil, header: ChatListSearchItemHeader(type: .addToExceptions, theme: theme, strings: strings, actionTitle: nil, action: nil), action: { _ in arguments.openPeer(peer) }, setPeerIdWithRevealedOptions: { _, _ in }) diff --git a/submodules/SettingsUI/Sources/Notifications/Exceptions/NotificationExceptionSettingsController.swift b/submodules/SettingsUI/Sources/Notifications/Exceptions/NotificationExceptionSettingsController.swift index 435d2cc6ce..1ae28d59c5 100644 --- a/submodules/SettingsUI/Sources/Notifications/Exceptions/NotificationExceptionSettingsController.swift +++ b/submodules/SettingsUI/Sources/Notifications/Exceptions/NotificationExceptionSettingsController.swift @@ -375,7 +375,7 @@ public func notificationPeerExceptionController(context: AccountContext, updated arguments.complete() }) - let controllerState = ItemListControllerState(presentationData: ItemListPresentationData(presentationData), title: .text(peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)), leftNavigationButton: leftNavigationButton, rightNavigationButton: rightNavigationButton, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back)) + let controllerState = ItemListControllerState(presentationData: ItemListPresentationData(presentationData), title: .text(EnginePeer(peer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)), leftNavigationButton: leftNavigationButton, rightNavigationButton: rightNavigationButton, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back)) let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: notificationPeerExceptionEntries(presentationData: presentationData, state: state), style: .blocks, animateChanges: false) return (controllerState, (listState, arguments)) diff --git a/submodules/SettingsUI/Sources/Privacy and Security/BlockedPeersController.swift b/submodules/SettingsUI/Sources/Privacy and Security/BlockedPeersController.swift index e180a40d92..80ec132418 100644 --- a/submodules/SettingsUI/Sources/Privacy and Security/BlockedPeersController.swift +++ b/submodules/SettingsUI/Sources/Privacy and Security/BlockedPeersController.swift @@ -132,7 +132,7 @@ private enum BlockedPeersEntry: ItemListNodeEntry { arguments.removePeer(peer.id) })]) - return ItemListPeerItem(presentationData: presentationData, dateTimeFormat: dateTimeFormat, nameDisplayOrder: nameDisplayOrder, context: arguments.context, peer: peer, presence: nil, text: .none, label: .none, editing: editing, revealOptions: revealOptions, switchValue: nil, enabled: enabled, selectable: true, sectionId: self.section, action: { + return ItemListPeerItem(presentationData: presentationData, dateTimeFormat: dateTimeFormat, nameDisplayOrder: nameDisplayOrder, context: arguments.context, peer: EnginePeer(peer), presence: nil, text: .none, label: .none, editing: editing, revealOptions: revealOptions, switchValue: nil, enabled: enabled, selectable: true, sectionId: self.section, action: { arguments.openPeer(peer) }, setPeerIdWithRevealedOptions: { previousId, id in arguments.setPeerIdWithRevealedOptions(previousId, id) diff --git a/submodules/SettingsUI/Sources/Privacy and Security/Recent Sessions/ItemListWebsiteItem.swift b/submodules/SettingsUI/Sources/Privacy and Security/Recent Sessions/ItemListWebsiteItem.swift index 6743534d02..a198bdbb7e 100644 --- a/submodules/SettingsUI/Sources/Privacy and Security/Recent Sessions/ItemListWebsiteItem.swift +++ b/submodules/SettingsUI/Sources/Privacy and Security/Recent Sessions/ItemListWebsiteItem.swift @@ -195,7 +195,7 @@ class ItemListWebsiteItemNode: ItemListRevealOptionsItemNode { let rightInset: CGFloat = params.rightInset if let user = item.peer as? TelegramUser { - titleAttributedString = NSAttributedString(string: user.displayTitle(strings: item.strings, displayOrder: item.nameDisplayOrder), font: titleFont, textColor: item.theme.list.itemPrimaryTextColor) + titleAttributedString = NSAttributedString(string: EnginePeer(user).displayTitle(strings: item.strings, displayOrder: item.nameDisplayOrder), font: titleFont, textColor: item.theme.list.itemPrimaryTextColor) } var appString = "" diff --git a/submodules/SettingsUI/Sources/Privacy and Security/SelectivePrivacySettingsController.swift b/submodules/SettingsUI/Sources/Privacy and Security/SelectivePrivacySettingsController.swift index d878a8953c..b50c1c749f 100644 --- a/submodules/SettingsUI/Sources/Privacy and Security/SelectivePrivacySettingsController.swift +++ b/submodules/SettingsUI/Sources/Privacy and Security/SelectivePrivacySettingsController.swift @@ -938,8 +938,7 @@ func selectivePrivacySettingsController(context: AccountContext, kind: Selective let signal = combineLatest(context.sharedContext.presentationData, statePromise.get(), peer) |> deliverOnMainQueue |> map { presentationData, state, peer -> (ItemListControllerState, (ItemListNodeState, Any)) in - - let peerName = peer?.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) + let peerName = peer.flatMap(EnginePeer.init)?.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) let title: String switch kind { diff --git a/submodules/SettingsUI/Sources/Privacy and Security/SelectivePrivacySettingsPeersController.swift b/submodules/SettingsUI/Sources/Privacy and Security/SelectivePrivacySettingsPeersController.swift index 9b76216883..c85e7f4dab 100644 --- a/submodules/SettingsUI/Sources/Privacy and Security/SelectivePrivacySettingsPeersController.swift +++ b/submodules/SettingsUI/Sources/Privacy and Security/SelectivePrivacySettingsPeersController.swift @@ -140,7 +140,7 @@ private enum SelectivePrivacyPeersEntry: ItemListNodeEntry { } } } - return ItemListPeerItem(presentationData: presentationData, dateTimeFormat: dateTimeFormat, nameDisplayOrder: nameDisplayOrder, context: arguments.context, peer: peer.peer, presence: nil, text: text, label: .none, editing: editing, switchValue: nil, enabled: enabled, selectable: true, sectionId: self.section, action: { + return ItemListPeerItem(presentationData: presentationData, dateTimeFormat: dateTimeFormat, nameDisplayOrder: nameDisplayOrder, context: arguments.context, peer: EnginePeer(peer.peer), presence: nil, text: text, label: .none, editing: editing, switchValue: nil, enabled: enabled, selectable: true, sectionId: self.section, action: { arguments.openPeer(peer.peer.id) }, setPeerIdWithRevealedOptions: { previousId, id in arguments.setPeerIdWithRevealedOptions(previousId, id) diff --git a/submodules/SettingsUI/Sources/TabBarAccountSwitchControllerNode.swift b/submodules/SettingsUI/Sources/TabBarAccountSwitchControllerNode.swift index 4c12bdf00c..72b96a4221 100644 --- a/submodules/SettingsUI/Sources/TabBarAccountSwitchControllerNode.swift +++ b/submodules/SettingsUI/Sources/TabBarAccountSwitchControllerNode.swift @@ -131,7 +131,7 @@ private final class SwitchAccountItemNode: ASDisplayNode, AbstractSwitchAccountI self.titleNode = ImmediateTextNode() self.titleNode.maximumNumberOfLines = 1 - self.titleNode.attributedText = NSAttributedString(string: peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), font: Font.regular(17.0), textColor: presentationData.theme.actionSheet.primaryTextColor) + self.titleNode.attributedText = NSAttributedString(string: EnginePeer(peer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), font: Font.regular(17.0), textColor: presentationData.theme.actionSheet.primaryTextColor) self.checkNode = ASImageNode() self.checkNode.image = generateItemListCheckIcon(color: presentationData.theme.actionSheet.primaryTextColor) diff --git a/submodules/ShareController/Sources/ShareContentContainerNode.swift b/submodules/ShareController/Sources/ShareContentContainerNode.swift index 8526858de6..649a5ef10e 100644 --- a/submodules/ShareController/Sources/ShareContentContainerNode.swift +++ b/submodules/ShareController/Sources/ShareContentContainerNode.swift @@ -2,11 +2,12 @@ import Foundation import UIKit import Display import Postbox +import TelegramCore public protocol ShareContentContainerNode: AnyObject { func activate() func deactivate() - func setEnsurePeerVisibleOnLayout(_ peerId: PeerId?) + func setEnsurePeerVisibleOnLayout(_ peerId: EnginePeer.Id?) func setContentOffsetUpdated(_ f: ((CGFloat, ContainedViewLayoutTransition) -> Void)?) func updateLayout(size: CGSize, bottomInset: CGFloat, transition: ContainedViewLayoutTransition) func updateSelectedPeers() diff --git a/submodules/ShareController/Sources/ShareController.swift b/submodules/ShareController/Sources/ShareController.swift index e917287c86..f1020e7bf8 100644 --- a/submodules/ShareController/Sources/ShareController.swift +++ b/submodules/ShareController/Sources/ShareController.swift @@ -119,7 +119,7 @@ private func collectExternalShareItems(strings: PresentationStrings, dateTimeFor authorsPromise.set(postbox.transaction { transaction in var result: [PeerId: String] = [:] for peerId in authorsPeerIds { - if let title = transaction.getPeer(peerId)?.displayTitle(strings: strings, displayOrder: nameOrder) { + if let title = transaction.getPeer(peerId).flatMap(EnginePeer.init)?.displayTitle(strings: strings, displayOrder: nameOrder) { result[peerId] = title } } @@ -629,7 +629,7 @@ public final class ShareController: ViewController { } if !displayedError, case .slowmodeActive = error { displayedError = true - strongSelf.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: strongSelf.presentationData), title: peer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder), text: strongSelf.presentationData.strings.Chat_SlowmodeSendError, actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {})]), in: .window(.root)) + strongSelf.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: strongSelf.presentationData), title: EnginePeer(peer).displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder), text: strongSelf.presentationData.strings.Chat_SlowmodeSendError, actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {})]), in: .window(.root)) } }) } @@ -789,7 +789,7 @@ public final class ShareController: ViewController { } var items: [ActionSheetItem] = [] for info in strongSelf.switchableAccounts { - items.append(ActionSheetPeerItem(context: strongSelf.sharedContext.makeTempAccountContext(account: info.account), peer: EnginePeer(info.peer), title: info.peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), isSelected: info.account.id == strongSelf.currentAccount.id, strings: presentationData.strings, theme: presentationData.theme, action: { [weak self] in + items.append(ActionSheetPeerItem(context: strongSelf.sharedContext.makeTempAccountContext(account: info.account), peer: EnginePeer(info.peer), title: EnginePeer(info.peer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), isSelected: info.account.id == strongSelf.currentAccount.id, strings: presentationData.strings, theme: presentationData.theme, action: { [weak self] in dismissAction() self?.switchToAccount(account: info.account, animateIn: true) })) diff --git a/submodules/ShareController/Sources/ShareControllerPeerGridItem.swift b/submodules/ShareController/Sources/ShareControllerPeerGridItem.swift index 909d4ad7aa..443196781f 100644 --- a/submodules/ShareController/Sources/ShareControllerPeerGridItem.swift +++ b/submodules/ShareController/Sources/ShareControllerPeerGridItem.swift @@ -221,7 +221,7 @@ final class ShareControllerPeerGridItemNode: GridItemNode { self.currentState = (context, theme, strings, peer, search, presence) self.setNeedsLayout() if let presence = presence as? TelegramUserPresence { - self.presenceManager?.reset(presence: presence) + self.presenceManager?.reset(presence: EnginePeer.Presence(presence)) } } self.updateSelection(animated: false) diff --git a/submodules/ShareController/Sources/SharePeersContainerNode.swift b/submodules/ShareController/Sources/SharePeersContainerNode.swift index 1fefaac8f0..6d784124ac 100644 --- a/submodules/ShareController/Sources/SharePeersContainerNode.swift +++ b/submodules/ShareController/Sources/SharePeersContainerNode.swift @@ -422,7 +422,7 @@ final class SharePeersContainerNode: ASDisplayNode, ShareContentContainerNode { if peer.peerId == self.accountPeer.id { text = self.strings.DialogList_SavedMessages } else { - text = peer.chatMainPeer?.displayTitle(strings: self.strings, displayOrder: self.nameDisplayOrder) ?? "" + text = peer.chatMainPeer.flatMap(EnginePeer.init)?.displayTitle(strings: self.strings, displayOrder: self.nameDisplayOrder) ?? "" } if !string.isEmpty { diff --git a/submodules/StatisticsUI/Sources/GroupStatsController.swift b/submodules/StatisticsUI/Sources/GroupStatsController.swift index c30312174b..81079d347c 100644 --- a/submodules/StatisticsUI/Sources/GroupStatsController.swift +++ b/submodules/StatisticsUI/Sources/GroupStatsController.swift @@ -411,7 +411,7 @@ private enum StatsEntry: ItemListNodeEntry { })) } } - return ItemListPeerItem(presentationData: presentationData, dateTimeFormat: dateTimeFormat, nameDisplayOrder: .firstLast, context: arguments.context, peer: peer, height: .generic, aliasHandling: .standard, nameColor: .primary, nameStyle: .plain, presence: nil, text: .text(textComponents.joined(separator: ", "), .secondary), label: .none, editing: ItemListPeerItemEditing(editable: true, editing: false, revealed: revealed), revealOptions: ItemListPeerItemRevealOptions(options: options), switchValue: nil, enabled: true, highlighted: false, selectable: arguments.context.account.peerId != peer.id, sectionId: self.section, action: { + return ItemListPeerItem(presentationData: presentationData, dateTimeFormat: dateTimeFormat, nameDisplayOrder: .firstLast, context: arguments.context, peer: EnginePeer(peer), height: .generic, aliasHandling: .standard, nameColor: .primary, nameStyle: .plain, presence: nil, text: .text(textComponents.joined(separator: ", "), .secondary), label: .none, editing: ItemListPeerItemEditing(editable: true, editing: false, revealed: revealed), revealOptions: ItemListPeerItemRevealOptions(options: options), switchValue: nil, enabled: true, highlighted: false, selectable: arguments.context.account.peerId != peer.id, sectionId: self.section, action: { arguments.openPeer(peer.id) }, setPeerIdWithRevealedOptions: { peerId, fromPeerId in arguments.setPostersPeerIdWithRevealedOptions(peerId, fromPeerId) @@ -442,7 +442,7 @@ private enum StatsEntry: ItemListNodeEntry { })) } } - return ItemListPeerItem(presentationData: presentationData, dateTimeFormat: dateTimeFormat, nameDisplayOrder: .firstLast, context: arguments.context, peer: peer, height: .generic, aliasHandling: .standard, nameColor: .primary, nameStyle: .plain, presence: nil, text: .text(textComponents.joined(separator: ", "), .secondary), label: .none, editing: ItemListPeerItemEditing(editable: true, editing: false, revealed: revealed), revealOptions: ItemListPeerItemRevealOptions(options: options), switchValue: nil, enabled: true, highlighted: false, selectable: arguments.context.account.peerId != peer.id, sectionId: self.section, action: { + return ItemListPeerItem(presentationData: presentationData, dateTimeFormat: dateTimeFormat, nameDisplayOrder: .firstLast, context: arguments.context, peer: EnginePeer(peer), height: .generic, aliasHandling: .standard, nameColor: .primary, nameStyle: .plain, presence: nil, text: .text(textComponents.joined(separator: ", "), .secondary), label: .none, editing: ItemListPeerItemEditing(editable: true, editing: false, revealed: revealed), revealOptions: ItemListPeerItemRevealOptions(options: options), switchValue: nil, enabled: true, highlighted: false, selectable: arguments.context.account.peerId != peer.id, sectionId: self.section, action: { arguments.openPeer(peer.id) }, setPeerIdWithRevealedOptions: { peerId, fromPeerId in arguments.setAdminsPeerIdWithRevealedOptions(peerId, fromPeerId) @@ -465,7 +465,7 @@ private enum StatsEntry: ItemListNodeEntry { })) } } - return ItemListPeerItem(presentationData: presentationData, dateTimeFormat: dateTimeFormat, nameDisplayOrder: .firstLast, context: arguments.context, peer: peer, height: .generic, aliasHandling: .standard, nameColor: .primary, nameStyle: .plain, presence: nil, text: .text(textComponents.joined(separator: ", "), .secondary), label: .none, editing: ItemListPeerItemEditing(editable: true, editing: false, revealed: revealed), revealOptions: ItemListPeerItemRevealOptions(options: options), switchValue: nil, enabled: true, highlighted: false, selectable: arguments.context.account.peerId != peer.id, sectionId: self.section, action: { + return ItemListPeerItem(presentationData: presentationData, dateTimeFormat: dateTimeFormat, nameDisplayOrder: .firstLast, context: arguments.context, peer: EnginePeer(peer), height: .generic, aliasHandling: .standard, nameColor: .primary, nameStyle: .plain, presence: nil, text: .text(textComponents.joined(separator: ", "), .secondary), label: .none, editing: ItemListPeerItemEditing(editable: true, editing: false, revealed: revealed), revealOptions: ItemListPeerItemRevealOptions(options: options), switchValue: nil, enabled: true, highlighted: false, selectable: arguments.context.account.peerId != peer.id, sectionId: self.section, action: { arguments.openPeer(peer.id) }, setPeerIdWithRevealedOptions: { peerId, fromPeerId in arguments.setInvitersPeerIdWithRevealedOptions(peerId, fromPeerId) diff --git a/submodules/StatisticsUI/Sources/MessageStatsController.swift b/submodules/StatisticsUI/Sources/MessageStatsController.swift index 327578570d..83567a43b7 100644 --- a/submodules/StatisticsUI/Sources/MessageStatsController.swift +++ b/submodules/StatisticsUI/Sources/MessageStatsController.swift @@ -143,7 +143,7 @@ private enum StatsEntry: ItemListNodeEntry { } let text: String = presentationData.strings.Stats_MessageViews(views) - return ItemListPeerItem(presentationData: presentationData, dateTimeFormat: PresentationDateTimeFormat(), nameDisplayOrder: .firstLast, context: arguments.context, peer: message.peers[message.id.peerId]!, height: .generic, aliasHandling: .standard, nameColor: .primary, nameStyle: .plain, presence: nil, text: .text(text, .secondary), label: .none, editing: ItemListPeerItemEditing(editable: false, editing: false, revealed: nil), revealOptions: nil, switchValue: nil, enabled: true, highlighted: false, selectable: true, sectionId: self.section, action: { + return ItemListPeerItem(presentationData: presentationData, dateTimeFormat: PresentationDateTimeFormat(), nameDisplayOrder: .firstLast, context: arguments.context, peer: EnginePeer(message.peers[message.id.peerId]!), height: .generic, aliasHandling: .standard, nameColor: .primary, nameStyle: .plain, presence: nil, text: .text(text, .secondary), label: .none, editing: ItemListPeerItemEditing(editable: false, editing: false, revealed: nil), revealOptions: nil, switchValue: nil, enabled: true, highlighted: false, selectable: true, sectionId: self.section, action: { arguments.openMessage(message.id) }, setPeerIdWithRevealedOptions: { _, _ in }, removePeer: { _ in }, toggleUpdated: nil, contextAction: nil) } diff --git a/submodules/TelegramBaseController/Sources/LocationBroadcastNavigationAccessoryPanel.swift b/submodules/TelegramBaseController/Sources/LocationBroadcastNavigationAccessoryPanel.swift index e15d47c31d..708806b2a4 100644 --- a/submodules/TelegramBaseController/Sources/LocationBroadcastNavigationAccessoryPanel.swift +++ b/submodules/TelegramBaseController/Sources/LocationBroadcastNavigationAccessoryPanel.swift @@ -3,7 +3,6 @@ import UIKit import AsyncDisplayKit import Display import TelegramCore -import Postbox import TelegramPresentationData import TelegramUIPreferences import TextFormat @@ -20,7 +19,7 @@ enum LocationBroadcastNavigationAccessoryPanelMode { } final class LocationBroadcastNavigationAccessoryPanel: ASDisplayNode { - private let accountPeerId: PeerId + private let accountPeerId: EnginePeer.Id private var theme: PresentationTheme private var strings: PresentationStrings private var nameDisplayOrder: PresentationPersonNameOrder @@ -38,9 +37,9 @@ final class LocationBroadcastNavigationAccessoryPanel: ASDisplayNode { private let separatorNode: ASDisplayNode private var validLayout: (CGSize, CGFloat, CGFloat)? - private var peersAndMode: ([Peer], LocationBroadcastNavigationAccessoryPanelMode, Bool)? + private var peersAndMode: ([EnginePeer], LocationBroadcastNavigationAccessoryPanelMode, Bool)? - init(accountPeerId: PeerId, theme: PresentationTheme, strings: PresentationStrings, nameDisplayOrder: PresentationPersonNameOrder, tapAction: @escaping () -> Void, close: @escaping () -> Void) { + init(accountPeerId: EnginePeer.Id, theme: PresentationTheme, strings: PresentationStrings, nameDisplayOrder: PresentationPersonNameOrder, tapAction: @escaping () -> Void, close: @escaping () -> Void) { self.accountPeerId = accountPeerId self.theme = theme self.strings = strings @@ -178,7 +177,7 @@ final class LocationBroadcastNavigationAccessoryPanel: ASDisplayNode { transition.updateFrame(node: self.separatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: size.width, height: UIScreenPixel))) } - func update(peers: [Peer], mode: LocationBroadcastNavigationAccessoryPanelMode, canClose: Bool) { + func update(peers: [EnginePeer], mode: LocationBroadcastNavigationAccessoryPanelMode, canClose: Bool) { self.peersAndMode = (peers, mode, canClose) if let layout = validLayout { self.updateLayout(size: layout.0, leftInset: layout.1, rightInset: layout.2, transition: .immediate) diff --git a/submodules/TelegramBaseController/Sources/MediaNavigationAccessoryHeaderNode.swift b/submodules/TelegramBaseController/Sources/MediaNavigationAccessoryHeaderNode.swift index 9900650e24..4b62b4d876 100644 --- a/submodules/TelegramBaseController/Sources/MediaNavigationAccessoryHeaderNode.swift +++ b/submodules/TelegramBaseController/Sources/MediaNavigationAccessoryHeaderNode.swift @@ -50,11 +50,11 @@ private class MediaHeaderItemNode: ASDisplayNode { subtitleString = NSAttributedString(string: subtitleText, font: subtitleFont, textColor: theme.rootController.navigationBar.secondaryTextColor) case let .voice(author, peer): rateButtonHidden = false - let titleText: String = author?.displayTitle(strings: strings, displayOrder: nameDisplayOrder) ?? "" + let titleText: String = author.flatMap(EnginePeer.init)?.displayTitle(strings: strings, displayOrder: nameDisplayOrder) ?? "" let subtitleText: String if let peer = peer { if peer is TelegramGroup || peer is TelegramChannel { - subtitleText = peer.displayTitle(strings: strings, displayOrder: nameDisplayOrder) + subtitleText = EnginePeer(peer).displayTitle(strings: strings, displayOrder: nameDisplayOrder) } else { subtitleText = strings.MusicPlayer_VoiceNote } @@ -66,12 +66,12 @@ private class MediaHeaderItemNode: ASDisplayNode { subtitleString = NSAttributedString(string: subtitleText, font: subtitleFont, textColor: theme.rootController.navigationBar.secondaryTextColor) case let .instantVideo(author, peer, timestamp): rateButtonHidden = false - let titleText: String = author?.displayTitle(strings: strings, displayOrder: nameDisplayOrder) ?? "" + let titleText: String = author.flatMap(EnginePeer.init)?.displayTitle(strings: strings, displayOrder: nameDisplayOrder) ?? "" var subtitleText: String if let peer = peer { if peer is TelegramGroup || peer is TelegramChannel { - subtitleText = peer.displayTitle(strings: strings, displayOrder: nameDisplayOrder) + subtitleText = EnginePeer(peer).displayTitle(strings: strings, displayOrder: nameDisplayOrder) } else { subtitleText = strings.Message_VideoMessage } diff --git a/submodules/TelegramBaseController/Sources/TelegramBaseController.swift b/submodules/TelegramBaseController/Sources/TelegramBaseController.swift index a9750aba2b..3df2f22d91 100644 --- a/submodules/TelegramBaseController/Sources/TelegramBaseController.swift +++ b/submodules/TelegramBaseController/Sources/TelegramBaseController.swift @@ -27,9 +27,9 @@ public enum LocationBroadcastPanelSource { } private func presentLiveLocationController(context: AccountContext, peerId: PeerId, controller: ViewController) { - let presentImpl: (Message?) -> Void = { [weak controller] message in + let presentImpl: (EngineMessage?) -> Void = { [weak controller] message in if let message = message, let strongController = controller { - let _ = context.sharedContext.openChatMessage(OpenChatMessageParams(context: context, chatLocation: nil, chatLocationContextHolder: nil, message: message, standalone: false, reverseMessageGalleryOrder: false, navigationController: strongController.navigationController as? NavigationController, modal: true, dismissInput: { + let _ = context.sharedContext.openChatMessage(OpenChatMessageParams(context: context, chatLocation: nil, chatLocationContextHolder: nil, message: message._asMessage(), standalone: false, reverseMessageGalleryOrder: false, navigationController: strongController.navigationController as? NavigationController, modal: true, dismissInput: { controller?.view.endEditing(true) }, present: { c, a in controller?.present(c, in: .window(.root), with: a, blockInteraction: true) @@ -48,13 +48,13 @@ private func presentLiveLocationController(context: AccountContext, peerId: Peer } } if let id = context.liveLocationManager?.internalMessageForPeerId(peerId) { - let _ = (context.account.postbox.transaction { transaction -> Message? in - return transaction.getMessage(id) + let _ = (context.account.postbox.transaction { transaction -> EngineMessage? in + return transaction.getMessage(id).flatMap(EngineMessage.init) } |> deliverOnMainQueue).start(next: presentImpl) } else if let liveLocationManager = context.liveLocationManager { let _ = (liveLocationManager.summaryManager.peersBroadcastingTo(peerId: peerId) |> take(1) - |> map { peersAndMessages -> Message? in + |> map { peersAndMessages -> EngineMessage? in return peersAndMessages?.first?.1 } |> deliverOnMainQueue).start(next: presentImpl) } @@ -81,8 +81,8 @@ open class TelegramBaseController: ViewController, KeyShortcutResponder { public var mediaAccessoryPanel: (MediaNavigationAccessoryPanel, MediaManagerPlayerType)? private var locationBroadcastMode: LocationBroadcastNavigationAccessoryPanelMode? - private var locationBroadcastPeers: [Peer]? - private var locationBroadcastMessages: [MessageId: Message]? + private var locationBroadcastPeers: [EnginePeer]? + private var locationBroadcastMessages: [EngineMessage.Id: EngineMessage]? private var locationBroadcastAccessoryPanel: LocationBroadcastNavigationAccessoryPanel? private var groupCallPanelData: GroupCallPanelData? @@ -175,7 +175,7 @@ open class TelegramBaseController: ViewController, KeyShortcutResponder { case .none: self.locationBroadcastMode = nil case .summary, .peer: - let signal: Signal<([Peer]?, [MessageId: Message]?), NoError> + let signal: Signal<([EnginePeer]?, [EngineMessage.Id: EngineMessage]?), NoError> switch locationBroadcastPanelSource { case let .peer(peerId): self.locationBroadcastMode = .peer @@ -195,14 +195,14 @@ open class TelegramBaseController: ViewController, KeyShortcutResponder { default: self.locationBroadcastMode = .summary signal = liveLocationManager.summaryManager.broadcastingToMessages() - |> map { messages -> ([Peer]?, [MessageId: Message]?) in + |> map { messages -> ([EnginePeer]?, [EngineMessage.Id: EngineMessage]?) in if messages.isEmpty { return (nil, nil) } else { - var peers: [Peer] = [] + var peers: [EnginePeer] = [] for message in messages.values.sorted(by: { $0.index < $1.index }) { if let peer = message.peers[message.id.peerId] { - peers.append(peer) + peers.append(EnginePeer(peer)) } } return (peers, messages) @@ -216,7 +216,7 @@ open class TelegramBaseController: ViewController, KeyShortcutResponder { if let strongSelf = self { var updated = false if let current = strongSelf.locationBroadcastPeers, let peers = peers { - updated = !arePeerArraysEqual(current, peers) + updated = current != peers } else if (strongSelf.locationBroadcastPeers != nil) != (peers != nil) { updated = true } @@ -486,7 +486,7 @@ open class TelegramBaseController: ViewController, KeyShortcutResponder { } if let beginTimeAndTimeout = beginTimeAndTimeout { - items.append(LocationBroadcastActionSheetItem(context: strongSelf.context, peer: peer, title: peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), beginTimestamp: beginTimeAndTimeout.0, timeout: beginTimeAndTimeout.1, strings: presentationData.strings, action: { + items.append(LocationBroadcastActionSheetItem(context: strongSelf.context, peer: peer, title: EnginePeer(peer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), beginTimestamp: beginTimeAndTimeout.0, timeout: beginTimeAndTimeout.1, strings: presentationData.strings, action: { dismissAction() if let strongSelf = self { presentLiveLocationController(context: strongSelf.context, peerId: peer.id, controller: strongSelf) @@ -518,8 +518,8 @@ open class TelegramBaseController: ViewController, KeyShortcutResponder { } }, close: { [weak self] in if let strongSelf = self { - var closePeers: [Peer]? - var closePeerId: PeerId? + var closePeers: [EnginePeer]? + var closePeerId: EnginePeer.Id? switch strongSelf.locationBroadcastPanelSource { case .none: break @@ -937,7 +937,7 @@ open class TelegramBaseController: ViewController, KeyShortcutResponder { } } - items.append(VoiceChatPeerActionSheetItem(context: context, peer: peer.peer, title: peer.peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), subtitle: subtitle ?? "", action: { + items.append(VoiceChatPeerActionSheetItem(context: context, peer: peer.peer, title: EnginePeer(peer.peer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), subtitle: subtitle ?? "", action: { dismissAction() completion(peer.peer.id) })) diff --git a/submodules/TelegramCallsUI/Sources/CallControllerNode.swift b/submodules/TelegramCallsUI/Sources/CallControllerNode.swift index d50d67a57a..d66d16280a 100644 --- a/submodules/TelegramCallsUI/Sources/CallControllerNode.swift +++ b/submodules/TelegramCallsUI/Sources/CallControllerNode.swift @@ -762,10 +762,10 @@ final class CallControllerNode: ViewControllerTracingNode, CallControllerNodePro self.dimNode.isHidden = true } - self.toastNode.title = peer.compactDisplayTitle - self.statusNode.title = peer.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) + self.toastNode.title = EnginePeer(peer).compactDisplayTitle + self.statusNode.title = EnginePeer(peer).displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) if hasOther { - self.statusNode.subtitle = self.presentationData.strings.Call_AnsweringWithAccount(accountPeer.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder)).string + self.statusNode.subtitle = self.presentationData.strings.Call_AnsweringWithAccount(EnginePeer(accountPeer).displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder)).string if let callState = self.callState { self.updateCallState(callState) @@ -841,7 +841,7 @@ final class CallControllerNode: ViewControllerTracingNode, CallControllerNodePro strongSelf.maybeScheduleUIHidingForActiveVideoCall() } - let incomingVideoNode = CallVideoNode(videoView: incomingVideoView, disabledText: strongSelf.presentationData.strings.Call_RemoteVideoPaused(strongSelf.peer?.compactDisplayTitle ?? "").string, assumeReadyAfterTimeout: false, isReadyUpdated: { + let incomingVideoNode = CallVideoNode(videoView: incomingVideoView, disabledText: strongSelf.presentationData.strings.Call_RemoteVideoPaused(strongSelf.peer.flatMap(EnginePeer.init)?.compactDisplayTitle ?? "").string, assumeReadyAfterTimeout: false, isReadyUpdated: { if delayUntilInitialized { Queue.mainQueue().after(0.1, { applyNode() @@ -1036,9 +1036,9 @@ final class CallControllerNode: ViewControllerTracingNode, CallControllerNodePro let text: String if isVideo { - text = self.presentationData.strings.Call_ParticipantVideoVersionOutdatedError(peer.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder)).string + text = self.presentationData.strings.Call_ParticipantVideoVersionOutdatedError(EnginePeer(peer).displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder)).string } else { - text = self.presentationData.strings.Call_ParticipantVersionOutdatedError(peer.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder)).string + text = self.presentationData.strings.Call_ParticipantVersionOutdatedError(EnginePeer(peer).displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder)).string } self.present?(textAlertController(sharedContext: self.sharedContext, title: nil, text: text, actions: [TextAlertAction(type: .defaultAction, title: self.presentationData.strings.Common_OK, action: { @@ -1716,7 +1716,7 @@ final class CallControllerNode: ViewControllerTracingNode, CallControllerNodePro @objc func keyPressed() { if self.keyPreviewNode == nil, let keyText = self.keyTextData?.1, let peer = self.peer { - let keyPreviewNode = CallControllerKeyPreviewNode(keyText: keyText, infoText: self.presentationData.strings.Call_EmojiDescription(peer.compactDisplayTitle).string.replacingOccurrences(of: "%%", with: "%"), dismiss: { [weak self] in + let keyPreviewNode = CallControllerKeyPreviewNode(keyText: keyText, infoText: self.presentationData.strings.Call_EmojiDescription(EnginePeer(peer).compactDisplayTitle).string.replacingOccurrences(of: "%%", with: "%"), dismiss: { [weak self] in if let _ = self?.keyPreviewNode { self?.backPressed() } diff --git a/submodules/TelegramCallsUI/Sources/CallStatusBarNode.swift b/submodules/TelegramCallsUI/Sources/CallStatusBarNode.swift index 95bd44981b..cb4eff8305 100644 --- a/submodules/TelegramCallsUI/Sources/CallStatusBarNode.swift +++ b/submodules/TelegramCallsUI/Sources/CallStatusBarNode.swift @@ -388,7 +388,7 @@ public class CallStatusBarNodeImpl: CallStatusBarNode { if let voiceChatTitle = self.currentGroupCallState?.info?.title, !voiceChatTitle.isEmpty { title = voiceChatTitle } else if let currentPeer = self.currentPeer { - title = currentPeer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) + title = EnginePeer(currentPeer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) } var membersCount: Int32? if let groupCallState = self.currentGroupCallState { @@ -409,7 +409,7 @@ public class CallStatusBarNodeImpl: CallStatusBarNode { } if let speakingPeer = speakingPeer { - speakerSubtitle = speakingPeer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) + speakerSubtitle = EnginePeer(speakingPeer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) } displaySpeakerSubtitle = speakerSubtitle != title && !speakerSubtitle.isEmpty diff --git a/submodules/TelegramCallsUI/Sources/LegacyCallControllerNode.swift b/submodules/TelegramCallsUI/Sources/LegacyCallControllerNode.swift index 47189cc186..3d69c38833 100644 --- a/submodules/TelegramCallsUI/Sources/LegacyCallControllerNode.swift +++ b/submodules/TelegramCallsUI/Sources/LegacyCallControllerNode.swift @@ -178,9 +178,9 @@ final class LegacyCallControllerNode: ASDisplayNode, CallControllerNodeProtocol self.dimNode.isHidden = true } - self.statusNode.title = peer.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) + self.statusNode.title = EnginePeer(peer).displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) if hasOther { - self.statusNode.subtitle = self.presentationData.strings.Call_AnsweringWithAccount(accountPeer.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder)).string + self.statusNode.subtitle = self.presentationData.strings.Call_AnsweringWithAccount(EnginePeer(accountPeer).displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder)).string if let callState = callState { self.updateCallState(callState) @@ -443,7 +443,7 @@ final class LegacyCallControllerNode: ASDisplayNode, CallControllerNodeProtocol @objc func keyPressed() { if self.keyPreviewNode == nil, let keyText = self.keyTextData?.1, let peer = self.peer { - let keyPreviewNode = CallControllerKeyPreviewNode(keyText: keyText, infoText: self.presentationData.strings.Call_EmojiDescription(peer.compactDisplayTitle).string.replacingOccurrences(of: "%%", with: "%"), dismiss: { [weak self] in + let keyPreviewNode = CallControllerKeyPreviewNode(keyText: keyText, infoText: self.presentationData.strings.Call_EmojiDescription(EnginePeer(peer).compactDisplayTitle).string.replacingOccurrences(of: "%%", with: "%"), dismiss: { [weak self] in if let _ = self?.keyPreviewNode { self?.backPressed() } diff --git a/submodules/TelegramCallsUI/Sources/PresentationGroupCall.swift b/submodules/TelegramCallsUI/Sources/PresentationGroupCall.swift index d3ecb1d38c..8b33151b27 100644 --- a/submodules/TelegramCallsUI/Sources/PresentationGroupCall.swift +++ b/submodules/TelegramCallsUI/Sources/PresentationGroupCall.swift @@ -1930,7 +1930,7 @@ public final class PresentationGroupCallImpl: PresentationGroupCall { if let voiceChatTitle = strongSelf.stateValue.title { title = voiceChatTitle } else if let peer = peerViewMainPeer(view) { - title = peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) + title = EnginePeer(peer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) } else { title = nil } diff --git a/submodules/TelegramCallsUI/Sources/VoiceChatController.swift b/submodules/TelegramCallsUI/Sources/VoiceChatController.swift index 693199e278..275e8a9033 100644 --- a/submodules/TelegramCallsUI/Sources/VoiceChatController.swift +++ b/submodules/TelegramCallsUI/Sources/VoiceChatController.swift @@ -1244,15 +1244,15 @@ public final class VoiceChatController: ViewController { if strongSelf.call.invitePeer(participant.peer.id) { let text: String if let channel = strongSelf.peer as? TelegramChannel, case .broadcast = channel.info { - text = strongSelf.presentationData.strings.LiveStream_InvitedPeerText(peer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder)).string + text = strongSelf.presentationData.strings.LiveStream_InvitedPeerText(EnginePeer(peer).displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder)).string } else { - text = strongSelf.presentationData.strings.VoiceChat_InvitedPeerText(peer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder)).string + text = strongSelf.presentationData.strings.VoiceChat_InvitedPeerText(EnginePeer(peer).displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder)).string } strongSelf.presentUndoOverlay(content: .invitedToVoiceChat(context: strongSelf.context, peer: participant.peer, text: text), action: { _ in return false }) } } else { if let groupPeer = groupPeer as? TelegramChannel, let listenerLink = inviteLinks?.listenerLink, !groupPeer.hasPermission(.inviteMembers) { - let text = strongSelf.presentationData.strings.VoiceChat_SendPublicLinkText(peer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder), groupPeer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder)).string + let text = strongSelf.presentationData.strings.VoiceChat_SendPublicLinkText(EnginePeer(peer).displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder), EnginePeer(groupPeer).displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder)).string strongSelf.controller?.present(textAlertController(context: strongSelf.context, forceTheme: strongSelf.darkTheme, title: nil, text: text, actions: [TextAlertAction(type: .genericAction, title: presentationData.strings.Common_Cancel, action: {}), TextAlertAction(type: .defaultAction, title: presentationData.strings.VoiceChat_SendPublicLinkSend, action: { [weak self] in dismissController?() @@ -1261,7 +1261,7 @@ public final class VoiceChatController: ViewController { let _ = (enqueueMessages(account: strongSelf.context.account, peerId: peer.id, messages: [.message(text: listenerLink, attributes: [], mediaReference: nil, replyToMessageId: nil, localGroupingKey: nil, correlationId: nil)]) |> deliverOnMainQueue).start(next: { [weak self] _ in if let strongSelf = self { - strongSelf.presentUndoOverlay(content: .forward(savedMessages: false, text: strongSelf.presentationData.strings.UserInfo_LinkForwardTooltip_Chat_One(peer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder)).string), action: { _ in return true }) + strongSelf.presentUndoOverlay(content: .forward(savedMessages: false, text: strongSelf.presentationData.strings.UserInfo_LinkForwardTooltip_Chat_One(EnginePeer(peer).displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder)).string), action: { _ in return true }) } }) } @@ -1269,9 +1269,9 @@ public final class VoiceChatController: ViewController { } else { let text: String if let groupPeer = groupPeer as? TelegramChannel, case .broadcast = groupPeer.info { - text = strongSelf.presentationData.strings.VoiceChat_InviteMemberToChannelFirstText(peer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder), groupPeer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder)).string + text = strongSelf.presentationData.strings.VoiceChat_InviteMemberToChannelFirstText(EnginePeer(peer).displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder), EnginePeer(groupPeer).displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder)).string } else { - text = strongSelf.presentationData.strings.VoiceChat_InviteMemberToGroupFirstText(peer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder), groupPeer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder)).string + text = strongSelf.presentationData.strings.VoiceChat_InviteMemberToGroupFirstText(EnginePeer(peer).displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder), EnginePeer(groupPeer).displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder)).string } strongSelf.controller?.present(textAlertController(context: strongSelf.context, forceTheme: strongSelf.darkTheme, title: nil, text: text, actions: [TextAlertAction(type: .genericAction, title: presentationData.strings.Common_Cancel, action: {}), TextAlertAction(type: .defaultAction, title: presentationData.strings.VoiceChat_InviteMemberToGroupFirstAdd, action: { @@ -1350,9 +1350,9 @@ public final class VoiceChatController: ViewController { if strongSelf.call.invitePeer(peer.id) { let text: String if let channel = strongSelf.peer as? TelegramChannel, case .broadcast = channel.info { - text = strongSelf.presentationData.strings.LiveStream_InvitedPeerText(peer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder)).string + text = strongSelf.presentationData.strings.LiveStream_InvitedPeerText(EnginePeer(peer).displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder)).string } else { - text = strongSelf.presentationData.strings.VoiceChat_InvitedPeerText(peer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder)).string + text = strongSelf.presentationData.strings.VoiceChat_InvitedPeerText(EnginePeer(peer).displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder)).string } strongSelf.presentUndoOverlay(content: .invitedToVoiceChat(context: strongSelf.context, peer: peer, text: text), action: { _ in return false }) } @@ -1399,7 +1399,7 @@ public final class VoiceChatController: ViewController { case .privacy: let _ = (strongSelf.context.account.postbox.loadedPeerWithId(peer.id) |> deliverOnMainQueue).start(next: { peer in - self?.controller?.present(textAlertController(context: context, title: nil, text: presentationData.strings.Privacy_GroupsAndChannels_InviteToGroupError(peer.compactDisplayTitle, peer.compactDisplayTitle).string, actions: [TextAlertAction(type: .genericAction, title: presentationData.strings.Common_OK, action: {})]), in: .window(.root)) + self?.controller?.present(textAlertController(context: context, title: nil, text: presentationData.strings.Privacy_GroupsAndChannels_InviteToGroupError(EnginePeer(peer).compactDisplayTitle, EnginePeer(peer).compactDisplayTitle).string, actions: [TextAlertAction(type: .genericAction, title: presentationData.strings.Common_OK, action: {})]), in: .window(.root)) }) case .notMutualContact: strongSelf.controller?.present(textAlertController(context: context, title: nil, text: presentationData.strings.GroupInfo_AddUserLeftError, actions: [TextAlertAction(type: .genericAction, title: presentationData.strings.Common_OK, action: {})]), in: .window(.root)) @@ -1418,9 +1418,9 @@ public final class VoiceChatController: ViewController { if strongSelf.call.invitePeer(peer.id) { let text: String if let channel = strongSelf.peer as? TelegramChannel, case .broadcast = channel.info { - text = strongSelf.presentationData.strings.LiveStream_InvitedPeerText(peer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder)).string + text = strongSelf.presentationData.strings.LiveStream_InvitedPeerText(EnginePeer(peer).displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder)).string } else { - text = strongSelf.presentationData.strings.VoiceChat_InvitedPeerText(peer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder)).string + text = strongSelf.presentationData.strings.VoiceChat_InvitedPeerText(EnginePeer(peer).displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder)).string } strongSelf.presentUndoOverlay(content: .invitedToVoiceChat(context: strongSelf.context, peer: peer, text: text), action: { _ in return false }) } @@ -1620,7 +1620,7 @@ public final class VoiceChatController: ViewController { let _ = strongSelf.call.updateMuteState(peerId: peer.id, isMuted: false) f(.default) - strongSelf.presentUndoOverlay(content: .voiceChatCanSpeak(text: presentationData.strings.VoiceChat_UserCanNowSpeak(entry.peer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder)).string), action: { _ in return true }) + strongSelf.presentUndoOverlay(content: .voiceChatCanSpeak(text: presentationData.strings.VoiceChat_UserCanNowSpeak(EnginePeer(entry.peer).displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder)).string), action: { _ in return true }) }))) } else { items.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.VoiceChat_MutePeer, icon: { theme in @@ -1722,7 +1722,7 @@ public final class VoiceChatController: ViewController { let _ = strongSelf.context.peerChannelMemberCategoriesContextsManager.updateMemberBannedRights(engine: strongSelf.context.engine, peerId: strongSelf.call.peerId, memberId: peer.id, bannedRights: TelegramChatBannedRights(flags: [.banReadMessages], untilDate: Int32.max)).start() strongSelf.call.removedPeer(peer.id) - strongSelf.presentUndoOverlay(content: .banned(text: strongSelf.presentationData.strings.VoiceChat_RemovedPeerText(peer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder)).string), action: { _ in return false }) + strongSelf.presentUndoOverlay(content: .banned(text: strongSelf.presentationData.strings.VoiceChat_RemovedPeerText(EnginePeer(peer).displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder)).string), action: { _ in return false }) })) actionSheet.setItemGroups([ @@ -1997,7 +1997,7 @@ public final class VoiceChatController: ViewController { strongSelf.peer = peer strongSelf.currentTitleIsCustom = title != nil - strongSelf.currentTitle = title ?? peer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder) + strongSelf.currentTitle = title ?? EnginePeer(peer).displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder) strongSelf.updateTitle(transition: .immediate) strongSelf.titleNode.isRecording = isRecording @@ -2230,7 +2230,7 @@ public final class VoiceChatController: ViewController { if let channel = strongSelf.peer as? TelegramChannel, case .broadcast = channel.info { return } - let text = strongSelf.presentationData.strings.VoiceChat_PeerJoinedText(event.peer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder)).string + let text = strongSelf.presentationData.strings.VoiceChat_PeerJoinedText(EnginePeer(event.peer).displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder)).string strongSelf.presentUndoOverlay(content: .invitedToVoiceChat(context: strongSelf.context, peer: event.peer, text: text), action: { _ in return false }) } })) @@ -2242,9 +2242,9 @@ public final class VoiceChatController: ViewController { } let text: String if let channel = strongSelf.peer as? TelegramChannel, case .broadcast = channel.info { - text = strongSelf.presentationData.strings.LiveStream_DisplayAsSuccess(peer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder)).string + text = strongSelf.presentationData.strings.LiveStream_DisplayAsSuccess(EnginePeer(peer).displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder)).string } else { - text = strongSelf.presentationData.strings.VoiceChat_DisplayAsSuccess(peer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder)).string + text = strongSelf.presentationData.strings.VoiceChat_DisplayAsSuccess(EnginePeer(peer).displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder)).string } strongSelf.presentUndoOverlay(content: .invitedToVoiceChat(context: strongSelf.context, peer: peer, text: text), action: { _ in return false }) })) @@ -2483,7 +2483,7 @@ public final class VoiceChatController: ViewController { if peers.count > 1 { for peer in peers { if peer.peer.id == myPeerId { - items.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.VoiceChat_DisplayAs, textLayout: .secondLineWithValue(peer.peer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder)), icon: { _ in nil }, iconSource: ContextMenuActionItemIconSource(size: avatarSize, signal: peerAvatarCompleteImage(account: strongSelf.context.account, peer: peer.peer, size: avatarSize)), action: { c, _ in + items.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.VoiceChat_DisplayAs, textLayout: .secondLineWithValue(EnginePeer(peer.peer).displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder)), icon: { _ in nil }, iconSource: ContextMenuActionItemIconSource(size: avatarSize, signal: peerAvatarCompleteImage(account: strongSelf.context.account, peer: peer.peer, size: avatarSize)), action: { c, _ in guard let strongSelf = self else { return } @@ -2899,7 +2899,7 @@ public final class VoiceChatController: ViewController { } } - items.append(.action(ContextMenuActionItem(text: peer.peer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder), textLayout: subtitle.flatMap { .secondLineWithValue($0) } ?? .singleLine, icon: { _ in nil }, iconSource: ContextMenuActionItemIconSource(size: isSelected ? extendedAvatarSize : avatarSize, signal: avatarSignal), action: { _, f in + items.append(.action(ContextMenuActionItem(text: EnginePeer(peer.peer).displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder), textLayout: subtitle.flatMap { .secondLineWithValue($0) } ?? .singleLine, icon: { _ in nil }, iconSource: ContextMenuActionItemIconSource(size: isSelected ? extendedAvatarSize : avatarSize, signal: avatarSignal), action: { _, f in f(.default) guard let strongSelf = self else { @@ -3381,14 +3381,14 @@ public final class VoiceChatController: ViewController { var isSavedMessages = false if peers.count == 1, let peer = peers.first { isSavedMessages = peer.id == strongSelf.context.account.peerId - let peerName = peer.id == strongSelf.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) + let peerName = peer.id == strongSelf.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : EnginePeer(peer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) text = presentationData.strings.VoiceChat_ForwardTooltip_Chat(peerName).string } else if peers.count == 2, let firstPeer = peers.first, let secondPeer = peers.last { - let firstPeerName = firstPeer.id == strongSelf.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : firstPeer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) - let secondPeerName = secondPeer.id == strongSelf.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : secondPeer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) + let firstPeerName = firstPeer.id == strongSelf.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : EnginePeer(firstPeer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) + let secondPeerName = secondPeer.id == strongSelf.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : EnginePeer(secondPeer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) text = presentationData.strings.VoiceChat_ForwardTooltip_TwoChats(firstPeerName, secondPeerName).string } else if let peer = peers.first { - let peerName = peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) + let peerName = EnginePeer(peer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) text = presentationData.strings.VoiceChat_ForwardTooltip_ManyChats(peerName, "\(peers.count - 1)").string } else { text = "" @@ -5406,7 +5406,7 @@ public final class VoiceChatController: ViewController { for peerId in Array(speakingPeers) { updatedSpeakers.append(peerId) if let peer = entryByPeerId[peerId]?.peer { - let displayName = speakingPeers.count == 1 ? peer.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) : peer.compactDisplayTitle + let displayName = speakingPeers.count == 1 ? EnginePeer(peer).displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) : EnginePeer(peer).compactDisplayTitle if currentSpeakingSubtitle.isEmpty { currentSpeakingSubtitle.append(displayName) } else { @@ -6062,7 +6062,7 @@ public final class VoiceChatController: ViewController { text = strongSelf.presentationData.strings.VoiceChat_EditTitleText } - let controller = voiceChatTitleEditController(sharedContext: strongSelf.context.sharedContext, account: strongSelf.context.account, forceTheme: strongSelf.darkTheme, title: title, text: text, placeholder: chatPeer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder), value: initialTitle, maxLength: 40, apply: { title in + let controller = voiceChatTitleEditController(sharedContext: strongSelf.context.sharedContext, account: strongSelf.context.account, forceTheme: strongSelf.darkTheme, title: title, text: text, placeholder: EnginePeer(chatPeer).displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder), value: initialTitle, maxLength: 40, apply: { title in if let strongSelf = self, let title = title, title != initialTitle { strongSelf.call.updateTitle(title) @@ -6133,7 +6133,7 @@ public final class VoiceChatController: ViewController { guard let strongSelf = self else { return } - let controller = WebSearchController(context: strongSelf.context, peer: peer, chatLocation: nil, configuration: searchBotsConfiguration, mode: .avatar(initialQuery: peer.id.namespace == Namespaces.Peer.CloudUser ? nil : peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), completion: { [weak self] result in + let controller = WebSearchController(context: strongSelf.context, peer: peer, chatLocation: nil, configuration: searchBotsConfiguration, mode: .avatar(initialQuery: peer.id.namespace == Namespaces.Peer.CloudUser ? nil : EnginePeer(peer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), completion: { [weak self] result in assetsController?.dismiss() self?.updateProfilePhoto(result) })) diff --git a/submodules/TelegramCallsUI/Sources/VoiceChatJoinScreen.swift b/submodules/TelegramCallsUI/Sources/VoiceChatJoinScreen.swift index 81195fa8fa..69e1b1e11e 100644 --- a/submodules/TelegramCallsUI/Sources/VoiceChatJoinScreen.swift +++ b/submodules/TelegramCallsUI/Sources/VoiceChatJoinScreen.swift @@ -672,7 +672,7 @@ final class VoiceChatPreviewContentNode: ASDisplayNode, ShareContentContainerNod self.avatarNode.setPeer(context: context, theme: theme, peer: EnginePeer(peer), emptyColor: theme.list.mediaPlaceholderColor) self.addSubnode(self.titleNode) - self.titleNode.attributedText = NSAttributedString(string: title ?? peer.displayTitle(strings: strings, displayOrder: displayOrder), font: Font.semibold(16.0), textColor: theme.actionSheet.primaryTextColor) + self.titleNode.attributedText = NSAttributedString(string: title ?? EnginePeer(peer).displayTitle(strings: strings, displayOrder: displayOrder), font: Font.semibold(16.0), textColor: theme.actionSheet.primaryTextColor) self.addSubnode(self.countNode) diff --git a/submodules/TelegramCallsUI/Sources/VoiceChatMainStageNode.swift b/submodules/TelegramCallsUI/Sources/VoiceChatMainStageNode.swift index 7c0cc6f84d..59e62a17f4 100644 --- a/submodules/TelegramCallsUI/Sources/VoiceChatMainStageNode.swift +++ b/submodules/TelegramCallsUI/Sources/VoiceChatMainStageNode.swift @@ -641,7 +641,7 @@ final class VoiceChatMainStageNode: ASDisplayNode { let bodyAttributes = MarkdownAttributeSet(font: Font.regular(15.0), textColor: .white, additionalAttributes: [:]) let boldAttributes = MarkdownAttributeSet(font: Font.semibold(15.0), textColor: .white, additionalAttributes: [:]) - let attributedText = addAttributesToStringWithRanges(presentationData.strings.VoiceChat_ParticipantIsSpeaking(peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder))._tuple, body: bodyAttributes, argumentAttributes: [0: boldAttributes]) + let attributedText = addAttributesToStringWithRanges(presentationData.strings.VoiceChat_ParticipantIsSpeaking(EnginePeer(peer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder))._tuple, body: bodyAttributes, argumentAttributes: [0: boldAttributes]) strongSelf.speakingTitleNode.attributedText = attributedText strongSelf.speakingContainerNode.alpha = 0.0 @@ -771,7 +771,7 @@ final class VoiceChatMainStageNode: ASDisplayNode { } var microphoneColor = UIColor.white - var titleAttributedString = NSAttributedString(string: peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), font: Font.semibold(15.0), textColor: .white) + var titleAttributedString = NSAttributedString(string: EnginePeer(peer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), font: Font.semibold(15.0), textColor: .white) if mutedForYou { microphoneColor = destructiveColor diff --git a/submodules/TelegramCore/Sources/Account/AccountManager.swift b/submodules/TelegramCore/Sources/Account/AccountManager.swift index c7c4726a5b..a5785e1192 100644 --- a/submodules/TelegramCore/Sources/Account/AccountManager.swift +++ b/submodules/TelegramCore/Sources/Account/AccountManager.swift @@ -129,7 +129,6 @@ private var declaredEncodables: Void = { declareEncodable(CloudChatRemoveMessagesOperation.self, f: { CloudChatRemoveMessagesOperation(decoder: $0) }) declareEncodable(AutoremoveTimeoutMessageAttribute.self, f: { AutoremoveTimeoutMessageAttribute(decoder: $0) }) declareEncodable(AutoclearTimeoutMessageAttribute.self, f: { AutoclearTimeoutMessageAttribute(decoder: $0) }) - //declareEncodable(GlobalNotificationSettings.self, f: { GlobalNotificationSettings(decoder: $0) }) declareEncodable(CloudChatRemoveChatOperation.self, f: { CloudChatRemoveChatOperation(decoder: $0) }) declareEncodable(SynchronizePinnedChatsOperation.self, f: { SynchronizePinnedChatsOperation(decoder: $0) }) declareEncodable(SynchronizeConsumeMessageContentsOperation.self, f: { SynchronizeConsumeMessageContentsOperation(decoder: $0) }) diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Data/Messages.swift b/submodules/TelegramCore/Sources/TelegramEngine/Data/Messages.swift new file mode 100644 index 0000000000..c9051f4380 --- /dev/null +++ b/submodules/TelegramCore/Sources/TelegramEngine/Data/Messages.swift @@ -0,0 +1,55 @@ +import SwiftSignalKit +import Postbox + +public extension TelegramEngine.EngineData.Item { + enum Messages { + public struct Message: TelegramEngineDataItem, PostboxViewDataItem { + public typealias Result = Optional + + fileprivate var id: EngineMessage.Id + + public init(id: EngineMessage.Id) { + self.id = id + } + + var key: PostboxViewKey { + return .messages(Set([self.id])) + } + + func extract(view: PostboxView) -> Result { + guard let view = view as? MessagesView else { + preconditionFailure() + } + guard let message = view.messages[self.id] else { + return nil + } + return EngineMessage(message) + } + } + + public struct Messages: TelegramEngineDataItem, PostboxViewDataItem { + public typealias Result = [EngineMessage.Id: EngineMessage] + + fileprivate var ids: Set + + public init(ids: Set) { + self.ids = ids + } + + var key: PostboxViewKey { + return .messages(self.ids) + } + + func extract(view: PostboxView) -> Result { + guard let view = view as? MessagesView else { + preconditionFailure() + } + var result: [EngineMessage.Id: EngineMessage] = [:] + for (id, message) in view.messages { + result[id] = EngineMessage(message) + } + return result + } + } + } +} diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Messages/TelegramEngineMessages.swift b/submodules/TelegramCore/Sources/TelegramEngine/Messages/TelegramEngineMessages.swift index 934a54d47f..08b883f193 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Messages/TelegramEngineMessages.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Messages/TelegramEngineMessages.swift @@ -207,5 +207,39 @@ public extension TelegramEngine { public func messageReadStats(id: MessageId) -> Signal { return _internal_messageReadStats(account: self.account, id: id) } + + public func requestCancelLiveLocation(ids: [MessageId]) -> Signal { + return self.account.postbox.transaction { transaction -> Void in + for id in ids { + transaction.updateMessage(id, update: { currentMessage in + var storeForwardInfo: StoreMessageForwardInfo? + if let forwardInfo = currentMessage.forwardInfo { + storeForwardInfo = StoreMessageForwardInfo(authorId: forwardInfo.author?.id, sourceId: forwardInfo.source?.id, sourceMessageId: forwardInfo.sourceMessageId, date: forwardInfo.date, authorSignature: forwardInfo.authorSignature, psaType: forwardInfo.psaType, flags: forwardInfo.flags) + } + var updatedMedia = currentMessage.media + let timestamp = Int32(CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970) + for i in 0 ..< updatedMedia.count { + if let media = updatedMedia[i] as? TelegramMediaMap, let _ = media.liveBroadcastingTimeout { + updatedMedia[i] = TelegramMediaMap(latitude: media.latitude, longitude: media.longitude, heading: media.heading, accuracyRadius: media.accuracyRadius, geoPlace: media.geoPlace, venue: media.venue, liveBroadcastingTimeout: max(0, timestamp - currentMessage.timestamp - 1), liveProximityNotificationRadius: nil) + } + } + return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: currentMessage.attributes, media: updatedMedia)) + }) + } + } + |> ignoreValues + } + + public func activeLiveLocationMessages() -> Signal<[EngineMessage], NoError> { + let viewKey: PostboxViewKey = .localMessageTag(.OutgoingLiveLocation) + return self.account.postbox.combinedView(keys: [viewKey]) + |> map { view in + if let view = view.views[viewKey] as? LocalMessageTagsView { + return view.messages.values.map(EngineMessage.init) + } else { + return [] + } + } + } } } diff --git a/submodules/TelegramIntents/Sources/TelegramIntents.swift b/submodules/TelegramIntents/Sources/TelegramIntents.swift index 64378d8a68..56123b108b 100644 --- a/submodules/TelegramIntents/Sources/TelegramIntents.swift +++ b/submodules/TelegramIntents/Sources/TelegramIntents.swift @@ -178,12 +178,12 @@ public func donateSendMessageIntent(account: Account, sharedContext: SharedAccou displayTitle = presentationData.strings.DialogList_SavedMessages nameComponents.givenName = displayTitle } else { - displayTitle = peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) + displayTitle = EnginePeer(peer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) nameComponents.givenName = peer.firstName nameComponents.familyName = peer.lastName } } else { - displayTitle = peer.compactDisplayTitle + displayTitle = EnginePeer(peer).compactDisplayTitle nameComponents.givenName = displayTitle } diff --git a/submodules/TelegramNotices/Sources/Notices.swift b/submodules/TelegramNotices/Sources/Notices.swift index ef2045ddf3..b47747522c 100644 --- a/submodules/TelegramNotices/Sources/Notices.swift +++ b/submodules/TelegramNotices/Sources/Notices.swift @@ -991,7 +991,7 @@ public struct ApplicationSpecificNotice { public static func getInteractiveEmojiSyncTip(accountManager: AccountManager) -> Signal<(Int32, Int32), NoError> { return accountManager.transaction { transaction -> (Int32, Int32) in - if let value = transaction.getNotice(ApplicationSpecificNoticeKeys.interactiveEmojiSyncTip()) as? ApplicationSpecificTimestampAndCounterNotice { + if let value = transaction.getNotice(ApplicationSpecificNoticeKeys.interactiveEmojiSyncTip())?.get(ApplicationSpecificTimestampAndCounterNotice.self) { return (value.counter, value.timestamp) } else { return (0, 0) @@ -1002,13 +1002,15 @@ public struct ApplicationSpecificNotice { public static func incrementInteractiveEmojiSyncTip(accountManager: AccountManager, count: Int = 1, timestamp: Int32) -> Signal { return accountManager.transaction { transaction -> Int in var currentValue: Int32 = 0 - if let value = transaction.getNotice(ApplicationSpecificNoticeKeys.interactiveEmojiSyncTip()) as? ApplicationSpecificTimestampAndCounterNotice { + if let value = transaction.getNotice(ApplicationSpecificNoticeKeys.interactiveEmojiSyncTip())?.get(ApplicationSpecificTimestampAndCounterNotice.self) { currentValue = value.counter } let previousValue = currentValue currentValue += Int32(count) - - transaction.setNotice(ApplicationSpecificNoticeKeys.interactiveEmojiSyncTip(), ApplicationSpecificTimestampAndCounterNotice(counter: currentValue, timestamp: timestamp)) + + if let entry = CodableEntry(ApplicationSpecificTimestampAndCounterNotice(counter: currentValue, timestamp: timestamp)) { + transaction.setNotice(ApplicationSpecificNoticeKeys.interactiveEmojiSyncTip(), entry) + } return Int(previousValue) } diff --git a/submodules/TelegramStringFormatting/Sources/PeerDisplayName.swift b/submodules/TelegramStringFormatting/Sources/PeerDisplayName.swift index 7d496cd262..cdc730d8b9 100644 --- a/submodules/TelegramStringFormatting/Sources/PeerDisplayName.swift +++ b/submodules/TelegramStringFormatting/Sources/PeerDisplayName.swift @@ -1,10 +1,9 @@ import Foundation -import Postbox import TelegramPresentationData import TelegramUIPreferences import TelegramCore -public func stringForFullAuthorName(message: Message, strings: PresentationStrings, nameDisplayOrder: PresentationPersonNameOrder, accountPeerId: PeerId) -> String { +public func stringForFullAuthorName(message: EngineMessage, strings: PresentationStrings, nameDisplayOrder: PresentationPersonNameOrder, accountPeerId: EnginePeer.Id) -> String { var authorString = "" if let author = message.author, [Namespaces.Peer.CloudGroup, Namespaces.Peer.CloudChannel].contains(message.id.peerId.namespace) { var authorName = "" @@ -13,12 +12,12 @@ public func stringForFullAuthorName(message: Message, strings: PresentationStrin } else { authorName = author.compactDisplayTitle } - if let peer = message.peers[message.id.peerId], author.id != peer.id { + if let peer = message.peers[message.id.peerId].flatMap(EnginePeer.init), author.id != peer.id { authorString = "\(authorName) → \(peer.displayTitle(strings: strings, displayOrder: nameDisplayOrder))" } else { authorString = authorName } - } else if let peer = message.peers[message.id.peerId] { + } else if let peer = message.peers[message.id.peerId].flatMap(EnginePeer.init) { if message.id.peerId.namespace == Namespaces.Peer.CloudChannel { authorString = peer.displayTitle(strings: strings, displayOrder: nameDisplayOrder) } else { diff --git a/submodules/TelegramStringFormatting/Sources/PresenceStrings.swift b/submodules/TelegramStringFormatting/Sources/PresenceStrings.swift index edf9e67ab2..0b3901f83e 100644 --- a/submodules/TelegramStringFormatting/Sources/PresenceStrings.swift +++ b/submodules/TelegramStringFormatting/Sources/PresenceStrings.swift @@ -345,10 +345,8 @@ public func stringForRelativeLiveLocationUpdateTimestamp(strings: PresentationSt } } -public func stringAndActivityForUserPresence(strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, presence: TelegramUserPresence, relativeTo timestamp: Int32, expanded: Bool = false) -> (String, Bool) { +public func stringAndActivityForUserPresence(strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, presence: EnginePeer.Presence, relativeTo timestamp: Int32, expanded: Bool = false) -> (String, Bool) { switch presence.status { - case .none: - return (strings.LastSeen_Offline, false) case let .present(statusTimestamp): if statusTimestamp >= timestamp { return (strings.Presence_online, true) @@ -402,6 +400,8 @@ public func stringAndActivityForUserPresence(strings: PresentationStrings, dateT return (strings.LastSeen_WithinAWeek, false) case .lastMonth: return (strings.LastSeen_WithinAMonth, false) + case .longTimeAgo: + return (strings.LastSeen_ALongTimeAgo, false) } } diff --git a/submodules/TelegramStringFormatting/Sources/ServiceMessageStrings.swift b/submodules/TelegramStringFormatting/Sources/ServiceMessageStrings.swift index 38f10a80b6..1365862c44 100644 --- a/submodules/TelegramStringFormatting/Sources/ServiceMessageStrings.swift +++ b/submodules/TelegramStringFormatting/Sources/ServiceMessageStrings.swift @@ -45,7 +45,7 @@ public func universalServiceMessageString(presentationData: (PresentationTheme, for media in message.media { if let action = media as? TelegramMediaAction { - let authorName = message.author?.displayTitle(strings: strings, displayOrder: nameDisplayOrder) ?? "" + let authorName = message.author.flatMap(EnginePeer.init)?.displayTitle(strings: strings, displayOrder: nameDisplayOrder) ?? "" var isChannel = false if message.id.peerId.namespace == Namespaces.Peer.CloudChannel, let peer = message.peers[message.id.peerId] as? TelegramChannel, case .broadcast = peer.info { @@ -263,7 +263,7 @@ public func universalServiceMessageString(presentationData: (PresentationTheme, case let .messageAutoremoveTimeoutUpdated(timeout): let authorString: String if let author = messageMainPeer(message) { - authorString = author.compactDisplayTitle + authorString = EnginePeer(author).compactDisplayTitle } else { authorString = "" } @@ -326,7 +326,7 @@ public func universalServiceMessageString(presentationData: (PresentationTheme, case .historyScreenshot: let text: String if message.effectivelyIncoming(accountPeerId) { - text = strings.Notification_SecretChatMessageScreenshot(message.author?.compactDisplayTitle ?? "").string + text = strings.Notification_SecretChatMessageScreenshot(message.author.flatMap(EnginePeer.init)?.compactDisplayTitle ?? "").string } else { text = strings.Notification_SecretChatMessageScreenshotSelf } @@ -391,7 +391,7 @@ public func universalServiceMessageString(presentationData: (PresentationTheme, if let invoiceTitle = invoiceTitle { let botString: String if let peer = messageMainPeer(message) { - botString = peer.compactDisplayTitle + botString = EnginePeer(peer).compactDisplayTitle } else { botString = "" } @@ -514,7 +514,7 @@ public func universalServiceMessageString(presentationData: (PresentationTheme, typesString.append(strings.Notification_PassportValueEmail) } } - attributedString = NSAttributedString(string: strings.Notification_PassportValuesSentMessage(message.peers[message.id.peerId]?.compactDisplayTitle ?? "", typesString).string, font: titleFont, textColor: primaryTextColor) + attributedString = NSAttributedString(string: strings.Notification_PassportValuesSentMessage(message.peers[message.id.peerId].flatMap(EnginePeer.init)?.compactDisplayTitle ?? "", typesString).string, font: titleFont, textColor: primaryTextColor) case .peerJoined: attributedString = addAttributesToStringWithRanges(strings.Notification_Joined(authorName)._tuple, body: bodyAttributes, argumentAttributes: peerMentionsAttributes(primaryTextColor: primaryTextColor, peerIds: [(0, message.author?.id)])) case .phoneNumberRequest: @@ -522,11 +522,11 @@ public func universalServiceMessageString(presentationData: (PresentationTheme, case let .geoProximityReached(fromId, toId, distance): let distanceString = stringForDistance(strings: strings, distance: Double(distance)) if fromId == accountPeerId { - attributedString = addAttributesToStringWithRanges(strings.Notification_ProximityYouReached(distanceString, message.peers[toId]?.displayTitle(strings: strings, displayOrder: nameDisplayOrder) ?? "")._tuple, body: bodyAttributes, argumentAttributes: peerMentionsAttributes(primaryTextColor: primaryTextColor, peerIds: [(1, toId)])) + attributedString = addAttributesToStringWithRanges(strings.Notification_ProximityYouReached(distanceString, message.peers[toId].flatMap(EnginePeer.init)?.displayTitle(strings: strings, displayOrder: nameDisplayOrder) ?? "")._tuple, body: bodyAttributes, argumentAttributes: peerMentionsAttributes(primaryTextColor: primaryTextColor, peerIds: [(1, toId)])) } else if toId == accountPeerId { - attributedString = addAttributesToStringWithRanges(strings.Notification_ProximityReachedYou(message.peers[fromId]?.displayTitle(strings: strings, displayOrder: nameDisplayOrder) ?? "", distanceString)._tuple, body: bodyAttributes, argumentAttributes: peerMentionsAttributes(primaryTextColor: primaryTextColor, peerIds: [(0, fromId)])) + attributedString = addAttributesToStringWithRanges(strings.Notification_ProximityReachedYou(message.peers[fromId].flatMap(EnginePeer.init)?.displayTitle(strings: strings, displayOrder: nameDisplayOrder) ?? "", distanceString)._tuple, body: bodyAttributes, argumentAttributes: peerMentionsAttributes(primaryTextColor: primaryTextColor, peerIds: [(0, fromId)])) } else { - attributedString = addAttributesToStringWithRanges(strings.Notification_ProximityReached(message.peers[fromId]?.displayTitle(strings: strings, displayOrder: nameDisplayOrder) ?? "", distanceString, message.peers[toId]?.displayTitle(strings: strings, displayOrder: nameDisplayOrder) ?? "")._tuple, body: bodyAttributes, argumentAttributes: peerMentionsAttributes(primaryTextColor: primaryTextColor, peerIds: [(0, fromId), (2, toId)])) + attributedString = addAttributesToStringWithRanges(strings.Notification_ProximityReached(message.peers[fromId].flatMap(EnginePeer.init)?.displayTitle(strings: strings, displayOrder: nameDisplayOrder) ?? "", distanceString, message.peers[toId].flatMap(EnginePeer.init)?.displayTitle(strings: strings, displayOrder: nameDisplayOrder) ?? "")._tuple, body: bodyAttributes, argumentAttributes: peerMentionsAttributes(primaryTextColor: primaryTextColor, peerIds: [(0, fromId), (2, toId)])) } case let .inviteToGroupPhoneCall(_, _, peerIds): var attributePeerIds: [(Int, PeerId?)] = [(0, message.author?.id)] diff --git a/submodules/TelegramUI/Sources/AccountContext.swift b/submodules/TelegramUI/Sources/AccountContext.swift index c4981b6868..71639ef28c 100644 --- a/submodules/TelegramUI/Sources/AccountContext.swift +++ b/submodules/TelegramUI/Sources/AccountContext.swift @@ -165,7 +165,7 @@ public final class AccountContextImpl: AccountContext { self.downloadedMediaStoreManager = DownloadedMediaStoreManagerImpl(postbox: account.postbox, accountManager: sharedContext.accountManager) if let locationManager = self.sharedContextImpl.locationManager { - self.liveLocationManager = LiveLocationManagerImpl(engine: self.engine, account: account, locationManager: locationManager, inForeground: sharedContext.applicationBindings.applicationInForeground) + self.liveLocationManager = LiveLocationManagerImpl(engine: self.engine, locationManager: locationManager, inForeground: sharedContext.applicationBindings.applicationInForeground) } else { self.liveLocationManager = nil } @@ -350,10 +350,10 @@ public final class AccountContextImpl: AccountContext { let text: String if let channel = current as? TelegramChannel, case .broadcast = channel.info { title = presentationData.strings.Call_LiveStreamInProgressTitle - text = presentationData.strings.Call_LiveStreamInProgressMessage(current.compactDisplayTitle, peer.compactDisplayTitle).string + text = presentationData.strings.Call_LiveStreamInProgressMessage(EnginePeer(current).compactDisplayTitle, EnginePeer(peer).compactDisplayTitle).string } else { title = presentationData.strings.Call_VoiceChatInProgressTitle - text = presentationData.strings.Call_VoiceChatInProgressMessage(current.compactDisplayTitle, peer.compactDisplayTitle).string + text = presentationData.strings.Call_VoiceChatInProgressMessage(EnginePeer(current).compactDisplayTitle, EnginePeer(peer).compactDisplayTitle).string } strongSelf.sharedContext.mainWindow?.present(textAlertController(context: strongSelf, title: title, text: text, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_Cancel, action: {}), TextAlertAction(type: .genericAction, title: presentationData.strings.Common_OK, action: { @@ -365,9 +365,9 @@ public final class AccountContextImpl: AccountContext { } else { let text: String if let channel = peer as? TelegramChannel, case .broadcast = channel.info { - text = presentationData.strings.Call_CallInProgressLiveStreamMessage(current.compactDisplayTitle, peer.compactDisplayTitle).string + text = presentationData.strings.Call_CallInProgressLiveStreamMessage(EnginePeer(current).compactDisplayTitle, EnginePeer(peer).compactDisplayTitle).string } else { - text = presentationData.strings.Call_CallInProgressVoiceChatMessage(current.compactDisplayTitle, peer.compactDisplayTitle).string + text = presentationData.strings.Call_CallInProgressVoiceChatMessage(EnginePeer(current).compactDisplayTitle, EnginePeer(peer).compactDisplayTitle).string } strongSelf.sharedContext.mainWindow?.present(textAlertController(context: strongSelf, title: presentationData.strings.Call_CallInProgressTitle, text: text, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_Cancel, action: {}), TextAlertAction(type: .genericAction, title: presentationData.strings.Common_OK, action: { guard let strongSelf = self else { @@ -410,9 +410,9 @@ public final class AccountContextImpl: AccountContext { if current is TelegramChannel || current is TelegramGroup { let text: String if let channel = current as? TelegramChannel, case .broadcast = channel.info { - text = presentationData.strings.Call_LiveStreamInProgressCallMessage(current.compactDisplayTitle, peer.compactDisplayTitle).string + text = presentationData.strings.Call_LiveStreamInProgressCallMessage(EnginePeer(current).compactDisplayTitle, EnginePeer(peer).compactDisplayTitle).string } else { - text = presentationData.strings.Call_VoiceChatInProgressCallMessage(current.compactDisplayTitle, peer.compactDisplayTitle).string + text = presentationData.strings.Call_VoiceChatInProgressCallMessage(EnginePeer(current).compactDisplayTitle, EnginePeer(peer).compactDisplayTitle).string } strongSelf.sharedContext.mainWindow?.present(textAlertController(context: strongSelf, title: presentationData.strings.Call_VoiceChatInProgressTitle, text: text, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_Cancel, action: {}), TextAlertAction(type: .genericAction, title: presentationData.strings.Common_OK, action: { guard let strongSelf = self else { @@ -422,7 +422,7 @@ public final class AccountContextImpl: AccountContext { completion() })]), on: .root) } else { - strongSelf.sharedContext.mainWindow?.present(textAlertController(context: strongSelf, title: presentationData.strings.Call_CallInProgressTitle, text: presentationData.strings.Call_CallInProgressMessage(current.compactDisplayTitle, peer.compactDisplayTitle).string, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_Cancel, action: {}), TextAlertAction(type: .genericAction, title: presentationData.strings.Common_OK, action: { + strongSelf.sharedContext.mainWindow?.present(textAlertController(context: strongSelf, title: presentationData.strings.Call_CallInProgressTitle, text: presentationData.strings.Call_CallInProgressMessage(EnginePeer(current).compactDisplayTitle, EnginePeer(peer).compactDisplayTitle).string, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_Cancel, action: {}), TextAlertAction(type: .genericAction, title: presentationData.strings.Common_OK, action: { guard let strongSelf = self else { return } diff --git a/submodules/TelegramUI/Sources/AppDelegate.swift b/submodules/TelegramUI/Sources/AppDelegate.swift index 2051507394..d94725fda2 100644 --- a/submodules/TelegramUI/Sources/AppDelegate.swift +++ b/submodules/TelegramUI/Sources/AppDelegate.swift @@ -1261,7 +1261,7 @@ final class SharedApplicationContext { } |> map { accountAndPeer -> String? in if let (_, peer, _) = accountAndPeer { - return peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) + return EnginePeer(peer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) } else { return nil } diff --git a/submodules/TelegramUI/Sources/ChatController.swift b/submodules/TelegramUI/Sources/ChatController.swift index 03e45cf194..c560854080 100644 --- a/submodules/TelegramUI/Sources/ChatController.swift +++ b/submodules/TelegramUI/Sources/ChatController.swift @@ -1310,7 +1310,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G } strongSelf.chatDisplayNode.dismissInput() - strongSelf.effectiveNavigationController?.pushViewController(GameController(context: strongSelf.context, url: url, message: message)) + strongSelf.effectiveNavigationController?.pushViewController(GameController(context: strongSelf.context, url: url, message: EngineMessage(message))) } var botPeer: TelegramUser? @@ -1341,7 +1341,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G if value { openBot() } else { - strongSelf.present(textAlertController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, title: nil, text: strongSelf.presentationData.strings.Conversation_BotInteractiveUrlAlert(botPeer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder)).string, actions: [TextAlertAction(type: .genericAction, title: strongSelf.presentationData.strings.Common_Cancel, action: { }), TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: { + strongSelf.present(textAlertController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, title: nil, text: strongSelf.presentationData.strings.Conversation_BotInteractiveUrlAlert(EnginePeer(botPeer).displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder)).string, actions: [TextAlertAction(type: .genericAction, title: strongSelf.presentationData.strings.Common_Cancel, action: { }), TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: { if let strongSelf = self { let _ = ApplicationSpecificNotice.setBotGameNotice(accountManager: strongSelf.context.sharedContext.accountManager, peerId: botPeer.id).start() openBot() @@ -1461,7 +1461,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G case .default: strongSelf.openUrl(defaultUrl, concealed: false, skipUrlAuth: true) case let .request(domain, bot, requestWriteAccess): - let controller = chatMessageActionUrlAuthController(context: strongSelf.context, defaultUrl: defaultUrl, domain: domain, bot: bot, requestWriteAccess: requestWriteAccess, displayName: peer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder), open: { [weak self] authorize, allowWriteAccess in + let controller = chatMessageActionUrlAuthController(context: strongSelf.context, defaultUrl: defaultUrl, domain: domain, bot: bot, requestWriteAccess: requestWriteAccess, displayName: EnginePeer(peer).displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder), open: { [weak self] authorize, allowWriteAccess in if let strongSelf = self { if authorize { strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: true, { @@ -1706,14 +1706,14 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G savedMessages = true } else { if peers.count == 1, let peer = peers.first { - let peerName = peer.id == strongSelf.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) + let peerName = peer.id == strongSelf.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : EnginePeer(peer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) text = messages.count == 1 ? presentationData.strings.Conversation_ForwardTooltip_Chat_One(peerName).string : presentationData.strings.Conversation_ForwardTooltip_Chat_Many(peerName).string } else if peers.count == 2, let firstPeer = peers.first, let secondPeer = peers.last { - let firstPeerName = firstPeer.id == strongSelf.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : firstPeer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) - let secondPeerName = secondPeer.id == strongSelf.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : secondPeer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) + let firstPeerName = firstPeer.id == strongSelf.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : EnginePeer(firstPeer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) + let secondPeerName = secondPeer.id == strongSelf.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : EnginePeer(secondPeer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) text = messages.count == 1 ? presentationData.strings.Conversation_ForwardTooltip_TwoChats_One(firstPeerName, secondPeerName).string : presentationData.strings.Conversation_ForwardTooltip_TwoChats_Many(firstPeerName, secondPeerName).string } else if let peer = peers.first { - let peerName = peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) + let peerName = EnginePeer(peer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) text = messages.count == 1 ? presentationData.strings.Conversation_ForwardTooltip_ManyChats_One(peerName, "\(peers.count - 1)").string : presentationData.strings.Conversation_ForwardTooltip_ManyChats_Many(peerName, "\(peers.count - 1)").string } else { text = "" @@ -1756,7 +1756,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G if let cachedUserData = strongSelf.peerView?.cachedData as? CachedUserData, cachedUserData.callsPrivate { let presentationData = context.sharedContext.currentPresentationData.with { $0 } - strongSelf.present(textAlertController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, title: presentationData.strings.Call_ConnectionErrorTitle, text: presentationData.strings.Call_PrivacyErrorMessage(peer.compactDisplayTitle).string, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), in: .window(.root)) + strongSelf.present(textAlertController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, title: presentationData.strings.Call_ConnectionErrorTitle, text: presentationData.strings.Call_PrivacyErrorMessage(EnginePeer(peer).compactDisplayTitle).string, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), in: .window(.root)) return } @@ -2915,7 +2915,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G |> timeout(2.0, queue: Queue.mainQueue(), alternate: .single(false))).start(next: { [weak self] responded in if let strongSelf = self { if !responded { - strongSelf.present(UndoOverlayController(presentationData: strongSelf.presentationData, content: .sticker(context: strongSelf.context, file: file, text: strongSelf.presentationData.strings.Conversation_InteractiveEmojiSyncTip(peer.compactDisplayTitle).string), elevatedLayout: false, action: { _ in return false }), in: .current) + strongSelf.present(UndoOverlayController(presentationData: strongSelf.presentationData, content: .sticker(context: strongSelf.context, file: file, text: strongSelf.presentationData.strings.Conversation_InteractiveEmojiSyncTip(EnginePeer(peer).compactDisplayTitle).string), elevatedLayout: false, action: { _ in return false }), in: .current) let _ = ApplicationSpecificNotice.incrementInteractiveEmojiSyncTip(accountManager: strongSelf.context.sharedContext.accountManager, timestamp: currentTimestamp).start() } @@ -3154,7 +3154,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G |> map { state, options, count in if let peer = state.renderedPeer?.chatMainPeer { if let peer = peer as? TelegramUser { - let displayName = peer.compactDisplayTitle + let displayName = EnginePeer(peer).compactDisplayTitle if count == 1 { if options.hideNames { return state.strings.Conversation_ForwardOptions_UserMessageForwardHidden(displayName).string @@ -5569,7 +5569,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G } var reportSpam = true var items: [ActionSheetItem] = [] - items.append(ActionSheetTextItem(title: presentationData.strings.UserInfo_BlockConfirmationTitle(peer.compactDisplayTitle).string)) + items.append(ActionSheetTextItem(title: presentationData.strings.UserInfo_BlockConfirmationTitle(EnginePeer(peer).compactDisplayTitle).string)) items.append(contentsOf: [ ActionSheetCheckboxItem(title: presentationData.strings.Conversation_Moderate_Report, label: "", value: reportSpam, action: { [weak controller] checkValue in reportSpam = checkValue @@ -6583,7 +6583,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G }) } else { var contextItems: [ContextMenuItem] = [] - contextItems.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.Conversation_PinMessagesFor(peer.compactDisplayTitle).string, textColor: .primary, icon: { _ in nil }, action: { c, _ in + contextItems.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.Conversation_PinMessagesFor(EnginePeer(peer).compactDisplayTitle).string, textColor: .primary, icon: { _ in nil }, action: { c, _ in c.dismiss(completion: { pinAction(true, false) }) @@ -8943,7 +8943,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G let confirmationText: String switch canClearForEveryone { case .user: - text = strongSelf.presentationData.strings.ChatList_DeleteForEveryone(mainPeer.compactDisplayTitle).string + text = strongSelf.presentationData.strings.ChatList_DeleteForEveryone(EnginePeer(mainPeer).compactDisplayTitle).string confirmationText = strongSelf.presentationData.strings.ChatList_DeleteForEveryoneConfirmationText default: text = strongSelf.presentationData.strings.Conversation_DeleteMessagesForEveryone @@ -10323,7 +10323,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G private func presentPollCreation(isQuiz: Bool? = nil) { if let peer = self.presentationInterfaceState.renderedPeer?.peer { - self.effectiveNavigationController?.pushViewController(createPollController(context: self.context, updatedPresentationData: self.updatedPresentationData, peer: EnginePeer(peer), isQuiz: isQuiz, completion: { [weak self] message in + self.effectiveNavigationController?.pushViewController(createPollController(context: self.context, updatedPresentationData: self.updatedPresentationData, peer: EnginePeer(peer), isQuiz: isQuiz, completion: { [weak self] poll in guard let strongSelf = self else { return } @@ -10335,6 +10335,24 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G }) } }, nil) + let message: EnqueueMessage = .message( + text: "", + attributes: [], + mediaReference: .standalone(media: TelegramMediaPoll( + pollId: MediaId(namespace: Namespaces.Media.LocalPoll, id: Int64.random(in: Int64.min ... Int64.max)), + publicity: poll.publicity, + kind: poll.kind, + text: poll.text, + options: poll.options, + correctAnswers: poll.correctAnswers, + results: poll.results, + isClosed: false, + deadlineTimeout: poll.deadlineTimeout + )), + replyToMessageId: nil, + localGroupingKey: nil, + correlationId: nil + ) strongSelf.sendMessages([message.withUpdatedReplyToMessageId(replyMessageId)]) })) } @@ -11730,14 +11748,14 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G savedMessages = true } else { if displayPeers.count == 1, let peer = displayPeers.first { - let peerName = peer.id == strongSelf.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) + let peerName = peer.id == strongSelf.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : EnginePeer(peer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) text = messages.count == 1 ? presentationData.strings.Conversation_ForwardTooltip_Chat_One(peerName).string : presentationData.strings.Conversation_ForwardTooltip_Chat_Many(peerName).string } else if displayPeers.count == 2, let firstPeer = displayPeers.first, let secondPeer = displayPeers.last { - let firstPeerName = firstPeer.id == strongSelf.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : firstPeer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) - let secondPeerName = secondPeer.id == strongSelf.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : secondPeer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) + let firstPeerName = firstPeer.id == strongSelf.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : EnginePeer(firstPeer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) + let secondPeerName = secondPeer.id == strongSelf.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : EnginePeer(secondPeer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) text = messages.count == 1 ? presentationData.strings.Conversation_ForwardTooltip_TwoChats_One(firstPeerName, secondPeerName).string : presentationData.strings.Conversation_ForwardTooltip_TwoChats_Many(firstPeerName, secondPeerName).string } else if let peer = displayPeers.first { - let peerName = peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) + let peerName = EnginePeer(peer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) text = messages.count == 1 ? presentationData.strings.Conversation_ForwardTooltip_ManyChats_One(peerName, "\(displayPeers.count - 1)").string : presentationData.strings.Conversation_ForwardTooltip_ManyChats_Many(peerName, "\(displayPeers.count - 1)").string } else { text = "" @@ -12178,7 +12196,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G var deleteChat = true var items: [ActionSheetItem] = [] if !peer.isDeleted { - items.append(ActionSheetTextItem(title: presentationData.strings.UserInfo_BlockConfirmationTitle(peer.compactDisplayTitle).string)) + items.append(ActionSheetTextItem(title: presentationData.strings.UserInfo_BlockConfirmationTitle(EnginePeer(peer).compactDisplayTitle).string)) } items.append(contentsOf: [ ActionSheetCheckboxItem(title: presentationData.strings.Conversation_Moderate_Report, label: "", value: reportSpam, action: { [weak controller] checkValue in @@ -12199,7 +12217,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G return item }) }), - ActionSheetButtonItem(title: presentationData.strings.UserInfo_BlockActionTitle(peer.compactDisplayTitle).string, color: .destructive, action: { [weak self] in + ActionSheetButtonItem(title: presentationData.strings.UserInfo_BlockActionTitle(EnginePeer(peer).compactDisplayTitle).string, color: .destructive, action: { [weak self] in dismissAction() guard let strongSelf = self else { return @@ -12276,7 +12294,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G let actionSheet = ActionSheetController(presentationData: strongSelf.presentationData) var items: [ActionSheetItem] = [] - items.append(ActionSheetTextItem(title: strongSelf.presentationData.strings.Conversation_ShareMyPhoneNumberConfirmation(formatPhoneNumber(phoneNumber), peer.compactDisplayTitle).string)) + items.append(ActionSheetTextItem(title: strongSelf.presentationData.strings.Conversation_ShareMyPhoneNumberConfirmation(formatPhoneNumber(phoneNumber), EnginePeer(peer).compactDisplayTitle).string)) items.append(ActionSheetButtonItem(title: strongSelf.presentationData.strings.Conversation_ShareMyPhoneNumber, action: { [weak actionSheet] in actionSheet?.dismissAnimated() guard let strongSelf = self else { @@ -12292,7 +12310,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G guard let strongSelf = self else { return } - strongSelf.present(OverlayStatusController(theme: strongSelf.presentationData.theme, type: .genericSuccess(strongSelf.presentationData.strings.Conversation_ShareMyPhoneNumber_StatusSuccess(peer.compactDisplayTitle).string, true)), in: .window(.root)) + strongSelf.present(OverlayStatusController(theme: strongSelf.presentationData.theme, type: .genericSuccess(strongSelf.presentationData.strings.Conversation_ShareMyPhoneNumber_StatusSuccess(EnginePeer(peer).compactDisplayTitle).string, true)), in: .window(.root)) }) })) @@ -12316,7 +12334,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G if let phone = peer.phone, !phone.isEmpty { } - self?.present(OverlayStatusController(theme: strongSelf.presentationData.theme, type: .genericSuccess(strongSelf.presentationData.strings.AddContact_StatusSuccess(peer.compactDisplayTitle).string, true)), in: .window(.root)) + self?.present(OverlayStatusController(theme: strongSelf.presentationData.theme, type: .genericSuccess(strongSelf.presentationData.strings.AddContact_StatusSuccess(EnginePeer(peer).compactDisplayTitle).string, true)), in: .window(.root)) } }), completed: nil, cancelled: nil), in: .window(.root), with: ViewControllerPresentationArguments(presentationAnimation: .modalSheet)) } @@ -12631,7 +12649,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G } else if categoryId == 2 { title = strongSelf.presentationData.strings.Conversation_Moderate_Report } else if categoryId == 3 { - title = strongSelf.presentationData.strings.Conversation_Moderate_DeleteAllMessages(author.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder)).string + title = strongSelf.presentationData.strings.Conversation_Moderate_DeleteAllMessages(EnginePeer(author).displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder)).string } let index = itemIndex items.append(ActionSheetCheckboxItem(title: title, label: "", value: actions.contains(categoryId), action: { value in @@ -12677,9 +12695,9 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G var personalPeerName: String? var isChannel = false if let user = self.presentationInterfaceState.renderedPeer?.peer as? TelegramUser { - personalPeerName = user.compactDisplayTitle + personalPeerName = EnginePeer(user).compactDisplayTitle } else if let peer = self.presentationInterfaceState.renderedPeer?.peer as? TelegramSecretChat, let associatedPeerId = peer.associatedPeerId, let user = self.presentationInterfaceState.renderedPeer?.peers[associatedPeerId] as? TelegramUser { - personalPeerName = user.compactDisplayTitle + personalPeerName = EnginePeer(user).compactDisplayTitle } else if let channel = self.presentationInterfaceState.renderedPeer?.peer as? TelegramChannel, case .broadcast = channel.info { isChannel = true } @@ -13180,17 +13198,17 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G let reminderActivity = NSUserActivity(activityType: "RemindAboutChatIntent") self.reminderActivity = reminderActivity if peer is TelegramGroup { - reminderActivity.title = self.presentationData.strings.Activity_RemindAboutGroup(peer.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder)).string + reminderActivity.title = self.presentationData.strings.Activity_RemindAboutGroup(EnginePeer(peer).displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder)).string } else if let channel = peer as? TelegramChannel { if case .broadcast = channel.info { - reminderActivity.title = self.presentationData.strings.Activity_RemindAboutChannel(peer.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder)).string + reminderActivity.title = self.presentationData.strings.Activity_RemindAboutChannel(EnginePeer(peer).displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder)).string } else { - reminderActivity.title = self.presentationData.strings.Activity_RemindAboutGroup(peer.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder)).string + reminderActivity.title = self.presentationData.strings.Activity_RemindAboutGroup(EnginePeer(peer).displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder)).string } } else { - reminderActivity.title = self.presentationData.strings.Activity_RemindAboutUser(peer.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder)).string + reminderActivity.title = self.presentationData.strings.Activity_RemindAboutUser(EnginePeer(peer).displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder)).string } - reminderActivity.userInfo = ["peerId": peerId.toInt64(), "peerTitle": peer.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder)] + reminderActivity.userInfo = ["peerId": peerId.toInt64(), "peerTitle": EnginePeer(peer).displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder)] reminderActivity.isEligibleForHandoff = true reminderActivity.becomeCurrent() } @@ -13509,7 +13527,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G selectedEmoticon = nil } - let controller = ChatThemeScreen(context: context, updatedPresentationData: strongSelf.updatedPresentationData, animatedEmojiStickers: animatedEmojiStickers, initiallySelectedEmoticon: selectedEmoticon, peerName: strongSelf.presentationInterfaceState.renderedPeer?.chatMainPeer?.compactDisplayTitle ?? "", previewTheme: { [weak self] emoticon, dark in + let controller = ChatThemeScreen(context: context, updatedPresentationData: strongSelf.updatedPresentationData, animatedEmojiStickers: animatedEmojiStickers, initiallySelectedEmoticon: selectedEmoticon, peerName: strongSelf.presentationInterfaceState.renderedPeer?.chatMainPeer.flatMap(EnginePeer.init)?.compactDisplayTitle ?? "", previewTheme: { [weak self] emoticon, dark in if let strongSelf = self { strongSelf.presentCrossfadeSnapshot() strongSelf.themeEmoticonAndDarkAppearancePreviewPromise.set(.single((emoticon, dark))) diff --git a/submodules/TelegramUI/Sources/ChatEmptyNode.swift b/submodules/TelegramUI/Sources/ChatEmptyNode.swift index b4c4d099d4..978ce96ad3 100644 --- a/submodules/TelegramUI/Sources/ChatEmptyNode.swift +++ b/submodules/TelegramUI/Sources/ChatEmptyNode.swift @@ -307,7 +307,7 @@ final class ChatEmptyNodeNearbyChatContent: ASDisplayNode, ChatEmptyNodeStickerC if let renderedPeer = interfaceState.renderedPeer { if let chatPeer = renderedPeer.peers[renderedPeer.peerId] { - displayName = chatPeer.compactDisplayTitle + displayName = EnginePeer(chatPeer).compactDisplayTitle } } @@ -443,7 +443,7 @@ private final class ChatEmptyNodeSecretChatContent: ASDisplayNode, ChatEmptyNode incoming = true } if let user = renderedPeer.peers[chatPeer.regularPeerId] { - title = user.compactDisplayTitle + title = EnginePeer(user).compactDisplayTitle } } } diff --git a/submodules/TelegramUI/Sources/ChatMediaInputPeerSpecificItem.swift b/submodules/TelegramUI/Sources/ChatMediaInputPeerSpecificItem.swift index 0ccab940b2..b2a7894921 100644 --- a/submodules/TelegramUI/Sources/ChatMediaInputPeerSpecificItem.swift +++ b/submodules/TelegramUI/Sources/ChatMediaInputPeerSpecificItem.swift @@ -121,7 +121,7 @@ final class ChatMediaInputPeerSpecificItemNode: ListViewItemNode { self.highlightNode.image = PresentationResourcesChat.chatMediaInputPanelHighlightedIconImage(theme) - self.titleNode.attributedText = NSAttributedString(string: peer.compactDisplayTitle, font: Font.regular(11.0), textColor: theme.chat.inputPanel.primaryTextColor) + self.titleNode.attributedText = NSAttributedString(string: EnginePeer(peer).compactDisplayTitle, font: Font.regular(11.0), textColor: theme.chat.inputPanel.primaryTextColor) } self.containerNode.frame = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: expandedBoundingSize) diff --git a/submodules/TelegramUI/Sources/ChatMessageActionUrlAuthController.swift b/submodules/TelegramUI/Sources/ChatMessageActionUrlAuthController.swift index 583bbab9a2..4e65670b29 100644 --- a/submodules/TelegramUI/Sources/ChatMessageActionUrlAuthController.swift +++ b/submodules/TelegramUI/Sources/ChatMessageActionUrlAuthController.swift @@ -163,7 +163,7 @@ private final class ChatMessageActionUrlAuthAlertContentNode: AlertContentNode { self.textNode.attributedText = formattedText(strings.Conversation_OpenBotLinkText(self.defaultUrl).string, color: theme.primaryColor, textAlignment: .center) self.authorizeLabelNode.attributedText = formattedText(strings.Conversation_OpenBotLinkLogin(self.domain, self.displayName).string, color: theme.primaryColor) - self.allowWriteLabelNode.attributedText = formattedText(strings.Conversation_OpenBotLinkAllowMessages(self.bot.displayTitle(strings: self.strings, displayOrder: self.nameDisplayOrder)).string, color: theme.primaryColor) + self.allowWriteLabelNode.attributedText = formattedText(strings.Conversation_OpenBotLinkAllowMessages(EnginePeer(self.bot).displayTitle(strings: self.strings, displayOrder: self.nameDisplayOrder)).string, color: theme.primaryColor) self.actionNodesSeparator.backgroundColor = theme.separatorColor for actionNode in self.actionNodes { diff --git a/submodules/TelegramUI/Sources/ChatMessageAnimatedStickerItemNode.swift b/submodules/TelegramUI/Sources/ChatMessageAnimatedStickerItemNode.swift index fbb7f93d3c..2ae27e7385 100644 --- a/submodules/TelegramUI/Sources/ChatMessageAnimatedStickerItemNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageAnimatedStickerItemNode.swift @@ -953,7 +953,7 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView { if let sourcePeer = item.message.peers[attribute.messageId.peerId] { let inlineBotNameColor = serviceMessageColorComponents(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper).primaryText - let nameString = NSAttributedString(string: sourcePeer.displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder), font: inlineBotPrefixFont, textColor: inlineBotNameColor) + let nameString = NSAttributedString(string: EnginePeer(sourcePeer).displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder), font: inlineBotPrefixFont, textColor: inlineBotNameColor) viaBotApply = viaBotLayout(TextNodeLayoutArguments(attributedString: nameString, backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: max(0, availableContentWidth), height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets())) } } @@ -991,14 +991,14 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView { if let authorSignature = forwardInfo.authorSignature { forwardAuthorSignature = authorSignature } else if let forwardInfoAuthor = forwardInfo.author, forwardInfoAuthor.id != source.id { - forwardAuthorSignature = forwardInfoAuthor.displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder) + forwardAuthorSignature = EnginePeer(forwardInfoAuthor).displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder) } else { forwardAuthorSignature = nil } } else { if let currentForwardInfo = currentForwardInfo, forwardInfo.author == nil && currentForwardInfo.0 != nil { forwardSource = nil - forwardAuthorSignature = currentForwardInfo.0?.displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder) + forwardAuthorSignature = currentForwardInfo.0.flatMap(EnginePeer.init)?.displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder) } else { forwardSource = forwardInfo.author forwardAuthorSignature = forwardInfo.authorSignature diff --git a/submodules/TelegramUI/Sources/ChatMessageBubbleItemNode.swift b/submodules/TelegramUI/Sources/ChatMessageBubbleItemNode.swift index bb9b90e426..c195435489 100644 --- a/submodules/TelegramUI/Sources/ChatMessageBubbleItemNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageBubbleItemNode.swift @@ -1575,10 +1575,10 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode if initialDisplayHeader && displayAuthorInfo { if let peer = firstMessage.peers[firstMessage.id.peerId] as? TelegramChannel, case .broadcast = peer.info, item.content.firstMessage.adAttribute == nil { - authorNameString = peer.displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder) + authorNameString = EnginePeer(peer).displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder) authorNameColor = chatMessagePeerIdColors[Int(clamping: peer.id.id._internalGetInt64Value() % 7)] } else if let effectiveAuthor = effectiveAuthor { - authorNameString = effectiveAuthor.displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder) + authorNameString = EnginePeer(effectiveAuthor).displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder) if incoming { authorNameColor = chatMessagePeerIdColors[Int(clamping: effectiveAuthor.id.id._internalGetInt64Value() % 7)] @@ -1808,14 +1808,14 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode if let authorSignature = forwardInfo.authorSignature { forwardAuthorSignature = authorSignature } else if let forwardInfoAuthor = forwardInfo.author, forwardInfoAuthor.id != source.id { - forwardAuthorSignature = forwardInfoAuthor.displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder) + forwardAuthorSignature = EnginePeer(forwardInfoAuthor).displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder) } else { forwardAuthorSignature = nil } } else { if let currentForwardInfo = currentForwardInfo, forwardInfo.author == nil && currentForwardInfo.0 != nil { forwardSource = nil - forwardAuthorSignature = currentForwardInfo.0?.displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder) + forwardAuthorSignature = currentForwardInfo.0.flatMap(EnginePeer.init)?.displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder) } else { forwardSource = forwardInfo.author forwardAuthorSignature = forwardInfo.authorSignature diff --git a/submodules/TelegramUI/Sources/ChatMessageForwardInfoNode.swift b/submodules/TelegramUI/Sources/ChatMessageForwardInfoNode.swift index 91e6b77ac2..fc6bc9c4fb 100644 --- a/submodules/TelegramUI/Sources/ChatMessageForwardInfoNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageForwardInfoNode.swift @@ -102,9 +102,9 @@ class ChatMessageForwardInfoNode: ASDisplayNode { let peerString: String if let peer = peer { if let authorName = authorName { - peerString = "\(peer.displayTitle(strings: strings, displayOrder: presentationData.nameDisplayOrder)) (\(authorName))" + peerString = "\(EnginePeer(peer).displayTitle(strings: strings, displayOrder: presentationData.nameDisplayOrder)) (\(authorName))" } else { - peerString = peer.displayTitle(strings: strings, displayOrder: presentationData.nameDisplayOrder) + peerString = EnginePeer(peer).displayTitle(strings: strings, displayOrder: presentationData.nameDisplayOrder) } } else if let authorName = authorName { peerString = authorName diff --git a/submodules/TelegramUI/Sources/ChatMessageInstantVideoItemNode.swift b/submodules/TelegramUI/Sources/ChatMessageInstantVideoItemNode.swift index 4d6c98f4f1..917c8abe47 100644 --- a/submodules/TelegramUI/Sources/ChatMessageInstantVideoItemNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageInstantVideoItemNode.swift @@ -442,7 +442,7 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView, UIGestureRecognizerD if let sourcePeer = item.message.peers[attribute.messageId.peerId] { let inlineBotNameColor = serviceMessageColorComponents(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper).primaryText - let nameString = NSAttributedString(string: sourcePeer.displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder), font: inlineBotPrefixFont, textColor: inlineBotNameColor) + let nameString = NSAttributedString(string: EnginePeer(sourcePeer).displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder), font: inlineBotPrefixFont, textColor: inlineBotNameColor) viaBotApply = viaBotLayout(TextNodeLayoutArguments(attributedString: nameString, backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: max(0, availableWidth), height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets())) } @@ -497,14 +497,14 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView, UIGestureRecognizerD if let authorSignature = forwardInfo.authorSignature { forwardAuthorSignature = authorSignature } else if let forwardInfoAuthor = forwardInfo.author, forwardInfoAuthor.id != source.id { - forwardAuthorSignature = forwardInfoAuthor.displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder) + forwardAuthorSignature = EnginePeer(forwardInfoAuthor).displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder) } else { forwardAuthorSignature = nil } } else { if let currentForwardInfo = currentForwardInfo, forwardInfo.author == nil && currentForwardInfo.0 != nil { forwardSource = nil - forwardAuthorSignature = currentForwardInfo.0?.displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder) + forwardAuthorSignature = currentForwardInfo.0.flatMap(EnginePeer.init)?.displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder) } else { forwardSource = forwardInfo.author forwardAuthorSignature = forwardInfo.authorSignature diff --git a/submodules/TelegramUI/Sources/ChatMessageItemView.swift b/submodules/TelegramUI/Sources/ChatMessageItemView.swift index 5cadb4c823..c6b4eb8854 100644 --- a/submodules/TelegramUI/Sources/ChatMessageItemView.swift +++ b/submodules/TelegramUI/Sources/ChatMessageItemView.swift @@ -204,7 +204,7 @@ final class ChatMessageAccessibilityData { var value: String = "" if let chatPeer = message.peers[item.message.id.peerId] { - let authorName = message.author?.displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder) + let authorName = message.author.flatMap(EnginePeer.init)?.displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder) let (_, _, messageText) = chatListItemStrings(strings: item.presentationData.strings, nameDisplayOrder: item.presentationData.nameDisplayOrder, dateTimeFormat: item.presentationData.dateTimeFormat, messages: [message], chatPeer: RenderedPeer(peer: chatPeer), accountPeerId: item.context.account.peerId) @@ -557,7 +557,7 @@ final class ChatMessageAccessibilityData { if label.isEmpty { if let author = message.author { if isIncoming { - label = author.displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder) + label = EnginePeer(author).displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder) } else { label = item.presentationData.strings.VoiceOver_Chat_YourMessage } @@ -602,7 +602,7 @@ final class ChatMessageAccessibilityData { var replyLabel: String if replyMessage.flags.contains(.Incoming) { if let author = replyMessage.author { - replyLabel = item.presentationData.strings.VoiceOver_Chat_ReplyFrom(author.displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder)).string + replyLabel = item.presentationData.strings.VoiceOver_Chat_ReplyFrom(EnginePeer(author).displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder)).string } else { replyLabel = item.presentationData.strings.VoiceOver_Chat_Reply } @@ -629,9 +629,9 @@ final class ChatMessageAccessibilityData { let peerString: String if let peer = forwardInfo.author { if let authorName = forwardInfo.authorSignature { - peerString = "\(peer.displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder)) (\(authorName))" + peerString = "\(EnginePeer(peer).displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder)) (\(authorName))" } else { - peerString = peer.displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder) + peerString = EnginePeer(peer).displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder) } } else if let authorName = forwardInfo.authorSignature { peerString = authorName diff --git a/submodules/TelegramUI/Sources/ChatMessageNotificationItem.swift b/submodules/TelegramUI/Sources/ChatMessageNotificationItem.swift index 5a4117b696..d1c8e94fd8 100644 --- a/submodules/TelegramUI/Sources/ChatMessageNotificationItem.swift +++ b/submodules/TelegramUI/Sources/ChatMessageNotificationItem.swift @@ -114,29 +114,29 @@ final class ChatMessageNotificationItemNode: NotificationItemNode { var title: String? if let firstMessage = item.messages.first, let peer = messageMainPeer(firstMessage) { if let channel = peer as? TelegramChannel, case .broadcast = channel.info { - title = peer.displayTitle(strings: item.strings, displayOrder: item.nameDisplayOrder) + title = EnginePeer(peer).displayTitle(strings: item.strings, displayOrder: item.nameDisplayOrder) } else if let author = firstMessage.author { if firstMessage.id.peerId.isReplies, let _ = firstMessage.sourceReference, let effectiveAuthor = firstMessage.forwardInfo?.author { - title = effectiveAuthor.displayTitle(strings: item.strings, displayOrder: item.nameDisplayOrder) + "@" + peer.displayTitle(strings: item.strings, displayOrder: item.nameDisplayOrder) + title = EnginePeer(effectiveAuthor).displayTitle(strings: item.strings, displayOrder: item.nameDisplayOrder) + "@" + EnginePeer(peer).displayTitle(strings: item.strings, displayOrder: item.nameDisplayOrder) } else if author.id != peer.id { if author.id == item.context.account.peerId { - title = presentationData.strings.DialogList_You + "@" + peer.displayTitle(strings: item.strings, displayOrder: item.nameDisplayOrder) + title = presentationData.strings.DialogList_You + "@" + EnginePeer(peer).displayTitle(strings: item.strings, displayOrder: item.nameDisplayOrder) } else { - title = author.displayTitle(strings: item.strings, displayOrder: item.nameDisplayOrder) + "@" + peer.displayTitle(strings: item.strings, displayOrder: item.nameDisplayOrder) + title = EnginePeer(author).displayTitle(strings: item.strings, displayOrder: item.nameDisplayOrder) + "@" + EnginePeer(peer).displayTitle(strings: item.strings, displayOrder: item.nameDisplayOrder) } } else { - title = peer.displayTitle(strings: item.strings, displayOrder: item.nameDisplayOrder) + title = EnginePeer(peer).displayTitle(strings: item.strings, displayOrder: item.nameDisplayOrder) for attribute in firstMessage.attributes { if let attribute = attribute as? SourceReferenceMessageAttribute { if let sourcePeer = firstMessage.peers[attribute.messageId.peerId] { - title = sourcePeer.displayTitle(strings: item.strings, displayOrder: item.nameDisplayOrder) + "@" + peer.displayTitle(strings: item.strings, displayOrder: item.nameDisplayOrder) + title = EnginePeer(sourcePeer).displayTitle(strings: item.strings, displayOrder: item.nameDisplayOrder) + "@" + EnginePeer(peer).displayTitle(strings: item.strings, displayOrder: item.nameDisplayOrder) } break } } } } else { - title = peer.displayTitle(strings: item.strings, displayOrder: item.nameDisplayOrder) + title = EnginePeer(peer).displayTitle(strings: item.strings, displayOrder: item.nameDisplayOrder) } if let _ = title, firstMessage.flags.contains(.WasScheduled) { @@ -197,11 +197,11 @@ final class ChatMessageNotificationItemNode: NotificationItemNode { if item.messages[0].forwardInfo != nil && item.messages[0].sourceReference == nil { if let author = item.messages[0].author, displayAuthor { if !isReminder { - title = peer.displayTitle(strings: item.strings, displayOrder: item.nameDisplayOrder) + title = EnginePeer(peer).displayTitle(strings: item.strings, displayOrder: item.nameDisplayOrder) } - messageText = presentationData.strings.PUSH_CHAT_MESSAGE_FWDS_TEXT(Int32(item.messages.count)).replacingOccurrences(of: "{author}", with: author.compactDisplayTitle) + messageText = presentationData.strings.PUSH_CHAT_MESSAGE_FWDS_TEXT(Int32(item.messages.count)).replacingOccurrences(of: "{author}", with: EnginePeer(author).compactDisplayTitle) } else { - title = peer.displayTitle(strings: item.strings, displayOrder: item.nameDisplayOrder) + title = EnginePeer(peer).displayTitle(strings: item.strings, displayOrder: item.nameDisplayOrder) messageText = presentationData.strings.PUSH_MESSAGE_FWDS_TEXT(Int32(item.messages.count)) } } else if item.messages[0].groupingKey != nil { @@ -227,16 +227,16 @@ final class ChatMessageNotificationItemNode: NotificationItemNode { if isChannel { switch kind { case .image: - title = peer.displayTitle(strings: item.strings, displayOrder: item.nameDisplayOrder) + title = EnginePeer(peer).displayTitle(strings: item.strings, displayOrder: item.nameDisplayOrder) messageText = presentationData.strings.PUSH_CHANNEL_MESSAGE_PHOTOS_TEXT(Int32(item.messages.count)) case .video: - title = peer.displayTitle(strings: item.strings, displayOrder: item.nameDisplayOrder) + title = EnginePeer(peer).displayTitle(strings: item.strings, displayOrder: item.nameDisplayOrder) messageText = presentationData.strings.PUSH_CHANNEL_MESSAGE_VIDEOS_TEXT(Int32(item.messages.count)) case .file: - title = peer.displayTitle(strings: item.strings, displayOrder: item.nameDisplayOrder) + title = EnginePeer(peer).displayTitle(strings: item.strings, displayOrder: item.nameDisplayOrder) messageText = presentationData.strings.PUSH_CHANNEL_MESSAGE_DOCS_TEXT(Int32(item.messages.count)) default: - title = peer.displayTitle(strings: item.strings, displayOrder: item.nameDisplayOrder) + title = EnginePeer(peer).displayTitle(strings: item.strings, displayOrder: item.nameDisplayOrder) messageText = presentationData.strings.PUSH_CHANNEL_MESSAGES_TEXT(Int32(item.messages.count)) } } else if isGroup, var author = item.messages[0].author { @@ -245,31 +245,31 @@ final class ChatMessageNotificationItemNode: NotificationItemNode { } switch kind { case .image: - title = peer.displayTitle(strings: item.strings, displayOrder: item.nameDisplayOrder) - messageText = presentationData.strings.PUSH_CHAT_MESSAGE_PHOTOS_TEXT(Int32(item.messages.count)).replacingOccurrences(of: "{author}", with: author.compactDisplayTitle) + title = EnginePeer(peer).displayTitle(strings: item.strings, displayOrder: item.nameDisplayOrder) + messageText = presentationData.strings.PUSH_CHAT_MESSAGE_PHOTOS_TEXT(Int32(item.messages.count)).replacingOccurrences(of: "{author}", with: EnginePeer(author).compactDisplayTitle) case .video: - title = peer.displayTitle(strings: item.strings, displayOrder: item.nameDisplayOrder) - messageText = presentationData.strings.PUSH_CHAT_MESSAGE_VIDEOS_TEXT(Int32(item.messages.count)).replacingOccurrences(of: "{author}", with: author.compactDisplayTitle) + title = EnginePeer(peer).displayTitle(strings: item.strings, displayOrder: item.nameDisplayOrder) + messageText = presentationData.strings.PUSH_CHAT_MESSAGE_VIDEOS_TEXT(Int32(item.messages.count)).replacingOccurrences(of: "{author}", with: EnginePeer(author).compactDisplayTitle) case .file: - title = peer.displayTitle(strings: item.strings, displayOrder: item.nameDisplayOrder) - messageText = presentationData.strings.PUSH_CHAT_MESSAGE_DOCS_TEXT(Int32(item.messages.count)).replacingOccurrences(of: "{author}", with: author.compactDisplayTitle) + title = EnginePeer(peer).displayTitle(strings: item.strings, displayOrder: item.nameDisplayOrder) + messageText = presentationData.strings.PUSH_CHAT_MESSAGE_DOCS_TEXT(Int32(item.messages.count)).replacingOccurrences(of: "{author}", with: EnginePeer(author).compactDisplayTitle) default: - title = peer.displayTitle(strings: item.strings, displayOrder: item.nameDisplayOrder) - messageText = presentationData.strings.PUSH_CHAT_MESSAGES_TEXT(Int32(item.messages.count)).replacingOccurrences(of: "{author}", with: author.compactDisplayTitle) + title = EnginePeer(peer).displayTitle(strings: item.strings, displayOrder: item.nameDisplayOrder) + messageText = presentationData.strings.PUSH_CHAT_MESSAGES_TEXT(Int32(item.messages.count)).replacingOccurrences(of: "{author}", with: EnginePeer(author).compactDisplayTitle) } } else { switch kind { case .image: - title = peer.displayTitle(strings: item.strings, displayOrder: item.nameDisplayOrder) + title = EnginePeer(peer).displayTitle(strings: item.strings, displayOrder: item.nameDisplayOrder) messageText = presentationData.strings.PUSH_MESSAGE_PHOTOS_TEXT(Int32(item.messages.count)) case .video: - title = peer.displayTitle(strings: item.strings, displayOrder: item.nameDisplayOrder) + title = EnginePeer(peer).displayTitle(strings: item.strings, displayOrder: item.nameDisplayOrder) messageText = presentationData.strings.PUSH_MESSAGE_VIDEOS_TEXT(Int32(item.messages.count)) case .file: - title = peer.displayTitle(strings: item.strings, displayOrder: item.nameDisplayOrder) + title = EnginePeer(peer).displayTitle(strings: item.strings, displayOrder: item.nameDisplayOrder) messageText = presentationData.strings.PUSH_MESSAGE_FILES_TEXT(Int32(item.messages.count)) default: - title = peer.displayTitle(strings: item.strings, displayOrder: item.nameDisplayOrder) + title = EnginePeer(peer).displayTitle(strings: item.strings, displayOrder: item.nameDisplayOrder) messageText = presentationData.strings.PUSH_MESSAGES_TEXT(Int32(item.messages.count)) } } diff --git a/submodules/TelegramUI/Sources/ChatMessageReplyInfoNode.swift b/submodules/TelegramUI/Sources/ChatMessageReplyInfoNode.swift index 7b58467cd7..3c5ead8db0 100644 --- a/submodules/TelegramUI/Sources/ChatMessageReplyInfoNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageReplyInfoNode.swift @@ -54,11 +54,11 @@ class ChatMessageReplyInfoNode: ASDisplayNode { let titleFont = Font.medium(fontSize) let textFont = Font.regular(fontSize) - var titleString = message.effectiveAuthor?.displayTitle(strings: strings, displayOrder: presentationData.nameDisplayOrder) ?? strings.User_DeletedAccount + var titleString = message.effectiveAuthor.flatMap(EnginePeer.init)?.displayTitle(strings: strings, displayOrder: presentationData.nameDisplayOrder) ?? strings.User_DeletedAccount if let forwardInfo = message.forwardInfo, forwardInfo.flags.contains(.isImported) { if let author = forwardInfo.author { - titleString = author.displayTitle(strings: strings, displayOrder: presentationData.nameDisplayOrder) + titleString = EnginePeer(author).displayTitle(strings: strings, displayOrder: presentationData.nameDisplayOrder) } else if let authorSignature = forwardInfo.authorSignature { titleString = authorSignature } diff --git a/submodules/TelegramUI/Sources/ChatMessageStickerItemNode.swift b/submodules/TelegramUI/Sources/ChatMessageStickerItemNode.swift index 7ed856b179..a90140af01 100644 --- a/submodules/TelegramUI/Sources/ChatMessageStickerItemNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageStickerItemNode.swift @@ -558,7 +558,7 @@ class ChatMessageStickerItemNode: ChatMessageItemView { if let sourcePeer = item.message.peers[attribute.messageId.peerId] { let inlineBotNameColor = serviceMessageColorComponents(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper).primaryText - let nameString = NSAttributedString(string: sourcePeer.displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder), font: inlineBotPrefixFont, textColor: inlineBotNameColor) + let nameString = NSAttributedString(string: EnginePeer(sourcePeer).displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder), font: inlineBotPrefixFont, textColor: inlineBotNameColor) viaBotApply = viaBotLayout(TextNodeLayoutArguments(attributedString: nameString, backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: max(0, availableWidth), height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets())) } } @@ -598,14 +598,14 @@ class ChatMessageStickerItemNode: ChatMessageItemView { if let authorSignature = forwardInfo.authorSignature { forwardAuthorSignature = authorSignature } else if let forwardInfoAuthor = forwardInfo.author, forwardInfoAuthor.id != source.id { - forwardAuthorSignature = forwardInfoAuthor.displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder) + forwardAuthorSignature = EnginePeer(forwardInfoAuthor).displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder) } else { forwardAuthorSignature = nil } } else { if let currentForwardInfo = currentForwardInfo, forwardInfo.author == nil && currentForwardInfo.0 != nil { forwardSource = nil - forwardAuthorSignature = currentForwardInfo.0?.displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder) + forwardAuthorSignature = currentForwardInfo.0.flatMap(EnginePeer.init)?.displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder) } else { forwardSource = forwardInfo.author forwardAuthorSignature = forwardInfo.authorSignature diff --git a/submodules/TelegramUI/Sources/ChatOverlayNavigationBar.swift b/submodules/TelegramUI/Sources/ChatOverlayNavigationBar.swift index 7336d9db0e..983e777a69 100644 --- a/submodules/TelegramUI/Sources/ChatOverlayNavigationBar.swift +++ b/submodules/TelegramUI/Sources/ChatOverlayNavigationBar.swift @@ -28,7 +28,7 @@ final class ChatOverlayNavigationBar: ASDisplayNode { var title = "" if let peerView = self.peerView { if let peer = peerViewMainPeer(peerView) { - title = peer.displayTitle(strings: self.strings, displayOrder: self.nameDisplayOrder) + title = EnginePeer(peer).displayTitle(strings: self.strings, displayOrder: self.nameDisplayOrder) } } if self.peerTitle != title { diff --git a/submodules/TelegramUI/Sources/ChatPinnedMessageTitlePanelNode.swift b/submodules/TelegramUI/Sources/ChatPinnedMessageTitlePanelNode.swift index a895fb85fc..701bea9fad 100644 --- a/submodules/TelegramUI/Sources/ChatPinnedMessageTitlePanelNode.swift +++ b/submodules/TelegramUI/Sources/ChatPinnedMessageTitlePanelNode.swift @@ -406,7 +406,7 @@ final class ChatPinnedMessageTitlePanelNode: ChatTitleAccessoryPanelNode { if isReplyThread { let titleString: String if let author = message.effectiveAuthor { - titleString = author.displayTitle(strings: strings, displayOrder: nameDisplayOrder) + titleString = EnginePeer(author).displayTitle(strings: strings, displayOrder: nameDisplayOrder) } else { titleString = "" } diff --git a/submodules/TelegramUI/Sources/ChatRecentActionsFilterController.swift b/submodules/TelegramUI/Sources/ChatRecentActionsFilterController.swift index 6ceb91fc0f..a12d6a9e49 100644 --- a/submodules/TelegramUI/Sources/ChatRecentActionsFilterController.swift +++ b/submodules/TelegramUI/Sources/ChatRecentActionsFilterController.swift @@ -206,7 +206,7 @@ private enum ChatRecentActionsFilterEntry: ItemListNodeEntry { case .member: peerText = strings.ChatAdmins_AdminLabel.capitalized } - return ItemListPeerItem(presentationData: presentationData, dateTimeFormat: dateTimeFormat, nameDisplayOrder: nameDisplayOrder, context: arguments.context, peer: participant.peer, presence: nil, text: .text(peerText, .secondary), label: .none, editing: ItemListPeerItemEditing(editable: false, editing: false, revealed: false), switchValue: ItemListPeerItemSwitch(value: checked, style: .check), enabled: true, selectable: true, sectionId: self.section, action: { + return ItemListPeerItem(presentationData: presentationData, dateTimeFormat: dateTimeFormat, nameDisplayOrder: nameDisplayOrder, context: arguments.context, peer: EnginePeer(participant.peer), presence: nil, text: .text(peerText, .secondary), label: .none, editing: ItemListPeerItemEditing(editable: false, editing: false, revealed: false), switchValue: ItemListPeerItemSwitch(value: checked, style: .check), enabled: true, selectable: true, sectionId: self.section, action: { arguments.toggleAdmin(participant.peer.id) }, setPeerIdWithRevealedOptions: { _, _ in }, removePeer: { _ in }) diff --git a/submodules/TelegramUI/Sources/ChatRecentActionsHistoryTransition.swift b/submodules/TelegramUI/Sources/ChatRecentActionsHistoryTransition.swift index 7155a6e7cc..71a2658982 100644 --- a/submodules/TelegramUI/Sources/ChatRecentActionsHistoryTransition.swift +++ b/submodules/TelegramUI/Sources/ChatRecentActionsHistoryTransition.swift @@ -129,14 +129,14 @@ struct ChatRecentActionsEntry: Comparable, Identifiable { var text: String = "" var entities: [MessageTextEntity] = [] if let peer = peer as? TelegramChannel, case .broadcast = peer.info { - appendAttributedText(text: self.presentationData.strings.Channel_AdminLog_MessageChangedChannelAbout(author?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? ""), generateEntities: { index in + appendAttributedText(text: self.presentationData.strings.Channel_AdminLog_MessageChangedChannelAbout(author.flatMap(EnginePeer.init)?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? ""), generateEntities: { index in if index == 0, let author = author { return [.TextMention(peerId: author.id)] } return [] }, to: &text, entities: &entities) } else { - appendAttributedText(text: self.presentationData.strings.Channel_AdminLog_MessageChangedGroupAbout(author?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? ""), generateEntities: { index in + appendAttributedText(text: self.presentationData.strings.Channel_AdminLog_MessageChangedGroupAbout(author.flatMap(EnginePeer.init)?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? ""), generateEntities: { index in if index == 0, let author = author { return [.TextMention(peerId: author.id)] } @@ -167,14 +167,14 @@ struct ChatRecentActionsEntry: Comparable, Identifiable { var text: String = "" var entities: [MessageTextEntity] = [] if let peer = peer as? TelegramChannel, case .broadcast = peer.info { - appendAttributedText(text: self.presentationData.strings.Channel_AdminLog_MessageChangedChannelUsername(author?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? ""), generateEntities: { index in + appendAttributedText(text: self.presentationData.strings.Channel_AdminLog_MessageChangedChannelUsername(author.flatMap(EnginePeer.init)?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? ""), generateEntities: { index in if index == 0, let author = author { return [.TextMention(peerId: author.id)] } return [] }, to: &text, entities: &entities) } else { - appendAttributedText(text: self.presentationData.strings.Channel_AdminLog_MessageChangedGroupUsername(author?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? ""), generateEntities: { index in + appendAttributedText(text: self.presentationData.strings.Channel_AdminLog_MessageChangedGroupUsername(author.flatMap(EnginePeer.init)?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? ""), generateEntities: { index in if index == 0, let author = author { return [.TextMention(peerId: author.id)] } @@ -232,14 +232,14 @@ struct ChatRecentActionsEntry: Comparable, Identifiable { var text: String = "" var entities: [MessageTextEntity] = [] if value { - appendAttributedText(text: self.presentationData.strings.Channel_AdminLog_MessageToggleInvitesOn(author?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? ""), generateEntities: { index in + appendAttributedText(text: self.presentationData.strings.Channel_AdminLog_MessageToggleInvitesOn(author.flatMap(EnginePeer.init)?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? ""), generateEntities: { index in if index == 0, let author = author { return [.TextMention(peerId: author.id)] } return [] }, to: &text, entities: &entities) } else { - appendAttributedText(text: self.presentationData.strings.Channel_AdminLog_MessageToggleInvitesOff(author?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? ""), generateEntities: { index in + appendAttributedText(text: self.presentationData.strings.Channel_AdminLog_MessageToggleInvitesOff(author.flatMap(EnginePeer.init)?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? ""), generateEntities: { index in if index == 0, let author = author { return [.TextMention(peerId: author.id)] } @@ -259,14 +259,14 @@ struct ChatRecentActionsEntry: Comparable, Identifiable { var text: String = "" var entities: [MessageTextEntity] = [] if value { - appendAttributedText(text: self.presentationData.strings.Channel_AdminLog_MessageToggleSignaturesOn(author?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? ""), generateEntities: { index in + appendAttributedText(text: self.presentationData.strings.Channel_AdminLog_MessageToggleSignaturesOn(author.flatMap(EnginePeer.init)?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? ""), generateEntities: { index in if index == 0, let author = author { return [.TextMention(peerId: author.id)] } return [] }, to: &text, entities: &entities) } else { - appendAttributedText(text: self.presentationData.strings.Channel_AdminLog_MessageToggleSignaturesOff(author?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? ""), generateEntities: { index in + appendAttributedText(text: self.presentationData.strings.Channel_AdminLog_MessageToggleSignaturesOff(author.flatMap(EnginePeer.init)?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? ""), generateEntities: { index in if index == 0, let author = author { return [.TextMention(peerId: author.id)] } @@ -290,7 +290,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable { var text: String = "" var entities: [MessageTextEntity] = [] - appendAttributedText(text: self.presentationData.strings.Channel_AdminLog_MessagePinned(author?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? ""), generateEntities: { index in + appendAttributedText(text: self.presentationData.strings.Channel_AdminLog_MessagePinned(author.flatMap(EnginePeer.init)?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? ""), generateEntities: { index in if index == 0, let author = author { return [.TextMention(peerId: author.id)] } @@ -329,7 +329,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable { var text: String = "" var entities: [MessageTextEntity] = [] - appendAttributedText(text: self.presentationData.strings.Channel_AdminLog_MessageUnpinned(author?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? ""), generateEntities: { index in + appendAttributedText(text: self.presentationData.strings.Channel_AdminLog_MessageUnpinned(author.flatMap(EnginePeer.init)?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? ""), generateEntities: { index in if index == 0, let author = author { return [.TextMention(peerId: author.id)] } @@ -369,9 +369,9 @@ struct ChatRecentActionsEntry: Comparable, Identifiable { let titleText: PresentationStrings.FormattedString if mediaUpdated || message.media.isEmpty { - titleText = self.presentationData.strings.Channel_AdminLog_MessageEdited(author?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? "") + titleText = self.presentationData.strings.Channel_AdminLog_MessageEdited(author.flatMap(EnginePeer.init)?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? "") } else { - titleText = self.presentationData.strings.Channel_AdminLog_CaptionEdited(author?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? "") + titleText = self.presentationData.strings.Channel_AdminLog_CaptionEdited(author.flatMap(EnginePeer.init)?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? "") } appendAttributedText(text: titleText, generateEntities: { index in @@ -417,7 +417,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable { var text: String = "" var entities: [MessageTextEntity] = [] - appendAttributedText(text: self.presentationData.strings.Channel_AdminLog_MessageDeleted(author?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? ""), generateEntities: { index in + appendAttributedText(text: self.presentationData.strings.Channel_AdminLog_MessageDeleted(author.flatMap(EnginePeer.init)?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? ""), generateEntities: { index in if index == 0, let author = author { return [.TextMention(peerId: author.id)] } @@ -525,7 +525,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable { } if (prevBanInfo == nil || !prevBanInfo!.rights.flags.contains(.banReadMessages)) && newFlags.contains(.banReadMessages) { - appendAttributedText(text: new.peer.addressName == nil ? self.presentationData.strings.Channel_AdminLog_MessageKickedName(new.peer.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder)) : self.presentationData.strings.Channel_AdminLog_MessageKickedNameUsername(new.peer.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder), "@" + new.peer.addressName!), generateEntities: { index in + appendAttributedText(text: new.peer.addressName == nil ? self.presentationData.strings.Channel_AdminLog_MessageKickedName(EnginePeer(new.peer).displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder)) : self.presentationData.strings.Channel_AdminLog_MessageKickedNameUsername(EnginePeer(new.peer).displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder), "@" + new.peer.addressName!), generateEntities: { index in var result: [MessageTextEntityType] = [] if index == 0 { result.append(.TextMention(peerId: new.peer.id)) @@ -536,7 +536,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable { }, to: &text, entities: &entities) text += "\n" } else if isBroadcast, newBanInfo == nil, prevBanInfo != nil { - appendAttributedText(text: new.peer.addressName == nil ? self.presentationData.strings.Channel_AdminLog_MessageUnkickedName(new.peer.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder)) : self.presentationData.strings.Channel_AdminLog_MessageUnkickedNameUsername(new.peer.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder), "@" + new.peer.addressName!), generateEntities: { index in + appendAttributedText(text: new.peer.addressName == nil ? self.presentationData.strings.Channel_AdminLog_MessageUnkickedName(EnginePeer(new.peer).displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder)) : self.presentationData.strings.Channel_AdminLog_MessageUnkickedNameUsername(EnginePeer(new.peer).displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder), "@" + new.peer.addressName!), generateEntities: { index in var result: [MessageTextEntityType] = [] if index == 0 { result.append(.TextMention(peerId: new.peer.id)) @@ -546,7 +546,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable { return result }, to: &text, entities: &entities) } else { - appendAttributedText(text: new.peer.addressName == nil ? self.presentationData.strings.Channel_AdminLog_MessageRestrictedName(new.peer.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder)) : self.presentationData.strings.Channel_AdminLog_MessageRestrictedNameUsername(new.peer.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder), "@" + new.peer.addressName!), generateEntities: { index in + appendAttributedText(text: new.peer.addressName == nil ? self.presentationData.strings.Channel_AdminLog_MessageRestrictedName(EnginePeer(new.peer).displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder)) : self.presentationData.strings.Channel_AdminLog_MessageRestrictedNameUsername(EnginePeer(new.peer).displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder), "@" + new.peer.addressName!), generateEntities: { index in var result: [MessageTextEntityType] = [] if index == 0 { result.append(.TextMention(peerId: new.peer.id)) @@ -632,7 +632,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable { var entities: [MessageTextEntity] = [] if case .member = prev.participant, case .creator = new.participant { - appendAttributedText(text: new.peer.addressName == nil ? self.presentationData.strings.Channel_AdminLog_MessageTransferedName(new.peer.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder)) : self.presentationData.strings.Channel_AdminLog_MessageTransferedNameUsername(new.peer.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder), "@" + new.peer.addressName!), generateEntities: { index in + appendAttributedText(text: new.peer.addressName == nil ? self.presentationData.strings.Channel_AdminLog_MessageTransferedName(EnginePeer(new.peer).displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder)) : self.presentationData.strings.Channel_AdminLog_MessageTransferedNameUsername(EnginePeer(new.peer).displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder), "@" + new.peer.addressName!), generateEntities: { index in var result: [MessageTextEntityType] = [] if index == 0 { result.append(.TextMention(peerId: new.peer.id)) @@ -646,7 +646,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable { if case let .creator(_, prevAdminInfo, prevRank) = prev.participant, case let .creator(_, newAdminInfo, newRank) = new.participant, (prevRank != newRank || prevAdminInfo?.rights.rights.contains(.canBeAnonymous) != newAdminInfo?.rights.rights.contains(.canBeAnonymous)) { if prevRank != newRank { - appendAttributedText(text: new.peer.addressName == nil ? self.presentationData.strings.Channel_AdminLog_MessageRankName(new.peer.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder), newRank ?? "") : self.presentationData.strings.Channel_AdminLog_MessageRankUsername(new.peer.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder), "@" + new.peer.addressName!, newRank ?? ""), generateEntities: { index in + appendAttributedText(text: new.peer.addressName == nil ? self.presentationData.strings.Channel_AdminLog_MessageRankName(EnginePeer(new.peer).displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder), newRank ?? "") : self.presentationData.strings.Channel_AdminLog_MessageRankUsername(EnginePeer(new.peer).displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder), "@" + new.peer.addressName!, newRank ?? ""), generateEntities: { index in var result: [MessageTextEntityType] = [] if index == 0 { result.append(.TextMention(peerId: new.peer.id)) @@ -674,7 +674,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable { if prevAdminInfo?.rights.rights.contains(flag) != newAdminInfo?.rights.rights.contains(flag) { if !appendedRightsHeader { appendedRightsHeader = true - appendAttributedText(text: new.peer.addressName == nil ? self.presentationData.strings.Channel_AdminLog_MessagePromotedName(new.peer.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder)) : self.presentationData.strings.Channel_AdminLog_MessagePromotedNameUsername(new.peer.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder), "@" + new.peer.addressName!), generateEntities: { index in + appendAttributedText(text: new.peer.addressName == nil ? self.presentationData.strings.Channel_AdminLog_MessagePromotedName(EnginePeer(new.peer).displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder)) : self.presentationData.strings.Channel_AdminLog_MessagePromotedNameUsername(EnginePeer(new.peer).displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder), "@" + new.peer.addressName!), generateEntities: { index in var result: [MessageTextEntityType] = [] if index == 0 { result.append(.TextMention(peerId: new.peer.id)) @@ -737,7 +737,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable { if !appendedRightsHeader { appendedRightsHeader = true if prevAdminRights == nil { - appendAttributedText(text: new.peer.addressName == nil ? self.presentationData.strings.Channel_AdminLog_MessageAddedAdminName(new.peer.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder)) : self.presentationData.strings.Channel_AdminLog_MessageAddedAdminNameUsername(new.peer.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder), "@" + new.peer.addressName!), generateEntities: { index in + appendAttributedText(text: new.peer.addressName == nil ? self.presentationData.strings.Channel_AdminLog_MessageAddedAdminName(EnginePeer(new.peer).displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder)) : self.presentationData.strings.Channel_AdminLog_MessageAddedAdminNameUsername(EnginePeer(new.peer).displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder), "@" + new.peer.addressName!), generateEntities: { index in var result: [MessageTextEntityType] = [] if index == 0 { result.append(.TextMention(peerId: new.peer.id)) @@ -749,7 +749,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable { return result }, to: &text, entities: &entities) } else { - appendAttributedText(text: new.peer.addressName == nil ? self.presentationData.strings.Channel_AdminLog_MessageRemovedAdminName(new.peer.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder)) : self.presentationData.strings.Channel_AdminLog_MessageRemovedAdminNameUsername(new.peer.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder), "@" + new.peer.addressName!), generateEntities: { index in + appendAttributedText(text: new.peer.addressName == nil ? self.presentationData.strings.Channel_AdminLog_MessageRemovedAdminName(EnginePeer(new.peer).displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder)) : self.presentationData.strings.Channel_AdminLog_MessageRemovedAdminNameUsername(EnginePeer(new.peer).displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder), "@" + new.peer.addressName!), generateEntities: { index in var result: [MessageTextEntityType] = [] if index == 0 { result.append(.TextMention(peerId: new.peer.id)) @@ -768,7 +768,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable { if prevFlags.contains(flag) != newFlags.contains(flag) { if !appendedRightsHeader { appendedRightsHeader = true - appendAttributedText(text: new.peer.addressName == nil ? self.presentationData.strings.Channel_AdminLog_MessagePromotedName(new.peer.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder)) : self.presentationData.strings.Channel_AdminLog_MessagePromotedNameUsername(new.peer.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder), "@" + new.peer.addressName!), generateEntities: { index in + appendAttributedText(text: new.peer.addressName == nil ? self.presentationData.strings.Channel_AdminLog_MessagePromotedName(EnginePeer(new.peer).displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder)) : self.presentationData.strings.Channel_AdminLog_MessagePromotedNameUsername(EnginePeer(new.peer).displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder), "@" + new.peer.addressName!), generateEntities: { index in var result: [MessageTextEntityType] = [] if index == 0 { result.append(.TextMention(peerId: new.peer.id)) @@ -803,7 +803,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable { return result }, to: &text, entities: &entities) } else { - appendAttributedText(text: new.peer.addressName == nil ? self.presentationData.strings.Channel_AdminLog_MessageRankName(new.peer.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder), newRank ?? "") : self.presentationData.strings.Channel_AdminLog_MessageRankUsername(new.peer.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder), "@" + new.peer.addressName!, newRank ?? ""), generateEntities: { index in + appendAttributedText(text: new.peer.addressName == nil ? self.presentationData.strings.Channel_AdminLog_MessageRankName(EnginePeer(new.peer).displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder), newRank ?? "") : self.presentationData.strings.Channel_AdminLog_MessageRankUsername(EnginePeer(new.peer).displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder), "@" + new.peer.addressName!, newRank ?? ""), generateEntities: { index in var result: [MessageTextEntityType] = [] if index == 0 { result.append(.TextMention(peerId: new.peer.id)) @@ -844,14 +844,14 @@ struct ChatRecentActionsEntry: Comparable, Identifiable { var entities: [MessageTextEntity] = [] if new != nil { - appendAttributedText(text: self.presentationData.strings.Channel_AdminLog_MessageChangedGroupStickerPack(author?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? ""), generateEntities: { index in + appendAttributedText(text: self.presentationData.strings.Channel_AdminLog_MessageChangedGroupStickerPack(author.flatMap(EnginePeer.init)?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? ""), generateEntities: { index in if index == 0, let author = author { return [.TextMention(peerId: author.id)] } return [] }, to: &text, entities: &entities) } else { - appendAttributedText(text: self.presentationData.strings.Channel_AdminLog_MessageRemovedGroupStickerPack(author?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? ""), generateEntities: { index in + appendAttributedText(text: self.presentationData.strings.Channel_AdminLog_MessageRemovedGroupStickerPack(author.flatMap(EnginePeer.init)?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? ""), generateEntities: { index in if index == 0, let author = author { return [.TextMention(peerId: author.id)] } @@ -874,14 +874,14 @@ struct ChatRecentActionsEntry: Comparable, Identifiable { var entities: [MessageTextEntity] = [] if !value { - appendAttributedText(text: self.presentationData.strings.Channel_AdminLog_MessageGroupPreHistoryVisible(author?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? ""), generateEntities: { index in + appendAttributedText(text: self.presentationData.strings.Channel_AdminLog_MessageGroupPreHistoryVisible(author.flatMap(EnginePeer.init)?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? ""), generateEntities: { index in if index == 0, let author = author { return [.TextMention(peerId: author.id)] } return [] }, to: &text, entities: &entities) } else { - appendAttributedText(text: self.presentationData.strings.Channel_AdminLog_MessageGroupPreHistoryHidden(author?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? ""), generateEntities: { index in + appendAttributedText(text: self.presentationData.strings.Channel_AdminLog_MessageGroupPreHistoryHidden(author.flatMap(EnginePeer.init)?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? ""), generateEntities: { index in if index == 0, let author = author { return [.TextMention(peerId: author.id)] } @@ -965,7 +965,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable { let titleText: PresentationStrings.FormattedString - titleText = self.presentationData.strings.Channel_AdminLog_PollStopped(author?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? "") + titleText = self.presentationData.strings.Channel_AdminLog_PollStopped(author.flatMap(EnginePeer.init)?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? "") appendAttributedText(text: titleText, generateEntities: { index in if index == 0, let author = author { @@ -1008,7 +1008,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable { if let updated = updated { if let peer = peer as? TelegramChannel, case .group = peer.info { - appendAttributedText(text: self.presentationData.strings.Channel_AdminLog_MessageChangedLinkedChannel(author?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? "", updated.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder)), generateEntities: { index in + appendAttributedText(text: self.presentationData.strings.Channel_AdminLog_MessageChangedLinkedChannel(author.flatMap(EnginePeer.init)?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? "", EnginePeer(updated).displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder)), generateEntities: { index in if index == 0, let author = author { return [.TextMention(peerId: author.id)] } else if index == 1 { @@ -1017,7 +1017,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable { return [] }, to: &text, entities: &entities) } else { - appendAttributedText(text: self.presentationData.strings.Channel_AdminLog_MessageChangedLinkedGroup(author?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? "", updated.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder)), generateEntities: { index in + appendAttributedText(text: self.presentationData.strings.Channel_AdminLog_MessageChangedLinkedGroup(author.flatMap(EnginePeer.init)?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? "", EnginePeer(updated).displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder)), generateEntities: { index in if index == 0, let author = author { return [.TextMention(peerId: author.id)] } else if index == 1 { @@ -1028,7 +1028,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable { } } else { if let peer = peer as? TelegramChannel, case .group = peer.info { - appendAttributedText(text: self.presentationData.strings.Channel_AdminLog_MessageChangedUnlinkedChannel(author?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? "", previous?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? ""), generateEntities: { index in + appendAttributedText(text: self.presentationData.strings.Channel_AdminLog_MessageChangedUnlinkedChannel(author.flatMap(EnginePeer.init)?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? "", previous.flatMap(EnginePeer.init)?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? ""), generateEntities: { index in if index == 0, let author = author { return [.TextMention(peerId: author.id)] } else if index == 1, let previous = previous { @@ -1037,7 +1037,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable { return [] }, to: &text, entities: &entities) } else { - appendAttributedText(text: self.presentationData.strings.Channel_AdminLog_MessageChangedUnlinkedGroup(author?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? "", previous?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? ""), generateEntities: { index in + appendAttributedText(text: self.presentationData.strings.Channel_AdminLog_MessageChangedUnlinkedGroup(author.flatMap(EnginePeer.init)?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? "", previous.flatMap(EnginePeer.init)?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? ""), generateEntities: { index in if index == 0, let author = author { return [.TextMention(peerId: author.id)] } else if index == 0, let previous = previous { @@ -1091,14 +1091,14 @@ struct ChatRecentActionsEntry: Comparable, Identifiable { var entities: [MessageTextEntity] = [] if let newValue = newValue { - appendAttributedText(text: self.presentationData.strings.Channel_AdminLog_SetSlowmode(author?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? "", shortTimeIntervalString(strings: self.presentationData.strings, value: newValue)), generateEntities: { index in + appendAttributedText(text: self.presentationData.strings.Channel_AdminLog_SetSlowmode(author.flatMap(EnginePeer.init)?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? "", shortTimeIntervalString(strings: self.presentationData.strings, value: newValue)), generateEntities: { index in if index == 0, let author = author { return [.TextMention(peerId: author.id)] } return [] }, to: &text, entities: &entities) } else { - appendAttributedText(text: self.presentationData.strings.Channel_AdminLog_DisabledSlowmode(author?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? ""), generateEntities: { index in + appendAttributedText(text: self.presentationData.strings.Channel_AdminLog_DisabledSlowmode(author.flatMap(EnginePeer.init)?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? ""), generateEntities: { index in if index == 0, let author = author { return [.TextMention(peerId: author.id)] } @@ -1123,15 +1123,15 @@ struct ChatRecentActionsEntry: Comparable, Identifiable { let rawText: PresentationStrings.FormattedString if case .startGroupCall = self.entry.event.action { if let peer = peer as? TelegramChannel, case .broadcast = peer.info { - rawText = self.presentationData.strings.Channel_AdminLog_StartedLiveStream(author?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? "") + rawText = self.presentationData.strings.Channel_AdminLog_StartedLiveStream(author.flatMap(EnginePeer.init)?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? "") } else { - rawText = self.presentationData.strings.Channel_AdminLog_StartedVoiceChat(author?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? "") + rawText = self.presentationData.strings.Channel_AdminLog_StartedVoiceChat(author.flatMap(EnginePeer.init)?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? "") } } else { if let peer = peer as? TelegramChannel, case .broadcast = peer.info { - rawText = self.presentationData.strings.Channel_AdminLog_EndedLiveStream(author?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? "") + rawText = self.presentationData.strings.Channel_AdminLog_EndedLiveStream(author.flatMap(EnginePeer.init)?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? "") } else { - rawText = self.presentationData.strings.Channel_AdminLog_EndedVoiceChat(author?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? "") + rawText = self.presentationData.strings.Channel_AdminLog_EndedVoiceChat(author.flatMap(EnginePeer.init)?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? "") } } @@ -1164,9 +1164,9 @@ struct ChatRecentActionsEntry: Comparable, Identifiable { let rawText: PresentationStrings.FormattedString if isMuted { - rawText = self.presentationData.strings.Channel_AdminLog_MutedParticipant(author?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? "", participant?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? "") + rawText = self.presentationData.strings.Channel_AdminLog_MutedParticipant(author.flatMap(EnginePeer.init)?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? "", participant.flatMap(EnginePeer.init)?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? "") } else { - rawText = self.presentationData.strings.Channel_AdminLog_UnmutedMutedParticipant(author?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? "", participant?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? "") + rawText = self.presentationData.strings.Channel_AdminLog_UnmutedMutedParticipant(author.flatMap(EnginePeer.init)?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? "", participant.flatMap(EnginePeer.init)?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? "") } appendAttributedText(text: rawText, generateEntities: { index in @@ -1193,9 +1193,9 @@ struct ChatRecentActionsEntry: Comparable, Identifiable { let rawText: PresentationStrings.FormattedString if joinMuted { - rawText = self.presentationData.strings.Channel_AdminLog_MutedNewMembers(author?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? "") + rawText = self.presentationData.strings.Channel_AdminLog_MutedNewMembers(author.flatMap(EnginePeer.init)?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? "") } else { - rawText = self.presentationData.strings.Channel_AdminLog_AllowedNewMembersToSpeak(author?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? "") + rawText = self.presentationData.strings.Channel_AdminLog_AllowedNewMembersToSpeak(author.flatMap(EnginePeer.init)?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? "") } appendAttributedText(text: rawText, generateEntities: { index in @@ -1225,7 +1225,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable { var text: String = "" var entities: [MessageTextEntity] = [] - let rawText: PresentationStrings.FormattedString = self.presentationData.strings.Channel_AdminLog_UpdatedParticipantVolume(author?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? "", participant?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? "", "\(volume / 100)%") + let rawText: PresentationStrings.FormattedString = self.presentationData.strings.Channel_AdminLog_UpdatedParticipantVolume(author.flatMap(EnginePeer.init)?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? "", participant.flatMap(EnginePeer.init)?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? "", "\(volume / 100)%") appendAttributedText(text: rawText, generateEntities: { index in if index == 0, let author = author { @@ -1251,7 +1251,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable { var text: String = "" var entities: [MessageTextEntity] = [] - let rawText: PresentationStrings.FormattedString = self.presentationData.strings.Channel_AdminLog_DeletedInviteLink(author?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? "", invite.link.replacingOccurrences(of: "https://", with: "")) + let rawText: PresentationStrings.FormattedString = self.presentationData.strings.Channel_AdminLog_DeletedInviteLink(author.flatMap(EnginePeer.init)?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? "", invite.link.replacingOccurrences(of: "https://", with: "")) appendAttributedText(text: rawText, generateEntities: { index in if index == 0, let author = author { @@ -1277,7 +1277,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable { var text: String = "" var entities: [MessageTextEntity] = [] - let rawText: PresentationStrings.FormattedString = self.presentationData.strings.Channel_AdminLog_RevokedInviteLink(author?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? "", invite.link.replacingOccurrences(of: "https://", with: "")) + let rawText: PresentationStrings.FormattedString = self.presentationData.strings.Channel_AdminLog_RevokedInviteLink(author.flatMap(EnginePeer.init)?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? "", invite.link.replacingOccurrences(of: "https://", with: "")) appendAttributedText(text: rawText, generateEntities: { index in if index == 0, let author = author { @@ -1303,7 +1303,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable { var text: String = "" var entities: [MessageTextEntity] = [] - let rawText: PresentationStrings.FormattedString = self.presentationData.strings.Channel_AdminLog_EditedInviteLink(author?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? "", updatedInvite.link.replacingOccurrences(of: "https://", with: "")) + let rawText: PresentationStrings.FormattedString = self.presentationData.strings.Channel_AdminLog_EditedInviteLink(author.flatMap(EnginePeer.init)?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? "", updatedInvite.link.replacingOccurrences(of: "https://", with: "")) appendAttributedText(text: rawText, generateEntities: { index in if index == 0, let author = author { @@ -1329,7 +1329,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable { var text: String = "" var entities: [MessageTextEntity] = [] - let rawText: PresentationStrings.FormattedString = self.presentationData.strings.Channel_AdminLog_JoinedViaInviteLink(author?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? "", invite.link.replacingOccurrences(of: "https://", with: "")) + let rawText: PresentationStrings.FormattedString = self.presentationData.strings.Channel_AdminLog_JoinedViaInviteLink(author.flatMap(EnginePeer.init)?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? "", invite.link.replacingOccurrences(of: "https://", with: "")) appendAttributedText(text: rawText, generateEntities: { index in if index == 0, let author = author { @@ -1357,9 +1357,9 @@ struct ChatRecentActionsEntry: Comparable, Identifiable { let rawText: PresentationStrings.FormattedString if let updatedValue = updatedValue { - rawText = self.presentationData.strings.Channel_AdminLog_MessageChangedAutoremoveTimeoutSet(author?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? "", timeIntervalString(strings: self.presentationData.strings, value: updatedValue)) + rawText = self.presentationData.strings.Channel_AdminLog_MessageChangedAutoremoveTimeoutSet(author.flatMap(EnginePeer.init)?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? "", timeIntervalString(strings: self.presentationData.strings, value: updatedValue)) } else { - rawText = self.presentationData.strings.Channel_AdminLog_MessageChangedAutoremoveTimeoutRemove(author?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? "") + rawText = self.presentationData.strings.Channel_AdminLog_MessageChangedAutoremoveTimeoutRemove(author.flatMap(EnginePeer.init)?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? "") } appendAttributedText(text: rawText, generateEntities: { index in @@ -1388,9 +1388,9 @@ struct ChatRecentActionsEntry: Comparable, Identifiable { let rawText: PresentationStrings.FormattedString if let updatedValue = updatedValue { - rawText = self.presentationData.strings.Channel_AdminLog_MessageChangedThemeSet(author?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? "", updatedValue) + rawText = self.presentationData.strings.Channel_AdminLog_MessageChangedThemeSet(author.flatMap(EnginePeer.init)?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? "", updatedValue) } else { - rawText = self.presentationData.strings.Channel_AdminLog_MessageChangedThemeRemove(author?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? "") + rawText = self.presentationData.strings.Channel_AdminLog_MessageChangedThemeRemove(author.flatMap(EnginePeer.init)?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? "") } appendAttributedText(text: rawText, generateEntities: { index in diff --git a/submodules/TelegramUI/Sources/ChatReportPeerTitlePanelNode.swift b/submodules/TelegramUI/Sources/ChatReportPeerTitlePanelNode.swift index 156638375c..7e4057ee0b 100644 --- a/submodules/TelegramUI/Sources/ChatReportPeerTitlePanelNode.swift +++ b/submodules/TelegramUI/Sources/ChatReportPeerTitlePanelNode.swift @@ -66,7 +66,7 @@ private func peerButtons(_ state: ChatPresentationInterfaceState) -> [ChatReport } } if buttons.isEmpty, let phone = peer.phone, !phone.isEmpty { - buttons.append(.addContact(peer.compactDisplayTitle)) + buttons.append(.addContact(EnginePeer(peer).compactDisplayTitle)) } else { buttons.append(.addContact(nil)) } @@ -152,9 +152,9 @@ private final class ChatInfoTitlePanelInviteInfoNode: ASDisplayNode { let stringAndRanges: PresentationStrings.FormattedString if let channel = chatPeer as? TelegramChannel, case .broadcast = channel.info { - stringAndRanges = strings.Conversation_NoticeInvitedByInChannel(invitedBy.compactDisplayTitle) + stringAndRanges = strings.Conversation_NoticeInvitedByInChannel(EnginePeer(invitedBy).compactDisplayTitle) } else { - stringAndRanges = strings.Conversation_NoticeInvitedByInGroup(invitedBy.compactDisplayTitle) + stringAndRanges = strings.Conversation_NoticeInvitedByInGroup(EnginePeer(invitedBy).compactDisplayTitle) } let attributedString = NSMutableAttributedString(string: stringAndRanges.string, font: Font.regular(13.0), textColor: primaryTextColor) @@ -249,7 +249,7 @@ private final class ChatInfoTitlePanelPeerNearbyInfoNode: ASDisplayNode { let bottomInset: CGFloat = 6.0 let sideInset: CGFloat = 16.0 - let stringAndRanges = strings.Conversation_PeerNearbyDistance(chatPeer.compactDisplayTitle, shortStringForDistance(strings: strings, distance: distance)) + let stringAndRanges = strings.Conversation_PeerNearbyDistance(EnginePeer(chatPeer).compactDisplayTitle, shortStringForDistance(strings: strings, distance: distance)) let attributedString = NSMutableAttributedString(string: stringAndRanges.string, font: Font.regular(13.0), textColor: primaryTextColor) diff --git a/submodules/TelegramUI/Sources/ChatSearchNavigationContentNode.swift b/submodules/TelegramUI/Sources/ChatSearchNavigationContentNode.swift index fcfbc6399c..f2dce4fdbf 100644 --- a/submodules/TelegramUI/Sources/ChatSearchNavigationContentNode.swift +++ b/submodules/TelegramUI/Sources/ChatSearchNavigationContentNode.swift @@ -112,7 +112,7 @@ final class ChatSearchNavigationContentNode: NavigationBarContentNode { self.searchBar.prefixString = NSAttributedString(string: strings.Conversation_SearchByName_Prefix, font: searchBarFont, textColor: theme.rootController.navigationSearchBar.inputTextColor) self.searchBar.placeholderString = nil case let .member(peer): - self.searchBar.tokens = [SearchBarToken(id: peer.id, icon: UIImage(bundleImageName: "Chat List/Search/User"), title: peer.compactDisplayTitle)] + self.searchBar.tokens = [SearchBarToken(id: peer.id, icon: UIImage(bundleImageName: "Chat List/Search/User"), title: EnginePeer(peer).compactDisplayTitle)] self.searchBar.prefixString = nil self.searchBar.placeholderString = nil } diff --git a/submodules/TelegramUI/Sources/ChatTextFormat.swift b/submodules/TelegramUI/Sources/ChatTextFormat.swift index f36db78ff4..03c67aed02 100644 --- a/submodules/TelegramUI/Sources/ChatTextFormat.swift +++ b/submodules/TelegramUI/Sources/ChatTextFormat.swift @@ -1,6 +1,7 @@ import Foundation import TextFormat import Postbox +import TelegramCore import AccountContext func chatTextInputAddFormattingAttribute(_ state: ChatTextInputState, attribute: NSAttributedString.Key) -> ChatTextInputState { @@ -90,9 +91,9 @@ func chatTextInputAddMentionAttribute(_ state: ChatTextInputState, peer: Peer) - let selectionPosition = range.lowerBound + (replacementText as NSString).length return ChatTextInputState(inputText: inputText, selectionRange: selectionPosition ..< selectionPosition) - } else if !peer.compactDisplayTitle.isEmpty { + } else if !EnginePeer(peer).compactDisplayTitle.isEmpty { let replacementText = NSMutableAttributedString() - replacementText.append(NSAttributedString(string: peer.compactDisplayTitle, attributes: [ChatTextInputAttributes.textMention: ChatTextInputTextMentionAttribute(peerId: peer.id)])) + replacementText.append(NSAttributedString(string: EnginePeer(peer).compactDisplayTitle, attributes: [ChatTextInputAttributes.textMention: ChatTextInputTextMentionAttribute(peerId: peer.id)])) replacementText.append(NSAttributedString(string: " ")) let updatedRange = NSRange(location: range.location , length: range.length) diff --git a/submodules/TelegramUI/Sources/ChatTitleView.swift b/submodules/TelegramUI/Sources/ChatTitleView.swift index 9bd9fe4cdf..5da89d82b8 100644 --- a/submodules/TelegramUI/Sources/ChatTitleView.swift +++ b/submodules/TelegramUI/Sources/ChatTitleView.swift @@ -130,7 +130,7 @@ final class ChatTitleView: UIView, NavigationBarTitleView { if !peerView.peerIsContact, let user = peer as? TelegramUser, !user.flags.contains(.isSupport), user.botInfo == nil, let phone = user.phone, !phone.isEmpty { segments = [.text(0, NSAttributedString(string: formatPhoneNumber(phone), font: titleFont, textColor: titleTheme.rootController.navigationBar.primaryTextColor))] } else { - segments = [.text(0, NSAttributedString(string: peer.displayTitle(strings: self.strings, displayOrder: self.nameDisplayOrder), font: titleFont, textColor: titleTheme.rootController.navigationBar.primaryTextColor))] + segments = [.text(0, NSAttributedString(string: EnginePeer(peer).displayTitle(strings: self.strings, displayOrder: self.nameDisplayOrder), font: titleFont, textColor: titleTheme.rootController.navigationBar.primaryTextColor))] } } if peer.isFake { @@ -350,7 +350,7 @@ final class ChatTitleView: UIView, NavigationBarTitleView { } } else { for (peer, _) in inputActivities { - let title = peer.compactDisplayTitle + let title = EnginePeer(peer).compactDisplayTitle if !title.isEmpty { if first { first = false @@ -411,11 +411,11 @@ final class ChatTitleView: UIView, NavigationBarTitleView { let userPresence: TelegramUserPresence if let presence = peerView.peerPresences[peer.id] as? TelegramUserPresence { userPresence = presence - self.presenceManager?.reset(presence: presence) + self.presenceManager?.reset(presence: EnginePeer.Presence(presence)) } else { userPresence = TelegramUserPresence(status: .none, lastActivity: 0) } - let (string, activity) = stringAndActivityForUserPresence(strings: self.strings, dateTimeFormat: self.dateTimeFormat, presence: userPresence, relativeTo: Int32(timestamp)) + let (string, activity) = stringAndActivityForUserPresence(strings: self.strings, dateTimeFormat: self.dateTimeFormat, presence: EnginePeer.Presence(userPresence), relativeTo: Int32(timestamp)) let attributedString = NSAttributedString(string: string, font: subtitleFont, textColor: activity ? titleTheme.rootController.navigationBar.accentTextColor : titleTheme.rootController.navigationBar.secondaryTextColor) state = .info(attributedString, activity ? .online : .lastSeenTime) } else { diff --git a/submodules/TelegramUI/Sources/ContactMultiselectionController.swift b/submodules/TelegramUI/Sources/ContactMultiselectionController.swift index ee3207fcdb..b6ae675b20 100644 --- a/submodules/TelegramUI/Sources/ContactMultiselectionController.swift +++ b/submodules/TelegramUI/Sources/ContactMultiselectionController.swift @@ -20,7 +20,7 @@ private func peerTokenTitle(accountPeerId: PeerId, peer: Peer, strings: Presenta } else if peer.id.isReplies { return strings.DialogList_Replies } else { - return peer.displayTitle(strings: strings, displayOrder: nameDisplayOrder) + return EnginePeer(peer).displayTitle(strings: strings, displayOrder: nameDisplayOrder) } } diff --git a/submodules/TelegramUI/Sources/CreateChannelController.swift b/submodules/TelegramUI/Sources/CreateChannelController.swift index 9e907e7507..a0f6c1327a 100644 --- a/submodules/TelegramUI/Sources/CreateChannelController.swift +++ b/submodules/TelegramUI/Sources/CreateChannelController.swift @@ -147,7 +147,7 @@ private enum CreateChannelEntry: ItemListNodeEntry { let arguments = arguments as! CreateChannelArguments switch self { case let .channelInfo(_, _, dateTimeFormat, peer, state, avatar): - return ItemListAvatarAndNameInfoItem(accountContext: arguments.context, presentationData: presentationData, dateTimeFormat: dateTimeFormat, mode: .editSettings, peer: peer, presence: nil, cachedData: nil, state: state, sectionId: ItemListSectionId(self.section), style: .blocks(withTopInset: false, withExtendedBottomInset: false), editingNameUpdated: { editingName in + return ItemListAvatarAndNameInfoItem(accountContext: arguments.context, presentationData: presentationData, dateTimeFormat: dateTimeFormat, mode: .editSettings, peer: peer.flatMap(EnginePeer.init), presence: nil, memberCount: nil, state: state, sectionId: ItemListSectionId(self.section), style: .blocks(withTopInset: false, withExtendedBottomInset: false), editingNameUpdated: { editingName in arguments.updateEditingName(editingName) }, editingNameCompleted: { arguments.focusOnDescription() diff --git a/submodules/TelegramUI/Sources/CreateGroupController.swift b/submodules/TelegramUI/Sources/CreateGroupController.swift index d0f04d282b..312b5719cc 100644 --- a/submodules/TelegramUI/Sources/CreateGroupController.swift +++ b/submodules/TelegramUI/Sources/CreateGroupController.swift @@ -233,7 +233,7 @@ private enum CreateGroupEntry: ItemListNodeEntry { let arguments = arguments as! CreateGroupArguments switch self { case let .groupInfo(_, _, dateTimeFormat, peer, state, avatar): - return ItemListAvatarAndNameInfoItem(accountContext: arguments.context, presentationData: presentationData, dateTimeFormat: dateTimeFormat, mode: .editSettings, peer: peer, presence: nil, cachedData: nil, state: state, sectionId: ItemListSectionId(self.section), style: .blocks(withTopInset: false, withExtendedBottomInset: false), editingNameUpdated: { editingName in + return ItemListAvatarAndNameInfoItem(accountContext: arguments.context, presentationData: presentationData, dateTimeFormat: dateTimeFormat, mode: .editSettings, peer: peer.flatMap(EnginePeer.init), presence: nil, memberCount: nil, state: state, sectionId: ItemListSectionId(self.section), style: .blocks(withTopInset: false, withExtendedBottomInset: false), editingNameUpdated: { editingName in arguments.updateEditingName(editingName) }, avatarTapped: { arguments.changeProfilePhoto() @@ -243,7 +243,7 @@ private enum CreateGroupEntry: ItemListNodeEntry { arguments.changeProfilePhoto() }) case let .member(_, _, _, dateTimeFormat, nameDisplayOrder, peer, presence): - return ItemListPeerItem(presentationData: presentationData, dateTimeFormat: dateTimeFormat, nameDisplayOrder: nameDisplayOrder, context: arguments.context, peer: peer, presence: presence, text: .presence, label: .none, editing: ItemListPeerItemEditing(editable: false, editing: false, revealed: false), switchValue: nil, enabled: true, selectable: true, sectionId: self.section, action: nil, setPeerIdWithRevealedOptions: { _, _ in }, removePeer: { _ in }) + return ItemListPeerItem(presentationData: presentationData, dateTimeFormat: dateTimeFormat, nameDisplayOrder: nameDisplayOrder, context: arguments.context, peer: EnginePeer(peer), presence: presence.flatMap(EnginePeer.Presence.init), text: .presence, label: .none, editing: ItemListPeerItemEditing(editable: false, editing: false, revealed: false), switchValue: nil, enabled: true, selectable: true, sectionId: self.section, action: nil, setPeerIdWithRevealedOptions: { _, _ in }, removePeer: { _ in }) case let .locationHeader(_, title): return ItemListSectionHeaderItem(presentationData: presentationData, text: title, sectionId: self.section) case let .location(theme, location): diff --git a/submodules/TelegramUI/Sources/ForwardAccessoryPanelNode.swift b/submodules/TelegramUI/Sources/ForwardAccessoryPanelNode.swift index 39ceb8f8ce..003a728897 100644 --- a/submodules/TelegramUI/Sources/ForwardAccessoryPanelNode.swift +++ b/submodules/TelegramUI/Sources/ForwardAccessoryPanelNode.swift @@ -164,11 +164,11 @@ final class ForwardAccessoryPanelNode: AccessoryPanelNode { if author.id == context.account.peerId { authors.append(strongSelf.strings.DialogList_You) } else { - authors.append(author.compactDisplayTitle) + authors.append(EnginePeer(author).compactDisplayTitle) } } if let peer = message.peers[message.id.peerId] { - sourcePeer = (peer.id.namespace == Namespaces.Peer.CloudUser, peer.displayTitle(strings: strongSelf.strings, displayOrder: strongSelf.nameDisplayOrder)) + sourcePeer = (peer.id.namespace == Namespaces.Peer.CloudUser, EnginePeer(peer).displayTitle(strings: strongSelf.strings, displayOrder: strongSelf.nameDisplayOrder)) } } diff --git a/submodules/TelegramUI/Sources/LegacyCamera.swift b/submodules/TelegramUI/Sources/LegacyCamera.swift index b74f6e4d8d..6e2cfa28ea 100644 --- a/submodules/TelegramUI/Sources/LegacyCamera.swift +++ b/submodules/TelegramUI/Sources/LegacyCamera.swift @@ -79,7 +79,7 @@ func presentedLegacyCamera(context: AccountContext, peer: Peer, chatLocation: Ch controller.allowGrouping = mediaGrouping controller.inhibitDocumentCaptions = false controller.suggestionContext = legacySuggestionContext(context: context, peerId: peer.id, chatLocation: chatLocation) - controller.recipientName = peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) + controller.recipientName = EnginePeer(peer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) if peer.id != context.account.peerId { if peer is TelegramUser { controller.hasTimer = hasSchedule diff --git a/submodules/TelegramUI/Sources/OverlayAudioPlayerController.swift b/submodules/TelegramUI/Sources/OverlayAudioPlayerController.swift index cc6de0a949..5897393c90 100644 --- a/submodules/TelegramUI/Sources/OverlayAudioPlayerController.swift +++ b/submodules/TelegramUI/Sources/OverlayAudioPlayerController.swift @@ -89,14 +89,14 @@ final class OverlayAudioPlayerControllerImpl: ViewController, OverlayAudioPlayer savedMessages = true } else { if peers.count == 1, let peer = peers.first { - let peerName = peer.id == strongSelf.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) + let peerName = peer.id == strongSelf.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : EnginePeer(peer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) text = presentationData.strings.Conversation_ForwardTooltip_Chat_One(peerName).string } else if peers.count == 2, let firstPeer = peers.first, let secondPeer = peers.last { - let firstPeerName = firstPeer.id == strongSelf.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : firstPeer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) - let secondPeerName = secondPeer.id == strongSelf.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : secondPeer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) + let firstPeerName = firstPeer.id == strongSelf.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : EnginePeer(firstPeer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) + let secondPeerName = secondPeer.id == strongSelf.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : EnginePeer(secondPeer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) text = presentationData.strings.Conversation_ForwardTooltip_TwoChats_One(firstPeerName, secondPeerName).string } else if let peer = peers.first { - let peerName = peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) + let peerName = EnginePeer(peer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) text = presentationData.strings.Conversation_ForwardTooltip_ManyChats_One(peerName, "\(peers.count - 1)").string } else { text = "" diff --git a/submodules/TelegramUI/Sources/PeerInfo/ListItems/PeerInfoScreenMemberItem.swift b/submodules/TelegramUI/Sources/PeerInfo/ListItems/PeerInfoScreenMemberItem.swift index 03019e6908..8b6e4af91c 100644 --- a/submodules/TelegramUI/Sources/PeerInfo/ListItems/PeerInfoScreenMemberItem.swift +++ b/submodules/TelegramUI/Sources/PeerInfo/ListItems/PeerInfoScreenMemberItem.swift @@ -184,7 +184,7 @@ private final class PeerInfoScreenMemberItemNode: PeerInfoScreenItemNode { itemText = .presence } - let peerItem = ItemListPeerItem(presentationData: ItemListPresentationData(presentationData), dateTimeFormat: presentationData.dateTimeFormat, nameDisplayOrder: presentationData.nameDisplayOrder, context: item.context, peer: item.member.peer, height: itemHeight, presence: item.member.presence, text: itemText, label: itemLabel, editing: ItemListPeerItemEditing(editable: !options.isEmpty, editing: false, revealed: nil), revealOptions: ItemListPeerItemRevealOptions(options: options), switchValue: nil, enabled: true, selectable: false, sectionId: 0, action: nil, setPeerIdWithRevealedOptions: { lhs, rhs in + let peerItem = ItemListPeerItem(presentationData: ItemListPresentationData(presentationData), dateTimeFormat: presentationData.dateTimeFormat, nameDisplayOrder: presentationData.nameDisplayOrder, context: item.context, peer: EnginePeer(item.member.peer), height: itemHeight, presence: item.member.presence.flatMap(EnginePeer.Presence.init), text: itemText, label: itemLabel, editing: ItemListPeerItemEditing(editable: !options.isEmpty, editing: false, revealed: nil), revealOptions: ItemListPeerItemRevealOptions(options: options), switchValue: nil, enabled: true, selectable: false, sectionId: 0, action: nil, setPeerIdWithRevealedOptions: { lhs, rhs in }, removePeer: { _ in diff --git a/submodules/TelegramUI/Sources/PeerInfo/Panes/PeerInfoGroupsInCommonPaneNode.swift b/submodules/TelegramUI/Sources/PeerInfo/Panes/PeerInfoGroupsInCommonPaneNode.swift index 8384900f4a..06c4b90ed4 100644 --- a/submodules/TelegramUI/Sources/PeerInfo/Panes/PeerInfoGroupsInCommonPaneNode.swift +++ b/submodules/TelegramUI/Sources/PeerInfo/Panes/PeerInfoGroupsInCommonPaneNode.swift @@ -36,7 +36,7 @@ private struct GroupsInCommonListEntry: Comparable, Identifiable { func item(context: AccountContext, presentationData: PresentationData, openPeer: @escaping (Peer) -> Void, openPeerContextAction: @escaping (Peer, ASDisplayNode, ContextGesture?) -> Void) -> ListViewItem { let peer = self.peer - return ItemListPeerItem(presentationData: ItemListPresentationData(presentationData), dateTimeFormat: presentationData.dateTimeFormat, nameDisplayOrder: presentationData.nameDisplayOrder, context: context, peer: self.peer, presence: nil, text: .none, label: .none, editing: ItemListPeerItemEditing(editable: false, editing: false, revealed: false), switchValue: nil, enabled: true, selectable: true, sectionId: 0, action: { + return ItemListPeerItem(presentationData: ItemListPresentationData(presentationData), dateTimeFormat: presentationData.dateTimeFormat, nameDisplayOrder: presentationData.nameDisplayOrder, context: context, peer: EnginePeer(self.peer), presence: nil, text: .none, label: .none, editing: ItemListPeerItemEditing(editable: false, editing: false, revealed: false), switchValue: nil, enabled: true, selectable: true, sectionId: 0, action: { openPeer(peer) }, setPeerIdWithRevealedOptions: { _, _ in }, removePeer: { _ in diff --git a/submodules/TelegramUI/Sources/PeerInfo/Panes/PeerInfoMembersPane.swift b/submodules/TelegramUI/Sources/PeerInfo/Panes/PeerInfoMembersPane.swift index 78a914e13e..e88fa7aae6 100644 --- a/submodules/TelegramUI/Sources/PeerInfo/Panes/PeerInfoMembersPane.swift +++ b/submodules/TelegramUI/Sources/PeerInfo/Panes/PeerInfoMembersPane.swift @@ -78,7 +78,7 @@ private struct PeerMembersListEntry: Comparable, Identifiable { })) } - return ItemListPeerItem(presentationData: ItemListPresentationData(presentationData), dateTimeFormat: presentationData.dateTimeFormat, nameDisplayOrder: presentationData.nameDisplayOrder, context: context, peer: member.peer, presence: member.presence, text: .presence, label: label == nil ? .none : .text(label!, .standard), editing: ItemListPeerItemEditing(editable: !options.isEmpty, editing: false, revealed: false), revealOptions: ItemListPeerItemRevealOptions(options: options), switchValue: nil, enabled: true, selectable: member.id != context.account.peerId, sectionId: 0, action: { + return ItemListPeerItem(presentationData: ItemListPresentationData(presentationData), dateTimeFormat: presentationData.dateTimeFormat, nameDisplayOrder: presentationData.nameDisplayOrder, context: context, peer: EnginePeer(member.peer), presence: member.presence.flatMap(EnginePeer.Presence.init), text: .presence, label: label == nil ? .none : .text(label!, .standard), editing: ItemListPeerItemEditing(editable: !options.isEmpty, editing: false, revealed: false), revealOptions: ItemListPeerItemRevealOptions(options: options), switchValue: nil, enabled: true, selectable: member.id != context.account.peerId, sectionId: 0, action: { action(member, .open) }, setPeerIdWithRevealedOptions: { _, _ in }, removePeer: { _ in diff --git a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoData.swift b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoData.swift index 668a68aba0..5d1db97d59 100644 --- a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoData.swift +++ b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoData.swift @@ -482,7 +482,7 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen let data = manager.with { manager -> PeerInfoStatusData? in if let presence = manager.currentValue { let timestamp = CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970 - let (text, isActivity) = stringAndActivityForUserPresence(strings: strings, dateTimeFormat: dateTimeFormat, presence: presence, relativeTo: Int32(timestamp), expanded: true) + let (text, isActivity) = stringAndActivityForUserPresence(strings: strings, dateTimeFormat: dateTimeFormat, presence: EnginePeer.Presence(presence), relativeTo: Int32(timestamp), expanded: true) return PeerInfoStatusData(text: text, isActivity: isActivity) } else { return nil @@ -537,7 +537,7 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen }) } updateManager.with { updateManager in - updateManager.reset(presence: presence) + updateManager.reset(presence: EnginePeer.Presence(presence)) } } else if let _ = manager.updateManager { manager.updateManager = nil diff --git a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoHeaderNode.swift b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoHeaderNode.swift index 12f4218ebb..b282277da7 100644 --- a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoHeaderNode.swift +++ b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoHeaderNode.swift @@ -2014,7 +2014,7 @@ final class PeerInfoHeaderNode: ASDisplayNode { } else if peer.id == self.context.account.peerId && !self.isSettings { titleString = NSAttributedString(string: presentationData.strings.DialogList_Replies, font: Font.semibold(24.0), textColor: presentationData.theme.list.itemPrimaryTextColor) } else { - titleString = NSAttributedString(string: peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), font: Font.semibold(24.0), textColor: presentationData.theme.list.itemPrimaryTextColor) + titleString = NSAttributedString(string: EnginePeer(peer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), font: Font.semibold(24.0), textColor: presentationData.theme.list.itemPrimaryTextColor) } if self.isSettings, let user = peer as? TelegramUser { diff --git a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift index 5bff95d688..db08ed5776 100644 --- a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift +++ b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift @@ -1222,7 +1222,7 @@ private func editingItems(data: PeerInfoScreenData?, context: AccountContext, pr if let addressName = peer.addressName, !addressName.isEmpty { discussionGroupTitle = "@\(addressName)" } else { - discussionGroupTitle = peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) + discussionGroupTitle = EnginePeer(peer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) } } else { discussionGroupTitle = presentationData.strings.Channel_DiscussionGroupAdd @@ -1329,7 +1329,7 @@ private func editingItems(data: PeerInfoScreenData?, context: AccountContext, pr if let addressName = linkedDiscussionPeer.addressName, !addressName.isEmpty { peerTitle = "@\(addressName)" } else { - peerTitle = linkedDiscussionPeer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) + peerTitle = EnginePeer(linkedDiscussionPeer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) } items[.peerPublicSettings]!.append(PeerInfoScreenDisclosureItem(id: ItemLinkedChannel, label: .text(peerTitle), text: presentationData.strings.Group_LinkedChannel, icon: UIImage(bundleImageName: "Chat/Info/GroupLinkedChannelIcon"), action: { interaction.editingOpenDiscussionGroupSetup() @@ -1805,7 +1805,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD var personalPeerName: String? var isChannel = false if let user = peer as? TelegramUser { - personalPeerName = user.compactDisplayTitle + personalPeerName = EnginePeer(user).compactDisplayTitle } else if let channel = peer as? TelegramChannel, case .broadcast = channel.info { isChannel = true } @@ -1939,7 +1939,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD var personalPeerName: String? var isChannel = false if let user = peer as? TelegramUser { - personalPeerName = user.compactDisplayTitle + personalPeerName = EnginePeer(user).compactDisplayTitle } else if let channel = peer as? TelegramChannel, case .broadcast = channel.info { isChannel = true } @@ -3606,14 +3606,14 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD savedMessages = true } else { if peers.count == 1, let peer = peers.first { - let peerName = peer.id == strongSelf.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) + let peerName = peer.id == strongSelf.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : EnginePeer(peer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) text = presentationData.strings.UserInfo_ContactForwardTooltip_Chat_One(peerName).string } else if peers.count == 2, let firstPeer = peers.first, let secondPeer = peers.last { - let firstPeerName = firstPeer.id == strongSelf.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : firstPeer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) - let secondPeerName = secondPeer.id == strongSelf.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : secondPeer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) + let firstPeerName = firstPeer.id == strongSelf.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : EnginePeer(firstPeer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) + let secondPeerName = secondPeer.id == strongSelf.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : EnginePeer(secondPeer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) text = presentationData.strings.UserInfo_ContactForwardTooltip_TwoChats_One(firstPeerName, secondPeerName).string } else if let peer = peers.first { - let peerName = peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) + let peerName = EnginePeer(peer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) text = presentationData.strings.UserInfo_ContactForwardTooltip_ManyChats_One(peerName, "\(peers.count - 1)").string } else { text = "" @@ -3852,7 +3852,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD return } if let controller = strongSelf.controller { - let displayTitle = peer?.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder) ?? "" + let displayTitle = peer.flatMap(EnginePeer.init)?.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder) ?? "" controller.present(textAlertController(context: strongSelf.context, updatedPresentationData: strongSelf.controller?.updatedPresentationData, title: nil, text: strongSelf.presentationData.strings.UserInfo_StartSecretChatConfirmation(displayTitle).string, actions: [TextAlertAction(type: .genericAction, title: strongSelf.presentationData.strings.Common_Cancel, action: {}), TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.UserInfo_StartSecretChatStart, action: { guard let strongSelf = self else { return @@ -3938,14 +3938,14 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD savedMessages = true } else { if peers.count == 1, let peer = peers.first { - let peerName = peer.id == strongSelf.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) + let peerName = peer.id == strongSelf.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : EnginePeer(peer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) text = presentationData.strings.UserInfo_LinkForwardTooltip_Chat_One(peerName).string } else if peers.count == 2, let firstPeer = peers.first, let secondPeer = peers.last { - let firstPeerName = firstPeer.id == strongSelf.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : firstPeer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) - let secondPeerName = secondPeer.id == strongSelf.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : secondPeer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) + let firstPeerName = firstPeer.id == strongSelf.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : EnginePeer(firstPeer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) + let secondPeerName = secondPeer.id == strongSelf.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : EnginePeer(secondPeer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) text = presentationData.strings.UserInfo_LinkForwardTooltip_TwoChats_One(firstPeerName, secondPeerName).string } else if let peer = peers.first { - let peerName = peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) + let peerName = EnginePeer(peer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) text = presentationData.strings.UserInfo_LinkForwardTooltip_ManyChats_One(peerName, "\(peers.count - 1)").string } else { text = "" @@ -3998,7 +3998,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD return } if cachedUserData.callsPrivate { - self.controller?.present(textAlertController(context: self.context, updatedPresentationData: self.controller?.updatedPresentationData, title: self.presentationData.strings.Call_ConnectionErrorTitle, text: self.presentationData.strings.Call_PrivacyErrorMessage(peer.compactDisplayTitle).string, actions: [TextAlertAction(type: .defaultAction, title: self.presentationData.strings.Common_OK, action: {})]), in: .window(.root)) + self.controller?.present(textAlertController(context: self.context, updatedPresentationData: self.controller?.updatedPresentationData, title: self.presentationData.strings.Call_ConnectionErrorTitle, text: self.presentationData.strings.Call_PrivacyErrorMessage(EnginePeer(peer).compactDisplayTitle).string, actions: [TextAlertAction(type: .defaultAction, title: self.presentationData.strings.Common_OK, action: {})]), in: .window(.root)) return } @@ -4231,7 +4231,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD |> deliverOnMainQueue).start(completed: { [weak self] in if let strongSelf = self, let peer = strongSelf.data?.peer { let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 } - let controller = UndoOverlayController(presentationData: presentationData, content: .info(text: presentationData.strings.Conversation_DeletedFromContacts(peer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder)).string), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }) + let controller = UndoOverlayController(presentationData: presentationData, content: .info(text: presentationData.strings.Conversation_DeletedFromContacts(EnginePeer(peer).displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder)).string), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }) controller.keepOnParentDismissal = true strongSelf.controller?.present(controller, in: .window(.root)) @@ -4308,8 +4308,8 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD let deleteChat = false actionSheet.setItemGroups([ ActionSheetItemGroup(items: [ - ActionSheetTextItem(title: presentationData.strings.UserInfo_BlockConfirmationTitle(peer.compactDisplayTitle).string), - ActionSheetButtonItem(title: presentationData.strings.UserInfo_BlockActionTitle(peer.compactDisplayTitle).string, color: .destructive, action: { + ActionSheetTextItem(title: presentationData.strings.UserInfo_BlockConfirmationTitle(EnginePeer(peer).compactDisplayTitle).string), + ActionSheetButtonItem(title: presentationData.strings.UserInfo_BlockActionTitle(EnginePeer(peer).compactDisplayTitle).string, color: .destructive, action: { dismissAction() guard let strongSelf = self else { return @@ -4333,9 +4333,9 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD } else { let text: String if block { - text = presentationData.strings.UserInfo_BlockConfirmation(peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)).string + text = presentationData.strings.UserInfo_BlockConfirmation(EnginePeer(peer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)).string } else { - text = presentationData.strings.UserInfo_UnblockConfirmation(peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)).string + text = presentationData.strings.UserInfo_UnblockConfirmation(EnginePeer(peer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)).string } strongSelf.controller?.present(textAlertController(context: strongSelf.context, updatedPresentationData: strongSelf.controller?.updatedPresentationData, title: nil, text: text, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_No, action: {}), TextAlertAction(type: .genericAction, title: presentationData.strings.Common_Yes, action: { guard let strongSelf = self else { @@ -4392,7 +4392,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD } if let peer = selectedPeer { let avatarSize = CGSize(width: 28.0, height: 28.0) - items.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.VoiceChat_DisplayAs, textLayout: .secondLineWithValue(peer.peer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder)), icon: { _ in nil }, iconSource: ContextMenuActionItemIconSource(size: avatarSize, signal: peerAvatarCompleteImage(account: strongSelf.context.account, peer: peer.peer, size: avatarSize)), action: { c, f in + items.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.VoiceChat_DisplayAs, textLayout: .secondLineWithValue(EnginePeer(peer.peer).displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder)), icon: { _ in nil }, iconSource: ContextMenuActionItemIconSource(size: avatarSize, signal: peerAvatarCompleteImage(account: strongSelf.context.account, peer: peer.peer, size: avatarSize)), action: { c, f in guard let strongSelf = self else { return } @@ -4505,7 +4505,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD let avatarSize = CGSize(width: 28.0, height: 28.0) let avatarSignal = peerAvatarCompleteImage(account: strongSelf.context.account, peer: peer.peer, size: avatarSize) - items.append(.action(ContextMenuActionItem(text: peer.peer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder), textLayout: subtitle.flatMap { .secondLineWithValue($0) } ?? .singleLine, icon: { _ in nil }, iconSource: ContextMenuActionItemIconSource(size: avatarSize, signal: avatarSignal), action: { _, f in + items.append(.action(ContextMenuActionItem(text: EnginePeer(peer.peer).displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder), textLayout: subtitle.flatMap { .secondLineWithValue($0) } ?? .singleLine, icon: { _ in nil }, iconSource: ContextMenuActionItemIconSource(size: avatarSize, signal: avatarSignal), action: { _, f in if dismissOnSelection { f(.dismissWithoutContent) } @@ -4610,14 +4610,14 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD savedMessages = true } else { if peers.count == 1, let peer = peers.first { - let peerName = peer.id == strongSelf.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) + let peerName = peer.id == strongSelf.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : EnginePeer(peer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) text = presentationData.strings.UserInfo_LinkForwardTooltip_Chat_One(peerName).string } else if peers.count == 2, let firstPeer = peers.first, let secondPeer = peers.last { - let firstPeerName = firstPeer.id == strongSelf.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : firstPeer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) - let secondPeerName = secondPeer.id == strongSelf.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : secondPeer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) + let firstPeerName = firstPeer.id == strongSelf.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : EnginePeer(firstPeer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) + let secondPeerName = secondPeer.id == strongSelf.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : EnginePeer(secondPeer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) text = presentationData.strings.UserInfo_LinkForwardTooltip_TwoChats_One(firstPeerName, secondPeerName).string } else if let peer = peers.first { - let peerName = peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) + let peerName = EnginePeer(peer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) text = presentationData.strings.UserInfo_LinkForwardTooltip_ManyChats_One(peerName, "\(peers.count - 1)").string } else { text = "" @@ -4765,7 +4765,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD } let context = self.context let presentationData = self.presentationData - let map = TelegramMediaMap(latitude: location.latitude, longitude: location.longitude, heading: nil, accuracyRadius: nil, geoPlace: nil, venue: MapVenue(title: peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), address: location.address, provider: nil, id: nil, type: nil), liveBroadcastingTimeout: nil, liveProximityNotificationRadius: nil) + let map = TelegramMediaMap(latitude: location.latitude, longitude: location.longitude, heading: nil, accuracyRadius: nil, geoPlace: nil, venue: MapVenue(title: EnginePeer(peer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), address: location.address, provider: nil, id: nil, type: nil), liveBroadcastingTimeout: nil, liveProximityNotificationRadius: nil) let controllerParams = LocationViewParams(sendLiveLocation: { _ in }, stopLiveLocation: { _ in @@ -5284,7 +5284,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD guard let strongSelf = self else { return } - let controller = WebSearchController(context: strongSelf.context, updatedPresentationData: strongSelf.controller?.updatedPresentationData, peer: peer, chatLocation: nil, configuration: searchBotsConfiguration, mode: .avatar(initialQuery: strongSelf.isSettings ? nil : peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), completion: { [weak self] result in + let controller = WebSearchController(context: strongSelf.context, updatedPresentationData: strongSelf.controller?.updatedPresentationData, peer: peer, chatLocation: nil, configuration: searchBotsConfiguration, mode: .avatar(initialQuery: strongSelf.isSettings ? nil : EnginePeer(peer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), completion: { [weak self] result in assetsController?.dismiss() self?.updateProfilePhoto(result) })) @@ -5633,7 +5633,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD var personalPeerName: String? var isChannel = false if let user = peer as? TelegramUser { - personalPeerName = user.compactDisplayTitle + personalPeerName = EnginePeer(user).compactDisplayTitle } else if let channel = peer as? TelegramChannel, case .broadcast = channel.info { isChannel = true } @@ -5759,14 +5759,14 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD savedMessages = true } else { if displayPeers.count == 1, let peer = displayPeers.first { - let peerName = peer.id == strongSelf.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) + let peerName = peer.id == strongSelf.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : EnginePeer(peer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) text = messageIds.count == 1 ? presentationData.strings.Conversation_ForwardTooltip_Chat_One(peerName).string : presentationData.strings.Conversation_ForwardTooltip_Chat_Many(peerName).string } else if displayPeers.count == 2, let firstPeer = displayPeers.first, let secondPeer = displayPeers.last { - let firstPeerName = firstPeer.id == strongSelf.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : firstPeer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) - let secondPeerName = secondPeer.id == strongSelf.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : secondPeer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) + let firstPeerName = firstPeer.id == strongSelf.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : EnginePeer(firstPeer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) + let secondPeerName = secondPeer.id == strongSelf.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : EnginePeer(secondPeer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) text = messageIds.count == 1 ? presentationData.strings.Conversation_ForwardTooltip_TwoChats_One(firstPeerName, secondPeerName).string : presentationData.strings.Conversation_ForwardTooltip_TwoChats_Many(firstPeerName, secondPeerName).string } else if let peer = displayPeers.first { - let peerName = peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) + let peerName = EnginePeer(peer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) text = messageIds.count == 1 ? presentationData.strings.Conversation_ForwardTooltip_ManyChats_One(peerName, "\(displayPeers.count - 1)").string : presentationData.strings.Conversation_ForwardTooltip_ManyChats_Many(peerName, "\(displayPeers.count - 1)").string } else { text = "" @@ -6889,7 +6889,7 @@ public final class PeerInfoScreenImpl: ViewController, PeerInfoScreen { let avatarSize = CGSize(width: 28.0, height: 28.0) - items.append(.action(ContextMenuActionItem(text: primary.1.displayTitle(strings: strings, displayOrder: presentationData.nameDisplayOrder), icon: { _ in nil }, iconSource: ContextMenuActionItemIconSource(size: avatarSize, signal: peerAvatarCompleteImage(account: primary.0.account, peer: primary.1, size: avatarSize)), action: { _, f in + items.append(.action(ContextMenuActionItem(text: EnginePeer(primary.1).displayTitle(strings: strings, displayOrder: presentationData.nameDisplayOrder), icon: { _ in nil }, iconSource: ContextMenuActionItemIconSource(size: avatarSize, signal: peerAvatarCompleteImage(account: primary.0.account, peer: primary.1, size: avatarSize)), action: { _, f in f(.default) }))) @@ -6899,7 +6899,7 @@ public final class PeerInfoScreenImpl: ViewController, PeerInfoScreen { for account in other { let id = account.0.account.id - items.append(.action(ContextMenuActionItem(text: account.1.displayTitle(strings: strings, displayOrder: presentationData.nameDisplayOrder), badge: account.2 != 0 ? ContextMenuActionBadge(value: "\(account.2)", color: .accent) : nil, icon: { _ in nil }, iconSource: ContextMenuActionItemIconSource(size: avatarSize, signal: peerAvatarCompleteImage(account: account.0.account, peer: account.1, size: avatarSize)), action: { [weak self] _, f in + items.append(.action(ContextMenuActionItem(text: EnginePeer(account.1).displayTitle(strings: strings, displayOrder: presentationData.nameDisplayOrder), badge: account.2 != 0 ? ContextMenuActionBadge(value: "\(account.2)", color: .accent) : nil, icon: { _ in nil }, iconSource: ContextMenuActionItemIconSource(size: avatarSize, signal: peerAvatarCompleteImage(account: account.0.account, peer: account.1, size: avatarSize)), action: { [weak self] _, f in guard let strongSelf = self else { return } @@ -7276,7 +7276,7 @@ func presentAddMembers(context: AccountContext, updatedPresentationData: (initia let result = ValuePromise() let presentationData = context.sharedContext.currentPresentationData.with { $0 } if let contactsController = contactsController { - let alertController = textAlertController(context: context, updatedPresentationData: updatedPresentationData, title: nil, text: presentationData.strings.GroupInfo_AddParticipantConfirmation(peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)).string, actions: [ + let alertController = textAlertController(context: context, updatedPresentationData: updatedPresentationData, title: nil, text: presentationData.strings.GroupInfo_AddParticipantConfirmation(EnginePeer(peer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)).string, actions: [ TextAlertAction(type: .genericAction, title: presentationData.strings.Common_No, action: { result.set(false) }), @@ -7311,7 +7311,7 @@ func presentAddMembers(context: AccountContext, updatedPresentationData: (initia case .privacy: let _ = (context.account.postbox.loadedPeerWithId(memberId) |> deliverOnMainQueue).start(next: { peer in - parentController?.present(textAlertController(context: context, updatedPresentationData: updatedPresentationData, title: nil, text: presentationData.strings.Privacy_GroupsAndChannels_InviteToGroupError(peer.compactDisplayTitle, peer.compactDisplayTitle).string, actions: [TextAlertAction(type: .genericAction, title: presentationData.strings.Common_OK, action: {})]), in: .window(.root)) + parentController?.present(textAlertController(context: context, updatedPresentationData: updatedPresentationData, title: nil, text: presentationData.strings.Privacy_GroupsAndChannels_InviteToGroupError(EnginePeer(peer).compactDisplayTitle, EnginePeer(peer).compactDisplayTitle).string, actions: [TextAlertAction(type: .genericAction, title: presentationData.strings.Common_OK, action: {})]), in: .window(.root)) }) return .complete() case .notMutualContact: @@ -7436,7 +7436,7 @@ func presentAddMembers(context: AccountContext, updatedPresentationData: (initia case let .peer(peerId): let _ = (context.account.postbox.loadedPeerWithId(peerId) |> deliverOnMainQueue).start(next: { peer in - parentController?.present(textAlertController(context: context, updatedPresentationData: updatedPresentationData, title: nil, text: presentationData.strings.Privacy_GroupsAndChannels_InviteToGroupError(peer.compactDisplayTitle, peer.compactDisplayTitle).string, actions: [TextAlertAction(type: .genericAction, title: presentationData.strings.Common_OK, action: {})]), in: .window(.root)) + parentController?.present(textAlertController(context: context, updatedPresentationData: updatedPresentationData, title: nil, text: presentationData.strings.Privacy_GroupsAndChannels_InviteToGroupError(EnginePeer(peer).compactDisplayTitle, EnginePeer(peer).compactDisplayTitle).string, actions: [TextAlertAction(type: .genericAction, title: presentationData.strings.Common_OK, action: {})]), in: .window(.root)) }) default: break diff --git a/submodules/TelegramUI/Sources/PollResultsController.swift b/submodules/TelegramUI/Sources/PollResultsController.swift index b5f56ded9a..bd48610c82 100644 --- a/submodules/TelegramUI/Sources/PollResultsController.swift +++ b/submodules/TelegramUI/Sources/PollResultsController.swift @@ -187,7 +187,7 @@ private enum PollResultsEntry: ItemListNodeEntry { let header = ItemListPeerItemHeader(theme: presentationData.theme, strings: presentationData.strings, text: optionText, additionalText: optionAdditionalText, actionTitle: optionExpanded ? presentationData.strings.PollResults_Collapse : presentationData.strings.MessagePoll_VotedCount(optionCount), id: Int64(optionId), action: optionExpanded ? { arguments.collapseOption(opaqueIdentifier) } : nil) - return ItemListPeerItem(presentationData: presentationData, dateTimeFormat: PresentationDateTimeFormat(), nameDisplayOrder: .firstLast, context: arguments.context, peer: peer.peers[peer.peerId]!, presence: nil, text: .none, label: .none, editing: ItemListPeerItemEditing(editable: false, editing: false, revealed: false), switchValue: nil, enabled: true, selectable: shimmeringAlternation == nil, sectionId: self.section, action: { + return ItemListPeerItem(presentationData: presentationData, dateTimeFormat: PresentationDateTimeFormat(), nameDisplayOrder: .firstLast, context: arguments.context, peer: EnginePeer(peer.peers[peer.peerId]!), presence: nil, text: .none, label: .none, editing: ItemListPeerItemEditing(editable: false, editing: false, revealed: false), switchValue: nil, enabled: true, selectable: shimmeringAlternation == nil, sectionId: self.section, action: { arguments.openPeer(peer) }, setPeerIdWithRevealedOptions: { _, _ in }, removePeer: { _ in diff --git a/submodules/TelegramUI/Sources/ReplyAccessoryPanelNode.swift b/submodules/TelegramUI/Sources/ReplyAccessoryPanelNode.swift index bf0d35951b..02db078c90 100644 --- a/submodules/TelegramUI/Sources/ReplyAccessoryPanelNode.swift +++ b/submodules/TelegramUI/Sources/ReplyAccessoryPanelNode.swift @@ -98,12 +98,12 @@ final class ReplyAccessoryPanelNode: AccessoryPanelNode { var text = "" if let forwardInfo = message?.forwardInfo, forwardInfo.flags.contains(.isImported) { if let author = forwardInfo.author { - authorName = author.displayTitle(strings: strings, displayOrder: nameDisplayOrder) + authorName = EnginePeer(author).displayTitle(strings: strings, displayOrder: nameDisplayOrder) } else if let authorSignature = forwardInfo.authorSignature { authorName = authorSignature } } else if let author = message?.effectiveAuthor { - authorName = author.displayTitle(strings: strings, displayOrder: nameDisplayOrder) + authorName = EnginePeer(author).displayTitle(strings: strings, displayOrder: nameDisplayOrder) } if let message = message { (text, _) = descriptionStringForMessage(contentSettings: context.currentContentSettings.with { $0 }, message: message, strings: strings, nameDisplayOrder: nameDisplayOrder, dateTimeFormat: dateTimeFormat, accountPeerId: context.account.peerId) @@ -187,7 +187,7 @@ final class ReplyAccessoryPanelNode: AccessoryPanelNode { let headerString: String if let message = message, message.flags.contains(.Incoming), let author = message.author { - headerString = "Reply to message. From: \(author.displayTitle(strings: strings, displayOrder: nameDisplayOrder))" + headerString = "Reply to message. From: \(EnginePeer(author).displayTitle(strings: strings, displayOrder: nameDisplayOrder))" } else if let message = message, !message.flags.contains(.Incoming) { headerString = "Reply to your message" } else { diff --git a/submodules/TelegramUI/Sources/SecretChatHandshakeStatusInputPanelNode.swift b/submodules/TelegramUI/Sources/SecretChatHandshakeStatusInputPanelNode.swift index f44fffea32..7f17fdb540 100644 --- a/submodules/TelegramUI/Sources/SecretChatHandshakeStatusInputPanelNode.swift +++ b/submodules/TelegramUI/Sources/SecretChatHandshakeStatusInputPanelNode.swift @@ -53,7 +53,7 @@ final class SecretChatHandshakeStatusInputPanelNode: ChatInputPanelNode { let text: String switch peer.role { case .creator: - text = interfaceState.strings.DialogList_AwaitingEncryption(userPeer.compactDisplayTitle).string + text = interfaceState.strings.DialogList_AwaitingEncryption(EnginePeer(userPeer).compactDisplayTitle).string case .participant: text = interfaceState.strings.Conversation_EncryptionProcessing } diff --git a/submodules/TelegramUI/Sources/ShareExtensionContext.swift b/submodules/TelegramUI/Sources/ShareExtensionContext.swift index cc908889e4..9b06a1f1df 100644 --- a/submodules/TelegramUI/Sources/ShareExtensionContext.swift +++ b/submodules/TelegramUI/Sources/ShareExtensionContext.swift @@ -854,9 +854,9 @@ public class ShareRootControllerImpl { switch result { case .allowed: if let title = title { - text = presentationData.strings.ChatImport_SelectionConfirmationUserWithTitle(title, peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)).string + text = presentationData.strings.ChatImport_SelectionConfirmationUserWithTitle(title, EnginePeer(peer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)).string } else { - text = presentationData.strings.ChatImport_SelectionConfirmationUserWithoutTitle(peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)).string + text = presentationData.strings.ChatImport_SelectionConfirmationUserWithoutTitle(EnginePeer(peer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)).string } case let .alert(textValue): text = textValue @@ -956,9 +956,9 @@ public class ShareRootControllerImpl { switch result { case .allowed: if let title = peerTitle { - text = presentationData.strings.ChatImport_SelectionConfirmationUserWithTitle(title, peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)).string + text = presentationData.strings.ChatImport_SelectionConfirmationUserWithTitle(title, EnginePeer(peer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)).string } else { - text = presentationData.strings.ChatImport_SelectionConfirmationUserWithoutTitle(peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)).string + text = presentationData.strings.ChatImport_SelectionConfirmationUserWithoutTitle(EnginePeer(peer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)).string } case let .alert(textValue): text = textValue diff --git a/submodules/TelegramUI/Sources/SharedNotificationManager.swift b/submodules/TelegramUI/Sources/SharedNotificationManager.swift index 51118a6d08..54e872d58c 100644 --- a/submodules/TelegramUI/Sources/SharedNotificationManager.swift +++ b/submodules/TelegramUI/Sources/SharedNotificationManager.swift @@ -429,7 +429,7 @@ public final class SharedNotificationManager { self.currentNotificationCall = call if let notificationCall = call { - let rawText = strings.PUSH_PHONE_CALL_REQUEST(notificationCall.peer?.displayTitle(strings: strings, displayOrder: nameOrder) ?? "").string + let rawText = strings.PUSH_PHONE_CALL_REQUEST(notificationCall.peer.flatMap(EnginePeer.init)?.displayTitle(strings: strings, displayOrder: nameOrder) ?? "").string let title: String? let body: String if let index = rawText.firstIndex(of: "|") { diff --git a/submodules/TelegramUI/Sources/StringForMessageTimestampStatus.swift b/submodules/TelegramUI/Sources/StringForMessageTimestampStatus.swift index f869b52d15..c3ba9fb771 100644 --- a/submodules/TelegramUI/Sources/StringForMessageTimestampStatus.swift +++ b/submodules/TelegramUI/Sources/StringForMessageTimestampStatus.swift @@ -51,7 +51,7 @@ func stringForMessageTimestampStatus(accountPeerId: PeerId, message: Message, da var authorTitle: String? if let author = message.author as? TelegramUser { if let peer = message.peers[message.id.peerId] as? TelegramChannel, case .broadcast = peer.info { - authorTitle = author.displayTitle(strings: strings, displayOrder: nameDisplayOrder) + authorTitle = EnginePeer(author).displayTitle(strings: strings, displayOrder: nameDisplayOrder) } else if let forwardInfo = message.forwardInfo, forwardInfo.sourceMessageId?.peerId.namespace == Namespaces.Peer.CloudChannel { authorTitle = forwardInfo.authorSignature } diff --git a/submodules/WebSearchUI/Sources/LegacyWebSearchGallery.swift b/submodules/WebSearchUI/Sources/LegacyWebSearchGallery.swift index 6c9362e217..15f33aea6d 100644 --- a/submodules/WebSearchUI/Sources/LegacyWebSearchGallery.swift +++ b/submodules/WebSearchUI/Sources/LegacyWebSearchGallery.swift @@ -335,7 +335,7 @@ func presentLegacyWebSearchGallery(context: AccountContext, peer: Peer?, chatLoc let (items, focusItem) = galleryItems(account: context.account, results: results, current: current, selectionContext: selectionContext, editingContext: editingContext) - let model = TGMediaPickerGalleryModel(context: legacyController.context, items: items, focus: focusItem, selectionContext: selectionContext, editingContext: editingContext, hasCaptions: false, allowCaptionEntities: true, hasTimer: false, onlyCrop: false, inhibitDocumentCaptions: false, hasSelectionPanel: false, hasCamera: false, recipientName: peer?.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder))! + let model = TGMediaPickerGalleryModel(context: legacyController.context, items: items, focus: focusItem, selectionContext: selectionContext, editingContext: editingContext, hasCaptions: false, allowCaptionEntities: true, hasTimer: false, onlyCrop: false, inhibitDocumentCaptions: false, hasSelectionPanel: false, hasCamera: false, recipientName: peer.flatMap(EnginePeer.init)?.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder))! model.stickersContext = paintStickersContext if let peer = peer, let chatLocation = chatLocation { model.suggestionContext = legacySuggestionContext(context: context, peerId: peer.id, chatLocation: chatLocation) diff --git a/submodules/WebSearchUI/Sources/WebSearchGalleryController.swift b/submodules/WebSearchUI/Sources/WebSearchGalleryController.swift index e64647fcc0..2b6a4024e5 100644 --- a/submodules/WebSearchUI/Sources/WebSearchGalleryController.swift +++ b/submodules/WebSearchUI/Sources/WebSearchGalleryController.swift @@ -115,7 +115,7 @@ class WebSearchGalleryController: ViewController { self?.dismiss(forceAway: true) }, selectionState: selectionState, editingState: editingState) - if let title = peer?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) { + if let title = peer.flatMap(EnginePeer.init)?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) { let recipientNode = GalleryNavigationRecipientNode(color: .white, title: title) let leftItem = UIBarButtonItem(customDisplayNode: recipientNode) self.navigationItem.leftBarButtonItem = leftItem diff --git a/submodules/WidgetSetupScreen/BUILD b/submodules/WidgetSetupScreen/BUILD deleted file mode 100644 index 2eac6be9de..0000000000 --- a/submodules/WidgetSetupScreen/BUILD +++ /dev/null @@ -1,27 +0,0 @@ -load("@build_bazel_rules_swift//swift:swift.bzl", "swift_library") - -swift_library( - name = "WidgetSetupScreen", - module_name = "WidgetSetupScreen", - srcs = glob([ - "Sources/**/*.swift", - ]), - copts = [ - "-warnings-as-errors", - ], - deps = [ - "//submodules/Display:Display", - "//submodules/AsyncDisplayKit:AsyncDisplayKit", - "//submodules/Postbox:Postbox", - "//submodules/TelegramCore:TelegramCore", - "//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit", - "//submodules/ItemListUI:ItemListUI", - "//submodules/ItemListPeerItem:ItemListPeerItem", - "//submodules/ItemListPeerActionItem:ItemListPeerActionItem", - "//submodules/PresentationDataUtils:PresentationDataUtils", - "//submodules/AccountContext:AccountContext", - ], - visibility = [ - "//visibility:public", - ], -) diff --git a/submodules/WidgetSetupScreen/Sources/WidgetSetupScreen.swift b/submodules/WidgetSetupScreen/Sources/WidgetSetupScreen.swift deleted file mode 100644 index ebe97ba61b..0000000000 --- a/submodules/WidgetSetupScreen/Sources/WidgetSetupScreen.swift +++ /dev/null @@ -1,451 +0,0 @@ -import Foundation -import UIKit -import Display -import SwiftSignalKit -import Postbox -import TelegramCore -import TelegramPresentationData -import TelegramUIPreferences -import ItemListUI -import PresentationDataUtils -import AccountContext -import ItemListPeerItem -import ItemListPeerActionItem - -private final class Arguments { - let context: AccountContext - - let updateUseHints: (Bool) -> Void - let setPeerIdWithRevealedOptions: (PeerId?, PeerId?) -> Void - let removePeer: (PeerId) -> Void - let addPeer: () -> Void - let openPeer: (PeerId) -> Void - - init(context: AccountContext, updateUseHints: @escaping (Bool) -> Void, setPeerIdWithRevealedOptions: @escaping (PeerId?, PeerId?) -> Void, removePeer: @escaping (PeerId) -> Void, addPeer: @escaping () -> Void, openPeer: @escaping (PeerId) -> Void) { - self.context = context - self.updateUseHints = updateUseHints - self.setPeerIdWithRevealedOptions = setPeerIdWithRevealedOptions - self.removePeer = removePeer - self.addPeer = addPeer - self.openPeer = openPeer - } -} - -private enum WidgetSetupScreenEntry: ItemListNodeEntry { - enum Section: Int32 { - case mode - case peers - } - - enum StableId: Hashable { - case useHints - case peersHeaderItem - case add - case peer(PeerId) - } - - case useHints(String, Bool) - case peersHeaderItem(String) - case peerItem(Int32, PresentationDateTimeFormat, PresentationPersonNameOrder, SelectivePrivacyPeer, ItemListPeerItemEditing, Bool) - case addItem(String, Bool) - - var section: ItemListSectionId { - switch self { - case .useHints: - return Section.mode.rawValue - case .peersHeaderItem, .peerItem: - return Section.peers.rawValue - case .addItem: - return Section.peers.rawValue - } - } - - var stableId: StableId { - switch self { - case .useHints: - return .useHints - case .peersHeaderItem: - return .peersHeaderItem - case let .peerItem(_, _, _, peer, _, _): - return .peer(peer.peer.id) - case .addItem: - return .add - } - } - - var sortIndex: Int32 { - switch self { - case .useHints: - return 0 - case .peersHeaderItem: - return 1 - case .addItem: - return 2 - case let .peerItem(index, _, _, _, _, _): - return 10 + index - } - } - - static func ==(lhs: WidgetSetupScreenEntry, rhs: WidgetSetupScreenEntry) -> Bool { - switch lhs { - case let .useHints(text, value): - if case .useHints(text, value) = rhs { - return true - } else { - return false - } - case let .peersHeaderItem(text): - if case .peersHeaderItem(text) = rhs { - return true - } else { - return false - } - case let .peerItem(lhsIndex, lhsDateTimeFormat, lhsNameOrder, lhsPeer, lhsEditing, lhsEnabled): - if case let .peerItem(rhsIndex, rhsDateTimeFormat, rhsNameOrder, rhsPeer, rhsEditing, rhsEnabled) = rhs { - if lhsIndex != rhsIndex { - return false - } - if lhsDateTimeFormat != rhsDateTimeFormat { - return false - } - if lhsNameOrder != rhsNameOrder { - return false - } - if lhsPeer != rhsPeer { - return false - } - if lhsEditing != rhsEditing { - return false - } - if lhsEnabled != rhsEnabled { - return false - } - return true - } else { - return false - } - case let .addItem(lhsText, lhsEditing): - if case let .addItem(rhsText, rhsEditing) = rhs, lhsText == rhsText, lhsEditing == rhsEditing { - return true - } else { - return false - } - } - } - - static func <(lhs: WidgetSetupScreenEntry, rhs: WidgetSetupScreenEntry) -> Bool { - return lhs.sortIndex < rhs.sortIndex - } - - func item(presentationData: ItemListPresentationData, arguments: Any) -> ListViewItem { - let arguments = arguments as! Arguments - switch self { - case let .useHints(text, value): - return ItemListSwitchItem(presentationData: presentationData, title: text, value: value, sectionId: self.section, style: .blocks, updated: { value in - arguments.updateUseHints(value) - }) - case let .peersHeaderItem(text): - return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section) - case let .peerItem(_, dateTimeFormat, nameOrder, peer, editing, enabled): - var text: ItemListPeerItemText = .none - if let group = peer.peer as? TelegramGroup { - text = .text(presentationData.strings.Conversation_StatusMembers(Int32(group.participantCount)), .secondary) - } else if let channel = peer.peer as? TelegramChannel { - if let participantCount = peer.participantCount { - text = .text(presentationData.strings.Conversation_StatusMembers(Int32(participantCount)), .secondary) - } else { - switch channel.info { - case .group: - text = .text(presentationData.strings.Group_Status, .secondary) - case .broadcast: - text = .text(presentationData.strings.Channel_Status, .secondary) - } - } - } - return ItemListPeerItem(presentationData: presentationData, dateTimeFormat: dateTimeFormat, nameDisplayOrder: nameOrder, context: arguments.context, peer: peer.peer, presence: nil, text: text, label: .none, editing: editing, switchValue: nil, enabled: enabled, selectable: true, sectionId: self.section, action: { - arguments.openPeer(peer.peer.id) - }, setPeerIdWithRevealedOptions: { previousId, id in - arguments.setPeerIdWithRevealedOptions(previousId, id) - }, removePeer: { peerId in - arguments.removePeer(peerId) - }) - case let .addItem(text, editing): - return ItemListPeerActionItem(presentationData: presentationData, icon: PresentationResourcesItemList.plusIconImage(presentationData.theme), title: text, sectionId: self.section, editing: editing, action: { - arguments.addPeer() - }) - } - } -} - -private struct WidgetSetupScreenControllerState: Equatable { - var editing: Bool = false - var peerIdWithRevealedOptions: PeerId? = nil -} - -private func selectivePrivacyPeersControllerEntries(presentationData: PresentationData, state: WidgetSetupScreenControllerState, useHints: Bool, peers: [SelectivePrivacyPeer]) -> [WidgetSetupScreenEntry] { - var entries: [WidgetSetupScreenEntry] = [] - - entries.append(.useHints("Show Recent Chats", useHints)) - - if !useHints { - entries.append(.peersHeaderItem(presentationData.strings.Privacy_ChatsTitle)) - entries.append(.addItem(presentationData.strings.Privacy_AddNewPeer, state.editing)) - var index: Int32 = 0 - for peer in peers { - entries.append(.peerItem(index, presentationData.dateTimeFormat, presentationData.nameDisplayOrder, peer, ItemListPeerItemEditing(editable: true, editing: state.editing, canBeReordered: state.editing, revealed: peer.peer.id == state.peerIdWithRevealedOptions), true)) - index += 1 - } - } - - return entries -} - -public func widgetSetupScreen(context: AccountContext) -> ViewController { - let statePromise = ValuePromise(WidgetSetupScreenControllerState(), ignoreRepeated: true) - let stateValue = Atomic(value: WidgetSetupScreenControllerState()) - let updateState: ((WidgetSetupScreenControllerState) -> WidgetSetupScreenControllerState) -> Void = { f in - statePromise.set(stateValue.modify { f($0) }) - } - - var presentControllerImpl: ((ViewController, ViewControllerPresentationArguments?) -> Void)? - var pushControllerImpl: ((ViewController) -> Void)? - - let actionsDisposable = DisposableSet() - let addPeerDisposable = MetaDisposable() - actionsDisposable.add(addPeerDisposable) - - let arguments = Arguments(context: context, updateUseHints: { value in - let _ = (updateWidgetSettingsInteractively(postbox: context.account.postbox, { settings in - var settings = settings - settings.useHints = value - return settings - }) - |> deliverOnMainQueue).start() - }, setPeerIdWithRevealedOptions: { peerId, fromPeerId in - updateState { state in - var state = state - if (peerId == nil && fromPeerId == state.peerIdWithRevealedOptions) || (peerId != nil && fromPeerId == nil) { - state.peerIdWithRevealedOptions = peerId - } - return state - } - }, removePeer: { memberId in - let _ = (updateWidgetSettingsInteractively(postbox: context.account.postbox, { settings in - var settings = settings - settings.peers.removeAll(where: { $0 == memberId }) - return settings - }) - |> deliverOnMainQueue).start() - }, addPeer: { - let controller = context.sharedContext.makeContactMultiselectionController(ContactMultiselectionControllerParams(context: context, mode: .peerSelection(searchChatList: true, searchGroups: true, searchChannels: false), options: [])) - addPeerDisposable.set((controller.result - |> take(1) - |> deliverOnMainQueue).start(next: { [weak controller] result in - var peerIds: [ContactListPeerId] = [] - if case let .result(peerIdsValue, _) = result { - peerIds = peerIdsValue - } - - let _ = (updateWidgetSettingsInteractively(postbox: context.account.postbox, { settings in - var settings = settings - for peerId in peerIds { - switch peerId { - case let .peer(peerId): - settings.peers.removeAll(where: { $0 == peerId }) - settings.peers.insert(peerId, at: 0) - case .deviceContact: - break - } - } - return settings - }) - |> deliverOnMainQueue).start(completed: { - controller?.dismiss() - }) - })) - presentControllerImpl?(controller, ViewControllerPresentationArguments(presentationAnimation: .modalSheet)) - }, openPeer: { peerId in - let _ = (context.account.postbox.transaction { transaction -> Peer? in - return transaction.getPeer(peerId) - } - |> deliverOnMainQueue).start(next: { peer in - guard let peer = peer, let controller = context.sharedContext.makePeerInfoController(context: context, updatedPresentationData: nil, peer: peer, mode: .generic, avatarInitiallyExpanded: false, fromChat: false) else { - return - } - pushControllerImpl?(controller) - }) - }) - - var previousPeers: [SelectivePrivacyPeer]? - var previousState: WidgetSetupScreenControllerState? - - struct InputData { - var settings: WidgetSettings - var peers: [SelectivePrivacyPeer] - } - - let preferencesKey: PostboxViewKey = .preferences(keys: Set([ - ApplicationSpecificPreferencesKeys.widgetSettings - ])) - - let inputData: Signal = context.account.postbox.combinedView(keys: [ - preferencesKey - ]) - |> mapToSignal { views -> Signal in - let widgetSettings: WidgetSettings - if let view = views.views[preferencesKey] as? PreferencesView, let value = view.values[ApplicationSpecificPreferencesKeys.widgetSettings]?.get(WidgetSettings.self) { - widgetSettings = value - } else { - widgetSettings = .default - } - - return context.account.postbox.transaction { transaction -> InputData in - return InputData( - settings: widgetSettings, - peers: widgetSettings.peers.compactMap { peerId -> SelectivePrivacyPeer? in - guard let peer = transaction.getPeer(peerId) else { - return nil - } - return SelectivePrivacyPeer(peer: peer, participantCount: nil) - } - ) - } - } - - let signal = combineLatest(context.sharedContext.presentationData, statePromise.get(), inputData) - |> deliverOnMainQueue - |> map { presentationData, state, inputData -> (ItemListControllerState, (ItemListNodeState, Any)) in - var rightNavigationButton: ItemListNavigationButton? - if !inputData.peers.isEmpty { - if state.editing { - rightNavigationButton = ItemListNavigationButton(content: .text(presentationData.strings.Common_Done), style: .bold, enabled: true, action: { - updateState { state in - var state = state - state.editing = false - return state - } - }) - } else { - rightNavigationButton = ItemListNavigationButton(content: .text(presentationData.strings.Common_Edit), style: .regular, enabled: true, action: { - updateState { state in - var state = state - state.editing = true - return state - } - }) - } - } - - let previous = previousPeers - previousPeers = inputData.peers - - let controllerState = ItemListControllerState(presentationData: ItemListPresentationData(presentationData), title: .text("Widget"), leftNavigationButton: nil, rightNavigationButton: rightNavigationButton, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back), animateChanges: true) - - var animated = true - if let previous = previous { - if previous.count <= inputData.peers.count { - if Set(previous.map { $0.peer.id }) == Set(inputData.peers.map { $0.peer.id }) && previous.map({ $0.peer.id }) != inputData.peers.map({ $0.peer.id }) { - } else { - animated = false - } - } - } else { - animated = false - } - if let previousState = previousState { - if previousState.editing != state.editing { - animated = true - } - } else { - animated = false - } - - previousState = state - - let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: selectivePrivacyPeersControllerEntries(presentationData: presentationData, state: state, useHints: inputData.settings.useHints, peers: inputData.peers), style: .blocks, emptyStateItem: nil, animateChanges: animated) - - return (controllerState, (listState, arguments)) - } - |> afterDisposed { - actionsDisposable.dispose() - } - - let controller = ItemListController(context: context, state: signal) - presentControllerImpl = { [weak controller] c, p in - if let controller = controller { - controller.present(c, in: .window(.root), with: p) - } - } - pushControllerImpl = { [weak controller] c in - if let navigationController = controller?.navigationController as? NavigationController { - navigationController.pushViewController(c) - } - } - - controller.setReorderEntry({ (fromIndex: Int, toIndex: Int, entries: [WidgetSetupScreenEntry]) -> Signal in - let fromEntry = entries[fromIndex] - guard case let .peerItem(_, _, _, fromPeer, _, _) = fromEntry else { - return .single(false) - } - var referencePeerId: PeerId? - var beforeAll = false - var afterAll = false - if toIndex < entries.count { - switch entries[toIndex] { - case let .peerItem(_, _, _, peer, _, _): - referencePeerId = peer.peer.id - default: - if entries[toIndex] < fromEntry { - beforeAll = true - } else { - afterAll = true - } - } - } else { - afterAll = true - } - - return context.account.postbox.transaction { transaction -> Bool in - var updatedOrder = false - - updateWidgetSettingsInteractively(transaction: transaction, { settings in - let initialPeers = settings.peers - var settings = settings - - if let index = settings.peers.firstIndex(of: fromPeer.peer.id) { - settings.peers.remove(at: index) - } - if let referencePeerId = referencePeerId { - var inserted = false - for i in 0 ..< settings.peers.count { - if settings.peers[i] == referencePeerId { - if fromIndex < toIndex { - settings.peers.insert(fromPeer.peer.id, at: i + 1) - } else { - settings.peers.insert(fromPeer.peer.id, at: i) - } - inserted = true - break - } - } - if !inserted { - settings.peers.append(fromPeer.peer.id) - } - } else if beforeAll { - settings.peers.insert(fromPeer.peer.id, at: 0) - } else if afterAll { - settings.peers.append(fromPeer.peer.id) - } - - if initialPeers != settings.peers { - updatedOrder = true - } - return settings - }) - - return updatedOrder - } - }) - - return controller -} From b778c66226773295ad16b7b539c1267967f3ccd9 Mon Sep 17 00:00:00 2001 From: Ali <> Date: Mon, 20 Sep 2021 23:07:38 +0300 Subject: [PATCH 13/30] Refactoring --- .../Sources/CallListController.swift | 2 +- .../Sources/ChatListController.swift | 10 +- .../Sources/ChatListSearchContainerNode.swift | 4 +- .../Sources/Node/ChatListItemStrings.swift | 8 +- .../Sources/ContactsControllerNode.swift | 2 +- submodules/ContextUI/BUILD | 1 - .../ContextUI/Sources/ContextController.swift | 201 +------ .../ContextUI/Sources/PinchController.swift | 1 - .../GalleryData/Sources/GalleryData.swift | 6 +- .../ChatItemGalleryFooterContentNode.swift | 4 +- .../Items/UniversalVideoGalleryItem.swift | 2 +- .../SecretMediaPreviewController.swift | 2 +- .../Sources/InviteLinkInviteController.swift | 2 +- .../Sources/InviteLinkListController.swift | 4 +- .../Sources/InviteLinkViewController.swift | 2 +- .../Sources/ChannelVisibilityController.swift | 2 +- submodules/PeersNearbyUI/BUILD | 1 - .../Sources/PeersNearbyController.swift | 66 +-- submodules/ReactionSelectionNode/BUILD | 24 - .../Sources/ReactionAttachedNode.swift | 323 ----------- .../Sources/ReactionContextNode.swift | 523 ------------------ .../Sources/ReactionGestureItem.swift | 8 - .../Sources/ReactionSelectionNode.swift | 487 ---------------- .../Sources/ReactionSelectionParentNode.swift | 85 --- .../ReactionSwipeGestureRecognizer.swift | 193 ------- submodules/SelectablePeerNode/BUILD | 1 - .../Themes/ThemeSettingsController.swift | 4 +- submodules/SlotMachineAnimationNode/BUILD | 1 - .../Sources/SlotMachineAnimationNode.swift | 1 - .../Sources/ChannelStatsController.swift | 2 +- .../Sources/StatsMessageItem.swift | 2 +- .../MediaNavigationAccessoryHeaderNode.swift | 2 +- .../Sources/VoiceChatController.swift | 4 +- .../Sources/Account/Account.swift | 1 - .../Account/AccountIntermediateState.swift | 4 - .../ApiUtils/ReactionsMessageAttribute.swift | 101 ---- .../ApiUtils/StoreMessage_Telegram.swift | 4 - .../PendingMessages/EnqueueMessage.swift | 2 +- .../State/AccountStateManagementUtils.swift | 22 - .../Sources/State/AccountViewTracker.swift | 83 --- .../Sources/State/MessageReactions.swift | 227 -------- .../SyncCore_ReactionsMessageAttribute.swift | 31 +- .../TelegramEngine/Messages/Media.swift | 80 +++ .../Sources/Utils/PeerUtils.swift | 6 +- submodules/TelegramPermissions/BUILD | 1 - .../Sources/Permission.swift | 1 - submodules/TelegramStringFormatting/BUILD | 1 - .../Sources/MessageContentKind.swift | 29 +- .../Sources/ServiceMessageStrings.swift | 47 +- submodules/TelegramUI/BUILD | 1 - .../TelegramUI/Sources/ChatController.swift | 120 +--- .../Sources/ChatControllerInteraction.swift | 16 - .../Sources/ChatControllerNode.swift | 11 - .../Sources/ChatHistoryListNode.swift | 14 - .../Sources/ChatMediaInputNode.swift | 2 +- .../Sources/ChatMessageActionItemNode.swift | 2 +- .../ChatMessageAnimatedStickerItemNode.swift | 30 +- .../ChatMessageAttachedContentNode.swift | 25 +- .../ChatMessageBubbleContentNode.swift | 4 - .../Sources/ChatMessageBubbleItemNode.swift | 302 +--------- .../ChatMessageCallBubbleContentNode.swift | 6 +- .../ChatMessageContactBubbleContentNode.swift | 24 +- .../ChatMessageDateAndStatusNode.swift | 276 +-------- .../ChatMessageFileBubbleContentNode.swift | 4 - .../ChatMessageGameBubbleContentNode.swift | 4 - .../ChatMessageInstantVideoItemNode.swift | 4 - .../ChatMessageInteractiveFileNode.swift | 24 +- ...atMessageInteractiveInstantVideoNode.swift | 17 +- .../ChatMessageInteractiveMediaNode.swift | 3 +- .../ChatMessageInvoiceBubbleContentNode.swift | 4 - .../ChatMessageMapBubbleContentNode.swift | 24 +- .../ChatMessageMediaBubbleContentNode.swift | 23 +- .../Sources/ChatMessageNotificationItem.swift | 28 +- .../ChatMessagePollBubbleContentNode.swift | 24 +- .../Sources/ChatMessageReplyInfoNode.swift | 2 +- ...atMessageRestrictedBubbleContentNode.swift | 24 +- .../Sources/ChatMessageStickerItemNode.swift | 30 +- .../Sources/ChatMessageSwipeToReplyNode.swift | 4 - .../ChatMessageTextBubbleContentNode.swift | 31 +- .../ChatMessageWebpageBubbleContentNode.swift | 4 - .../ChatPinnedMessageTitlePanelNode.swift | 2 +- .../ChatRecentActionsControllerNode.swift | 4 - .../ChatSearchResultsContollerNode.swift | 2 +- .../Sources/DrawingStickersScreen.swift | 4 - .../Sources/EditAccessoryPanelNode.swift | 4 +- .../OverlayAudioPlayerControllerNode.swift | 4 - .../Sources/PeerInfo/PeerInfoScreen.swift | 24 +- .../Sources/ReplyAccessoryPanelNode.swift | 4 +- .../Sources/SharedAccountContext.swift | 4 - .../StringForMessageTimestampStatus.swift | 2 +- .../WebpagePreviewAccessoryPanelNode.swift | 2 +- 91 files changed, 290 insertions(+), 3473 deletions(-) delete mode 100644 submodules/ReactionSelectionNode/BUILD delete mode 100644 submodules/ReactionSelectionNode/Sources/ReactionAttachedNode.swift delete mode 100644 submodules/ReactionSelectionNode/Sources/ReactionContextNode.swift delete mode 100644 submodules/ReactionSelectionNode/Sources/ReactionGestureItem.swift delete mode 100644 submodules/ReactionSelectionNode/Sources/ReactionSelectionNode.swift delete mode 100644 submodules/ReactionSelectionNode/Sources/ReactionSelectionParentNode.swift delete mode 100644 submodules/ReactionSelectionNode/Sources/ReactionSwipeGestureRecognizer.swift delete mode 100644 submodules/TelegramCore/Sources/ApiUtils/ReactionsMessageAttribute.swift delete mode 100644 submodules/TelegramCore/Sources/State/MessageReactions.swift diff --git a/submodules/CallListUI/Sources/CallListController.swift b/submodules/CallListUI/Sources/CallListController.swift index 2c18b5e7ea..a9ce802c2e 100644 --- a/submodules/CallListUI/Sources/CallListController.swift +++ b/submodules/CallListUI/Sources/CallListController.swift @@ -358,7 +358,7 @@ public final class CallListController: TelegramBaseController { } } - let contextController = ContextController(account: self.context.account, presentationData: self.presentationData, source: .extracted(ExtractedContentSourceImpl(controller: self, sourceNode: buttonNode.contentNode, keepInPlace: false, blurBackground: false)), items: .single(ContextController.Items(items: items)), reactionItems: [], gesture: nil) + let contextController = ContextController(account: self.context.account, presentationData: self.presentationData, source: .extracted(ExtractedContentSourceImpl(controller: self, sourceNode: buttonNode.contentNode, keepInPlace: false, blurBackground: false)), items: .single(ContextController.Items(items: items)), gesture: nil) self.presentInGlobalOverlay(contextController) } diff --git a/submodules/ChatListUI/Sources/ChatListController.swift b/submodules/ChatListUI/Sources/ChatListController.swift index fdb3d251ab..3a09af35c9 100644 --- a/submodules/ChatListUI/Sources/ChatListController.swift +++ b/submodules/ChatListUI/Sources/ChatListController.swift @@ -839,12 +839,12 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController case let .groupReference(groupId, _, _, _, _): let chatListController = ChatListControllerImpl(context: strongSelf.context, groupId: groupId, controlsHistoryPreload: false, hideNetworkActivityStatus: true, previewing: true, enableDebugActions: false) chatListController.navigationPresentation = .master - let contextController = ContextController(account: strongSelf.context.account, presentationData: strongSelf.presentationData, source: .controller(ContextControllerContentSourceImpl(controller: chatListController, sourceNode: node, navigationController: strongSelf.navigationController as? NavigationController)), items: archiveContextMenuItems(context: strongSelf.context, groupId: groupId, chatListController: strongSelf) |> map { ContextController.Items(items: $0) }, reactionItems: [], gesture: gesture) + let contextController = ContextController(account: strongSelf.context.account, presentationData: strongSelf.presentationData, source: .controller(ContextControllerContentSourceImpl(controller: chatListController, sourceNode: node, navigationController: strongSelf.navigationController as? NavigationController)), items: archiveContextMenuItems(context: strongSelf.context, groupId: groupId, chatListController: strongSelf) |> map { ContextController.Items(items: $0) }, gesture: gesture) strongSelf.presentInGlobalOverlay(contextController) case let .peer(_, peer, _, _, _, _, _, _, promoInfo, _, _, _): let chatController = strongSelf.context.sharedContext.makeChatController(context: strongSelf.context, chatLocation: .peer(peer.peerId), subject: nil, botStart: nil, mode: .standard(previewing: true)) chatController.canReadHistory.set(false) - let contextController = ContextController(account: strongSelf.context.account, presentationData: strongSelf.presentationData, source: .controller(ContextControllerContentSourceImpl(controller: chatController, sourceNode: node, navigationController: strongSelf.navigationController as? NavigationController)), items: chatContextMenuItems(context: strongSelf.context, peerId: peer.peerId, promoInfo: promoInfo, source: .chatList(filter: strongSelf.chatListDisplayNode.containerNode.currentItemNode.chatListFilter), chatListController: strongSelf, joined: joined) |> map { ContextController.Items(items: $0) }, reactionItems: [], gesture: gesture) + let contextController = ContextController(account: strongSelf.context.account, presentationData: strongSelf.presentationData, source: .controller(ContextControllerContentSourceImpl(controller: chatController, sourceNode: node, navigationController: strongSelf.navigationController as? NavigationController)), items: chatContextMenuItems(context: strongSelf.context, peerId: peer.peerId, promoInfo: promoInfo, source: .chatList(filter: strongSelf.chatListDisplayNode.containerNode.currentItemNode.chatListFilter), chatListController: strongSelf, joined: joined) |> map { ContextController.Items(items: $0) }, gesture: gesture) strongSelf.presentInGlobalOverlay(contextController) } } @@ -868,7 +868,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController contextContentSource = .controller(ContextControllerContentSourceImpl(controller: chatController, sourceNode: node, navigationController: strongSelf.navigationController as? NavigationController)) } - let contextController = ContextController(account: strongSelf.context.account, presentationData: strongSelf.presentationData, source: contextContentSource, items: chatContextMenuItems(context: strongSelf.context, peerId: peer.id, promoInfo: nil, source: .search(source), chatListController: strongSelf, joined: false) |> map { ContextController.Items(items: $0) }, reactionItems: [], gesture: gesture) + let contextController = ContextController(account: strongSelf.context.account, presentationData: strongSelf.presentationData, source: contextContentSource, items: chatContextMenuItems(context: strongSelf.context, peerId: peer.id, promoInfo: nil, source: .search(source), chatListController: strongSelf, joined: false) |> map { ContextController.Items(items: $0) }, gesture: gesture) strongSelf.presentInGlobalOverlay(contextController) } @@ -1095,7 +1095,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController }))) } - let controller = ContextController(account: strongSelf.context.account, presentationData: strongSelf.presentationData, source: .extracted(ChatListHeaderBarContextExtractedContentSource(controller: strongSelf, sourceNode: sourceNode, keepInPlace: keepInPlace)), items: .single(ContextController.Items(items: items)), reactionItems: [], recognizer: nil, gesture: gesture) + let controller = ContextController(account: strongSelf.context.account, presentationData: strongSelf.presentationData, source: .extracted(ChatListHeaderBarContextExtractedContentSource(controller: strongSelf, sourceNode: sourceNode, keepInPlace: keepInPlace)), items: .single(ContextController.Items(items: items)), recognizer: nil, gesture: gesture) strongSelf.context.sharedContext.mainWindow?.presentInGlobalOverlay(controller) }) } @@ -2842,7 +2842,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController } } - let controller = ContextController(account: strongSelf.context.account, presentationData: strongSelf.presentationData, source: .extracted(ChatListTabBarContextExtractedContentSource(controller: strongSelf, sourceNode: sourceNode)), items: .single(ContextController.Items(items: items)), reactionItems: [], recognizer: nil, gesture: gesture) + let controller = ContextController(account: strongSelf.context.account, presentationData: strongSelf.presentationData, source: .extracted(ChatListTabBarContextExtractedContentSource(controller: strongSelf, sourceNode: sourceNode)), items: .single(ContextController.Items(items: items)), recognizer: nil, gesture: gesture) strongSelf.context.sharedContext.mainWindow?.presentInGlobalOverlay(controller) }) } diff --git a/submodules/ChatListUI/Sources/ChatListSearchContainerNode.swift b/submodules/ChatListUI/Sources/ChatListSearchContainerNode.swift index 653800451a..49be4fa6eb 100644 --- a/submodules/ChatListUI/Sources/ChatListSearchContainerNode.swift +++ b/submodules/ChatListUI/Sources/ChatListSearchContainerNode.swift @@ -737,7 +737,7 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo return items } - let controller = ContextController(account: self.context.account, presentationData: self.presentationData, source: .extracted(MessageContextExtractedContentSource(sourceNode: node)), items: items |> map { ContextController.Items(items: $0) }, reactionItems: [], recognizer: nil, gesture: gesture) + let controller = ContextController(account: self.context.account, presentationData: self.presentationData, source: .extracted(MessageContextExtractedContentSource(sourceNode: node)), items: items |> map { ContextController.Items(items: $0) }, recognizer: nil, gesture: gesture) self.presentInGlobalOverlay?(controller, nil) } @@ -797,7 +797,7 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo switch previewData { case let .gallery(gallery): gallery.setHintWillBePresentedInPreviewingContext(true) - let contextController = ContextController(account: strongSelf.context.account, presentationData: strongSelf.presentationData, source: .controller(ContextControllerContentSourceImpl(controller: gallery, sourceNode: node)), items: items |> map { ContextController.Items(items: $0) }, reactionItems: [], gesture: gesture) + let contextController = ContextController(account: strongSelf.context.account, presentationData: strongSelf.presentationData, source: .controller(ContextControllerContentSourceImpl(controller: gallery, sourceNode: node)), items: items |> map { ContextController.Items(items: $0) }, gesture: gesture) strongSelf.presentInGlobalOverlay?(contextController, nil) case .instantPage: break diff --git a/submodules/ChatListUI/Sources/Node/ChatListItemStrings.swift b/submodules/ChatListUI/Sources/Node/ChatListItemStrings.swift index c55ebd95b6..dcae9682c3 100644 --- a/submodules/ChatListUI/Sources/Node/ChatListItemStrings.swift +++ b/submodules/ChatListUI/Sources/Node/ChatListItemStrings.swift @@ -53,8 +53,8 @@ public func chatListItemStrings(strings: PresentationStrings, nameDisplayOrder: var hideAuthor = false var messageText: String if let message = message { - if let messageMain = messageMainPeer(message) { - peer = messageMain + if let messageMain = messageMainPeer(EngineMessage(message)) { + peer = messageMain._asPeer() } else { peer = chatPeer.chatMainPeer } @@ -261,12 +261,12 @@ public func chatListItemStrings(strings: PresentationStrings, nameDisplayOrder: } default: hideAuthor = true - if let text = plainServiceMessageString(strings: strings, nameDisplayOrder: nameDisplayOrder, dateTimeFormat: dateTimeFormat, message: message, accountPeerId: accountPeerId, forChatList: true) { + if let text = plainServiceMessageString(strings: strings, nameDisplayOrder: nameDisplayOrder, dateTimeFormat: dateTimeFormat, message: EngineMessage(message), accountPeerId: accountPeerId, forChatList: true) { messageText = text } } case _ as TelegramMediaExpiredContent: - if let text = plainServiceMessageString(strings: strings, nameDisplayOrder: nameDisplayOrder, dateTimeFormat: dateTimeFormat, message: message, accountPeerId: accountPeerId, forChatList: true) { + if let text = plainServiceMessageString(strings: strings, nameDisplayOrder: nameDisplayOrder, dateTimeFormat: dateTimeFormat, message: EngineMessage(message), accountPeerId: accountPeerId, forChatList: true) { messageText = text } case let poll as TelegramMediaPoll: diff --git a/submodules/ContactListUI/Sources/ContactsControllerNode.swift b/submodules/ContactListUI/Sources/ContactsControllerNode.swift index fa8f33eb82..ed873ef808 100644 --- a/submodules/ContactListUI/Sources/ContactsControllerNode.swift +++ b/submodules/ContactListUI/Sources/ContactsControllerNode.swift @@ -175,7 +175,7 @@ final class ContactsControllerNode: ASDisplayNode { } let chatController = self.context.sharedContext.makeChatController(context: self.context, chatLocation: .peer(peer.id), subject: nil, botStart: nil, mode: .standard(previewing: true)) chatController.canReadHistory.set(false) - let contextController = ContextController(account: self.context.account, presentationData: self.presentationData, source: .controller(ContextControllerContentSourceImpl(controller: chatController, sourceNode: node)), items: contactContextMenuItems(context: self.context, peerId: peer.id, contactsController: contactsController) |> map { ContextController.Items(items: $0) }, reactionItems: [], gesture: gesture) + let contextController = ContextController(account: self.context.account, presentationData: self.presentationData, source: .controller(ContextControllerContentSourceImpl(controller: chatController, sourceNode: node)), items: contactContextMenuItems(context: self.context, peerId: peer.id, contactsController: contactsController) |> map { ContextController.Items(items: $0) }, gesture: gesture) contactsController.presentInGlobalOverlay(contextController) } diff --git a/submodules/ContextUI/BUILD b/submodules/ContextUI/BUILD index 8f1126f0c8..df3cad27f7 100644 --- a/submodules/ContextUI/BUILD +++ b/submodules/ContextUI/BUILD @@ -15,7 +15,6 @@ swift_library( "//submodules/Display:Display", "//submodules/TelegramPresentationData:TelegramPresentationData", "//submodules/TextSelectionNode:TextSelectionNode", - "//submodules/ReactionSelectionNode:ReactionSelectionNode", "//submodules/AppBundle:AppBundle", ], visibility = [ diff --git a/submodules/ContextUI/Sources/ContextController.swift b/submodules/ContextUI/Sources/ContextController.swift index b6eebef7c0..dfa5bfbf5c 100644 --- a/submodules/ContextUI/Sources/ContextController.swift +++ b/submodules/ContextUI/Sources/ContextController.swift @@ -4,7 +4,6 @@ import AsyncDisplayKit import Display import TelegramPresentationData import TextSelectionNode -import ReactionSelectionNode import TelegramCore import SwiftSignalKit @@ -119,7 +118,6 @@ private final class ContextControllerNode: ViewControllerTracingNode, UIScrollVi private let source: ContextContentSource private var items: Signal private let beginDismiss: (ContextMenuActionResult) -> Void - private let reactionSelected: (ReactionContextItem.Reaction) -> Void private let beganAnimatingOut: () -> Void private let attemptTransitionControllerIntoNavigation: () -> Void fileprivate var dismissedForCancel: (() -> Void)? @@ -150,14 +148,11 @@ private final class ContextControllerNode: ViewControllerTracingNode, UIScrollVi private var contentAreaInScreenSpace: CGRect? private let contentContainerNode: ContextContentContainerNode private var actionsContainerNode: ContextActionsContainerNode - private var reactionContextNode: ReactionContextNode? - private var reactionContextNodeIsAnimatingOut = false private var didCompleteAnimationIn = false private var initialContinueGesturePoint: CGPoint? private var didMoveFromInitialGesturePoint = false private var highlightedActionNode: ContextActionNodeProtocol? - private var highlightedReaction: ReactionContextItem.Reaction? private let hapticFeedback = HapticFeedback() @@ -168,12 +163,11 @@ private final class ContextControllerNode: ViewControllerTracingNode, UIScrollVi private let blurBackground: Bool - init(account: Account, controller: ContextController, presentationData: PresentationData, source: ContextContentSource, items: Signal, reactionItems: [ReactionContextItem], beginDismiss: @escaping (ContextMenuActionResult) -> Void, recognizer: TapLongTapOrDoubleTapGestureRecognizer?, gesture: ContextGesture?, reactionSelected: @escaping (ReactionContextItem.Reaction) -> Void, beganAnimatingOut: @escaping () -> Void, attemptTransitionControllerIntoNavigation: @escaping () -> Void) { + init(account: Account, controller: ContextController, presentationData: PresentationData, source: ContextContentSource, items: Signal, beginDismiss: @escaping (ContextMenuActionResult) -> Void, recognizer: TapLongTapOrDoubleTapGestureRecognizer?, gesture: ContextGesture?, beganAnimatingOut: @escaping () -> Void, attemptTransitionControllerIntoNavigation: @escaping () -> Void) { self.presentationData = presentationData self.source = source self.items = items self.beginDismiss = beginDismiss - self.reactionSelected = reactionSelected self.beganAnimatingOut = beganAnimatingOut self.attemptTransitionControllerIntoNavigation = attemptTransitionControllerIntoNavigation self.gesture = gesture @@ -237,13 +231,6 @@ private final class ContextControllerNode: ViewControllerTracingNode, UIScrollVi feedbackTap?() }, blurBackground: blurBackground) - if !reactionItems.isEmpty { - let reactionContextNode = ReactionContextNode(account: account, theme: presentationData.theme, items: reactionItems) - self.reactionContextNode = reactionContextNode - } else { - self.reactionContextNode = nil - } - super.init() feedbackTap = { [weak self] in @@ -265,7 +252,6 @@ private final class ContextControllerNode: ViewControllerTracingNode, UIScrollVi self.scrollNode.addSubnode(self.dismissAccessibilityArea) self.scrollNode.addSubnode(self.actionsContainerNode) - self.reactionContextNode.flatMap(self.addSubnode) if let recognizer = recognizer { recognizer.externalUpdated = { [weak self, weak recognizer] view, point in @@ -298,24 +284,6 @@ private final class ContextControllerNode: ViewControllerTracingNode, UIScrollVi strongSelf.hapticFeedback.tap() } } - - if let reactionContextNode = strongSelf.reactionContextNode { - let highlightedReaction = reactionContextNode.reaction(at: strongSelf.view.convert(localPoint, to: reactionContextNode.view)).flatMap { value -> ReactionContextItem.Reaction? in - switch value { - case .like: - return .like - case .unlike: - return .unlike - } - } - if strongSelf.highlightedReaction != highlightedReaction { - strongSelf.highlightedReaction = highlightedReaction - reactionContextNode.setHighlightedReaction(highlightedReaction) - if let _ = highlightedReaction { - strongSelf.hapticFeedback.tap() - } - } - } } } } @@ -330,20 +298,11 @@ private final class ContextControllerNode: ViewControllerTracingNode, UIScrollVi strongSelf.highlightedActionNode = nil highlightedActionNode.performAction() } - if let _ = strongSelf.reactionContextNode { - if let reaction = strongSelf.highlightedReaction { - strongSelf.reactionSelected(reaction) - } - } } else { if let highlightedActionNode = strongSelf.highlightedActionNode { strongSelf.highlightedActionNode = nil highlightedActionNode.setIsHighlighted(false) } - if let reactionContextNode = strongSelf.reactionContextNode, let _ = strongSelf.highlightedReaction { - strongSelf.highlightedReaction = nil - reactionContextNode.setHighlightedReaction(nil) - } } } } @@ -382,24 +341,6 @@ private final class ContextControllerNode: ViewControllerTracingNode, UIScrollVi strongSelf.hapticFeedback.tap() } } - - if let reactionContextNode = strongSelf.reactionContextNode { - let highlightedReaction = reactionContextNode.reaction(at: strongSelf.view.convert(localPoint, to: reactionContextNode.view)).flatMap { value -> ReactionContextItem.Reaction? in - switch value { - case .like: - return .like - case .unlike: - return .unlike - } - } - if strongSelf.highlightedReaction != highlightedReaction { - strongSelf.highlightedReaction = highlightedReaction - reactionContextNode.setHighlightedReaction(highlightedReaction) - if let _ = highlightedReaction { - strongSelf.hapticFeedback.tap() - } - } - } } } } @@ -414,39 +355,16 @@ private final class ContextControllerNode: ViewControllerTracingNode, UIScrollVi strongSelf.highlightedActionNode = nil highlightedActionNode.performAction() } - if let _ = strongSelf.reactionContextNode { - if let reaction = strongSelf.highlightedReaction { - strongSelf.reactionSelected(reaction) - } - } } else { if let highlightedActionNode = strongSelf.highlightedActionNode { strongSelf.highlightedActionNode = nil highlightedActionNode.setIsHighlighted(false) } - if let reactionContextNode = strongSelf.reactionContextNode, let _ = strongSelf.highlightedReaction { - strongSelf.highlightedReaction = nil - reactionContextNode.setHighlightedReaction(nil) - } } } } } - if let reactionContextNode = self.reactionContextNode { - reactionContextNode.reactionSelected = { [weak self] reaction in - guard let _ = self else { - return - } - switch reaction { - case .like: - reactionSelected(.like) - case .unlike: - reactionSelected(.unlike) - } - } - } - self.itemsDisposable.set((items |> deliverOnMainQueue).start(next: { [weak self] items in self?.setItems(items: items, minHeight: nil, previousActionsTransition: .scale) @@ -527,26 +445,6 @@ private final class ContextControllerNode: ViewControllerTracingNode, UIScrollVi strongSelf.updateLayout(layout: validLayout, transition: .animated(duration: 0.2 * animationDurationFactor, curve: .easeInOut), previousActionsContainerNode: nil) } } - takenViewInfo.contentContainingNode.updateDistractionFreeMode = { [weak self] value in - guard let strongSelf = self, let reactionContextNode = strongSelf.reactionContextNode else { - return - } - if value { - if !reactionContextNode.alpha.isZero { - reactionContextNode.alpha = 0.0 - reactionContextNode.allowsGroupOpacity = true - reactionContextNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3 * animationDurationFactor, completion: { [weak reactionContextNode] _ in - reactionContextNode?.allowsGroupOpacity = false - }) - } - } else if reactionContextNode.alpha != 1.0 { - reactionContextNode.alpha = 1.0 - reactionContextNode.allowsGroupOpacity = true - reactionContextNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3 * animationDurationFactor, completion: { [weak reactionContextNode] _ in - reactionContextNode?.allowsGroupOpacity = false - }) - } - } self.contentAreaInScreenSpace = takenViewInfo.contentAreaInScreenSpace self.contentContainerNode.addSubnode(takenViewInfo.contentContainingNode.contentNode) @@ -695,10 +593,6 @@ private final class ContextControllerNode: ViewControllerTracingNode, UIScrollVi localContentSourceFrame = localSourceFrame } - if let reactionContextNode = self.reactionContextNode { - reactionContextNode.animateIn(from: CGRect(origin: CGPoint(x: originalProjectedContentViewFrame.1.minX, y: originalProjectedContentViewFrame.1.minY), size: contentParentNode.contentRect.size)) - } - self.actionsContainerNode.layer.animateSpring(from: NSValue(cgPoint: CGPoint(x: localSourceFrame.center.x - self.actionsContainerNode.position.x, y: localSourceFrame.center.y - self.actionsContainerNode.position.y + actionsOffset)), to: NSValue(cgPoint: CGPoint()), keyPath: "position", duration: actionsDuration, initialVelocity: 0.0, damping: springDamping, additive: true) let contentContainerOffset = CGPoint(x: localContentSourceFrame.center.x - self.contentContainerNode.frame.center.x - contentParentNode.contentRect.minX, y: localContentSourceFrame.center.y - self.contentContainerNode.frame.center.y - contentParentNode.contentRect.minY) self.contentContainerNode.layer.animateSpring(from: NSValue(cgPoint: contentContainerOffset), to: NSValue(cgPoint: CGPoint()), keyPath: "position", duration: contentDuration, initialVelocity: 0.0, damping: springDamping, additive: true, completion: { [weak self] _ in @@ -968,10 +862,6 @@ private final class ContextControllerNode: ViewControllerTracingNode, UIScrollVi contentParentNode.updateAbsoluteRect?(self.contentContainerNode.frame.offsetBy(dx: 0.0, dy: -self.scrollNode.view.contentOffset.y + contentContainerOffset.y), self.bounds.size) contentParentNode.applyAbsoluteOffset?(CGPoint(x: 0.0, y: -contentContainerOffset.y), transitionCurve, transitionDuration) - if let reactionContextNode = self.reactionContextNode { - reactionContextNode.animateOut(to: CGRect(origin: CGPoint(x: originalProjectedContentViewFrame.1.minX, y: originalProjectedContentViewFrame.1.minY), size: contentParentNode.contentRect.size), animatingOutToReaction: self.reactionContextNodeIsAnimatingOut) - } - contentParentNode.willUpdateIsExtractedToContextPreview?(false, .animated(duration: 0.2, curve: .easeInOut)) } else { if let snapshotView = contentParentNode.contentNode.view.snapshotContentTree(keepTransform: true) { @@ -990,10 +880,6 @@ private final class ContextControllerNode: ViewControllerTracingNode, UIScrollVi contentParentNode.contentNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2) contentParentNode.willUpdateIsExtractedToContextPreview?(false, .animated(duration: 0.2, curve: .easeInOut)) - - if let reactionContextNode = self.reactionContextNode { - reactionContextNode.animateOut(to: nil, animatingOutToReaction: self.reactionContextNodeIsAnimatingOut) - } } case let .controller(source): guard let maybeContentNode = self.contentContainerNode.contentNode, case let .controller(controller) = maybeContentNode else { @@ -1132,42 +1018,9 @@ private final class ContextControllerNode: ViewControllerTracingNode, UIScrollVi completedContentNode = true intermediateCompletion() }) - - if let reactionContextNode = self.reactionContextNode { - reactionContextNode.animateOut(to: nil, animatingOutToReaction: self.reactionContextNodeIsAnimatingOut) - } } } } - - func animateOutToReaction(value: String, targetEmptyNode: ASDisplayNode, targetFilledNode: ASDisplayNode, hideNode: Bool, completion: @escaping () -> Void) { - guard let reactionContextNode = self.reactionContextNode else { - self.animateOut(result: .default, completion: completion) - return - } - var contentCompleted = false - var reactionCompleted = false - let intermediateCompletion: () -> Void = { - if contentCompleted && reactionCompleted { - completion() - } - } - - self.reactionContextNodeIsAnimatingOut = true - self.animateOut(result: .default, completion: { - contentCompleted = true - intermediateCompletion() - }) - reactionContextNode.animateOutToReaction(value: value, targetEmptyNode: targetEmptyNode, targetFilledNode: targetFilledNode, hideNode: hideNode, completion: { [weak self] in - guard let strongSelf = self else { - return - } - strongSelf.reactionContextNode?.removeFromSupernode() - strongSelf.reactionContextNode = nil - reactionCompleted = true - intermediateCompletion() - }) - } func getActionsMinHeight() -> ContextController.ActionsHeight? { if !self.actionsContainerNode.bounds.height.isZero { @@ -1281,10 +1134,8 @@ private final class ContextControllerNode: ViewControllerTracingNode, UIScrollVi transition.updateFrame(node: self.scrollNode, frame: CGRect(origin: CGPoint(), size: layout.size)) let actionsSideInset: CGFloat = layout.safeInsets.left + 11.0 - var contentTopInset: CGFloat = max(11.0, layout.statusBarHeight ?? 0.0) - if let _ = self.reactionContextNode { - contentTopInset += 34.0 - } + let contentTopInset: CGFloat = max(11.0, layout.statusBarHeight ?? 0.0) + let actionsBottomInset: CGFloat = 11.0 if let contentNode = self.contentContainerNode.contentNode { @@ -1506,12 +1357,6 @@ private final class ContextControllerNode: ViewControllerTracingNode, UIScrollVi let absoluteContentRect = contentContainerFrame.offsetBy(dx: 0.0, dy: -self.scrollNode.view.contentOffset.y) contentParentNode.updateAbsoluteRect?(absoluteContentRect, layout.size) - - if let reactionContextNode = self.reactionContextNode { - let insets = layout.insets(options: [.statusBar]) - transition.updateFrame(node: reactionContextNode, frame: CGRect(origin: CGPoint(), size: layout.size)) - reactionContextNode.updateLayout(size: layout.size, insets: insets, anchorRect: CGRect(origin: CGPoint(x: absoluteContentRect.minX + contentParentNode.contentRect.minX, y: absoluteContentRect.minY + contentParentNode.contentRect.minY), size: contentParentNode.contentRect.size), transition: transition) - } } case let .controller(contentParentNode): var projectedFrame: CGRect = convertFrame(contentParentNode.sourceNode.bounds, from: contentParentNode.sourceNode.view, to: self.view) @@ -1642,14 +1487,6 @@ private final class ContextControllerNode: ViewControllerTracingNode, UIScrollVi transition.animateOffsetAdditive(node: self.scrollNode, offset: currentContainerFrame.minY - previousContainerFrame.minY) } } - - let absoluteContentRect = contentContainerFrame.offsetBy(dx: 0.0, dy: -self.scrollNode.view.contentOffset.y) - - if let reactionContextNode = self.reactionContextNode { - let insets = layout.insets(options: [.statusBar]) - transition.updateFrame(node: reactionContextNode, frame: CGRect(origin: CGPoint(), size: layout.size)) - reactionContextNode.updateLayout(size: layout.size, insets: insets, anchorRect: CGRect(origin: CGPoint(x: absoluteContentRect.minX, y: absoluteContentRect.minY), size: contentSize), transition: transition) - } } } } @@ -1734,11 +1571,6 @@ private final class ContextControllerNode: ViewControllerTracingNode, UIScrollVi if !self.bounds.contains(point) { return nil } - if let reactionContextNode = self.reactionContextNode { - if let result = reactionContextNode.hitTest(self.view.convert(point, to: reactionContextNode.view), with: event) { - return result - } - } let mappedPoint = self.view.convert(point, to: self.scrollNode.view) if let maybeContentNode = self.contentContainerNode.contentNode { switch maybeContentNode { @@ -1918,7 +1750,6 @@ public final class ContextController: ViewController, StandalonePresentableContr private var presentationData: PresentationData private let source: ContextContentSource private var items: Signal - private var reactionItems: [ReactionContextItem] private let _ready = Promise() override public var ready: Promise { @@ -1934,8 +1765,7 @@ public final class ContextController: ViewController, StandalonePresentableContr private var controllerNode: ContextControllerNode { return self.displayNode as! ContextControllerNode } - - public var reactionSelected: ((ReactionContextItem.Reaction) -> Void)? + public var dismissed: (() -> Void)? public var dismissedForCancel: (() -> Void)? { didSet { @@ -1948,12 +1778,11 @@ public final class ContextController: ViewController, StandalonePresentableContr private var shouldBeDismissedDisposable: Disposable? - public init(account: Account, presentationData: PresentationData, source: ContextContentSource, items: Signal, reactionItems: [ReactionContextItem], recognizer: TapLongTapOrDoubleTapGestureRecognizer? = nil, gesture: ContextGesture? = nil) { + public init(account: Account, presentationData: PresentationData, source: ContextContentSource, items: Signal, recognizer: TapLongTapOrDoubleTapGestureRecognizer? = nil, gesture: ContextGesture? = nil) { self.account = account self.presentationData = presentationData self.source = source self.items = items - self.reactionItems = reactionItems self.recognizer = recognizer self.gesture = gesture @@ -2004,14 +1833,9 @@ public final class ContextController: ViewController, StandalonePresentableContr } override public func loadDisplayNode() { - self.displayNode = ContextControllerNode(account: self.account, controller: self, presentationData: self.presentationData, source: self.source, items: self.items, reactionItems: self.reactionItems, beginDismiss: { [weak self] result in + self.displayNode = ContextControllerNode(account: self.account, controller: self, presentationData: self.presentationData, source: self.source, items: self.items, beginDismiss: { [weak self] result in self?.dismiss(result: result, completion: nil) - }, recognizer: self.recognizer, gesture: self.gesture, reactionSelected: { [weak self] value in - guard let strongSelf = self else { - return - } - strongSelf.reactionSelected?(value) - }, beganAnimatingOut: { [weak self] in + }, recognizer: self.recognizer, gesture: self.gesture, beganAnimatingOut: { [weak self] in self?.statusBar.statusBarStyle = .Ignore }, attemptTransitionControllerIntoNavigation: { [weak self] in guard let strongSelf = self else { @@ -2096,15 +1920,4 @@ public final class ContextController: ViewController, StandalonePresentableContr override public func dismiss(completion: (() -> Void)? = nil) { self.dismiss(result: .default, completion: completion) } - - public func dismissWithReaction(value: String, targetEmptyNode: ASDisplayNode, targetFilledNode: ASDisplayNode, hideNode: Bool, completion: (() -> Void)?) { - if !self.wasDismissed { - self.wasDismissed = true - self.controllerNode.animateOutToReaction(value: value, targetEmptyNode: targetEmptyNode, targetFilledNode: targetFilledNode, hideNode: hideNode, completion: { [weak self] in - self?.presentingViewController?.dismiss(animated: false, completion: nil) - completion?() - }) - self.dismissed?() - } - } } diff --git a/submodules/ContextUI/Sources/PinchController.swift b/submodules/ContextUI/Sources/PinchController.swift index 8f2a93e12a..e7db5ab007 100644 --- a/submodules/ContextUI/Sources/PinchController.swift +++ b/submodules/ContextUI/Sources/PinchController.swift @@ -4,7 +4,6 @@ import AsyncDisplayKit import Display import TelegramPresentationData import TextSelectionNode -import ReactionSelectionNode import TelegramCore import SwiftSignalKit diff --git a/submodules/GalleryData/Sources/GalleryData.swift b/submodules/GalleryData/Sources/GalleryData.swift index 43632cd6ac..6820a64b07 100644 --- a/submodules/GalleryData/Sources/GalleryData.swift +++ b/submodules/GalleryData/Sources/GalleryData.swift @@ -97,9 +97,9 @@ public func chatMessageGalleryControllerData(context: AccountContext, chatLocati if let action = media as? TelegramMediaAction { switch action.action { case let .photoUpdated(image): - if let peer = messageMainPeer(message), let image = image { - let promise: Promise<[AvatarGalleryEntry]> = Promise([AvatarGalleryEntry.image(image.imageId, image.reference, image.representations.map({ ImageRepresentationWithReference(representation: $0, reference: .media(media: .message(message: MessageReference(message), media: media), resource: $0.resource)) }), image.videoRepresentations.map({ VideoRepresentationWithReference(representation: $0, reference: .media(media: .message(message: MessageReference(message), media: media), resource: $0.resource)) }), peer, message.timestamp, nil, message.id, image.immediateThumbnailData, "action")]) - let galleryController = AvatarGalleryController(context: context, peer: peer, sourceCorners: .roundRect(15.5), remoteEntries: promise, skipInitial: true, replaceRootController: { controller, ready in + if let peer = messageMainPeer(EngineMessage(message)), let image = image { + let promise: Promise<[AvatarGalleryEntry]> = Promise([AvatarGalleryEntry.image(image.imageId, image.reference, image.representations.map({ ImageRepresentationWithReference(representation: $0, reference: .media(media: .message(message: MessageReference(message), media: media), resource: $0.resource)) }), image.videoRepresentations.map({ VideoRepresentationWithReference(representation: $0, reference: .media(media: .message(message: MessageReference(message), media: media), resource: $0.resource)) }), peer._asPeer(), message.timestamp, nil, message.id, image.immediateThumbnailData, "action")]) + let galleryController = AvatarGalleryController(context: context, peer: peer._asPeer(), sourceCorners: .roundRect(15.5), remoteEntries: promise, skipInitial: true, replaceRootController: { controller, ready in }) return .chatAvatars(galleryController, image) diff --git a/submodules/GalleryUI/Sources/ChatItemGalleryFooterContentNode.swift b/submodules/GalleryUI/Sources/ChatItemGalleryFooterContentNode.swift index 5d62e2242b..9f0381b93b 100644 --- a/submodules/GalleryUI/Sources/ChatItemGalleryFooterContentNode.swift +++ b/submodules/GalleryUI/Sources/ChatItemGalleryFooterContentNode.swift @@ -954,7 +954,7 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll var generalMessageContentKind: MessageContentKind? for message in messages { - let currentKind = messageContentKind(contentSettings: strongSelf.context.currentContentSettings.with { $0 }, message: message, strings: presentationData.strings, nameDisplayOrder: presentationData.nameDisplayOrder, dateTimeFormat: presentationData.dateTimeFormat, accountPeerId: strongSelf.context.account.peerId) + let currentKind = messageContentKind(contentSettings: strongSelf.context.currentContentSettings.with { $0 }, message: EngineMessage(message), strings: presentationData.strings, nameDisplayOrder: presentationData.nameDisplayOrder, dateTimeFormat: presentationData.dateTimeFormat, accountPeerId: strongSelf.context.account.peerId) if generalMessageContentKind == nil || generalMessageContentKind == currentKind { generalMessageContentKind = currentKind } else { @@ -1103,7 +1103,7 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll var messageContentKinds = Set() for message in messages { - let currentKind = messageContentKind(contentSettings: strongSelf.context.currentContentSettings.with { $0 }, message: message, strings: presentationData.strings, nameDisplayOrder: presentationData.nameDisplayOrder, dateTimeFormat: presentationData.dateTimeFormat, accountPeerId: strongSelf.context.account.peerId) + let currentKind = messageContentKind(contentSettings: strongSelf.context.currentContentSettings.with { $0 }, message: EngineMessage(message), strings: presentationData.strings, nameDisplayOrder: presentationData.nameDisplayOrder, dateTimeFormat: presentationData.dateTimeFormat, accountPeerId: strongSelf.context.account.peerId) if beganContentKindScanning && currentKind != generalMessageContentKind { generalMessageContentKind = nil } else if !beganContentKindScanning || currentKind == generalMessageContentKind { diff --git a/submodules/GalleryUI/Sources/Items/UniversalVideoGalleryItem.swift b/submodules/GalleryUI/Sources/Items/UniversalVideoGalleryItem.swift index 754c243979..b8bbf7064b 100644 --- a/submodules/GalleryUI/Sources/Items/UniversalVideoGalleryItem.swift +++ b/submodules/GalleryUI/Sources/Items/UniversalVideoGalleryItem.swift @@ -2032,7 +2032,7 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode { return } - let contextController = ContextController(account: self.context.account, presentationData: self.presentationData.withUpdated(theme: defaultDarkColorPresentationTheme), source: .reference(HeaderContextReferenceContentSource(controller: controller, sourceNode: self.moreBarButton.referenceNode)), items: items |> map { ContextController.Items(items: $0) }, reactionItems: [], gesture: gesture) + let contextController = ContextController(account: self.context.account, presentationData: self.presentationData.withUpdated(theme: defaultDarkColorPresentationTheme), source: .reference(HeaderContextReferenceContentSource(controller: controller, sourceNode: self.moreBarButton.referenceNode)), items: items |> map { ContextController.Items(items: $0) }, gesture: gesture) self.isShowingContextMenuPromise.set(true) controller.presentInGlobalOverlay(contextController) diff --git a/submodules/GalleryUI/Sources/SecretMediaPreviewController.swift b/submodules/GalleryUI/Sources/SecretMediaPreviewController.swift index f0de0120e9..de83c7efb2 100644 --- a/submodules/GalleryUI/Sources/SecretMediaPreviewController.swift +++ b/submodules/GalleryUI/Sources/SecretMediaPreviewController.swift @@ -300,7 +300,7 @@ public final class SecretMediaPreviewController: ViewController { }, transition: .immediate) } else { let contentNode = SecretMediaPreviewFooterContentNode() - let peerTitle = messageMainPeer(message).flatMap(EnginePeer.init)?.compactDisplayTitle ?? "" + let peerTitle = messageMainPeer(EngineMessage(message))?.compactDisplayTitle ?? "" let text: String if let file = media as? TelegramMediaFile { if file.isAnimated { diff --git a/submodules/InviteLinksUI/Sources/InviteLinkInviteController.swift b/submodules/InviteLinksUI/Sources/InviteLinkInviteController.swift index f2d5a47df1..5f901ff199 100644 --- a/submodules/InviteLinksUI/Sources/InviteLinkInviteController.swift +++ b/submodules/InviteLinksUI/Sources/InviteLinkInviteController.swift @@ -418,7 +418,7 @@ public final class InviteLinkInviteController: ViewController { }) }))) - let contextController = ContextController(account: context.account, presentationData: presentationData, source: .reference(InviteLinkContextReferenceContentSource(controller: controller, sourceNode: node)), items: .single(ContextController.Items(items: items)), reactionItems: [], gesture: gesture) + let contextController = ContextController(account: context.account, presentationData: presentationData, source: .reference(InviteLinkContextReferenceContentSource(controller: controller, sourceNode: node)), items: .single(ContextController.Items(items: items)), gesture: gesture) self?.controller?.presentInGlobalOverlay(contextController) }, copyLink: { [weak self] invite in UIPasteboard.general.string = invite.link diff --git a/submodules/InviteLinksUI/Sources/InviteLinkListController.swift b/submodules/InviteLinksUI/Sources/InviteLinkListController.swift index 765e509835..14eb5afa78 100644 --- a/submodules/InviteLinksUI/Sources/InviteLinkListController.swift +++ b/submodules/InviteLinksUI/Sources/InviteLinkListController.swift @@ -550,7 +550,7 @@ public func inviteLinkListController(context: AccountContext, updatedPresentatio }))) } - let contextController = ContextController(account: context.account, presentationData: presentationData, source: .reference(InviteLinkContextReferenceContentSource(controller: controller, sourceNode: node)), items: .single(ContextController.Items(items: items)), reactionItems: [], gesture: gesture) + let contextController = ContextController(account: context.account, presentationData: presentationData, source: .reference(InviteLinkContextReferenceContentSource(controller: controller, sourceNode: node)), items: .single(ContextController.Items(items: items)), gesture: gesture) presentInGlobalOverlayImpl?(contextController) }, createLink: { let controller = inviteLinkEditController(context: context, updatedPresentationData: updatedPresentationData, peerId: peerId, invite: nil, completion: { invite in @@ -714,7 +714,7 @@ public func inviteLinkListController(context: AccountContext, updatedPresentatio }))) } - let contextController = ContextController(account: context.account, presentationData: presentationData, source: .extracted(InviteLinkContextExtractedContentSource(controller: controller, sourceNode: node, blurBackground: true)), items: .single(ContextController.Items(items: items)), reactionItems: [], gesture: gesture) + let contextController = ContextController(account: context.account, presentationData: presentationData, source: .extracted(InviteLinkContextExtractedContentSource(controller: controller, sourceNode: node, blurBackground: true)), items: .single(ContextController.Items(items: items)), gesture: gesture) presentInGlobalOverlayImpl?(contextController) }, openAdmin: { admin in let controller = inviteLinkListController(context: context, peerId: peerId, admin: admin) diff --git a/submodules/InviteLinksUI/Sources/InviteLinkViewController.swift b/submodules/InviteLinksUI/Sources/InviteLinkViewController.swift index dd42de62c0..54053c4597 100644 --- a/submodules/InviteLinksUI/Sources/InviteLinkViewController.swift +++ b/submodules/InviteLinksUI/Sources/InviteLinkViewController.swift @@ -565,7 +565,7 @@ public final class InviteLinkViewController: ViewController { }))) } - let contextController = ContextController(account: context.account, presentationData: presentationData, source: .reference(InviteLinkContextReferenceContentSource(controller: controller, sourceNode: node)), items: .single(ContextController.Items(items: items)), reactionItems: [], gesture: gesture) + let contextController = ContextController(account: context.account, presentationData: presentationData, source: .reference(InviteLinkContextReferenceContentSource(controller: controller, sourceNode: node)), items: .single(ContextController.Items(items: items)), gesture: gesture) self?.controller?.presentInGlobalOverlay(contextController) }) diff --git a/submodules/PeerInfoUI/Sources/ChannelVisibilityController.swift b/submodules/PeerInfoUI/Sources/ChannelVisibilityController.swift index 6d9e63b974..36fb8366b1 100644 --- a/submodules/PeerInfoUI/Sources/ChannelVisibilityController.swift +++ b/submodules/PeerInfoUI/Sources/ChannelVisibilityController.swift @@ -1050,7 +1050,7 @@ public func channelVisibilityController(context: AccountContext, updatedPresenta }) }))) - let contextController = ContextController(account: context.account, presentationData: presentationData, source: .extracted(InviteLinkContextExtractedContentSource(controller: controller, sourceNode: node)), items: .single(ContextController.Items(items: items)), reactionItems: [], gesture: gesture) + let contextController = ContextController(account: context.account, presentationData: presentationData, source: .extracted(InviteLinkContextExtractedContentSource(controller: controller, sourceNode: node)), items: .single(ContextController.Items(items: items)), gesture: gesture) presentInGlobalOverlayImpl?(contextController) }, manageInviteLinks: { let controller = inviteLinkListController(context: context, updatedPresentationData: updatedPresentationData, peerId: peerId, admin: nil) diff --git a/submodules/PeersNearbyUI/BUILD b/submodules/PeersNearbyUI/BUILD index a83643a764..4ebbdcdbb5 100644 --- a/submodules/PeersNearbyUI/BUILD +++ b/submodules/PeersNearbyUI/BUILD @@ -13,7 +13,6 @@ swift_library( "//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit", "//submodules/AsyncDisplayKit:AsyncDisplayKit", "//submodules/Display:Display", - "//submodules/Postbox:Postbox", "//submodules/TelegramCore:TelegramCore", "//submodules/TelegramPresentationData:TelegramPresentationData", "//submodules/AccountContext:AccountContext", diff --git a/submodules/PeersNearbyUI/Sources/PeersNearbyController.swift b/submodules/PeersNearbyUI/Sources/PeersNearbyController.swift index f89a075977..d140c63ae3 100644 --- a/submodules/PeersNearbyUI/Sources/PeersNearbyController.swift +++ b/submodules/PeersNearbyUI/Sources/PeersNearbyController.swift @@ -3,7 +3,6 @@ import UIKit import AsyncDisplayKit import Display import SwiftSignalKit -import Postbox import TelegramCore import MapKit import TelegramPresentationData @@ -27,14 +26,15 @@ import TelegramStringFormatting private let maxUsersDisplayedLimit: Int32 = 5 private struct PeerNearbyEntry { - let peer: (Peer, CachedPeerData?) + let peer: EnginePeer + let memberCount: Int32? let expires: Int32 let distance: Int32 } private func arePeersNearbyEqual(_ lhs: PeerNearbyEntry?, _ rhs: PeerNearbyEntry?) -> Bool { if let lhs = lhs, let rhs = rhs { - return lhs.peer.0.isEqual(rhs.peer.0) && lhs.expires == rhs.expires && lhs.distance == rhs.distance + return lhs.peer == rhs.peer && lhs.expires == rhs.expires && lhs.distance == rhs.distance } else { return (lhs != nil) == (rhs != nil) } @@ -45,7 +45,7 @@ private func arePeerNearbyArraysEqual(_ lhs: [PeerNearbyEntry], _ rhs: [PeerNear return false } for i in 0 ..< lhs.count { - if !lhs[i].peer.0.isEqual(rhs[i].peer.0) || lhs[i].expires != rhs[i].expires || lhs[i].distance != rhs[i].distance { + if lhs[i].peer != rhs[i].peer || lhs[i].expires != rhs[i].expires || lhs[i].distance != rhs[i].distance { return false } } @@ -55,13 +55,13 @@ private func arePeerNearbyArraysEqual(_ lhs: [PeerNearbyEntry], _ rhs: [PeerNear private final class PeersNearbyControllerArguments { let context: AccountContext let toggleVisibility: (Bool) -> Void - let openProfile: (Peer, Int32) -> Void - let openChat: (Peer) -> Void + let openProfile: (EnginePeer, Int32) -> Void + let openChat: (EnginePeer) -> Void let openCreateGroup: (Double, Double, String?) -> Void - let contextAction: (Peer, ASDisplayNode, ContextGesture?) -> Void + let contextAction: (EnginePeer, ASDisplayNode, ContextGesture?) -> Void let expandUsers: () -> Void - init(context: AccountContext, toggleVisibility: @escaping (Bool) -> Void, openProfile: @escaping (Peer, Int32) -> Void, openChat: @escaping (Peer) -> Void, openCreateGroup: @escaping (Double, Double, String?) -> Void, contextAction: @escaping (Peer, ASDisplayNode, ContextGesture?) -> Void, expandUsers: @escaping () -> Void) { + init(context: AccountContext, toggleVisibility: @escaping (Bool) -> Void, openProfile: @escaping (EnginePeer, Int32) -> Void, openChat: @escaping (EnginePeer) -> Void, openCreateGroup: @escaping (Double, Double, String?) -> Void, contextAction: @escaping (EnginePeer, ASDisplayNode, ContextGesture?) -> Void, expandUsers: @escaping () -> Void) { self.context = context self.toggleVisibility = toggleVisibility self.openProfile = openProfile @@ -226,13 +226,13 @@ private enum PeersNearbyEntry: ItemListNodeEntry { }) case let .user(_, _, strings, dateTimeFormat, nameDisplayOrder, peer): var text = strings.Map_DistanceAway(shortStringForDistance(strings: strings, distance: peer.distance)).string - let isSelfPeer = peer.peer.0.id == arguments.context.account.peerId + let isSelfPeer = peer.peer.id == arguments.context.account.peerId if isSelfPeer { text = strings.PeopleNearby_VisibleUntil(humanReadableStringForTimestamp(strings: strings, dateTimeFormat: dateTimeFormat, timestamp: peer.expires).string).string } - return ItemListPeerItem(presentationData: presentationData, dateTimeFormat: dateTimeFormat, nameDisplayOrder: nameDisplayOrder, context: arguments.context, peer: EnginePeer(peer.peer.0), aliasHandling: .standard, nameColor: .primary, nameStyle: .distinctBold, presence: nil, text: .text(text, .secondary), label: .none, editing: ItemListPeerItemEditing(editable: false, editing: false, revealed: false), revealOptions: nil, switchValue: nil, enabled: true, selectable: !isSelfPeer, sectionId: self.section, action: { + return ItemListPeerItem(presentationData: presentationData, dateTimeFormat: dateTimeFormat, nameDisplayOrder: nameDisplayOrder, context: arguments.context, peer: peer.peer, aliasHandling: .standard, nameColor: .primary, nameStyle: .distinctBold, presence: nil, text: .text(text, .secondary), label: .none, editing: ItemListPeerItemEditing(editable: false, editing: false, revealed: false), revealOptions: nil, switchValue: nil, enabled: true, selectable: !isSelfPeer, sectionId: self.section, action: { if !isSelfPeer { - arguments.openProfile(peer.peer.0, peer.distance) + arguments.openProfile(peer.peer, peer.distance) } }, setPeerIdWithRevealedOptions: { _, _ in }, removePeer: { _ in }, toggleUpdated: nil, contextAction: nil, hasTopGroupInset: false, tag: nil) case let .expand(theme, title): @@ -249,29 +249,29 @@ private enum PeersNearbyEntry: ItemListNodeEntry { }) case let .group(_, _, strings, dateTimeFormat, nameDisplayOrder, peer, highlighted): var text: ItemListPeerItemText - if let cachedData = peer.peer.1 as? CachedChannelData, let memberCount = cachedData.participantsSummary.memberCount { + if let memberCount = peer.memberCount { text = .text("\(strings.Map_DistanceAway(shortStringForDistance(strings: strings, distance: peer.distance)).string), \(memberCount > 0 ? strings.Conversation_StatusMembers(memberCount) : strings.PeopleNearby_NoMembers)", .secondary) } else { text = .text(strings.Map_DistanceAway(shortStringForDistance(strings: strings, distance: peer.distance)).string, .secondary) } - return ItemListPeerItem(presentationData: presentationData, dateTimeFormat: dateTimeFormat, nameDisplayOrder: nameDisplayOrder, context: arguments.context, peer: EnginePeer(peer.peer.0), aliasHandling: .standard, nameColor: .primary, nameStyle: .distinctBold, presence: nil, text: text, label: .none, editing: ItemListPeerItemEditing(editable: false, editing: false, revealed: false), revealOptions: nil, switchValue: nil, enabled: true, highlighted: highlighted, selectable: true, sectionId: self.section, action: { - arguments.openChat(peer.peer.0) + return ItemListPeerItem(presentationData: presentationData, dateTimeFormat: dateTimeFormat, nameDisplayOrder: nameDisplayOrder, context: arguments.context, peer: peer.peer, aliasHandling: .standard, nameColor: .primary, nameStyle: .distinctBold, presence: nil, text: text, label: .none, editing: ItemListPeerItemEditing(editable: false, editing: false, revealed: false), revealOptions: nil, switchValue: nil, enabled: true, highlighted: highlighted, selectable: true, sectionId: self.section, action: { + arguments.openChat(peer.peer) }, setPeerIdWithRevealedOptions: { _, _ in }, removePeer: { _ in }, toggleUpdated: nil, contextAction: { node, gesture in - arguments.contextAction(peer.peer.0, node, gesture) + arguments.contextAction(peer.peer, node, gesture) }, hasTopGroupInset: false, tag: nil) case let .channelsHeader(_, text): return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section) case let .channel(_, _, strings, dateTimeFormat, nameDisplayOrder, peer, highlighted): var text: ItemListPeerItemText - if let cachedData = peer.peer.1 as? CachedChannelData, let memberCount = cachedData.participantsSummary.memberCount { + if let memberCount = peer.memberCount { text = .text("\(strings.Map_DistanceAway(shortStringForDistance(strings: strings, distance: peer.distance)).string), \(strings.Conversation_StatusSubscribers(memberCount))", .secondary) } else { text = .text(strings.Map_DistanceAway(shortStringForDistance(strings: strings, distance: peer.distance)).string, .secondary) } - return ItemListPeerItem(presentationData: presentationData, dateTimeFormat: dateTimeFormat, nameDisplayOrder: nameDisplayOrder, context: arguments.context, peer: EnginePeer(peer.peer.0), aliasHandling: .standard, nameColor: .primary, nameStyle: .distinctBold, presence: nil, text: text, label: .none, editing: ItemListPeerItemEditing(editable: false, editing: false, revealed: false), revealOptions: nil, switchValue: nil, enabled: true, highlighted: highlighted, selectable: true, sectionId: self.section, action: { - arguments.openChat(peer.peer.0) + return ItemListPeerItem(presentationData: presentationData, dateTimeFormat: dateTimeFormat, nameDisplayOrder: nameDisplayOrder, context: arguments.context, peer: peer.peer, aliasHandling: .standard, nameColor: .primary, nameStyle: .distinctBold, presence: nil, text: text, label: .none, editing: ItemListPeerItemEditing(editable: false, editing: false, revealed: false), revealOptions: nil, switchValue: nil, enabled: true, highlighted: highlighted, selectable: true, sectionId: self.section, action: { + arguments.openChat(peer.peer) }, setPeerIdWithRevealedOptions: { _, _ in }, removePeer: { _ in }, toggleUpdated: nil, contextAction: { node, gesture in - arguments.contextAction(peer.peer.0, node, gesture) + arguments.contextAction(peer.peer, node, gesture) }, hasTopGroupInset: false, tag: nil) } } @@ -282,12 +282,12 @@ private struct PeersNearbyData: Equatable { let longitude: Double let address: String? let visible: Bool - let accountPeerId: PeerId + let accountPeerId: EnginePeer.Id let users: [PeerNearbyEntry] let groups: [PeerNearbyEntry] let channels: [PeerNearbyEntry] - init(latitude: Double, longitude: Double, address: String?, visible: Bool, accountPeerId: PeerId, users: [PeerNearbyEntry], groups: [PeerNearbyEntry], channels: [PeerNearbyEntry]) { + init(latitude: Double, longitude: Double, address: String?, visible: Bool, accountPeerId: EnginePeer.Id, users: [PeerNearbyEntry], groups: [PeerNearbyEntry], channels: [PeerNearbyEntry]) { self.latitude = latitude self.longitude = longitude self.address = address @@ -314,7 +314,7 @@ private func peersNearbyControllerEntries(data: PeersNearbyData?, state: PeersNe if let data = data, !data.users.isEmpty { var index: Int32 = 0 - var users = data.users.filter { $0.peer.0.id != data.accountPeerId } + var users = data.users.filter { $0.peer.id != data.accountPeerId } var effectiveExpanded = expanded if users.count > maxUsersDisplayedLimit && !expanded { users = Array(users.prefix(Int(maxUsersDisplayedLimit))) @@ -332,7 +332,7 @@ private func peersNearbyControllerEntries(data: PeersNearbyData?, state: PeersNe } } - var highlightedPeerId: PeerId? + var highlightedPeerId: EnginePeer.Id? if let chatLocation = chatLocation, case let .peer(peerId) = chatLocation { highlightedPeerId = peerId } @@ -342,7 +342,7 @@ private func peersNearbyControllerEntries(data: PeersNearbyData?, state: PeersNe if let data = data, !data.groups.isEmpty { var i: Int32 = 0 for group in data.groups { - entries.append(.group(i, presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, presentationData.nameDisplayOrder, group, highlightedPeerId == group.peer.0.id)) + entries.append(.group(i, presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, presentationData.nameDisplayOrder, group, highlightedPeerId == group.peer.id)) i += 1 } } @@ -350,7 +350,7 @@ private func peersNearbyControllerEntries(data: PeersNearbyData?, state: PeersNe if let data = data, !data.channels.isEmpty { var i: Int32 = 0 for channel in data.channels { - entries.append(.channel(i, presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, presentationData.nameDisplayOrder, channel, highlightedPeerId == channel.peer.0.id)) + entries.append(.channel(i, presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, presentationData.nameDisplayOrder, channel, highlightedPeerId == channel.peer.id)) i += 1 } } @@ -386,7 +386,7 @@ private final class ContextControllerContentSourceImpl: ContextControllerContent } } -private func peerNearbyContextMenuItems(context: AccountContext, peerId: PeerId, present: @escaping (ViewController) -> Void) -> Signal<[ContextMenuItem], NoError> { +private func peerNearbyContextMenuItems(context: AccountContext, peerId: EnginePeer.Id, present: @escaping (ViewController) -> Void) -> Signal<[ContextMenuItem], NoError> { return context.account.postbox.transaction { _ -> [ContextMenuItem] in let items: [ContextMenuItem] = [] @@ -409,8 +409,8 @@ public func peersNearbyController(context: AccountContext) -> ViewController { var replaceTopControllerImpl: ((ViewController) -> Void)? var presentControllerImpl: ((ViewController, ViewControllerPresentationArguments?) -> Void)? var presentInGlobalOverlayImpl: ((ViewController) -> Void)? - var navigateToProfileImpl: ((Peer, Int32) -> Void)? - var navigateToChatImpl: ((Peer) -> Void)? + var navigateToProfileImpl: ((EnginePeer, Int32) -> Void)? + var navigateToChatImpl: ((EnginePeer) -> Void)? let actionsDisposable = DisposableSet() let checkCreationAvailabilityDisposable = MetaDisposable() @@ -494,7 +494,7 @@ public func peersNearbyController(context: AccountContext) -> ViewController { chatController.canReadHistory.set(false) let contextController = ContextController(account: context.account, presentationData: presentationData, source: .controller(ContextControllerContentSourceImpl(controller: chatController, sourceNode: node)), items: peerNearbyContextMenuItems(context: context, peerId: peer.id, present: { c in presentControllerImpl?(c, nil) - }) |> map { ContextController.Items(items: $0) }, reactionItems: [], gesture: gesture) + }) |> map { ContextController.Items(items: $0) }, gesture: gesture) presentInGlobalOverlayImpl?(contextController) }, expandUsers: { expandedPromise.set(true) @@ -533,16 +533,16 @@ public func peersNearbyController(context: AccountContext) -> ViewController { case let .peer(id, expires, distance): if let peer = transaction.getPeer(id) { if id.namespace == Namespaces.Peer.CloudUser { - users.append(PeerNearbyEntry(peer: (peer, nil), expires: expires, distance: distance)) + users.append(PeerNearbyEntry(peer: EnginePeer(peer), memberCount: nil, expires: expires, distance: distance)) } else { let cachedData = transaction.getPeerCachedData(peerId: id) as? CachedChannelData - groups.append(PeerNearbyEntry(peer: (peer, cachedData), expires: expires, distance: distance)) + groups.append(PeerNearbyEntry(peer: EnginePeer(peer), memberCount: cachedData?.participantsSummary.memberCount, expires: expires, distance: distance)) } } case let .selfPeer(expires): visible = true if let peer = transaction.getPeer(context.account.peerId) { - users.append(PeerNearbyEntry(peer: (peer, nil), expires: expires, distance: 0)) + users.append(PeerNearbyEntry(peer: EnginePeer(peer), memberCount: nil, expires: expires, distance: 0)) } } } @@ -598,7 +598,7 @@ public func peersNearbyController(context: AccountContext) -> ViewController { controller?.clearItemNodesHighlight(animated: true) } navigateToProfileImpl = { [weak controller] peer, distance in - if let navigationController = controller?.navigationController as? NavigationController, let controller = context.sharedContext.makePeerInfoController(context: context, updatedPresentationData: nil, peer: peer, mode: .nearbyPeer(distance: distance), avatarInitiallyExpanded: peer.largeProfileImage != nil, fromChat: false) { + if let navigationController = controller?.navigationController as? NavigationController, let controller = context.sharedContext.makePeerInfoController(context: context, updatedPresentationData: nil, peer: peer._asPeer(), mode: .nearbyPeer(distance: distance), avatarInitiallyExpanded: peer.largeProfileImage != nil, fromChat: false) { navigationController.pushViewController(controller) } } diff --git a/submodules/ReactionSelectionNode/BUILD b/submodules/ReactionSelectionNode/BUILD deleted file mode 100644 index 9e1c9e099d..0000000000 --- a/submodules/ReactionSelectionNode/BUILD +++ /dev/null @@ -1,24 +0,0 @@ -load("@build_bazel_rules_swift//swift:swift.bzl", "swift_library") - -swift_library( - name = "ReactionSelectionNode", - module_name = "ReactionSelectionNode", - srcs = glob([ - "Sources/**/*.swift", - ]), - copts = [ - "-warnings-as-errors", - ], - deps = [ - "//submodules/Postbox:Postbox", - "//submodules/TelegramCore:TelegramCore", - "//submodules/AsyncDisplayKit:AsyncDisplayKit", - "//submodules/Display:Display", - "//submodules/AnimatedStickerNode:AnimatedStickerNode", - "//submodules/TelegramAnimatedStickerNode:TelegramAnimatedStickerNode", - "//submodules/TelegramPresentationData:TelegramPresentationData", - ], - visibility = [ - "//visibility:public", - ], -) diff --git a/submodules/ReactionSelectionNode/Sources/ReactionAttachedNode.swift b/submodules/ReactionSelectionNode/Sources/ReactionAttachedNode.swift deleted file mode 100644 index 3056366991..0000000000 --- a/submodules/ReactionSelectionNode/Sources/ReactionAttachedNode.swift +++ /dev/null @@ -1,323 +0,0 @@ -/*import Foundation -import AsyncDisplayKit -import AnimatedStickerNode -import Display -import Postbox -import TelegramCore -import TelegramPresentationData -import AppBundle - -private func generateBubbleImage(foreground: UIColor, diameter: CGFloat, shadowBlur: CGFloat) -> UIImage? { - return generateImage(CGSize(width: diameter + shadowBlur * 2.0, height: diameter + shadowBlur * 2.0), rotatedContext: { size, context in - context.clear(CGRect(origin: CGPoint(), size: size)) - context.setFillColor(foreground.cgColor) - context.fillEllipse(in: CGRect(origin: CGPoint(x: shadowBlur, y: shadowBlur), size: CGSize(width: diameter, height: diameter))) - })?.stretchableImage(withLeftCapWidth: Int(diameter / 2.0 + shadowBlur / 2.0), topCapHeight: Int(diameter / 2.0 + shadowBlur / 2.0)) -} - -private func generateBubbleShadowImage(shadow: UIColor, diameter: CGFloat, shadowBlur: CGFloat) -> UIImage? { - return generateImage(CGSize(width: diameter + shadowBlur * 2.0, height: diameter + shadowBlur * 2.0), rotatedContext: { size, context in - context.clear(CGRect(origin: CGPoint(), size: size)) - context.setFillColor(UIColor.white.cgColor) - context.setShadow(offset: CGSize(), blur: shadowBlur, color: shadow.cgColor) - context.fillEllipse(in: CGRect(origin: CGPoint(x: shadowBlur, y: shadowBlur), size: CGSize(width: diameter, height: diameter))) - context.setShadow(offset: CGSize(), blur: 1.0, color: shadow.cgColor) - context.fillEllipse(in: CGRect(origin: CGPoint(x: shadowBlur, y: shadowBlur), size: CGSize(width: diameter, height: diameter))) - context.setFillColor(UIColor.clear.cgColor) - context.setBlendMode(.copy) - context.fillEllipse(in: CGRect(origin: CGPoint(x: shadowBlur, y: shadowBlur), size: CGSize(width: diameter, height: diameter))) - })?.stretchableImage(withLeftCapWidth: Int(diameter / 2.0 + shadowBlur / 2.0), topCapHeight: Int(diameter / 2.0 + shadowBlur / 2.0)) -} - -final class ReactionAttachedNode: ASDisplayNode { - private let account: Account - private let theme: PresentationTheme - private let reactions: [ReactionGestureItem] - - private let backgroundNode: ASImageNode - private let backgroundShadowNode: ASImageNode - private let bubbleNodes: [(ASImageNode, ASImageNode)] - private var reactionNodes: [ReactionNode] = [] - private var hasSelectedNode = false - - private let hapticFeedback = HapticFeedback() - - private var shadowBlur: CGFloat = 8.0 - private var minimizedReactionSize: CGFloat = 30.0 - private var maximizedReactionSize: CGFloat = 60.0 - private var smallCircleSize: CGFloat = 8.0 - - public init(account: Account, theme: PresentationTheme, reactions: [ReactionGestureItem]) { - self.account = account - self.theme = theme - self.reactions = reactions - - self.backgroundNode = ASImageNode() - self.backgroundNode.displaysAsynchronously = false - self.backgroundNode.displayWithoutProcessing = true - - self.backgroundShadowNode = ASImageNode() - self.backgroundShadowNode.displaysAsynchronously = false - self.backgroundShadowNode.displayWithoutProcessing = true - - self.bubbleNodes = (0 ..< 2).map { i -> (ASImageNode, ASImageNode) in - let imageNode = ASImageNode() - imageNode.displaysAsynchronously = false - imageNode.displayWithoutProcessing = true - - let shadowNode = ASImageNode() - shadowNode.displaysAsynchronously = false - shadowNode.displayWithoutProcessing = true - - return (imageNode, shadowNode) - } - - super.init() - - self.bubbleNodes.forEach { _, shadow in - self.addSubnode(shadow) - } - self.addSubnode(self.backgroundShadowNode) - self.bubbleNodes.forEach { foreground, _ in - self.addSubnode(foreground) - } - self.addSubnode(self.backgroundNode) - } - - func updateLayout(constrainedSize: CGSize, startingPoint: CGPoint, offsetFromStart: CGFloat, isInitial: Bool) { - let initialAnchorX = startingPoint.x - - if isInitial && self.reactionNodes.isEmpty { - let availableContentWidth = constrainedSize.width - var minimizedReactionSize = (availableContentWidth - self.maximizedReactionSize) / (CGFloat(self.reactions.count - 1) + CGFloat(self.reactions.count + 1) * 0.2) - minimizedReactionSize = max(16.0, floor(minimizedReactionSize)) - minimizedReactionSize = min(30.0, minimizedReactionSize) - - self.minimizedReactionSize = minimizedReactionSize - self.shadowBlur = floor(minimizedReactionSize * 0.26) - self.smallCircleSize = 8.0 - - let backgroundHeight = floor(minimizedReactionSize * 1.4) - - self.backgroundNode.image = generateBubbleImage(foreground: .white, diameter: backgroundHeight, shadowBlur: self.shadowBlur) - self.backgroundShadowNode.image = generateBubbleShadowImage(shadow: UIColor(white: 0.0, alpha: 0.2), diameter: backgroundHeight, shadowBlur: self.shadowBlur) - for i in 0 ..< self.bubbleNodes.count { - self.bubbleNodes[i].0.image = generateBubbleImage(foreground: .white, diameter: CGFloat(i + 1) * self.smallCircleSize, shadowBlur: self.shadowBlur) - self.bubbleNodes[i].1.image = generateBubbleShadowImage(shadow: UIColor(white: 0.0, alpha: 0.2), diameter: CGFloat(i + 1) * self.smallCircleSize, shadowBlur: self.shadowBlur) - } - - self.reactionNodes = self.reactions.map { reaction -> ReactionNode in - return ReactionNode(account: self.account, theme: self.theme, reaction: reaction, maximizedReactionSize: self.maximizedReactionSize, loadFirstFrame: true) - } - self.reactionNodes.forEach(self.addSubnode(_:)) - } - - let backgroundHeight: CGFloat = floor(self.minimizedReactionSize * 1.4) - - let reactionSpacing: CGFloat = floor(self.minimizedReactionSize * 0.2) - let minimizedReactionVerticalInset: CGFloat = floor((backgroundHeight - minimizedReactionSize) / 2.0) - - let contentWidth: CGFloat = CGFloat(self.reactionNodes.count - 1) * (minimizedReactionSize) + maximizedReactionSize + CGFloat(self.reactionNodes.count + 1) * reactionSpacing - - var backgroundFrame = CGRect(origin: CGPoint(x: -shadowBlur, y: -shadowBlur), size: CGSize(width: contentWidth + shadowBlur * 2.0, height: backgroundHeight + shadowBlur * 2.0)) - backgroundFrame = backgroundFrame.offsetBy(dx: initialAnchorX - contentWidth + backgroundHeight / 2.0, dy: startingPoint.y - backgroundHeight - 16.0) - backgroundFrame.origin.x = max(0.0, backgroundFrame.minX) - backgroundFrame.origin.x = min(constrainedSize.width - backgroundFrame.width, backgroundFrame.minX) - - self.backgroundNode.frame = backgroundFrame - self.backgroundShadowNode.frame = backgroundFrame - - let anchorMinX = backgroundFrame.minX + shadowBlur + backgroundHeight / 2.0 - let anchorMaxX = backgroundFrame.maxX - shadowBlur - backgroundHeight / 2.0 - let anchorX = max(anchorMinX, min(anchorMaxX, offsetFromStart)) - - var reactionX: CGFloat = backgroundFrame.minX + shadowBlur + reactionSpacing - if offsetFromStart > backgroundFrame.maxX - shadowBlur || offsetFromStart < backgroundFrame.minX { - self.hasSelectedNode = false - } else { - self.hasSelectedNode = true - } - - var maximizedIndex = Int(((anchorX - anchorMinX) / (anchorMaxX - anchorMinX)) * CGFloat(self.reactionNodes.count)) - maximizedIndex = max(0, min(self.reactionNodes.count - 1, maximizedIndex)) - - for iterationIndex in 0 ..< self.reactionNodes.count { - var i = iterationIndex - let isMaximized = i == maximizedIndex - - let reactionSize: CGFloat - if isMaximized { - reactionSize = maximizedReactionSize - } else { - reactionSize = minimizedReactionSize - } - - let transition: ContainedViewLayoutTransition - if isInitial { - transition = .immediate - } else { - transition = .animated(duration: 0.18, curve: .easeInOut) - } - - if self.reactionNodes[i].isMaximized != isMaximized { - self.reactionNodes[i].isMaximized = isMaximized - self.reactionNodes[i].updateIsAnimating(isMaximized, animated: !isInitial) - if isMaximized && !isInitial { - self.hapticFeedback.tap() - } - } - - var reactionFrame = CGRect(origin: CGPoint(x: reactionX, y: backgroundFrame.maxY - shadowBlur - minimizedReactionVerticalInset - reactionSize), size: CGSize(width: reactionSize, height: reactionSize)) - if isMaximized { - reactionFrame.origin.x -= 9.0 - reactionFrame.size.width += 18.0 - } - self.reactionNodes[i].updateLayout(size: reactionFrame.size, scale: reactionFrame.size.width / (maximizedReactionSize + 18.0), transition: transition, displayText: isMaximized) - - transition.updateFrame(node: self.reactionNodes[i], frame: reactionFrame, beginWithCurrentState: true) - - reactionX += reactionSize + reactionSpacing - } - - let mainBubbleFrame = CGRect(origin: CGPoint(x: anchorX - self.smallCircleSize - shadowBlur, y: backgroundFrame.maxY - shadowBlur - self.smallCircleSize - shadowBlur), size: CGSize(width: self.smallCircleSize * 2.0 + shadowBlur * 2.0, height: self.smallCircleSize * 2.0 + shadowBlur * 2.0)) - self.bubbleNodes[1].0.frame = mainBubbleFrame - self.bubbleNodes[1].1.frame = mainBubbleFrame - - let secondaryBubbleFrame = CGRect(origin: CGPoint(x: mainBubbleFrame.midX - 10.0 - (self.smallCircleSize + shadowBlur * 2.0) / 2.0, y: mainBubbleFrame.midY + 10.0 - (self.smallCircleSize + shadowBlur * 2.0) / 2.0), size: CGSize(width: self.smallCircleSize + shadowBlur * 2.0, height: self.smallCircleSize + shadowBlur * 2.0)) - self.bubbleNodes[0].0.frame = secondaryBubbleFrame - self.bubbleNodes[0].1.frame = secondaryBubbleFrame - } - - func animateIn() { - self.bubbleNodes[1].0.layer.animateScale(from: 0.01, to: 1.0, duration: 0.11, delay: 0.0, timingFunction: CAMediaTimingFunctionName.easeOut.rawValue) - self.bubbleNodes[1].1.layer.animateScale(from: 0.01, to: 1.0, duration: 0.11, delay: 0.0, timingFunction: CAMediaTimingFunctionName.easeOut.rawValue) - - self.bubbleNodes[0].0.layer.animateScale(from: 0.01, to: 1.0, duration: 0.11, delay: 0.05, timingFunction: CAMediaTimingFunctionName.easeOut.rawValue) - self.bubbleNodes[0].1.layer.animateScale(from: 0.01, to: 1.0, duration: 0.11, delay: 0.05, timingFunction: CAMediaTimingFunctionName.easeOut.rawValue) - - let backgroundOffset = CGPoint(x: -(self.backgroundNode.frame.width - shadowBlur) / 2.0 + 42.0, y: (self.backgroundNode.frame.height - shadowBlur) / 2.0) - let damping: CGFloat = 100.0 - - for i in 0 ..< self.reactionNodes.count { - let animationOffset: Double = 1.0 - Double(i) / Double(self.reactionNodes.count - 1) - var nodeOffset = CGPoint(x: self.reactionNodes[i].frame.minX - (self.backgroundNode.frame.minX + shadowBlur) / 2.0 - 42.0, y: self.reactionNodes[i].frame.minY - self.backgroundNode.frame.maxY - shadowBlur) - nodeOffset.x = -nodeOffset.x - nodeOffset.y = 30.0 - self.reactionNodes[i].layer.animateSpring(from: 0.01 as NSNumber, to: 1.0 as NSNumber, keyPath: "transform.scale", duration: 0.5 + animationOffset * 0.28, initialVelocity: 0.0, damping: damping) - self.reactionNodes[i].layer.animateSpring(from: NSValue(cgPoint: nodeOffset), to: NSValue(cgPoint: CGPoint()), keyPath: "position", duration: 0.5, initialVelocity: 0.0, damping: damping, additive: true) - } - - self.backgroundNode.layer.animateSpring(from: 0.01 as NSNumber, to: 1.0 as NSNumber, keyPath: "transform.scale", duration: 0.5, initialVelocity: 0.0, damping: damping) - self.backgroundNode.layer.animateSpring(from: NSValue(cgPoint: backgroundOffset), to: NSValue(cgPoint: CGPoint()), keyPath: "position", duration: 0.5, initialVelocity: 0.0, damping: damping, additive: true) - self.backgroundShadowNode.layer.animateSpring(from: 0.01 as NSNumber, to: 1.0 as NSNumber, keyPath: "transform.scale", duration: 0.5, initialVelocity: 0.0, damping: damping) - self.backgroundShadowNode.layer.animateSpring(from: NSValue(cgPoint: backgroundOffset), to: NSValue(cgPoint: CGPoint()), keyPath: "position", duration: 0.5, initialVelocity: 0.0, damping: damping, additive: true) - } - - func animateOut(into targetNode: ASImageNode?, hideTarget: Bool, completion: @escaping () -> Void) { - self.hapticFeedback.prepareTap() - - var completedContainer = false - var completedTarget = true - - let intermediateCompletion: () -> Void = { - if completedContainer && completedTarget { - completion() - } - } - - if let targetNode = targetNode { - for i in 0 ..< self.reactionNodes.count { - if let isMaximized = self.reactionNodes[i].isMaximized, isMaximized { - if let snapshotView = self.reactionNodes[i].view.snapshotContentTree() { - let targetSnapshotView = UIImageView() - targetSnapshotView.image = targetNode.image - targetSnapshotView.frame = self.view.convert(targetNode.bounds, from: targetNode.view) - self.reactionNodes[i].isHidden = true - self.view.addSubview(targetSnapshotView) - self.view.addSubview(snapshotView) - completedTarget = false - let targetPosition = self.view.convert(targetNode.bounds.center, from: targetNode.view) - let duration: Double = 0.3 - if hideTarget { - targetNode.isHidden = true - } - - snapshotView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.25, removeOnCompletion: false) - targetSnapshotView.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2) - targetSnapshotView.layer.animateScale(from: snapshotView.bounds.width / targetSnapshotView.bounds.width, to: 0.5, duration: 0.3, removeOnCompletion: false) - - - let sourcePoint = snapshotView.center - let midPoint = CGPoint(x: (sourcePoint.x + targetPosition.x) / 2.0, y: sourcePoint.y - 30.0) - - let x1 = sourcePoint.x - let y1 = sourcePoint.y - let x2 = midPoint.x - let y2 = midPoint.y - let x3 = targetPosition.x - let y3 = targetPosition.y - - let a = (x3 * (y2 - y1) + x2 * (y1 - y3) + x1 * (y3 - y2)) / ((x1 - x2) * (x1 - x3) * (x2 - x3)) - let b = (x1 * x1 * (y2 - y3) + x3 * x3 * (y1 - y2) + x2 * x2 * (y3 - y1)) / ((x1 - x2) * (x1 - x3) * (x2 - x3)) - let c = (x2 * x2 * (x3 * y1 - x1 * y3) + x2 * (x1 * x1 * y3 - x3 * x3 * y1) + x1 * x3 * (x3 - x1) * y2) / ((x1 - x2) * (x1 - x3) * (x2 - x3)) - - var keyframes: [AnyObject] = [] - for i in 0 ..< 10 { - let k = CGFloat(i) / CGFloat(10 - 1) - let x = sourcePoint.x * (1.0 - k) + targetPosition.x * k - let y = a * x * x + b * x + c - keyframes.append(NSValue(cgPoint: CGPoint(x: x, y: y))) - } - - snapshotView.layer.animateKeyframes(values: keyframes, duration: 0.3, keyPath: "position", removeOnCompletion: false, completion: { [weak self] _ in - if let strongSelf = self { - strongSelf.hapticFeedback.tap() - } - completedTarget = true - if hideTarget { - targetNode.isHidden = false - targetNode.layer.animateSpring(from: 0.5 as NSNumber, to: 1.0 as NSNumber, keyPath: "transform.scale", duration: duration, initialVelocity: 0.0, damping: 90.0) - } - intermediateCompletion() - }) - targetSnapshotView.layer.animateKeyframes(values: keyframes, duration: 0.3, keyPath: "position", removeOnCompletion: false) - - snapshotView.layer.animateScale(from: 1.0, to: (targetSnapshotView.bounds.width * 0.5) / snapshotView.bounds.width, duration: 0.3, removeOnCompletion: false) - } - break - } - } - } - - self.backgroundNode.layer.animateScale(from: 1.0, to: 0.01, duration: 0.2, removeOnCompletion: false) - self.backgroundShadowNode.layer.animateScale(from: 1.0, to: 0.01, duration: 0.2, removeOnCompletion: false) - self.backgroundNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false) - self.backgroundShadowNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false, completion: { _ in - completedContainer = true - intermediateCompletion() - }) - for (node, shadow) in self.bubbleNodes { - node.layer.animateScale(from: 1.0, to: 0.01, duration: 0.2, removeOnCompletion: false) - node.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false) - shadow.layer.animateScale(from: 1.0, to: 0.01, duration: 0.2, removeOnCompletion: false) - shadow.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false) - } - for i in 0 ..< self.reactionNodes.count { - self.reactionNodes[i].layer.animateScale(from: 1.0, to: 0.01, duration: 0.2, removeOnCompletion: false) - self.reactionNodes[i].layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false) - } - } - - func selectedReaction() -> ReactionGestureItem? { - if !self.hasSelectedNode { - return nil - } - for i in 0 ..< self.reactionNodes.count { - if let isMaximized = self.reactionNodes[i].isMaximized, isMaximized { - return self.reactionNodes[i].reaction - } - } - return nil - } -} -*/ diff --git a/submodules/ReactionSelectionNode/Sources/ReactionContextNode.swift b/submodules/ReactionSelectionNode/Sources/ReactionContextNode.swift deleted file mode 100644 index 1018936ef4..0000000000 --- a/submodules/ReactionSelectionNode/Sources/ReactionContextNode.swift +++ /dev/null @@ -1,523 +0,0 @@ -import Foundation -import AsyncDisplayKit -import Display -import AnimatedStickerNode -import TelegramCore -import TelegramPresentationData - -public final class ReactionContextItem { - public enum Reaction { - case like - case unlike - } - - public let reaction: ReactionContextItem.Reaction - - public init(reaction: ReactionContextItem.Reaction) { - self.reaction = reaction - } -} - -private let largeCircleSize: CGFloat = 16.0 -private let smallCircleSize: CGFloat = 8.0 - -private func generateBackgroundImage(foreground: UIColor, diameter: CGFloat, shadowBlur: CGFloat) -> UIImage? { - return generateImage(CGSize(width: diameter + shadowBlur * 2.0, height: diameter + shadowBlur * 2.0), rotatedContext: { size, context in - context.clear(CGRect(origin: CGPoint(), size: size)) - context.setFillColor(foreground.cgColor) - context.fillEllipse(in: CGRect(origin: CGPoint(x: shadowBlur, y: shadowBlur), size: CGSize(width: diameter, height: diameter))) - })?.stretchableImage(withLeftCapWidth: Int(shadowBlur + diameter / 2.0), topCapHeight: Int(shadowBlur + diameter / 2.0)) -} - -private func generateBackgroundShadowImage(shadow: UIColor, diameter: CGFloat, shadowBlur: CGFloat) -> UIImage? { - return generateImage(CGSize(width: diameter * 2.0 + shadowBlur * 2.0, height: diameter + shadowBlur * 2.0), rotatedContext: { size, context in - context.clear(CGRect(origin: CGPoint(), size: size)) - context.setFillColor(shadow.cgColor) - context.setShadow(offset: CGSize(), blur: shadowBlur, color: shadow.cgColor) - - context.fillEllipse(in: CGRect(origin: CGPoint(x: shadowBlur, y: shadowBlur), size: CGSize(width: diameter, height: diameter))) - context.fillEllipse(in: CGRect(origin: CGPoint(x: shadowBlur + diameter, y: shadowBlur), size: CGSize(width: diameter, height: diameter))) - context.fill(CGRect(origin: CGPoint(x: shadowBlur + diameter / 2.0, y: shadowBlur), size: CGSize(width: diameter, height: diameter))) - - context.setFillColor(UIColor.clear.cgColor) - context.setBlendMode(.copy) - - context.fillEllipse(in: CGRect(origin: CGPoint(x: shadowBlur, y: shadowBlur), size: CGSize(width: diameter, height: diameter))) - context.fillEllipse(in: CGRect(origin: CGPoint(x: shadowBlur + diameter, y: shadowBlur), size: CGSize(width: diameter, height: diameter))) - context.fill(CGRect(origin: CGPoint(x: shadowBlur + diameter / 2.0, y: shadowBlur), size: CGSize(width: diameter, height: diameter))) - })?.stretchableImage(withLeftCapWidth: Int(diameter + shadowBlur / 2.0), topCapHeight: Int(diameter / 2.0 + shadowBlur / 2.0)) -} - -private func generateBubbleImage(foreground: UIColor, diameter: CGFloat, shadowBlur: CGFloat) -> UIImage? { - return generateImage(CGSize(width: diameter + shadowBlur * 2.0, height: diameter + shadowBlur * 2.0), rotatedContext: { size, context in - context.clear(CGRect(origin: CGPoint(), size: size)) - context.setFillColor(foreground.cgColor) - context.fillEllipse(in: CGRect(origin: CGPoint(x: shadowBlur, y: shadowBlur), size: CGSize(width: diameter, height: diameter))) - })?.stretchableImage(withLeftCapWidth: Int(diameter / 2.0 + shadowBlur / 2.0), topCapHeight: Int(diameter / 2.0 + shadowBlur / 2.0)) -} - -private func generateBubbleShadowImage(shadow: UIColor, diameter: CGFloat, shadowBlur: CGFloat) -> UIImage? { - return generateImage(CGSize(width: diameter + shadowBlur * 2.0, height: diameter + shadowBlur * 2.0), rotatedContext: { size, context in - context.clear(CGRect(origin: CGPoint(), size: size)) - context.setFillColor(shadow.cgColor) - context.setShadow(offset: CGSize(), blur: shadowBlur, color: shadow.cgColor) - context.fillEllipse(in: CGRect(origin: CGPoint(x: shadowBlur, y: shadowBlur), size: CGSize(width: diameter, height: diameter))) - context.setShadow(offset: CGSize(), blur: 1.0, color: shadow.cgColor) - context.fillEllipse(in: CGRect(origin: CGPoint(x: shadowBlur, y: shadowBlur), size: CGSize(width: diameter, height: diameter))) - context.setFillColor(UIColor.clear.cgColor) - context.setBlendMode(.copy) - context.fillEllipse(in: CGRect(origin: CGPoint(x: shadowBlur, y: shadowBlur), size: CGSize(width: diameter, height: diameter))) - })?.stretchableImage(withLeftCapWidth: Int(diameter / 2.0 + shadowBlur / 2.0), topCapHeight: Int(diameter / 2.0 + shadowBlur / 2.0)) -} - -public final class ReactionContextNode: ASDisplayNode { - private let theme: PresentationTheme - private let items: [ReactionContextItem] - - private let backgroundNode: ASImageNode - private let backgroundShadowNode: ASImageNode - private let backgroundContainerNode: ASDisplayNode - - private let largeCircleNode: ASImageNode - private let largeCircleShadowNode: ASImageNode - - private let smallCircleNode: ASImageNode - private let smallCircleShadowNode: ASImageNode - - private let contentContainer: ASDisplayNode - private var itemNodes: [ReactionNode] = [] - private let disclosureButton: HighlightTrackingButtonNode - - private var isExpanded: Bool = true - private var highlightedReaction: ReactionContextItem.Reaction? - private var validLayout: (CGSize, UIEdgeInsets, CGRect)? - - public var reactionSelected: ((ReactionGestureItem) -> Void)? - - private let hapticFeedback = HapticFeedback() - - public init(account: Account, theme: PresentationTheme, items: [ReactionContextItem]) { - self.theme = theme - self.items = items - - let shadowBlur: CGFloat = 5.0 - - self.backgroundNode = ASImageNode() - self.backgroundNode.displayWithoutProcessing = true - self.backgroundNode.displaysAsynchronously = false - - self.backgroundShadowNode = ASImageNode() - self.backgroundShadowNode.displayWithoutProcessing = true - self.backgroundShadowNode.displaysAsynchronously = false - - self.backgroundContainerNode = ASDisplayNode() - self.backgroundContainerNode.allowsGroupOpacity = true - - self.largeCircleNode = ASImageNode() - self.largeCircleNode.displayWithoutProcessing = true - self.largeCircleNode.displaysAsynchronously = false - - self.largeCircleShadowNode = ASImageNode() - self.largeCircleShadowNode.displayWithoutProcessing = true - self.largeCircleShadowNode.displaysAsynchronously = false - - self.smallCircleNode = ASImageNode() - self.smallCircleNode.displayWithoutProcessing = true - self.smallCircleNode.displaysAsynchronously = false - - self.smallCircleShadowNode = ASImageNode() - self.smallCircleShadowNode.displayWithoutProcessing = true - self.smallCircleShadowNode.displaysAsynchronously = false - - self.backgroundNode.image = generateBackgroundImage(foreground: theme.contextMenu.backgroundColor.withAlphaComponent(1.0), diameter: 52.0, shadowBlur: shadowBlur) - - self.backgroundShadowNode.image = generateBackgroundShadowImage(shadow: UIColor(white: 0.0, alpha: 0.2), diameter: 52.0, shadowBlur: shadowBlur) - - self.largeCircleNode.image = generateBubbleImage(foreground: theme.contextMenu.backgroundColor.withAlphaComponent(1.0), diameter: largeCircleSize, shadowBlur: shadowBlur) - self.smallCircleNode.image = generateBubbleImage(foreground: theme.contextMenu.backgroundColor.withAlphaComponent(1.0), diameter: smallCircleSize, shadowBlur: shadowBlur) - - self.largeCircleShadowNode.image = generateBubbleShadowImage(shadow: UIColor(white: 0.0, alpha: 0.2), diameter: largeCircleSize, shadowBlur: shadowBlur) - self.smallCircleShadowNode.image = generateBubbleShadowImage(shadow: UIColor(white: 0.0, alpha: 0.2), diameter: smallCircleSize, shadowBlur: shadowBlur) - - self.contentContainer = ASDisplayNode() - self.contentContainer.clipsToBounds = true - - self.disclosureButton = HighlightTrackingButtonNode() - self.disclosureButton.hitTestSlop = UIEdgeInsets(top: -6.0, left: -6.0, bottom: -6.0, right: -6.0) - let buttonImage = generateImage(CGSize(width: 30.0, height: 30.0), rotatedContext: { size, context in - context.clear(CGRect(origin: CGPoint(), size: size)) - context.setFillColor(theme.contextMenu.dimColor.cgColor) - context.fillEllipse(in: CGRect(origin: CGPoint(), size: size)) - context.setBlendMode(.copy) - context.setStrokeColor(UIColor.clear.cgColor) - context.setLineWidth(2.0) - context.setLineCap(.round) - context.setLineJoin(.round) - context.beginPath() - context.move(to: CGPoint(x: 8.0, y: size.height / 2.0 + 3.0)) - context.addLine(to: CGPoint(x: size.width / 2.0, y: 11.0)) - context.addLine(to: CGPoint(x: size.width - 8.0, y: size.height / 2.0 + 3.0)) - context.strokePath() - }) - self.disclosureButton.setImage(buttonImage, for: []) - - super.init() - - self.addSubnode(self.smallCircleShadowNode) - self.addSubnode(self.largeCircleShadowNode) - self.addSubnode(self.backgroundShadowNode) - - self.backgroundContainerNode.addSubnode(self.smallCircleNode) - self.backgroundContainerNode.addSubnode(self.largeCircleNode) - self.backgroundContainerNode.addSubnode(self.backgroundNode) - self.addSubnode(self.backgroundContainerNode) - - self.contentContainer.addSubnode(self.disclosureButton) - - self.itemNodes = self.items.map { item in - let reactionItem: ReactionGestureItem - switch item.reaction { - case .like: - reactionItem = .like - case .unlike: - reactionItem = .unlike - } - return ReactionNode(account: account, theme: theme, reaction: reactionItem, maximizedReactionSize: 30.0, loadFirstFrame: true) - } - self.itemNodes.forEach(self.contentContainer.addSubnode) - - self.addSubnode(self.contentContainer) - - self.disclosureButton.addTarget(self, action: #selector(self.disclosurePressed), forControlEvents: .touchUpInside) - self.disclosureButton.highligthedChanged = { [weak self] highlighted in - if highlighted { - self?.disclosureButton.layer.animateScale(from: 1.0, to: 0.8, duration: 0.15, removeOnCompletion: false) - } else { - self?.disclosureButton.layer.animateScale(from: 0.8, to: 1.0, duration: 0.25) - } - } - } - - override public func didLoad() { - super.didLoad() - - self.view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.tapGesture(_:)))) - } - - public func updateLayout(size: CGSize, insets: UIEdgeInsets, anchorRect: CGRect, transition: ContainedViewLayoutTransition) { - self.updateLayout(size: size, insets: insets, anchorRect: anchorRect, transition: transition, animateInFromAnchorRect: nil, animateOutToAnchorRect: nil) - } - - private func calculateBackgroundFrame(containerSize: CGSize, insets: UIEdgeInsets, anchorRect: CGRect, contentSize: CGSize) -> (CGRect, Bool) { - var contentSize = contentSize - contentSize.width = max(52.0, contentSize.width) - contentSize.height = 52.0 - - let sideInset: CGFloat = 12.0 - let backgroundOffset: CGPoint = CGPoint(x: 22.0, y: -7.0) - - var rect: CGRect - let isLeftAligned: Bool - if anchorRect.maxX < containerSize.width - backgroundOffset.x - sideInset { - rect = CGRect(origin: CGPoint(x: anchorRect.maxX - contentSize.width + backgroundOffset.x, y: anchorRect.minY - contentSize.height + backgroundOffset.y), size: contentSize) - isLeftAligned = true - } else { - rect = CGRect(origin: CGPoint(x: anchorRect.minX - backgroundOffset.x - 4.0, y: anchorRect.minY - contentSize.height + backgroundOffset.y), size: contentSize) - isLeftAligned = false - } - rect.origin.x = max(sideInset, rect.origin.x) - rect.origin.y = max(insets.top + sideInset, rect.origin.y) - rect.origin.x = min(containerSize.width - contentSize.width - sideInset, rect.origin.x) - return (rect, isLeftAligned) - } - - private func updateLayout(size: CGSize, insets: UIEdgeInsets, anchorRect: CGRect, transition: ContainedViewLayoutTransition, animateInFromAnchorRect: CGRect?, animateOutToAnchorRect: CGRect?, animateReactionHighlight: Bool = false) { - self.validLayout = (size, insets, anchorRect) - - let sideInset: CGFloat = 12.0 - let itemSpacing: CGFloat = 6.0 - let minimizedItemSize: CGFloat = 30.0 - let maximizedItemSize: CGFloat = 30.0 - 18.0 - let shadowBlur: CGFloat = 5.0 - let verticalInset: CGFloat = 13.0 - let rowHeight: CGFloat = 30.0 - let rowSpacing: CGFloat = itemSpacing - - let columnCount = min(6, self.items.count) - let contentWidth = CGFloat(columnCount) * minimizedItemSize + (CGFloat(columnCount) - 1.0) * itemSpacing + sideInset * 2.0 - let rowCount = self.items.count / columnCount + (self.items.count % columnCount == 0 ? 0 : 1) - - let expandedRowCount = self.isExpanded ? rowCount : 1 - - let contentHeight = verticalInset * 2.0 + rowHeight * CGFloat(expandedRowCount) + CGFloat(expandedRowCount - 1) * rowSpacing - - let (backgroundFrame, isLeftAligned) = self.calculateBackgroundFrame(containerSize: size, insets: insets, anchorRect: anchorRect, contentSize: CGSize(width: contentWidth, height: contentHeight)) - - transition.updateFrame(node: self.contentContainer, frame: backgroundFrame) - - for i in 0 ..< self.items.count { - let rowIndex = i / columnCount - let columnIndex = i % columnCount - let row = CGFloat(rowIndex) - let column = CGFloat(columnIndex) - - let itemSize: CGFloat = minimizedItemSize - let itemOffset: CGFloat = 0.0 - - let itemFrame = CGRect(origin: CGPoint(x: sideInset + column * (minimizedItemSize + itemSpacing) - itemOffset, y: verticalInset + row * (rowHeight + rowSpacing) + floor((rowHeight - minimizedItemSize) / 2.0) - itemOffset), size: CGSize(width: itemSize, height: itemSize)) - transition.updateFrame(node: self.itemNodes[i], frame: itemFrame, beginWithCurrentState: true) - self.itemNodes[i].updateLayout(size: CGSize(width: itemSize, height: itemSize), scale: itemSize / (maximizedItemSize + 18.0), transition: transition, displayText: false) - self.itemNodes[i].updateIsAnimating(false, animated: false) - if rowIndex != 0 || columnIndex == columnCount - 1 { - if self.isExpanded { - if self.itemNodes[i].alpha.isZero { - self.itemNodes[i].alpha = 1.0 - if transition.isAnimated { - let delayOffset: Double = 1.0 - Double(columnIndex) / Double(columnCount - 1) - self.itemNodes[i].layer.animateSpring(from: 0.1 as NSNumber, to: 1.0 as NSNumber, keyPath: "transform.scale", duration: 0.4 + delayOffset * 0.32, initialVelocity: 0.0, damping: 95.0) - self.itemNodes[i].layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.05) - } - } - } else { - self.itemNodes[i].alpha = 0.0 - } - } else { - self.itemNodes[i].alpha = 1.0 - } - - if rowIndex == 0 && columnIndex == columnCount - 1 { - transition.updateFrame(node: self.disclosureButton, frame: itemFrame) - if self.isExpanded { - if self.disclosureButton.alpha.isEqual(to: 1.0) { - self.disclosureButton.alpha = 0.0 - if transition.isAnimated { - self.disclosureButton.layer.animateScale(from: 0.8, to: 0.1, duration: 0.2, removeOnCompletion: false) - self.disclosureButton.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, completion: { [weak self] _ in - self?.disclosureButton.layer.removeAnimation(forKey: "scale") - }) - } - } - } else { - self.disclosureButton.alpha = 1.0 - } - } - } - - let isInOverflow = backgroundFrame.maxY > anchorRect.minY - let backgroundAlpha: CGFloat = isInOverflow ? 1.0 : 0.8 - let shadowAlpha: CGFloat = isInOverflow ? 1.0 : 0.0 - transition.updateAlpha(node: self.backgroundContainerNode, alpha: backgroundAlpha) - transition.updateAlpha(node: self.backgroundShadowNode, alpha: shadowAlpha) - transition.updateAlpha(node: self.largeCircleShadowNode, alpha: shadowAlpha) - transition.updateAlpha(node: self.smallCircleShadowNode, alpha: shadowAlpha) - - transition.updateFrame(node: self.backgroundContainerNode, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: size.width, height: size.height))) - - transition.updateFrame(node: self.backgroundNode, frame: backgroundFrame.insetBy(dx: -shadowBlur, dy: -shadowBlur)) - transition.updateFrame(node: self.backgroundShadowNode, frame: backgroundFrame.insetBy(dx: -shadowBlur, dy: -shadowBlur)) - - let largeCircleFrame: CGRect - let smallCircleFrame: CGRect - if isLeftAligned { - largeCircleFrame = CGRect(origin: CGPoint(x: backgroundFrame.midX - floor(largeCircleSize / 2.0), y: backgroundFrame.maxY - largeCircleSize / 2.0), size: CGSize(width: largeCircleSize, height: largeCircleSize)) - smallCircleFrame = CGRect(origin: CGPoint(x: largeCircleFrame.maxX - 3.0, y: largeCircleFrame.maxY + 2.0), size: CGSize(width: smallCircleSize, height: smallCircleSize)) - } else { - largeCircleFrame = CGRect(origin: CGPoint(x: backgroundFrame.midX - floor(largeCircleSize / 2.0), y: backgroundFrame.maxY - largeCircleSize / 2.0), size: CGSize(width: largeCircleSize, height: largeCircleSize)) - smallCircleFrame = CGRect(origin: CGPoint(x: largeCircleFrame.minX + 3.0 - smallCircleSize, y: largeCircleFrame.maxY + 2.0), size: CGSize(width: smallCircleSize, height: smallCircleSize)) - } - - transition.updateFrame(node: self.largeCircleNode, frame: largeCircleFrame.insetBy(dx: -shadowBlur, dy: -shadowBlur)) - transition.updateFrame(node: self.largeCircleShadowNode, frame: largeCircleFrame.insetBy(dx: -shadowBlur, dy: -shadowBlur)) - transition.updateFrame(node: self.smallCircleNode, frame: smallCircleFrame.insetBy(dx: -shadowBlur, dy: -shadowBlur)) - transition.updateFrame(node: self.smallCircleShadowNode, frame: smallCircleFrame.insetBy(dx: -shadowBlur, dy: -shadowBlur)) - - if let animateInFromAnchorRect = animateInFromAnchorRect { - let springDuration: Double = 0.42 - let springDamping: CGFloat = 104.0 - - let sourceBackgroundFrame = self.calculateBackgroundFrame(containerSize: size, insets: insets, anchorRect: animateInFromAnchorRect, contentSize: CGSize(width: contentWidth, height: contentHeight)).0 - - self.layer.animateSpring(from: NSValue(cgPoint: CGPoint(x: sourceBackgroundFrame.minX - backgroundFrame.minX, y: sourceBackgroundFrame.minY - backgroundFrame.minY)), to: NSValue(cgPoint: CGPoint()), keyPath: "position", duration: springDuration, initialVelocity: 0.0, damping: springDamping, additive: true) - } else if let animateOutToAnchorRect = animateOutToAnchorRect { - let targetBackgroundFrame = self.calculateBackgroundFrame(containerSize: size, insets: insets, anchorRect: animateOutToAnchorRect, contentSize: CGSize(width: contentWidth, height: contentHeight)).0 - - self.layer.animatePosition(from: CGPoint(), to: CGPoint(x: targetBackgroundFrame.minX - backgroundFrame.minX, y: targetBackgroundFrame.minY - backgroundFrame.minY), duration: 0.2, removeOnCompletion: false, additive: true) - } - } - - public func animateIn(from sourceAnchorRect: CGRect) { - self.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.15) - - if let (size, insets, anchorRect) = self.validLayout { - self.updateLayout(size: size, insets: insets, anchorRect: anchorRect, transition: .immediate, animateInFromAnchorRect: sourceAnchorRect, animateOutToAnchorRect: nil) - } - - let smallCircleDuration: Double = 0.5 - let largeCircleDuration: Double = 0.5 - let largeCircleDelay: Double = 0.08 - let mainCircleDuration: Double = 0.5 - let mainCircleDelay: Double = 0.1 - - self.smallCircleNode.layer.animateSpring(from: 0.1 as NSNumber, to: 1.0 as NSNumber, keyPath: "transform.scale", duration: smallCircleDuration) - self.smallCircleShadowNode.layer.animateSpring(from: 0.1 as NSNumber, to: 1.0 as NSNumber, keyPath: "transform.scale", duration: smallCircleDuration) - - self.largeCircleNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.15, delay: largeCircleDelay) - self.largeCircleNode.layer.animateSpring(from: 0.1 as NSNumber, to: 1.0 as NSNumber, keyPath: "transform.scale", duration: largeCircleDuration, delay: largeCircleDelay) - self.largeCircleShadowNode.layer.animateSpring(from: 0.1 as NSNumber, to: 1.0 as NSNumber, keyPath: "transform.scale", duration: largeCircleDuration, delay: largeCircleDelay) - - self.backgroundNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.15, delay: mainCircleDelay) - self.backgroundNode.layer.animateSpring(from: 0.1 as NSNumber, to: 1.0 as NSNumber, keyPath: "transform.scale", duration: mainCircleDuration, delay: mainCircleDelay) - self.backgroundShadowNode.layer.animateSpring(from: 0.1 as NSNumber, to: 1.0 as NSNumber, keyPath: "transform.scale", duration: mainCircleDuration, delay: mainCircleDelay) - - if let itemNode = self.itemNodes.first { - itemNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.15, delay: mainCircleDelay) - itemNode.didAppear() - itemNode.layer.animateSpring(from: 0.1 as NSNumber, to: 1.0 as NSNumber, keyPath: "transform.scale", duration: mainCircleDuration, delay: mainCircleDelay, completion: { _ in - }) - } - } - - public func animateOut(to targetAnchorRect: CGRect?, animatingOutToReaction: Bool) { - self.backgroundNode.layer.animateAlpha(from: self.backgroundNode.alpha, to: 0.0, duration: 0.2, removeOnCompletion: false) - self.backgroundShadowNode.layer.animateAlpha(from: self.backgroundShadowNode.alpha, to: 0.0, duration: 0.2, removeOnCompletion: false) - self.largeCircleNode.layer.animateAlpha(from: self.largeCircleNode.alpha, to: 0.0, duration: 0.2, removeOnCompletion: false) - self.largeCircleShadowNode.layer.animateAlpha(from: self.largeCircleShadowNode.alpha, to: 0.0, duration: 0.2, removeOnCompletion: false) - self.smallCircleNode.layer.animateAlpha(from: self.smallCircleNode.alpha, to: 0.0, duration: 0.2, removeOnCompletion: false) - self.smallCircleShadowNode.layer.animateAlpha(from: self.smallCircleShadowNode.alpha, to: 0.0, duration: 0.2, removeOnCompletion: false) - for itemNode in self.itemNodes { - itemNode.layer.animateAlpha(from: itemNode.alpha, to: 0.0, duration: 0.2, removeOnCompletion: false) - } - self.disclosureButton.layer.animateAlpha(from: self.disclosureButton.alpha, to: 0.0, duration: 0.2, removeOnCompletion: false) - - if let targetAnchorRect = targetAnchorRect, let (size, insets, anchorRect) = self.validLayout { - self.updateLayout(size: size, insets: insets, anchorRect: anchorRect, transition: .immediate, animateInFromAnchorRect: nil, animateOutToAnchorRect: targetAnchorRect) - } - } - - public func animateOutToReaction(value: String, targetEmptyNode: ASDisplayNode, targetFilledNode: ASDisplayNode, hideNode: Bool, completion: @escaping () -> Void) { - for itemNode in self.itemNodes { - switch itemNode.reaction { - case .like: - if let snapshotView = itemNode.view.snapshotContentTree(keepTransform: true), let targetSnapshotView = targetFilledNode.view.snapshotContentTree() { - targetSnapshotView.frame = self.view.convert(targetFilledNode.bounds, from: targetFilledNode.view) - itemNode.isHidden = true - self.view.addSubview(targetSnapshotView) - self.view.addSubview(snapshotView) - snapshotView.frame = itemNode.view.convert(itemNode.view.bounds, to: self.view) - - var completedTarget = false - let intermediateCompletion: () -> Void = { - if completedTarget { - completion() - } - } - - let targetPosition = self.view.convert(targetFilledNode.bounds.center, from: targetFilledNode.view) - let duration: Double = 0.3 - if hideNode { - targetFilledNode.isHidden = true - } - - snapshotView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.25, removeOnCompletion: false) - targetSnapshotView.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2) - targetSnapshotView.layer.animateScale(from: snapshotView.bounds.width / targetSnapshotView.bounds.width, to: 0.5, duration: 0.3, removeOnCompletion: false) - - let sourcePoint = snapshotView.center - let midPoint = CGPoint(x: (sourcePoint.x + targetPosition.x) / 2.0, y: sourcePoint.y - 30.0) - - let x1 = sourcePoint.x - let y1 = sourcePoint.y - let x2 = midPoint.x - let y2 = midPoint.y - let x3 = targetPosition.x - let y3 = targetPosition.y - - let a = (x3 * (y2 - y1) + x2 * (y1 - y3) + x1 * (y3 - y2)) / ((x1 - x2) * (x1 - x3) * (x2 - x3)) - let b = (x1 * x1 * (y2 - y3) + x3 * x3 * (y1 - y2) + x2 * x2 * (y3 - y1)) / ((x1 - x2) * (x1 - x3) * (x2 - x3)) - let c = (x2 * x2 * (x3 * y1 - x1 * y3) + x2 * (x1 * x1 * y3 - x3 * x3 * y1) + x1 * x3 * (x3 - x1) * y2) / ((x1 - x2) * (x1 - x3) * (x2 - x3)) - - var keyframes: [AnyObject] = [] - for i in 0 ..< 10 { - let k = CGFloat(i) / CGFloat(10 - 1) - let x = sourcePoint.x * (1.0 - k) + targetPosition.x * k - let y = a * x * x + b * x + c - keyframes.append(NSValue(cgPoint: CGPoint(x: x, y: y))) - } - - snapshotView.layer.animateKeyframes(values: keyframes, duration: 0.3, keyPath: "position", removeOnCompletion: false, completion: { [weak self] _ in - if let strongSelf = self { - strongSelf.hapticFeedback.tap() - } - completedTarget = true - if hideNode { - targetFilledNode.isHidden = false - targetFilledNode.layer.animateSpring(from: 0.5 as NSNumber, to: 1.0 as NSNumber, keyPath: "transform.scale", duration: duration, initialVelocity: 0.0, damping: 90.0) - targetEmptyNode.layer.animateSpring(from: 0.5 as NSNumber, to: 1.0 as NSNumber, keyPath: "transform.scale", duration: duration, initialVelocity: 0.0, damping: 90.0) - } - intermediateCompletion() - }) - targetSnapshotView.layer.animateKeyframes(values: keyframes, duration: 0.3, keyPath: "position", removeOnCompletion: false) - - snapshotView.layer.animateScale(from: 1.0, to: (targetSnapshotView.bounds.width * 0.5) / snapshotView.bounds.width, duration: 0.3, removeOnCompletion: false) - return - } - default: - break - } - } - completion() - } - - override public func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { - let contentPoint = self.contentContainer.view.convert(point, from: self.view) - if !self.disclosureButton.alpha.isZero { - if let result = self.disclosureButton.hitTest(self.disclosureButton.view.convert(point, from: self.view), with: event) { - return result - } - } - for itemNode in self.itemNodes { - if !itemNode.alpha.isZero && itemNode.frame.contains(contentPoint) { - return self.view - } - } - return nil - } - - @objc private func tapGesture(_ recognizer: UITapGestureRecognizer) { - if case .ended = recognizer.state { - let point = recognizer.location(in: self.view) - if let reaction = self.reaction(at: point) { - self.reactionSelected?(reaction) - } - } - } - - public func reaction(at point: CGPoint) -> ReactionGestureItem? { - let contentPoint = self.contentContainer.view.convert(point, from: self.view) - for itemNode in self.itemNodes { - if !itemNode.alpha.isZero && itemNode.frame.contains(contentPoint) { - return itemNode.reaction - } - } - for itemNode in self.itemNodes { - if !itemNode.alpha.isZero && itemNode.frame.insetBy(dx: -8.0, dy: -8.0).contains(contentPoint) { - return itemNode.reaction - } - } - return nil - } - - public func setHighlightedReaction(_ value: ReactionContextItem.Reaction?) { - self.highlightedReaction = value - if let (size, insets, anchorRect) = self.validLayout { - self.updateLayout(size: size, insets: insets, anchorRect: anchorRect, transition: .animated(duration: 0.18, curve: .easeInOut), animateInFromAnchorRect: nil, animateOutToAnchorRect: nil, animateReactionHighlight: true) - } - } - - @objc private func disclosurePressed() { - self.isExpanded = true - if let (size, insets, anchorRect) = self.validLayout { - self.updateLayout(size: size, insets: insets, anchorRect: anchorRect, transition: .animated(duration: 0.3, curve: .spring), animateInFromAnchorRect: nil, animateOutToAnchorRect: nil, animateReactionHighlight: true) - } - } -} diff --git a/submodules/ReactionSelectionNode/Sources/ReactionGestureItem.swift b/submodules/ReactionSelectionNode/Sources/ReactionGestureItem.swift deleted file mode 100644 index e1adfa2fe8..0000000000 --- a/submodules/ReactionSelectionNode/Sources/ReactionGestureItem.swift +++ /dev/null @@ -1,8 +0,0 @@ -import Foundation -import Postbox -import TelegramCore - -public enum ReactionGestureItem { - case like - case unlike -} diff --git a/submodules/ReactionSelectionNode/Sources/ReactionSelectionNode.swift b/submodules/ReactionSelectionNode/Sources/ReactionSelectionNode.swift deleted file mode 100644 index b6f695e21c..0000000000 --- a/submodules/ReactionSelectionNode/Sources/ReactionSelectionNode.swift +++ /dev/null @@ -1,487 +0,0 @@ -import Foundation -import AsyncDisplayKit -import Display -import Postbox -import TelegramCore -import TelegramPresentationData -import AppBundle -import AnimatedStickerNode -import TelegramAnimatedStickerNode - -private func generateBubbleImage(foreground: UIColor, diameter: CGFloat, shadowBlur: CGFloat) -> UIImage? { - return generateImage(CGSize(width: diameter + shadowBlur * 2.0, height: diameter + shadowBlur * 2.0), rotatedContext: { size, context in - context.clear(CGRect(origin: CGPoint(), size: size)) - context.setFillColor(foreground.cgColor) - context.fillEllipse(in: CGRect(origin: CGPoint(x: shadowBlur, y: shadowBlur), size: CGSize(width: diameter, height: diameter))) - })?.stretchableImage(withLeftCapWidth: Int(diameter / 2.0 + shadowBlur / 2.0), topCapHeight: Int(diameter / 2.0 + shadowBlur / 2.0)) -} - -private func generateBubbleShadowImage(shadow: UIColor, diameter: CGFloat, shadowBlur: CGFloat) -> UIImage? { - return generateImage(CGSize(width: diameter + shadowBlur * 2.0, height: diameter + shadowBlur * 2.0), rotatedContext: { size, context in - context.clear(CGRect(origin: CGPoint(), size: size)) - context.setFillColor(UIColor.white.cgColor) - context.setShadow(offset: CGSize(), blur: shadowBlur, color: shadow.cgColor) - context.fillEllipse(in: CGRect(origin: CGPoint(x: shadowBlur, y: shadowBlur), size: CGSize(width: diameter, height: diameter))) - context.setShadow(offset: CGSize(), blur: 1.0, color: shadow.cgColor) - context.fillEllipse(in: CGRect(origin: CGPoint(x: shadowBlur, y: shadowBlur), size: CGSize(width: diameter, height: diameter))) - context.setFillColor(UIColor.clear.cgColor) - context.setBlendMode(.copy) - context.fillEllipse(in: CGRect(origin: CGPoint(x: shadowBlur, y: shadowBlur), size: CGSize(width: diameter, height: diameter))) - })?.stretchableImage(withLeftCapWidth: Int(diameter / 2.0 + shadowBlur / 2.0), topCapHeight: Int(diameter / 2.0 + shadowBlur / 2.0)) -} - -private let font = Font.medium(13.0) - -final class ReactionNode: ASDisplayNode { - let reaction: ReactionGestureItem - private let textBackgroundNode: ASImageNode - private let textNode: ImmediateTextNode - private let animationNode: AnimatedStickerNode - private let imageNode: ASImageNode - private let additionalImageNode: ASImageNode - var isMaximized: Bool? - private let intrinsicSize: CGSize - private let intrinsicOffset: CGPoint - - init(account: Account, theme: PresentationTheme, reaction: ReactionGestureItem, maximizedReactionSize: CGFloat, loadFirstFrame: Bool) { - self.reaction = reaction - - self.textBackgroundNode = ASImageNode() - self.textBackgroundNode.displaysAsynchronously = false - self.textBackgroundNode.displayWithoutProcessing = true - self.textBackgroundNode.image = generateStretchableFilledCircleImage(diameter: 20.0, color: theme.chat.serviceMessage.components.withDefaultWallpaper.dateFillFloating.withAlphaComponent(0.8)) - self.textBackgroundNode.alpha = 0.0 - - self.textNode = ImmediateTextNode() - self.textNode.displaysAsynchronously = false - self.textNode.isUserInteractionEnabled = false - - let reactionText: String = "" - - self.textNode.attributedText = NSAttributedString(string: reactionText, font: font, textColor: theme.chat.serviceMessage.dateTextColor.withWallpaper) - let textSize = self.textNode.updateLayout(CGSize(width: 200.0, height: 100.0)) - let textBackgroundSize = CGSize(width: textSize.width + 12.0, height: 20.0) - let textBackgroundFrame = CGRect(origin: CGPoint(), size: textBackgroundSize) - let textFrame = CGRect(origin: CGPoint(x: floor((textBackgroundFrame.width - textSize.width) / 2.0), y: floor((textBackgroundFrame.height - textSize.height) / 2.0)), size: textSize) - self.textBackgroundNode.frame = textBackgroundFrame - self.textNode.frame = textFrame - self.textNode.alpha = 0.0 - - self.animationNode = AnimatedStickerNode() - self.animationNode.automaticallyLoadFirstFrame = loadFirstFrame - self.animationNode.playToCompletionOnStop = true - - var intrinsicSize = CGSize(width: maximizedReactionSize + 14.0, height: maximizedReactionSize + 14.0) - - self.imageNode = ASImageNode() - self.additionalImageNode = ASImageNode() - switch reaction { - case .like: - self.intrinsicOffset = CGPoint(x: 0.0, y: 0.0) - self.imageNode.image = generateTintedImage(image: UIImage(bundleImageName: "Chat/Reactions/ContextHeartFilled"), color: UIColor(rgb: 0xfe1512)) - case .unlike: - self.intrinsicOffset = CGPoint(x: 0.0, y: 0.0) - self.imageNode.image = generateTintedImage(image: UIImage(bundleImageName: "Chat/Reactions/ContextHeartBrokenL"), color: UIColor(rgb: 0xfe1512)) - self.additionalImageNode.image = generateTintedImage(image: UIImage(bundleImageName: "Chat/Reactions/ContextHeartBrokenR"), color: UIColor(rgb: 0xfe1512)) - } - - if let image = self.imageNode.image { - intrinsicSize = image.size - } - - self.intrinsicSize = intrinsicSize - - super.init() - - //self.backgroundColor = .gray - - //self.textBackgroundNode.addSubnode(self.textNode) - //self.addSubnode(self.textBackgroundNode) - - //self.addSubnode(self.animationNode) - self.addSubnode(self.imageNode) - self.addSubnode(self.additionalImageNode) - self.animationNode.updateLayout(size: self.intrinsicSize) - self.animationNode.frame = CGRect(origin: CGPoint(), size: self.intrinsicSize) - - switch reaction { - case .like: - self.imageNode.frame = CGRect(origin: CGPoint(x: -5.0, y: -5.0), size: self.intrinsicSize) - case .unlike: - self.imageNode.frame = CGRect(origin: CGPoint(x: -6.0, y: -5.0), size: self.intrinsicSize) - self.additionalImageNode.frame = CGRect(origin: CGPoint(x: -3.0, y: -5.0), size: self.intrinsicSize) - } - } - - func updateLayout(size: CGSize, scale: CGFloat, transition: ContainedViewLayoutTransition, displayText: Bool) { - /*transition.updatePosition(node: self.animationNode, position: CGPoint(x: size.width / 2.0 + self.intrinsicOffset.x * scale, y: size.height / 2.0 + self.intrinsicOffset.y * scale), beginWithCurrentState: true) - transition.updateTransformScale(node: self.animationNode, scale: scale, beginWithCurrentState: true) - transition.updatePosition(node: self.imageNode, position: CGPoint(x: size.width / 2.0 + self.intrinsicOffset.x * scale, y: size.height / 2.0 + self.intrinsicOffset.y * scale), beginWithCurrentState: true) - transition.updateTransformScale(node: self.imageNode, scale: scale, beginWithCurrentState: true) - - transition.updatePosition(node: self.textBackgroundNode, position: CGPoint(x: size.width / 2.0, y: displayText ? -24.0 : (size.height / 2.0)), beginWithCurrentState: true) - transition.updateTransformScale(node: self.textBackgroundNode, scale: displayText ? 1.0 : 0.1, beginWithCurrentState: true) - - transition.updateAlpha(node: self.textBackgroundNode, alpha: displayText ? 1.0 : 0.0, beginWithCurrentState: true) - transition.updateAlpha(node: self.textNode, alpha: displayText ? 1.0 : 0.0, beginWithCurrentState: true)*/ - } - - func updateIsAnimating(_ isAnimating: Bool, animated: Bool) { - if isAnimating { - self.animationNode.visibility = true - } else { - self.animationNode.visibility = false - } - } - - func didAppear() { - switch self.reaction { - case .like: - self.imageNode.layer.animateScale(from: 1.0, to: 1.08, duration: 0.12, delay: 0.22, removeOnCompletion: false, completion: { [weak self] _ in - guard let strongSelf = self else { - return - } - strongSelf.imageNode.layer.animateScale(from: 1.08, to: 1.0, duration: 0.12) - }) - case .unlike: - self.imageNode.layer.animatePosition(from: CGPoint(x: -2.5, y: 0.0), to: CGPoint(), duration: 0.2, delay: 0.15, additive: true) - self.additionalImageNode.layer.animatePosition(from: CGPoint(x: 2.5, y: 0.0), to: CGPoint(), duration: 0.2, delay: 0.15, additive: true) - } - } -} - -final class ReactionSelectionNode: ASDisplayNode { - private let account: Account - private let theme: PresentationTheme - private let reactions: [ReactionGestureItem] - - private let backgroundNode: ASImageNode - private let backgroundShadowNode: ASImageNode - private let bubbleNodes: [(ASImageNode, ASImageNode)] - private var reactionNodes: [ReactionNode] = [] - private var hasSelectedNode = false - - private let hapticFeedback = HapticFeedback() - - private var shadowBlur: CGFloat = 8.0 - private var minimizedReactionSize: CGFloat = 28.0 - private var smallCircleSize: CGFloat = 14.0 - - private var isRightAligned: Bool = false - - public init(account: Account, theme: PresentationTheme, reactions: [ReactionGestureItem]) { - self.account = account - self.theme = theme - self.reactions = reactions - - self.backgroundNode = ASImageNode() - self.backgroundNode.displaysAsynchronously = false - self.backgroundNode.displayWithoutProcessing = true - - self.backgroundShadowNode = ASImageNode() - self.backgroundShadowNode.displaysAsynchronously = false - self.backgroundShadowNode.displayWithoutProcessing = true - - self.bubbleNodes = (0 ..< 2).map { i -> (ASImageNode, ASImageNode) in - let imageNode = ASImageNode() - imageNode.displaysAsynchronously = false - imageNode.displayWithoutProcessing = true - - let shadowNode = ASImageNode() - shadowNode.displaysAsynchronously = false - shadowNode.displayWithoutProcessing = true - - return (imageNode, shadowNode) - } - - super.init() - - self.bubbleNodes.forEach { _, shadow in - //self.addSubnode(shadow) - } - self.addSubnode(self.backgroundShadowNode) - self.bubbleNodes.forEach { foreground, _ in - //self.addSubnode(foreground) - } - self.addSubnode(self.backgroundNode) - } - - func updateLayout(constrainedSize: CGSize, startingPoint: CGPoint, offsetFromStart: CGFloat, isInitial: Bool, touchPoint: CGPoint) { - let initialAnchorX = startingPoint.x - - var isRightAligned = false - if initialAnchorX > constrainedSize.width / 2.0 { - isRightAligned = true - } - - let reactionSideInset: CGFloat = 10.0 - let reactionSpacing: CGFloat = 6.0 - let minReactionSpacing: CGFloat = 2.0 - let minimizedReactionSize = self.minimizedReactionSize - let contentWidth: CGFloat = CGFloat(self.reactions.count) * (minimizedReactionSize) + CGFloat(self.reactions.count - 1) * reactionSpacing + reactionSideInset * 2.0 - let spaceForMaximizedReaction = CGFloat(self.reactions.count - 1) * reactionSpacing - CGFloat(self.reactions.count - 1) * minReactionSpacing - let maximizedReactionSize: CGFloat = minimizedReactionSize + spaceForMaximizedReaction - let backgroundHeight: CGFloat = floor(self.minimizedReactionSize * 1.8) - - var backgroundFrame = CGRect(origin: CGPoint(x: -shadowBlur, y: -shadowBlur), size: CGSize(width: contentWidth + shadowBlur * 2.0, height: backgroundHeight + shadowBlur * 2.0)) - if constrainedSize.width > 500.0 { - backgroundFrame = backgroundFrame.offsetBy(dx: constrainedSize.width - contentWidth - 44.0, dy: startingPoint.y - backgroundHeight - 12.0) - } else { - backgroundFrame = backgroundFrame.offsetBy(dx: floor((constrainedSize.width - contentWidth) / 2.0), dy: startingPoint.y - backgroundHeight - 12.0) - } - backgroundFrame.origin.x = max(0.0, backgroundFrame.minX) - backgroundFrame.origin.x = min(constrainedSize.width - backgroundFrame.width, backgroundFrame.minX) - - let anchorMinX = backgroundFrame.minX + shadowBlur + backgroundHeight / 2.0 - let anchorMaxX = backgroundFrame.maxX - shadowBlur - backgroundHeight / 2.0 - let anchorX = max(anchorMinX, min(anchorMaxX, offsetFromStart)) - - var maximizedIndex = -1 - /*if let reaction = self.reactions.last, case .reply = reaction { - maximizedIndex = self.reactions.count - 1 - }*/ - if backgroundFrame.insetBy(dx: -10.0, dy: -10.0).offsetBy(dx: 0.0, dy: 10.0).contains(touchPoint) { - maximizedIndex = Int(((touchPoint.x - anchorMinX) / (anchorMaxX - anchorMinX)) * CGFloat(self.reactionNodes.count)) - maximizedIndex = max(0, min(self.reactionNodes.count - 1, maximizedIndex)) - } - - let interReactionSpacing: CGFloat - if maximizedIndex != -1 { - interReactionSpacing = minReactionSpacing - } else { - interReactionSpacing = reactionSpacing - } - - if isInitial && self.reactionNodes.isEmpty { - self.shadowBlur = floor(minimizedReactionSize * 0.26) - self.smallCircleSize = 14.0 - - self.backgroundNode.image = generateBubbleImage(foreground: .white, diameter: backgroundHeight, shadowBlur: self.shadowBlur) - self.backgroundShadowNode.image = generateBubbleShadowImage(shadow: UIColor(white: 0.0, alpha: 0.2), diameter: backgroundHeight, shadowBlur: self.shadowBlur) - for i in 0 ..< self.bubbleNodes.count { - self.bubbleNodes[i].0.image = generateBubbleImage(foreground: .white, diameter: CGFloat(i + 1) * self.smallCircleSize, shadowBlur: self.shadowBlur) - self.bubbleNodes[i].1.image = generateBubbleShadowImage(shadow: UIColor(white: 0.0, alpha: 0.2), diameter: CGFloat(i + 1) * self.smallCircleSize, shadowBlur: self.shadowBlur) - } - - self.reactionNodes = self.reactions.map { reaction -> ReactionNode in - return ReactionNode(account: self.account, theme: self.theme, reaction: reaction, maximizedReactionSize: maximizedReactionSize - 12.0, loadFirstFrame: true) - } - self.reactionNodes.forEach(self.addSubnode(_:)) - } - - let minimizedReactionVerticalInset: CGFloat = floor((backgroundHeight - minimizedReactionSize) / 2.0) - - - /*if maximizedIndex == -1 { - backgroundFrame.size.width -= maximizedReactionSize - minimizedReactionSize - backgroundFrame.origin.x += maximizedReactionSize - minimizedReactionSize - }*/ - - self.isRightAligned = isRightAligned - - let backgroundTransition: ContainedViewLayoutTransition - if isInitial { - backgroundTransition = .immediate - } else { - backgroundTransition = .animated(duration: 0.18, curve: .easeInOut) - } - backgroundTransition.updateFrame(node: self.backgroundNode, frame: backgroundFrame) - backgroundTransition.updateFrame(node: self.backgroundShadowNode, frame: backgroundFrame) - - var reactionX: CGFloat = backgroundFrame.minX + shadowBlur + reactionSideInset - if maximizedIndex != -1 { - self.hasSelectedNode = false - } else { - self.hasSelectedNode = true - } - - for iterationIndex in 0 ..< self.reactionNodes.count { - var i = iterationIndex - let isMaximized = i == maximizedIndex - if !isRightAligned { - i = self.reactionNodes.count - 1 - i - } - - let reactionSize: CGFloat - if isMaximized { - reactionSize = maximizedReactionSize - } else { - reactionSize = minimizedReactionSize - } - - let transition: ContainedViewLayoutTransition - if isInitial { - transition = .immediate - } else { - transition = .animated(duration: 0.18, curve: .easeInOut) - } - - if self.reactionNodes[i].isMaximized != isMaximized { - self.reactionNodes[i].isMaximized = isMaximized - self.reactionNodes[i].updateIsAnimating(isMaximized, animated: !isInitial) - if isMaximized && !isInitial { - self.hapticFeedback.tap() - } - } - - var reactionFrame = CGRect(origin: CGPoint(x: reactionX, y: backgroundFrame.maxY - shadowBlur - minimizedReactionVerticalInset - reactionSize), size: CGSize(width: reactionSize, height: reactionSize)) - if isMaximized { - reactionFrame.origin.x -= 7.0 - reactionFrame.size.width += 14.0 - } - self.reactionNodes[i].updateLayout(size: reactionFrame.size, scale: reactionFrame.size.width / (maximizedReactionSize + 14.0), transition: transition, displayText: isMaximized) - - transition.updateFrame(node: self.reactionNodes[i], frame: reactionFrame, beginWithCurrentState: true) - - reactionX += reactionSize + interReactionSpacing - } - - let mainBubbleFrame = CGRect(origin: CGPoint(x: anchorX - self.smallCircleSize - shadowBlur, y: backgroundFrame.maxY - shadowBlur - self.smallCircleSize - shadowBlur), size: CGSize(width: self.smallCircleSize * 2.0 + shadowBlur * 2.0, height: self.smallCircleSize * 2.0 + shadowBlur * 2.0)) - self.bubbleNodes[1].0.frame = mainBubbleFrame - self.bubbleNodes[1].1.frame = mainBubbleFrame - - let secondaryBubbleFrame = CGRect(origin: CGPoint(x: mainBubbleFrame.midX - 10.0 - (self.smallCircleSize + shadowBlur * 2.0) / 2.0, y: mainBubbleFrame.midY + 10.0 - (self.smallCircleSize + shadowBlur * 2.0) / 2.0), size: CGSize(width: self.smallCircleSize + shadowBlur * 2.0, height: self.smallCircleSize + shadowBlur * 2.0)) - self.bubbleNodes[0].0.frame = secondaryBubbleFrame - self.bubbleNodes[0].1.frame = secondaryBubbleFrame - } - - func animateIn() { - self.bubbleNodes[1].0.layer.animateScale(from: 0.01, to: 1.0, duration: 0.11, delay: 0.0, timingFunction: CAMediaTimingFunctionName.easeOut.rawValue) - self.bubbleNodes[1].1.layer.animateScale(from: 0.01, to: 1.0, duration: 0.11, delay: 0.0, timingFunction: CAMediaTimingFunctionName.easeOut.rawValue) - - self.bubbleNodes[0].0.layer.animateScale(from: 0.01, to: 1.0, duration: 0.11, delay: 0.05, timingFunction: CAMediaTimingFunctionName.easeOut.rawValue) - self.bubbleNodes[0].1.layer.animateScale(from: 0.01, to: 1.0, duration: 0.11, delay: 0.05, timingFunction: CAMediaTimingFunctionName.easeOut.rawValue) - - let backgroundOffset: CGPoint - if self.isRightAligned { - backgroundOffset = CGPoint(x: (self.backgroundNode.frame.width - shadowBlur) / 2.0 - 42.0, y: 10.0) - } else { - backgroundOffset = CGPoint(x: -(self.backgroundNode.frame.width - shadowBlur) / 2.0 + 42.0, y: 10.0) - } - let damping: CGFloat = 100.0 - - for i in 0 ..< self.reactionNodes.count { - let animationOffset: Double = 1.0 - Double(i) / Double(self.reactionNodes.count - 1) - var nodeOffset: CGPoint - if self.isRightAligned { - nodeOffset = CGPoint(x: self.reactionNodes[i].frame.minX - (self.backgroundNode.frame.maxX - shadowBlur) / 2.0 - 42.0, y: 10.0) - } else { - nodeOffset = CGPoint(x: self.reactionNodes[i].frame.minX - (self.backgroundNode.frame.minX + shadowBlur) / 2.0 - 42.0, y: 10.0) - } - nodeOffset.x = 0.0 - nodeOffset.y = 30.0 - self.reactionNodes[i].layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.04, delay: animationOffset * 0.1) - self.reactionNodes[i].layer.animateSpring(from: 0.01 as NSNumber, to: 1.0 as NSNumber, keyPath: "transform.scale", duration: 0.5, delay: animationOffset * 0.1, initialVelocity: 0.0, damping: damping) - //self.reactionNodes[i].layer.animateSpring(from: NSValue(cgPoint: nodeOffset), to: NSValue(cgPoint: CGPoint()), keyPath: "position", duration: 0.5, delay: animationOffset * 0.1, initialVelocity: 0.0, damping: damping, additive: true) - } - - self.backgroundNode.layer.animateSpring(from: 0.01 as NSNumber, to: 1.0 as NSNumber, keyPath: "transform.scale", duration: 0.5, initialVelocity: 0.0, damping: damping) - self.backgroundNode.layer.animateSpring(from: NSValue(cgPoint: backgroundOffset), to: NSValue(cgPoint: CGPoint()), keyPath: "position", duration: 0.5, initialVelocity: 0.0, damping: damping, additive: true) - self.backgroundShadowNode.layer.animateSpring(from: 0.01 as NSNumber, to: 1.0 as NSNumber, keyPath: "transform.scale", duration: 0.5, initialVelocity: 0.0, damping: damping) - self.backgroundShadowNode.layer.animateSpring(from: NSValue(cgPoint: backgroundOffset), to: NSValue(cgPoint: CGPoint()), keyPath: "position", duration: 0.5, initialVelocity: 0.0, damping: damping, additive: true) - } - - func animateOut(into targetNode: ASDisplayNode?, hideTarget: Bool, completion: @escaping () -> Void) { - self.hapticFeedback.prepareTap() - - var completedContainer = false - var completedTarget = true - - let intermediateCompletion: () -> Void = { - if completedContainer && completedTarget { - completion() - } - } - - if let targetNode = targetNode { - for i in 0 ..< self.reactionNodes.count { - if let isMaximized = self.reactionNodes[i].isMaximized, isMaximized { - targetNode.recursivelyEnsureDisplaySynchronously(true) - if let snapshotView = self.reactionNodes[i].view.snapshotContentTree(), let targetSnapshotView = targetNode.view.snapshotContentTree() { - targetSnapshotView.frame = self.view.convert(targetNode.bounds, from: targetNode.view) - self.reactionNodes[i].isHidden = true - self.view.addSubview(targetSnapshotView) - self.view.addSubview(snapshotView) - completedTarget = false - let targetPosition = self.view.convert(targetNode.bounds.center, from: targetNode.view) - let duration: Double = 0.3 - if hideTarget { - targetNode.isHidden = true - } - - snapshotView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.25, removeOnCompletion: false) - targetSnapshotView.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2) - targetSnapshotView.layer.animateScale(from: snapshotView.bounds.width / targetSnapshotView.bounds.width, to: 0.5, duration: 0.3, removeOnCompletion: false) - - - let sourcePoint = snapshotView.center - let midPoint = CGPoint(x: (sourcePoint.x + targetPosition.x) / 2.0, y: sourcePoint.y - 30.0) - - let x1 = sourcePoint.x - let y1 = sourcePoint.y - let x2 = midPoint.x - let y2 = midPoint.y - let x3 = targetPosition.x - let y3 = targetPosition.y - - let a = (x3 * (y2 - y1) + x2 * (y1 - y3) + x1 * (y3 - y2)) / ((x1 - x2) * (x1 - x3) * (x2 - x3)) - let b = (x1 * x1 * (y2 - y3) + x3 * x3 * (y1 - y2) + x2 * x2 * (y3 - y1)) / ((x1 - x2) * (x1 - x3) * (x2 - x3)) - let c = (x2 * x2 * (x3 * y1 - x1 * y3) + x2 * (x1 * x1 * y3 - x3 * x3 * y1) + x1 * x3 * (x3 - x1) * y2) / ((x1 - x2) * (x1 - x3) * (x2 - x3)) - - var keyframes: [AnyObject] = [] - for i in 0 ..< 10 { - let k = CGFloat(i) / CGFloat(10 - 1) - let x = sourcePoint.x * (1.0 - k) + targetPosition.x * k - let y = a * x * x + b * x + c - keyframes.append(NSValue(cgPoint: CGPoint(x: x, y: y))) - } - - snapshotView.layer.animateKeyframes(values: keyframes, duration: 0.3, keyPath: "position", removeOnCompletion: false, completion: { [weak self] _ in - if let strongSelf = self { - strongSelf.hapticFeedback.tap() - } - completedTarget = true - if hideTarget { - targetNode.isHidden = false - targetNode.layer.animateSpring(from: 0.5 as NSNumber, to: 1.0 as NSNumber, keyPath: "transform.scale", duration: duration, initialVelocity: 0.0, damping: 90.0) - } - intermediateCompletion() - }) - targetSnapshotView.layer.animateKeyframes(values: keyframes, duration: 0.3, keyPath: "position", removeOnCompletion: false) - - snapshotView.layer.animateScale(from: 1.0, to: (targetSnapshotView.bounds.width * 0.5) / snapshotView.bounds.width, duration: 0.3, removeOnCompletion: false) - } - break - } - } - } - - //self.backgroundNode.layer.animateScale(from: 1.0, to: 0.01, duration: 0.2, removeOnCompletion: false) - self.backgroundShadowNode.layer.animateScale(from: 1.0, to: 0.01, duration: 0.2, removeOnCompletion: false) - self.backgroundNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false) - self.backgroundShadowNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false, completion: { _ in - completedContainer = true - intermediateCompletion() - }) - for (node, shadow) in self.bubbleNodes { - node.layer.animateScale(from: 1.0, to: 0.01, duration: 0.2, removeOnCompletion: false) - node.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false) - shadow.layer.animateScale(from: 1.0, to: 0.01, duration: 0.2, removeOnCompletion: false) - shadow.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false) - } - for i in 0 ..< self.reactionNodes.count { - self.reactionNodes[i].layer.animateScale(from: 1.0, to: 0.01, duration: 0.2, removeOnCompletion: false) - self.reactionNodes[i].layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false) - } - } - - func selectedReaction() -> ReactionGestureItem? { - for i in 0 ..< self.reactionNodes.count { - if let isMaximized = self.reactionNodes[i].isMaximized, isMaximized { - return self.reactionNodes[i].reaction - } - } - return nil - } -} - diff --git a/submodules/ReactionSelectionNode/Sources/ReactionSelectionParentNode.swift b/submodules/ReactionSelectionNode/Sources/ReactionSelectionParentNode.swift deleted file mode 100644 index 7c3889ce76..0000000000 --- a/submodules/ReactionSelectionNode/Sources/ReactionSelectionParentNode.swift +++ /dev/null @@ -1,85 +0,0 @@ -import Foundation -import AsyncDisplayKit -import Display -import Postbox -import TelegramCore -import TelegramPresentationData - -public final class ReactionSelectionParentNode: ASDisplayNode { - private let account: Account - private let theme: PresentationTheme - - private var currentNode: ReactionSelectionNode? - private var currentLocation: (CGPoint, CGFloat, CGPoint)? - - private var validLayout: (size: CGSize, insets: UIEdgeInsets)? - - public init(account: Account, theme: PresentationTheme) { - self.account = account - self.theme = theme - - super.init() - } - - func displayReactions(_ reactions: [ReactionGestureItem], at point: CGPoint, touchPoint: CGPoint) { - if let currentNode = self.currentNode { - currentNode.removeFromSupernode() - self.currentNode = nil - } - - let reactionNode = ReactionSelectionNode(account: self.account, theme: self.theme, reactions: reactions) - self.addSubnode(reactionNode) - self.currentNode = reactionNode - self.currentLocation = (point, point.x, touchPoint) - - if let (size, insets) = self.validLayout { - self.update(size: size, insets: insets, isInitial: true) - - reactionNode.animateIn() - } - } - - func selectedReaction() -> ReactionGestureItem? { - if let currentNode = self.currentNode { - return currentNode.selectedReaction() - } - return nil - } - - func dismissReactions(into targetNode: ASDisplayNode?, hideTarget: Bool) { - if let currentNode = self.currentNode { - currentNode.animateOut(into: targetNode, hideTarget: hideTarget, completion: { [weak currentNode] in - currentNode?.removeFromSupernode() - }) - self.currentNode = nil - } - } - - func updateReactionsAnchor(point: CGPoint, touchPoint: CGPoint) { - if let (currentPoint, _, _) = self.currentLocation { - self.currentLocation = (currentPoint, point.x, touchPoint) - - if let (size, insets) = self.validLayout { - self.update(size: size, insets: insets, isInitial: false) - } - } - } - - public func updateLayout(size: CGSize, insets: UIEdgeInsets, transition: ContainedViewLayoutTransition) { - self.validLayout = (size, insets) - - self.update(size: size, insets: insets, isInitial: false) - } - - private func update(size: CGSize, insets: UIEdgeInsets, isInitial: Bool) { - if let currentNode = self.currentNode, let (point, offset, touchPoint) = self.currentLocation { - currentNode.updateLayout(constrainedSize: size, startingPoint: CGPoint(x: size.width - 32.0, y: point.y), offsetFromStart: offset, isInitial: isInitial, touchPoint: touchPoint) - currentNode.frame = CGRect(origin: CGPoint(), size: size) - } - } - - override public func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { - return nil - } -} - diff --git a/submodules/ReactionSelectionNode/Sources/ReactionSwipeGestureRecognizer.swift b/submodules/ReactionSelectionNode/Sources/ReactionSwipeGestureRecognizer.swift deleted file mode 100644 index 44cc887651..0000000000 --- a/submodules/ReactionSelectionNode/Sources/ReactionSwipeGestureRecognizer.swift +++ /dev/null @@ -1,193 +0,0 @@ -import Foundation -import UIKit -import Display -import AsyncDisplayKit - -public final class ReactionSwipeGestureRecognizer: UIPanGestureRecognizer { - private var validatedGesture = false - - private var firstLocation: CGPoint = CGPoint() - private var currentLocation: CGPoint = CGPoint() - private var currentReactions: [ReactionGestureItem] = [] - private var isActivated = false - private var isAwaitingCompletion = false - private weak var currentContainer: ReactionSelectionParentNode? - private var activationTimer: Timer? - - public var availableReactions: (() -> [ReactionGestureItem])? - public var getReactionContainer: (() -> ReactionSelectionParentNode?)? - public var getAnchorPoint: (() -> CGPoint?)? - public var shouldElevateAnchorPoint: (() -> Bool)? - public var began: (() -> Void)? - public var updateOffset: ((CGFloat, Bool) -> Void)? - public var completed: ((ReactionGestureItem?) -> Void)? - public var displayReply: ((CGFloat) -> Void)? - public var activateReply: (() -> Void)? - - private var currentAnchorPoint: CGPoint? - private var currentAnchorStartPoint: CGPoint? - - override public init(target: Any?, action: Selector?) { - super.init(target: target, action: action) - - self.maximumNumberOfTouches = 1 - } - - override public func reset() { - super.reset() - - self.validatedGesture = false - self.currentReactions = [] - self.isActivated = false - self.isAwaitingCompletion = false - self.activationTimer?.invalidate() - self.activationTimer = nil - } - - override public func touchesBegan(_ touches: Set, with event: UIEvent) { - super.touchesBegan(touches, with: event) - - if let availableReactions = self.availableReactions?(), !availableReactions.isEmpty { - self.currentReactions = availableReactions - let touch = touches.first! - self.firstLocation = touch.location(in: nil) - self.currentLocation = self.firstLocation - } else { - self.state = .failed - } - } - - override public func touchesMoved(_ touches: Set, with event: UIEvent) { - if self.isAwaitingCompletion { - return - } - guard let _ = self.view else { - return - } - guard let location = touches.first?.location(in: nil) else { - return - } - self.currentLocation = location - - var translation = CGPoint(x: location.x - self.firstLocation.x, y: location.y - self.firstLocation.y) - - let absTranslationX: CGFloat = abs(translation.x) - let absTranslationY: CGFloat = abs(translation.y) - - var updatedOffset = false - - if !self.validatedGesture { - if translation.x > 0.0 { - self.state = .failed - } else if absTranslationY > 2.0 && absTranslationY > absTranslationX * 2.0 { - self.state = .failed - } else if absTranslationX > 2.0 && absTranslationY * 2.0 < absTranslationX { - self.validatedGesture = true - self.firstLocation = location - translation = CGPoint() - self.began?() - self.updateOffset?(0.0, false) - updatedOffset = true - - self.activationTimer?.invalidate() - final class TimerTarget: NSObject { - let f: () -> Void - - init(_ f: @escaping () -> Void) { - self.f = f - } - - @objc func event() { - self.f() - } - } - let elevate = self.shouldElevateAnchorPoint?() ?? false - - let activationTimer = Timer(timeInterval: elevate ? 0.15 : 0.01, target: TimerTarget { [weak self] in - guard let strongSelf = self else { - return - } - strongSelf.activationTimer = nil - if strongSelf.validatedGesture { - let location = strongSelf.currentLocation - if !strongSelf.currentReactions.isEmpty, let reactionContainer = strongSelf.getReactionContainer?(), let _ = strongSelf.getAnchorPoint?() { - strongSelf.currentContainer = reactionContainer - //let reactionContainerLocation = reactionContainer.view.convert(localAnchorPoint, from: strongSelf.view) - let elevate = strongSelf.shouldElevateAnchorPoint?() ?? false - let reactionContainerLocation = reactionContainer.view.convert(location, from: nil).offsetBy(dx: 0.0, dy: elevate ? -44.0 : 22.0) - let reactionContainerTouchPoint = reactionContainer.view.convert(location, from: nil) - strongSelf.currentAnchorPoint = reactionContainerLocation - strongSelf.currentAnchorStartPoint = location - reactionContainer.displayReactions(strongSelf.currentReactions, at: reactionContainerLocation, touchPoint: reactionContainerTouchPoint) - } - } - }, selector: #selector(TimerTarget.event), userInfo: nil, repeats: false) - self.activationTimer = activationTimer - RunLoop.main.add(activationTimer, forMode: .common) - } - } - - if self.validatedGesture { - if !updatedOffset { - self.updateOffset?(-min(0.0, translation.x), false) - } - if !self.isActivated { - if absTranslationX > 40.0 { - self.isActivated = true - self.displayReply?(-min(0.0, translation.x)) - } - } else { - if let reactionContainer = self.currentContainer, let currentAnchorPoint = self.currentAnchorPoint, let currentAnchorStartPoint = self.currentAnchorStartPoint { - let anchorPoint = CGPoint(x: currentAnchorPoint.x + location.x - currentAnchorStartPoint.x, y: currentAnchorPoint.y) - let reactionContainerLocation = anchorPoint - let reactionContainerTouchPoint = reactionContainer.view.convert(location, from: nil) - reactionContainer.updateReactionsAnchor(point: reactionContainerLocation, touchPoint: reactionContainerTouchPoint) - } - } - super.touchesMoved(touches, with: event) - } - } - - override public func touchesEnded(_ touches: Set, with event: UIEvent) { - if self.isAwaitingCompletion { - return - } - guard let location = touches.first?.location(in: nil) else { - return - } - if self.validatedGesture { - let translation = CGPoint(x: location.x - self.firstLocation.x, y: location.y - self.firstLocation.y) - if let reaction = self.currentContainer?.selectedReaction() { - self.isAwaitingCompletion = true - self.completed?(reaction) - } else { - if translation.x < -40.0 { - self.currentContainer?.dismissReactions(into: nil, hideTarget: false) - self.activateReply?() - self.state = .ended - } else { - self.currentContainer?.dismissReactions(into: nil, hideTarget: false) - self.completed?(nil) - self.state = .cancelled - super.touchesEnded(touches, with: event) - } - } - } else { - self.currentContainer?.dismissReactions(into: nil, hideTarget: false) - self.state = .cancelled - super.touchesEnded(touches, with: event) - } - } - - public func complete(into targetNode: ASDisplayNode?, hideTarget: Bool) { - if self.isAwaitingCompletion { - self.currentContainer?.dismissReactions(into: targetNode, hideTarget: hideTarget) - self.state = .ended - } - } - - public func cancel() { - self.state = .cancelled - } -} - diff --git a/submodules/SelectablePeerNode/BUILD b/submodules/SelectablePeerNode/BUILD index 752fbcac44..3ab6648992 100644 --- a/submodules/SelectablePeerNode/BUILD +++ b/submodules/SelectablePeerNode/BUILD @@ -11,7 +11,6 @@ swift_library( ], deps = [ "//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit", - "//submodules/Postbox:Postbox", "//submodules/TelegramCore:TelegramCore", "//submodules/AsyncDisplayKit:AsyncDisplayKit", "//submodules/Display:Display", diff --git a/submodules/SettingsUI/Sources/Themes/ThemeSettingsController.swift b/submodules/SettingsUI/Sources/Themes/ThemeSettingsController.swift index 90f64cb3d1..cf8ddebb65 100644 --- a/submodules/SettingsUI/Sources/Themes/ThemeSettingsController.swift +++ b/submodules/SettingsUI/Sources/Themes/ThemeSettingsController.swift @@ -804,7 +804,7 @@ public func themeSettingsController(context: AccountContext, focusOnItemTag: The }))) } - let contextController = ContextController(account: context.account, presentationData: presentationData, source: .controller(ContextControllerContentSourceImpl(controller: themeController, sourceNode: node)), items: .single(ContextController.Items(items: items)), reactionItems: [], gesture: gesture) + let contextController = ContextController(account: context.account, presentationData: presentationData, source: .controller(ContextControllerContentSourceImpl(controller: themeController, sourceNode: node)), items: .single(ContextController.Items(items: items)), gesture: gesture) presentInGlobalOverlayImpl?(contextController, nil) }) }, colorContextAction: { isCurrent, reference, accentColor, node, gesture in @@ -1041,7 +1041,7 @@ public func themeSettingsController(context: AccountContext, focusOnItemTag: The } } } - let contextController = ContextController(account: context.account, presentationData: presentationData, source: .controller(ContextControllerContentSourceImpl(controller: themeController, sourceNode: node)), items: .single(ContextController.Items(items: items)), reactionItems: [], gesture: gesture) + let contextController = ContextController(account: context.account, presentationData: presentationData, source: .controller(ContextControllerContentSourceImpl(controller: themeController, sourceNode: node)), items: .single(ContextController.Items(items: items)), gesture: gesture) presentInGlobalOverlayImpl?(contextController, nil) }) }) diff --git a/submodules/SlotMachineAnimationNode/BUILD b/submodules/SlotMachineAnimationNode/BUILD index 9ebdcc588e..6c660b314e 100644 --- a/submodules/SlotMachineAnimationNode/BUILD +++ b/submodules/SlotMachineAnimationNode/BUILD @@ -13,7 +13,6 @@ swift_library( "//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit", "//submodules/AsyncDisplayKit:AsyncDisplayKit", "//submodules/Display:Display", - "//submodules/Postbox:Postbox", "//submodules/TelegramCore:TelegramCore", "//submodules/AccountContext:AccountContext", "//submodules/StickerResources:StickerResources", diff --git a/submodules/SlotMachineAnimationNode/Sources/SlotMachineAnimationNode.swift b/submodules/SlotMachineAnimationNode/Sources/SlotMachineAnimationNode.swift index f12f6816a7..e14f224e66 100644 --- a/submodules/SlotMachineAnimationNode/Sources/SlotMachineAnimationNode.swift +++ b/submodules/SlotMachineAnimationNode/Sources/SlotMachineAnimationNode.swift @@ -1,7 +1,6 @@ import Foundation import Display import AsyncDisplayKit -import Postbox import TelegramCore import SwiftSignalKit import StickerResources diff --git a/submodules/StatisticsUI/Sources/ChannelStatsController.swift b/submodules/StatisticsUI/Sources/ChannelStatsController.swift index aa1b95f4f6..1cf81bf1b5 100644 --- a/submodules/StatisticsUI/Sources/ChannelStatsController.swift +++ b/submodules/StatisticsUI/Sources/ChannelStatsController.swift @@ -523,7 +523,7 @@ public func channelStatsController(context: AccountContext, updatedPresentationD }) }))) - let contextController = ContextController(account: context.account, presentationData: presentationData, source: .extracted(ChannelStatsContextExtractedContentSource(controller: controller, sourceNode: sourceNode, keepInPlace: false)), items: .single(ContextController.Items(items: items)), reactionItems: [], gesture: gesture) + let contextController = ContextController(account: context.account, presentationData: presentationData, source: .extracted(ChannelStatsContextExtractedContentSource(controller: controller, sourceNode: sourceNode, keepInPlace: false)), items: .single(ContextController.Items(items: items)), gesture: gesture) controller.presentInGlobalOverlay(contextController) } return controller diff --git a/submodules/StatisticsUI/Sources/StatsMessageItem.swift b/submodules/StatisticsUI/Sources/StatsMessageItem.swift index 512eac52d2..eaee3b6b98 100644 --- a/submodules/StatisticsUI/Sources/StatsMessageItem.swift +++ b/submodules/StatisticsUI/Sources/StatsMessageItem.swift @@ -241,7 +241,7 @@ public class StatsMessageItemNode: ListViewItemNode, ItemListItemNode { let titleFont = Font.regular(item.presentationData.fontSize.itemListBaseFontSize) let presentationData = item.context.sharedContext.currentPresentationData.with { $0 } - let contentKind = messageContentKind(contentSettings: item.context.currentContentSettings.with { $0 }, message: item.message, strings: item.presentationData.strings, nameDisplayOrder: .firstLast, dateTimeFormat: presentationData.dateTimeFormat, accountPeerId: item.context.account.peerId) + let contentKind = messageContentKind(contentSettings: item.context.currentContentSettings.with { $0 }, message: EngineMessage(item.message), strings: item.presentationData.strings, nameDisplayOrder: .firstLast, dateTimeFormat: presentationData.dateTimeFormat, accountPeerId: item.context.account.peerId) var text = !item.message.text.isEmpty ? item.message.text : stringForMediaKind(contentKind, strings: item.presentationData.strings).0 text = foldLineBreaks(text) diff --git a/submodules/TelegramBaseController/Sources/MediaNavigationAccessoryHeaderNode.swift b/submodules/TelegramBaseController/Sources/MediaNavigationAccessoryHeaderNode.swift index 4b62b4d876..304b18d52c 100644 --- a/submodules/TelegramBaseController/Sources/MediaNavigationAccessoryHeaderNode.swift +++ b/submodules/TelegramBaseController/Sources/MediaNavigationAccessoryHeaderNode.swift @@ -555,7 +555,7 @@ public final class MediaNavigationAccessoryHeaderNode: ASDisplayNode, UIScrollVi return } let items: Signal<[ContextMenuItem], NoError> = self.contextMenuSpeedItems() - let contextController = ContextController(account: self.context.account, presentationData: self.context.sharedContext.currentPresentationData.with { $0 }, source: .reference(HeaderContextReferenceContentSource(controller: controller, sourceNode: self.rateButton.referenceNode, shouldBeDismissed: self.dismissedPromise.get())), items: items |> map { ContextController.Items(items: $0) }, reactionItems: [], gesture: gesture) + let contextController = ContextController(account: self.context.account, presentationData: self.context.sharedContext.currentPresentationData.with { $0 }, source: .reference(HeaderContextReferenceContentSource(controller: controller, sourceNode: self.rateButton.referenceNode, shouldBeDismissed: self.dismissedPromise.get())), items: items |> map { ContextController.Items(items: $0) }, gesture: gesture) self.presentInGlobalOverlay?(contextController) } diff --git a/submodules/TelegramCallsUI/Sources/VoiceChatController.swift b/submodules/TelegramCallsUI/Sources/VoiceChatController.swift index 275e8a9033..f200e2579e 100644 --- a/submodules/TelegramCallsUI/Sources/VoiceChatController.swift +++ b/submodules/TelegramCallsUI/Sources/VoiceChatController.swift @@ -1791,7 +1791,7 @@ public final class VoiceChatController: ViewController { dismissPromise.set(true) } - let contextController = ContextController(account: strongSelf.context.account, presentationData: strongSelf.presentationData.withUpdated(theme: strongSelf.darkTheme), source: .extracted(source), items: items |> map { ContextController.Items(items: $0) }, reactionItems: [], gesture: gesture) + let contextController = ContextController(account: strongSelf.context.account, presentationData: strongSelf.presentationData.withUpdated(theme: strongSelf.darkTheme), source: .extracted(source), items: items |> map { ContextController.Items(items: $0) }, gesture: gesture) contextController.useComplexItemsTransitionAnimation = true strongSelf.controller?.presentInGlobalOverlay(contextController) }, getPeerVideo: { [weak self] endpointId, position in @@ -2458,7 +2458,7 @@ public final class VoiceChatController: ViewController { private func openSettingsMenu(sourceNode: ASDisplayNode, gesture: ContextGesture?) { let items: Signal<[ContextMenuItem], NoError> = self.contextMenuMainItems() if let controller = self.controller { - let contextController = ContextController(account: self.context.account, presentationData: self.presentationData.withUpdated(theme: self.darkTheme), source: .reference(VoiceChatContextReferenceContentSource(controller: controller, sourceNode: self.optionsButton.referenceNode)), items: items |> map { ContextController.Items(items: $0) }, reactionItems: [], gesture: gesture) + let contextController = ContextController(account: self.context.account, presentationData: self.presentationData.withUpdated(theme: self.darkTheme), source: .reference(VoiceChatContextReferenceContentSource(controller: controller, sourceNode: self.optionsButton.referenceNode)), items: items |> map { ContextController.Items(items: $0) }, gesture: gesture) controller.presentInGlobalOverlay(contextController) } } diff --git a/submodules/TelegramCore/Sources/Account/Account.swift b/submodules/TelegramCore/Sources/Account/Account.swift index 78fd20753c..e35af6f9e3 100644 --- a/submodules/TelegramCore/Sources/Account/Account.swift +++ b/submodules/TelegramCore/Sources/Account/Account.swift @@ -1020,7 +1020,6 @@ public class Account { self.managedOperationsDisposable.add(managedSynchronizeConsumeMessageContentOperations(postbox: self.postbox, network: self.network, stateManager: self.stateManager).start()) self.managedOperationsDisposable.add(managedConsumePersonalMessagesActions(postbox: self.postbox, network: self.network, stateManager: self.stateManager).start()) self.managedOperationsDisposable.add(managedSynchronizeMarkAllUnseenPersonalMessagesOperations(postbox: self.postbox, network: self.network, stateManager: self.stateManager).start()) - self.managedOperationsDisposable.add(managedApplyPendingMessageReactionsActions(postbox: self.postbox, network: self.network, stateManager: self.stateManager).start()) self.managedOperationsDisposable.add(managedSynchronizeEmojiKeywordsOperations(postbox: self.postbox, network: self.network).start()) self.managedOperationsDisposable.add(managedApplyPendingScheduledMessagesActions(postbox: self.postbox, network: self.network, stateManager: self.stateManager).start()) diff --git a/submodules/TelegramCore/Sources/Account/AccountIntermediateState.swift b/submodules/TelegramCore/Sources/Account/AccountIntermediateState.swift index 99c1264e63..b610a5dd6b 100644 --- a/submodules/TelegramCore/Sources/Account/AccountIntermediateState.swift +++ b/submodules/TelegramCore/Sources/Account/AccountIntermediateState.swift @@ -258,10 +258,6 @@ struct AccountMutableState { self.addOperation(.UpdateMessagePoll(id, poll, results)) } - /*mutating func updateMessageReactions(_ messageId: MessageId, reactions: Api.MessageReactions) { - self.addOperation(.UpdateMessageReactions(messageId, reactions)) - }*/ - mutating func updateMedia(_ id: MediaId, media: Media?) { self.addOperation(.UpdateMedia(id, media)) } diff --git a/submodules/TelegramCore/Sources/ApiUtils/ReactionsMessageAttribute.swift b/submodules/TelegramCore/Sources/ApiUtils/ReactionsMessageAttribute.swift deleted file mode 100644 index b435a2919a..0000000000 --- a/submodules/TelegramCore/Sources/ApiUtils/ReactionsMessageAttribute.swift +++ /dev/null @@ -1,101 +0,0 @@ -import Foundation -import Postbox -import TelegramApi - - -/*extension ReactionsMessageAttribute { - func withUpdatedResults(_ reactions: Api.MessageReactions) -> ReactionsMessageAttribute { - switch reactions { - case let .messageReactions(flags, results): - let min = (flags & (1 << 0)) != 0 - var reactions = results.map { result -> MessageReaction in - switch result { - case let .reactionCount(flags, reaction, count): - return MessageReaction(value: reaction, count: count, isSelected: (flags & (1 << 0)) != 0) - } - } - if min { - var currentSelectedReaction: String? - for reaction in self.reactions { - if reaction.isSelected { - currentSelectedReaction = reaction.value - break - } - } - if let currentSelectedReaction = currentSelectedReaction { - for i in 0 ..< reactions.count { - if reactions[i].value == currentSelectedReaction { - reactions[i].isSelected = true - } - } - } - } - return ReactionsMessageAttribute(reactions: reactions) - } - } -}*/ - -public func mergedMessageReactions(attributes: [MessageAttribute]) -> ReactionsMessageAttribute? { - var current: ReactionsMessageAttribute? - var pending: PendingReactionsMessageAttribute? - for attribute in attributes { - if let attribute = attribute as? ReactionsMessageAttribute { - current = attribute - } else if let attribute = attribute as? PendingReactionsMessageAttribute { - pending = attribute - } - } - - if let pending = pending { - var reactions = current?.reactions ?? [] - if let value = pending.value { - var found = false - for i in 0 ..< reactions.count { - if reactions[i].value == value { - found = true - if !reactions[i].isSelected { - reactions[i].isSelected = true - reactions[i].count += 1 - } - } - } - if !found { - reactions.append(MessageReaction(value: value, count: 1, isSelected: true)) - } - } - for i in (0 ..< reactions.count).reversed() { - if reactions[i].isSelected, pending.value != reactions[i].value { - if reactions[i].count == 1 { - reactions.remove(at: i) - } else { - reactions[i].isSelected = false - reactions[i].count -= 1 - } - } - } - if !reactions.isEmpty { - return ReactionsMessageAttribute(reactions: reactions) - } else { - return nil - } - } else if let current = current { - return current - } else { - return nil - } -} - -/*extension ReactionsMessageAttribute { - convenience init(apiReactions: Api.MessageReactions) { - switch apiReactions { - case let .messageReactions(_, results): - self.init(reactions: results.map { result in - switch result { - case let .reactionCount(flags, reaction, count): - return MessageReaction(value: reaction, count: count, isSelected: (flags & (1 << 0)) != 0) - } - }) - } - } -} -*/ diff --git a/submodules/TelegramCore/Sources/ApiUtils/StoreMessage_Telegram.swift b/submodules/TelegramCore/Sources/ApiUtils/StoreMessage_Telegram.swift index 9eb5c48031..c04933a70f 100644 --- a/submodules/TelegramCore/Sources/ApiUtils/StoreMessage_Telegram.swift +++ b/submodules/TelegramCore/Sources/ApiUtils/StoreMessage_Telegram.swift @@ -546,10 +546,6 @@ extension StoreMessage { attributes.append(ContentRequiresValidationMessageAttribute()) } - /*if let reactions = reactions { - attributes.append(ReactionsMessageAttribute(apiReactions: reactions)) - }*/ - if let replies = replies { let recentRepliersPeerIds: [PeerId]? switch replies { diff --git a/submodules/TelegramCore/Sources/PendingMessages/EnqueueMessage.swift b/submodules/TelegramCore/Sources/PendingMessages/EnqueueMessage.swift index aa6f2933ba..6c3086212e 100644 --- a/submodules/TelegramCore/Sources/PendingMessages/EnqueueMessage.swift +++ b/submodules/TelegramCore/Sources/PendingMessages/EnqueueMessage.swift @@ -648,7 +648,7 @@ func enqueueMessages(transaction: Transaction, account: Account, peerId: PeerId, if !hasHiddenForwardMedia { var sourceId: PeerId? = nil var sourceMessageId: MessageId? = nil - if let peer = messageMainPeer(sourceMessage) as? TelegramChannel, case .broadcast = peer.info { + if case let .channel(peer) = messageMainPeer(EngineMessage(sourceMessage)), case .broadcast = peer.info { sourceId = peer.id sourceMessageId = sourceMessage.id } diff --git a/submodules/TelegramCore/Sources/State/AccountStateManagementUtils.swift b/submodules/TelegramCore/Sources/State/AccountStateManagementUtils.swift index a489df1672..0265b043b2 100644 --- a/submodules/TelegramCore/Sources/State/AccountStateManagementUtils.swift +++ b/submodules/TelegramCore/Sources/State/AccountStateManagementUtils.swift @@ -1381,8 +1381,6 @@ private func finalStateWithUpdatesAndServerTime(postbox: Postbox, network: Netwo updatedState.updateLangPack(langCode: langCode, difference: difference) case let .updateMessagePoll(_, pollId, poll, results): updatedState.updateMessagePoll(MediaId(namespace: Namespaces.Media.CloudPoll, id: pollId), poll: poll, results: results) - /*case let .updateMessageReactions(peer, msgId, reactions): - updatedState.updateMessageReactions(MessageId(peerId: peer.peerId, namespace: Namespaces.Message.Cloud, id: msgId), reactions: reactions)*/ case let .updateFolderPeers(folderPeers, _, _): for folderPeer in folderPeers { switch folderPeer { @@ -2685,26 +2683,6 @@ func replayFinalState( updatedPoll = updatedPoll.withUpdatedResults(TelegramMediaPollResults(apiResults: results), min: resultsMin) updateMessageMedia(transaction: transaction, id: pollId, media: updatedPoll) } - /*case let .UpdateMessageReactions(messageId, reactions): - transaction.updateMessage(messageId, update: { currentMessage in - var storeForwardInfo: StoreMessageForwardInfo? - if let forwardInfo = currentMessage.forwardInfo { - storeForwardInfo = StoreMessageForwardInfo(authorId: forwardInfo.author?.id, sourceId: forwardInfo.source?.id, sourceMessageId: forwardInfo.sourceMessageId, date: forwardInfo.date, authorSignature: forwardInfo.authorSignature, psaType: forwardInfo.psaType, flags: forwardInfo.flags) - } - var attributes = currentMessage.attributes - var found = false - loop: for j in 0 ..< attributes.count { - if let attribute = attributes[j] as? ReactionsMessageAttribute { - attributes[j] = attribute.withUpdatedResults(reactions) - found = true - break loop - } - } - if !found { - attributes.append(ReactionsMessageAttribute(apiReactions: reactions)) - } - return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media)) - })*/ case let .UpdateMedia(id, media): if let media = media as? TelegramMediaWebpage { updatedWebpages[id] = media diff --git a/submodules/TelegramCore/Sources/State/AccountViewTracker.swift b/submodules/TelegramCore/Sources/State/AccountViewTracker.swift index b2b667e250..81667079b8 100644 --- a/submodules/TelegramCore/Sources/State/AccountViewTracker.swift +++ b/submodules/TelegramCore/Sources/State/AccountViewTracker.swift @@ -812,89 +812,6 @@ public final class AccountViewTracker { } } - public func updateReactionsForMessageIds(messageIds: Set) { - /*self.queue.async { - var addedMessageIds: [MessageId] = [] - let timestamp = Int32(CFAbsoluteTimeGetCurrent()) - for messageId in messageIds { - let messageTimestamp = self.updatedReactionsMessageIdsAndTimestamps[messageId] - if messageTimestamp == nil || messageTimestamp! < timestamp - 5 * 60 { - self.updatedReactionsMessageIdsAndTimestamps[messageId] = timestamp - addedMessageIds.append(messageId) - } - } - if !addedMessageIds.isEmpty { - for (peerId, messageIds) in messagesIdsGroupedByPeerId(Set(addedMessageIds)) { - let disposableId = self.nextUpdatedReactionsDisposableId - self.nextUpdatedReactionsDisposableId += 1 - - if let account = self.account { - let signal = (account.postbox.transaction { transaction -> Signal in - if let peer = transaction.getPeer(peerId), let inputPeer = apiInputPeer(peer) { - return account.network.request(Api.functions.messages.getMessagesReactions(peer: inputPeer, id: messageIds.map { $0.id })) - |> map(Optional.init) - |> `catch` { _ -> Signal in - return .single(nil) - } - |> mapToSignal { updates -> Signal in - guard let updates = updates else { - return .complete() - } - return account.postbox.transaction { transaction -> Void in - let updateList: [Api.Update] - switch updates { - case let .updates(updates, _, _, _, _): - updateList = updates - case let .updatesCombined(updates, _, _, _, _, _): - updateList = updates - case let .updateShort(update, _): - updateList = [update] - default: - updateList = [] - } - for update in updateList { - switch update { - case let .updateMessageReactions(peer, msgId, reactions): - transaction.updateMessage(MessageId(peerId: peer.peerId, namespace: Namespaces.Message.Cloud, id: msgId), update: { currentMessage in - - let updatedReactions = ReactionsMessageAttribute(apiReactions: reactions) - - let storeForwardInfo = currentMessage.forwardInfo.flatMap(StoreMessageForwardInfo.init) - var attributes = currentMessage.attributes - loop: for j in 0 ..< attributes.count { - if let attribute = attributes[j] as? ReactionsMessageAttribute { - if updatedReactions.reactions == attribute.reactions { - return .skip - } - attributes[j] = updatedReactions - break loop - } - } - return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media)) - }) - default: - break - } - } - } - } - } else { - return .complete() - } - } - |> switchToLatest) - |> afterDisposed { [weak self] in - self?.queue.async { - self?.updatedReactionsDisposables.set(nil, forKey: disposableId) - } - } - self.updatedReactionsDisposables.set(signal.start(), forKey: disposableId) - } - } - } - }*/ - } - public func updateSeenLiveLocationForMessageIds(messageIds: Set) { self.queue.async { var addedMessageIds: [MessageId] = [] diff --git a/submodules/TelegramCore/Sources/State/MessageReactions.swift b/submodules/TelegramCore/Sources/State/MessageReactions.swift deleted file mode 100644 index 87d43ad2d6..0000000000 --- a/submodules/TelegramCore/Sources/State/MessageReactions.swift +++ /dev/null @@ -1,227 +0,0 @@ -import Foundation -import Postbox -import SwiftSignalKit -import TelegramApi -import MtProtoKit - - -public func updateMessageReactionsInteractively(postbox: Postbox, messageId: MessageId, reaction: String?) -> Signal { - return postbox.transaction { transaction -> Void in - transaction.setPendingMessageAction(type: .updateReaction, id: messageId, action: UpdateMessageReactionsAction()) - transaction.updateMessage(messageId, update: { currentMessage in - var storeForwardInfo: StoreMessageForwardInfo? - if let forwardInfo = currentMessage.forwardInfo { - storeForwardInfo = StoreMessageForwardInfo(authorId: forwardInfo.author?.id, sourceId: forwardInfo.source?.id, sourceMessageId: forwardInfo.sourceMessageId, date: forwardInfo.date, authorSignature: forwardInfo.authorSignature, psaType: forwardInfo.psaType, flags: forwardInfo.flags) - } - var attributes = currentMessage.attributes - loop: for j in 0 ..< attributes.count { - if let _ = attributes[j] as? PendingReactionsMessageAttribute { - attributes.remove(at: j) - break loop - } - } - attributes.append(PendingReactionsMessageAttribute(value: reaction)) - return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media)) - }) - } - |> ignoreValues -} - -private enum RequestUpdateMessageReactionError { - case generic -} - -private func requestUpdateMessageReaction(postbox: Postbox, network: Network, stateManager: AccountStateManager, messageId: MessageId) -> Signal { - return .complete() - /*return postbox.transaction { transaction -> (Peer, String?)? in - guard let peer = transaction.getPeer(messageId.peerId) else { - return nil - } - guard let message = transaction.getMessage(messageId) else { - return nil - } - var value: String? - for attribute in message.attributes { - if let attribute = attribute as? PendingReactionsMessageAttribute { - value = attribute.value - break - } - } - return (peer, value) - } - |> castError(RequestUpdateMessageReactionError.self) - |> mapToSignal { peerAndValue in - guard let (peer, value) = peerAndValue else { - return .fail(.generic) - } - guard let inputPeer = apiInputPeer(peer) else { - return .fail(.generic) - } - if messageId.namespace != Namespaces.Message.Cloud { - return .fail(.generic) - } - return network.request(Api.functions.messages.sendReaction(flags: value == nil ? 0 : 1, peer: inputPeer, msgId: messageId.id, reaction: value)) - |> mapError { _ -> RequestUpdateMessageReactionError in - return .generic - } - |> mapToSignal { result -> Signal in - return postbox.transaction { transaction -> Void in - transaction.setPendingMessageAction(type: .updateReaction, id: messageId, action: UpdateMessageReactionsAction()) - transaction.updateMessage(messageId, update: { currentMessage in - var storeForwardInfo: StoreMessageForwardInfo? - if let forwardInfo = currentMessage.forwardInfo { - storeForwardInfo = StoreMessageForwardInfo(authorId: forwardInfo.author?.id, sourceId: forwardInfo.source?.id, sourceMessageId: forwardInfo.sourceMessageId, date: forwardInfo.date, authorSignature: forwardInfo.authorSignature, psaType: forwardInfo.psaType, flags: forwardInfo.flags) - } - let reactions = mergedMessageReactions(attributes: currentMessage.attributes) - var attributes = currentMessage.attributes - for j in (0 ..< attributes.count).reversed() { - if attributes[j] is PendingReactionsMessageAttribute || attributes[j] is ReactionsMessageAttribute { - attributes.remove(at: j) - } - } - if let reactions = reactions { - attributes.append(reactions) - } - return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media)) - }) - stateManager.addUpdates(result) - } - |> castError(RequestUpdateMessageReactionError.self) - |> ignoreValues - } - }*/ -} - -private final class ManagedApplyPendingMessageReactionsActionsHelper { - var operationDisposables: [MessageId: Disposable] = [:] - - func update(entries: [PendingMessageActionsEntry]) -> (disposeOperations: [Disposable], beginOperations: [(PendingMessageActionsEntry, MetaDisposable)]) { - var disposeOperations: [Disposable] = [] - var beginOperations: [(PendingMessageActionsEntry, MetaDisposable)] = [] - - var hasRunningOperationForPeerId = Set() - var validIds = Set() - for entry in entries { - if !hasRunningOperationForPeerId.contains(entry.id.peerId) { - hasRunningOperationForPeerId.insert(entry.id.peerId) - validIds.insert(entry.id) - - if self.operationDisposables[entry.id] == nil { - let disposable = MetaDisposable() - beginOperations.append((entry, disposable)) - self.operationDisposables[entry.id] = disposable - } - } - } - - var removeMergedIds: [MessageId] = [] - for (id, disposable) in self.operationDisposables { - if !validIds.contains(id) { - removeMergedIds.append(id) - disposeOperations.append(disposable) - } - } - - for id in removeMergedIds { - self.operationDisposables.removeValue(forKey: id) - } - - return (disposeOperations, beginOperations) - } - - func reset() -> [Disposable] { - let disposables = Array(self.operationDisposables.values) - self.operationDisposables.removeAll() - return disposables - } -} - -private func withTakenAction(postbox: Postbox, type: PendingMessageActionType, id: MessageId, _ f: @escaping (Transaction, PendingMessageActionsEntry?) -> Signal) -> Signal { - return postbox.transaction { transaction -> Signal in - var result: PendingMessageActionsEntry? - - if let action = transaction.getPendingMessageAction(type: type, id: id) as? UpdateMessageReactionsAction { - result = PendingMessageActionsEntry(id: id, action: action) - } - - return f(transaction, result) - } - |> switchToLatest -} - -func managedApplyPendingMessageReactionsActions(postbox: Postbox, network: Network, stateManager: AccountStateManager) -> Signal { - return Signal { _ in - let helper = Atomic(value: ManagedApplyPendingMessageReactionsActionsHelper()) - - let actionsKey = PostboxViewKey.pendingMessageActions(type: .updateReaction) - let disposable = postbox.combinedView(keys: [actionsKey]).start(next: { view in - var entries: [PendingMessageActionsEntry] = [] - if let v = view.views[actionsKey] as? PendingMessageActionsView { - entries = v.entries - } - - let (disposeOperations, beginOperations) = helper.with { helper -> (disposeOperations: [Disposable], beginOperations: [(PendingMessageActionsEntry, MetaDisposable)]) in - return helper.update(entries: entries) - } - - for disposable in disposeOperations { - disposable.dispose() - } - - for (entry, disposable) in beginOperations { - let signal = withTakenAction(postbox: postbox, type: .updateReaction, id: entry.id, { transaction, entry -> Signal in - if let entry = entry { - if let _ = entry.action as? UpdateMessageReactionsAction { - return synchronizeMessageReactions(transaction: transaction, postbox: postbox, network: network, stateManager: stateManager, id: entry.id) - } else { - assertionFailure() - } - } - return .complete() - }) - |> then( - postbox.transaction { transaction -> Void in - transaction.setPendingMessageAction(type: .updateReaction, id: entry.id, action: nil) - } - |> ignoreValues - ) - - disposable.set(signal.start()) - } - }) - - return ActionDisposable { - let disposables = helper.with { helper -> [Disposable] in - return helper.reset() - } - for disposable in disposables { - disposable.dispose() - } - disposable.dispose() - } - } -} - -private func synchronizeMessageReactions(transaction: Transaction, postbox: Postbox, network: Network, stateManager: AccountStateManager, id: MessageId) -> Signal { - return requestUpdateMessageReaction(postbox: postbox, network: network, stateManager: stateManager, messageId: id) - |> `catch` { _ -> Signal in - return postbox.transaction { transaction -> Void in - transaction.setPendingMessageAction(type: .updateReaction, id: id, action: nil) - transaction.updateMessage(id, update: { currentMessage in - var storeForwardInfo: StoreMessageForwardInfo? - if let forwardInfo = currentMessage.forwardInfo { - storeForwardInfo = StoreMessageForwardInfo(authorId: forwardInfo.author?.id, sourceId: forwardInfo.source?.id, sourceMessageId: forwardInfo.sourceMessageId, date: forwardInfo.date, authorSignature: forwardInfo.authorSignature, psaType: forwardInfo.psaType, flags: forwardInfo.flags) - } - var attributes = currentMessage.attributes - loop: for j in 0 ..< attributes.count { - if let _ = attributes[j] as? PendingReactionsMessageAttribute { - attributes.remove(at: j) - break loop - } - } - return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media)) - }) - } - |> ignoreValues - } -} diff --git a/submodules/TelegramCore/Sources/SyncCore/SyncCore_ReactionsMessageAttribute.swift b/submodules/TelegramCore/Sources/SyncCore/SyncCore_ReactionsMessageAttribute.swift index e281a8614f..4a1898a5c5 100644 --- a/submodules/TelegramCore/Sources/SyncCore/SyncCore_ReactionsMessageAttribute.swift +++ b/submodules/TelegramCore/Sources/SyncCore/SyncCore_ReactionsMessageAttribute.swift @@ -1,42 +1,13 @@ import Postbox -public struct MessageReaction: Equatable, PostboxCoding { - public var value: String - public var count: Int32 - public var isSelected: Bool - - public init(value: String, count: Int32, isSelected: Bool) { - self.value = value - self.count = count - self.isSelected = isSelected - } - - public init(decoder: PostboxDecoder) { - self.value = decoder.decodeStringForKey("v", orElse: "") - self.count = decoder.decodeInt32ForKey("c", orElse: 0) - self.isSelected = decoder.decodeInt32ForKey("s", orElse: 0) != 0 - } - - public func encode(_ encoder: PostboxEncoder) { - encoder.encodeString(self.value, forKey: "v") - encoder.encodeInt32(self.count, forKey: "c") - encoder.encodeInt32(self.isSelected ? 1 : 0, forKey: "s") - } -} - public final class ReactionsMessageAttribute: MessageAttribute { - public let reactions: [MessageReaction] - - public init(reactions: [MessageReaction]) { - self.reactions = reactions + public init() { } required public init(decoder: PostboxDecoder) { - self.reactions = decoder.decodeObjectArrayWithDecoderForKey("r") } public func encode(_ encoder: PostboxEncoder) { - encoder.encodeObjectArray(self.reactions, forKey: "r") } } diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Messages/Media.swift b/submodules/TelegramCore/Sources/TelegramEngine/Messages/Media.swift index 9b3a40c891..b83f597780 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Messages/Media.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Messages/Media.swift @@ -2,4 +2,84 @@ import Postbox public enum EngineMedia { public typealias Id = MediaId + + case image(TelegramMediaImage) + case file(TelegramMediaFile) + case geo(TelegramMediaMap) + case contact(TelegramMediaContact) + case action(TelegramMediaAction) + case dice(TelegramMediaDice) + case expiredContent(TelegramMediaExpiredContent) + case game(TelegramMediaGame) + case invoice(TelegramMediaInvoice) + case poll(TelegramMediaPoll) + case unsupported(TelegramMediaUnsupported) + case webFile(TelegramMediaWebFile) + case webpage(TelegramMediaWebpage) +} + +public extension EngineMedia { + init(_ media: Media) { + switch media { + case let image as TelegramMediaImage: + self = .image(image) + case let file as TelegramMediaFile: + self = .file(file) + case let geo as TelegramMediaMap: + self = .geo(geo) + case let contact as TelegramMediaContact: + self = .contact(contact) + case let action as TelegramMediaAction: + self = .action(action) + case let dice as TelegramMediaDice: + self = .dice(dice) + case let expiredContent as TelegramMediaExpiredContent: + self = .expiredContent(expiredContent) + case let game as TelegramMediaGame: + self = .game(game) + case let invoice as TelegramMediaInvoice: + self = .invoice(invoice) + case let poll as TelegramMediaPoll: + self = .poll(poll) + case let unsupported as TelegramMediaUnsupported: + self = .unsupported(unsupported) + case let webFile as TelegramMediaWebFile: + self = .webFile(webFile) + case let webpage as TelegramMediaWebpage: + self = .webpage(webpage) + default: + preconditionFailure() + } + } + + func _asMedia() -> Media { + switch self { + case let .image(image): + return image + case let .file(file): + return file + case let .geo(geo): + return geo + case let .contact(contact): + return contact + case let .action(action): + return action + case let .dice(dice): + return dice + case let .expiredContent(expiredContent): + return expiredContent + case let .game(game): + return game + case let .invoice(invoice): + return invoice + case let .poll(poll): + return poll + case let .unsupported(unsupported): + return unsupported + case let .webFile(webFile): + return webFile + case let .webpage(webpage): + return webpage + } + } } diff --git a/submodules/TelegramCore/Sources/Utils/PeerUtils.swift b/submodules/TelegramCore/Sources/Utils/PeerUtils.swift index 5efc7e35d6..ddbf97a2de 100644 --- a/submodules/TelegramCore/Sources/Utils/PeerUtils.swift +++ b/submodules/TelegramCore/Sources/Utils/PeerUtils.swift @@ -194,12 +194,12 @@ public func peerDebugDisplayTitles(_ peers: [Peer]) -> String { } } -public func messageMainPeer(_ message: Message) -> Peer? { +public func messageMainPeer(_ message: EngineMessage) -> EnginePeer? { if let peer = message.peers[message.id.peerId] { if let peer = peer as? TelegramSecretChat { - return message.peers[peer.regularPeerId] + return message.peers[peer.regularPeerId].flatMap(EnginePeer.init) } else { - return peer + return EnginePeer(peer) } } else { return nil diff --git a/submodules/TelegramPermissions/BUILD b/submodules/TelegramPermissions/BUILD index 5c9010b5d7..a5fb22cea8 100644 --- a/submodules/TelegramPermissions/BUILD +++ b/submodules/TelegramPermissions/BUILD @@ -10,7 +10,6 @@ swift_library( "-warnings-as-errors", ], deps = [ - "//submodules/Postbox:Postbox", "//submodules/TelegramCore:TelegramCore", "//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit", "//submodules/AccountContext:AccountContext", diff --git a/submodules/TelegramPermissions/Sources/Permission.swift b/submodules/TelegramPermissions/Sources/Permission.swift index dc7a30d5cc..02f94db8df 100644 --- a/submodules/TelegramPermissions/Sources/Permission.swift +++ b/submodules/TelegramPermissions/Sources/Permission.swift @@ -1,6 +1,5 @@ import Foundation import SwiftSignalKit -import Postbox import TelegramCore import DeviceAccess import AccountContext diff --git a/submodules/TelegramStringFormatting/BUILD b/submodules/TelegramStringFormatting/BUILD index 9c917401d3..932916cf5c 100644 --- a/submodules/TelegramStringFormatting/BUILD +++ b/submodules/TelegramStringFormatting/BUILD @@ -11,7 +11,6 @@ swift_library( ], deps = [ "//submodules/TelegramCore:TelegramCore", - "//submodules/Postbox:Postbox", "//submodules/Display:Display", "//submodules/PlatformRestrictionMatching:PlatformRestrictionMatching", "//submodules/LocalizedPeerData:LocalizedPeerData", diff --git a/submodules/TelegramStringFormatting/Sources/MessageContentKind.swift b/submodules/TelegramStringFormatting/Sources/MessageContentKind.swift index 5cd5cb9b08..e51050345e 100644 --- a/submodules/TelegramStringFormatting/Sources/MessageContentKind.swift +++ b/submodules/TelegramStringFormatting/Sources/MessageContentKind.swift @@ -1,5 +1,4 @@ import Foundation -import Postbox import TelegramCore import TelegramPresentationData import TelegramUIPreferences @@ -88,7 +87,7 @@ public enum MessageContentKind: Equatable { } } -public func messageContentKind(contentSettings: ContentSettings, message: Message, strings: PresentationStrings, nameDisplayOrder: PresentationPersonNameOrder, dateTimeFormat: PresentationDateTimeFormat, accountPeerId: PeerId) -> MessageContentKind { +public func messageContentKind(contentSettings: ContentSettings, message: EngineMessage, strings: PresentationStrings, nameDisplayOrder: PresentationPersonNameOrder, dateTimeFormat: PresentationDateTimeFormat, accountPeerId: EnginePeer.Id) -> MessageContentKind { for attribute in message.attributes { if let attribute = attribute as? RestrictedContentMessageAttribute { if let text = attribute.platformText(platform: "ios", contentSettings: contentSettings) { @@ -98,25 +97,25 @@ public func messageContentKind(contentSettings: ContentSettings, message: Messag } } for media in message.media { - if let kind = mediaContentKind(media, message: message, strings: strings, nameDisplayOrder: nameDisplayOrder, dateTimeFormat: dateTimeFormat, accountPeerId: accountPeerId) { + if let kind = mediaContentKind(EngineMedia(media), message: message, strings: strings, nameDisplayOrder: nameDisplayOrder, dateTimeFormat: dateTimeFormat, accountPeerId: accountPeerId) { return kind } } return .text(message.text) } -public func mediaContentKind(_ media: Media, message: Message? = nil, strings: PresentationStrings? = nil, nameDisplayOrder: PresentationPersonNameOrder? = nil, dateTimeFormat: PresentationDateTimeFormat? = nil, accountPeerId: PeerId? = nil) -> MessageContentKind? { +public func mediaContentKind(_ media: EngineMedia, message: EngineMessage? = nil, strings: PresentationStrings? = nil, nameDisplayOrder: PresentationPersonNameOrder? = nil, dateTimeFormat: PresentationDateTimeFormat? = nil, accountPeerId: EnginePeer.Id? = nil) -> MessageContentKind? { switch media { - case let expiredMedia as TelegramMediaExpiredContent: + case let .expiredContent(expiredMedia): switch expiredMedia.data { case .image: return .expiredImage case .file: return .expiredVideo } - case _ as TelegramMediaImage: + case .image: return .image - case let file as TelegramMediaFile: + case let .file(file): var fileName: String = "" for attribute in file.attributes { switch attribute { @@ -154,27 +153,27 @@ public func mediaContentKind(_ media: Media, message: Message? = nil, strings: P return .sticker("") } return .file(fileName) - case _ as TelegramMediaContact: + case .contact: return .contact - case let game as TelegramMediaGame: + case let .game(game): return .game(game.title) - case let location as TelegramMediaMap: + case let .geo(location): if location.liveBroadcastingTimeout != nil { return .liveLocation } else { return .location } - case _ as TelegramMediaAction: + case .action: if let message = message, let strings = strings, let nameDisplayOrder = nameDisplayOrder, let accountPeerId = accountPeerId { return .text(plainServiceMessageString(strings: strings, nameDisplayOrder: nameDisplayOrder, dateTimeFormat: dateTimeFormat ?? PresentationDateTimeFormat(timeFormat: .military, dateFormat: .dayFirst, dateSeparator: ".", dateSuffix: "", requiresFullYear: false, decimalSeparator: ".", groupingSeparator: ""), message: message, accountPeerId: accountPeerId, forChatList: false) ?? "") } else { return nil } - case let poll as TelegramMediaPoll: + case let .poll(poll): return .poll(poll.text) - case let dice as TelegramMediaDice: + case let .dice(dice): return .dice(dice.emoji) - case let invoice as TelegramMediaInvoice: + case let .invoice(invoice): return .invoice(invoice.title) default: return nil @@ -230,7 +229,7 @@ public func stringForMediaKind(_ kind: MessageContentKind, strings: Presentation } } -public func descriptionStringForMessage(contentSettings: ContentSettings, message: Message, strings: PresentationStrings, nameDisplayOrder: PresentationPersonNameOrder, dateTimeFormat: PresentationDateTimeFormat, accountPeerId: PeerId) -> (String, Bool) { +public func descriptionStringForMessage(contentSettings: ContentSettings, message: EngineMessage, strings: PresentationStrings, nameDisplayOrder: PresentationPersonNameOrder, dateTimeFormat: PresentationDateTimeFormat, accountPeerId: EnginePeer.Id) -> (String, Bool) { let contentKind = messageContentKind(contentSettings: contentSettings, message: message, strings: strings, nameDisplayOrder: nameDisplayOrder, dateTimeFormat: dateTimeFormat, accountPeerId: accountPeerId) if !message.text.isEmpty && ![.expiredImage, .expiredVideo].contains(contentKind.key) { return (foldLineBreaks(message.text), false) diff --git a/submodules/TelegramStringFormatting/Sources/ServiceMessageStrings.swift b/submodules/TelegramStringFormatting/Sources/ServiceMessageStrings.swift index 1365862c44..046745e403 100644 --- a/submodules/TelegramStringFormatting/Sources/ServiceMessageStrings.swift +++ b/submodules/TelegramStringFormatting/Sources/ServiceMessageStrings.swift @@ -1,6 +1,5 @@ import Foundation import UIKit -import Postbox import TelegramCore import TelegramPresentationData import TelegramUIPreferences @@ -12,11 +11,11 @@ import Markdown private let titleFont = Font.regular(13.0) private let titleBoldFont = Font.bold(13.0) -private func peerMentionAttributes(primaryTextColor: UIColor, peerId: PeerId) -> MarkdownAttributeSet { +private func peerMentionAttributes(primaryTextColor: UIColor, peerId: EnginePeer.Id) -> MarkdownAttributeSet { return MarkdownAttributeSet(font: titleBoldFont, textColor: primaryTextColor, additionalAttributes: [TelegramTextAttributes.PeerMention: TelegramPeerMention(peerId: peerId, mention: "")]) } -private func peerMentionsAttributes(primaryTextColor: UIColor, peerIds: [(Int, PeerId?)]) -> [Int: MarkdownAttributeSet] { +private func peerMentionsAttributes(primaryTextColor: UIColor, peerIds: [(Int, EnginePeer.Id?)]) -> [Int: MarkdownAttributeSet] { var result: [Int: MarkdownAttributeSet] = [:] for (index, peerId) in peerIds { if let peerId = peerId { @@ -26,11 +25,11 @@ private func peerMentionsAttributes(primaryTextColor: UIColor, peerIds: [(Int, P return result } -public func plainServiceMessageString(strings: PresentationStrings, nameDisplayOrder: PresentationPersonNameOrder, dateTimeFormat: PresentationDateTimeFormat, message: Message, accountPeerId: PeerId, forChatList: Bool) -> String? { +public func plainServiceMessageString(strings: PresentationStrings, nameDisplayOrder: PresentationPersonNameOrder, dateTimeFormat: PresentationDateTimeFormat, message: EngineMessage, accountPeerId: EnginePeer.Id, forChatList: Bool) -> String? { return universalServiceMessageString(presentationData: nil, strings: strings, nameDisplayOrder: nameDisplayOrder, dateTimeFormat: dateTimeFormat, message: message, accountPeerId: accountPeerId, forChatList: forChatList)?.string } -public func universalServiceMessageString(presentationData: (PresentationTheme, TelegramWallpaper)?, strings: PresentationStrings, nameDisplayOrder: PresentationPersonNameOrder, dateTimeFormat: PresentationDateTimeFormat, message: Message, accountPeerId: PeerId, forChatList: Bool) -> NSAttributedString? { +public func universalServiceMessageString(presentationData: (PresentationTheme, TelegramWallpaper)?, strings: PresentationStrings, nameDisplayOrder: PresentationPersonNameOrder, dateTimeFormat: PresentationDateTimeFormat, message: EngineMessage, accountPeerId: EnginePeer.Id, forChatList: Bool) -> NSAttributedString? { var attributedString: NSAttributedString? let primaryTextColor: UIColor @@ -45,7 +44,7 @@ public func universalServiceMessageString(presentationData: (PresentationTheme, for media in message.media { if let action = media as? TelegramMediaAction { - let authorName = message.author.flatMap(EnginePeer.init)?.displayTitle(strings: strings, displayOrder: nameDisplayOrder) ?? "" + let authorName = message.author?.displayTitle(strings: strings, displayOrder: nameDisplayOrder) ?? "" var isChannel = false if message.id.peerId.namespace == Namespaces.Peer.CloudChannel, let peer = message.peers[message.id.peerId] as? TelegramChannel, case .broadcast = peer.info { @@ -71,7 +70,7 @@ public func universalServiceMessageString(presentationData: (PresentationTheme, attributedString = addAttributesToStringWithRanges(strings.Notification_JoinedChat(authorName)._tuple, body: bodyAttributes, argumentAttributes: peerMentionsAttributes(primaryTextColor: primaryTextColor, peerIds: [(0, peerId)])) } } else { - var attributePeerIds: [(Int, PeerId?)] = [(0, message.author?.id)] + var attributePeerIds: [(Int, EnginePeer.Id?)] = [(0, message.author?.id)] let resultTitleString: PresentationStrings.FormattedString if peerIds.count == 1 { attributePeerIds.append((1, peerIds.first)) @@ -90,7 +89,7 @@ public func universalServiceMessageString(presentationData: (PresentationTheme, attributedString = addAttributesToStringWithRanges(strings.Notification_LeftChat(authorName)._tuple, body: bodyAttributes, argumentAttributes: peerMentionsAttributes(primaryTextColor: primaryTextColor, peerIds: [(0, message.author?.id)])) } } else { - var attributePeerIds: [(Int, PeerId?)] = [(0, message.author?.id)] + var attributePeerIds: [(Int, EnginePeer.Id?)] = [(0, message.author?.id)] if peerIds.count == 1 { attributePeerIds.append((1, peerIds.first)) } @@ -153,10 +152,10 @@ public func universalServiceMessageString(presentationData: (PresentationTheme, case deleted } - var pinnedMessage: Message? + var pinnedMessage: EngineMessage? for attribute in message.attributes { if let attribute = attribute as? ReplyMessageAttribute, let message = message.associatedMessages[attribute.messageId] { - pinnedMessage = message + pinnedMessage = EngineMessage(message) } } @@ -263,7 +262,7 @@ public func universalServiceMessageString(presentationData: (PresentationTheme, case let .messageAutoremoveTimeoutUpdated(timeout): let authorString: String if let author = messageMainPeer(message) { - authorString = EnginePeer(author).compactDisplayTitle + authorString = author.compactDisplayTitle } else { authorString = "" } @@ -325,8 +324,8 @@ public func universalServiceMessageString(presentationData: (PresentationTheme, break case .historyScreenshot: let text: String - if message.effectivelyIncoming(accountPeerId) { - text = strings.Notification_SecretChatMessageScreenshot(message.author.flatMap(EnginePeer.init)?.compactDisplayTitle ?? "").string + if message._asMessage().effectivelyIncoming(accountPeerId) { + text = strings.Notification_SecretChatMessageScreenshot(message.author?.compactDisplayTitle ?? "").string } else { text = strings.Notification_SecretChatMessageScreenshotSelf } @@ -372,10 +371,10 @@ public func universalServiceMessageString(presentationData: (PresentationTheme, argumentAttributes[1] = MarkdownAttributeSet(font: titleBoldFont, textColor: primaryTextColor, additionalAttributes: [:]) attributedString = addAttributesToStringWithRanges(formatWithArgumentRanges(baseString, ranges, [authorName, gameTitle ?? ""]), body: bodyAttributes, argumentAttributes: argumentAttributes) case let .paymentSent(currency, totalAmount): - var invoiceMessage: Message? + var invoiceMessage: EngineMessage? for attribute in message.attributes { if let attribute = attribute as? ReplyMessageAttribute, let message = message.associatedMessages[attribute.messageId] { - invoiceMessage = message + invoiceMessage = EngineMessage(message) } } @@ -391,7 +390,7 @@ public func universalServiceMessageString(presentationData: (PresentationTheme, if let invoiceTitle = invoiceTitle { let botString: String if let peer = messageMainPeer(message) { - botString = EnginePeer(peer).compactDisplayTitle + botString = peer.compactDisplayTitle } else { botString = "" } @@ -441,7 +440,7 @@ public func universalServiceMessageString(presentationData: (PresentationTheme, if let scheduleDate = scheduleDate { if message.author?.id.namespace == Namespaces.Peer.CloudChannel { let titleString: PresentationStrings.FormattedString - if let channel = message.author as? TelegramChannel, case .broadcast = channel.info { + if case let .channel(channel) = message.author, case .broadcast = channel.info { titleString = humanReadableStringForTimestamp(strings: strings, dateTimeFormat: dateTimeFormat, timestamp: scheduleDate, alwaysShowTime: true, allowYesterday: false, format: HumanReadableStringFormat(dateFormatString: { strings.Notification_LiveStreamScheduled($0) }, tomorrowFormatString: { strings.Notification_LiveStreamScheduledTomorrow($0) }, todayFormatString: { strings.Notification_LiveStreamScheduledToday($0) })) } else { titleString = humanReadableStringForTimestamp(strings: strings, dateTimeFormat: dateTimeFormat, timestamp: scheduleDate, alwaysShowTime: true, allowYesterday: false, format: HumanReadableStringFormat(dateFormatString: { strings.Notification_VoiceChatScheduledChannel($0) }, tomorrowFormatString: { strings.Notification_VoiceChatScheduledTomorrowChannel($0) }, todayFormatString: { strings.Notification_VoiceChatScheduledTodayChannel($0) })) @@ -449,34 +448,34 @@ public func universalServiceMessageString(presentationData: (PresentationTheme, attributedString = NSAttributedString(string: titleString.string, font: titleFont, textColor: primaryTextColor) } else { let titleString = humanReadableStringForTimestamp(strings: strings, dateTimeFormat: dateTimeFormat, timestamp: scheduleDate, alwaysShowTime: true, allowYesterday: false, format: HumanReadableStringFormat(dateFormatString: { strings.Notification_VoiceChatScheduled(authorName, $0) }, tomorrowFormatString: { strings.Notification_VoiceChatScheduledTomorrow(authorName, $0) }, todayFormatString: { strings.Notification_VoiceChatScheduledToday(authorName, $0) })) - let attributePeerIds: [(Int, PeerId?)] = [(0, message.author?.id)] + let attributePeerIds: [(Int, EnginePeer.Id?)] = [(0, message.author?.id)] attributedString = addAttributesToStringWithRanges(titleString._tuple, body: bodyAttributes, argumentAttributes: peerMentionsAttributes(primaryTextColor: primaryTextColor, peerIds: attributePeerIds)) } } else if let duration = duration { if message.author?.id.namespace == Namespaces.Peer.CloudChannel { let titleString: String - if let channel = message.author as? TelegramChannel, case .broadcast = channel.info { + if case let .channel(channel) = message.author, case .broadcast = channel.info { titleString = strings.Notification_LiveStreamEnded(callDurationString(strings: strings, value: duration)).string } else { titleString = strings.Notification_VoiceChatEnded(callDurationString(strings: strings, value: duration)).string } attributedString = NSAttributedString(string: titleString, font: titleFont, textColor: primaryTextColor) } else { - let attributePeerIds: [(Int, PeerId?)] = [(0, message.author?.id)] + let attributePeerIds: [(Int, EnginePeer.Id?)] = [(0, message.author?.id)] let titleString = strings.Notification_VoiceChatEndedGroup(authorName, callDurationString(strings: strings, value: duration)) attributedString = addAttributesToStringWithRanges(titleString._tuple, body: bodyAttributes, argumentAttributes: peerMentionsAttributes(primaryTextColor: primaryTextColor, peerIds: attributePeerIds)) } } else { if message.author?.id.namespace == Namespaces.Peer.CloudChannel { let titleString: String - if let channel = message.author as? TelegramChannel, case .broadcast = channel.info { + if case let .channel(channel) = message.author, case .broadcast = channel.info { titleString = strings.Notification_LiveStreamStarted } else { titleString = strings.Notification_VoiceChatStartedChannel } attributedString = NSAttributedString(string: titleString, font: titleFont, textColor: primaryTextColor) } else { - let attributePeerIds: [(Int, PeerId?)] = [(0, message.author?.id)] + let attributePeerIds: [(Int, EnginePeer.Id?)] = [(0, message.author?.id)] let titleString = strings.Notification_VoiceChatStarted(authorName) attributedString = addAttributesToStringWithRanges(titleString._tuple, body: bodyAttributes, argumentAttributes: peerMentionsAttributes(primaryTextColor: primaryTextColor, peerIds: attributePeerIds)) } @@ -529,7 +528,7 @@ public func universalServiceMessageString(presentationData: (PresentationTheme, attributedString = addAttributesToStringWithRanges(strings.Notification_ProximityReached(message.peers[fromId].flatMap(EnginePeer.init)?.displayTitle(strings: strings, displayOrder: nameDisplayOrder) ?? "", distanceString, message.peers[toId].flatMap(EnginePeer.init)?.displayTitle(strings: strings, displayOrder: nameDisplayOrder) ?? "")._tuple, body: bodyAttributes, argumentAttributes: peerMentionsAttributes(primaryTextColor: primaryTextColor, peerIds: [(0, fromId), (2, toId)])) } case let .inviteToGroupPhoneCall(_, _, peerIds): - var attributePeerIds: [(Int, PeerId?)] = [(0, message.author?.id)] + var attributePeerIds: [(Int, EnginePeer.Id?)] = [(0, message.author?.id)] let resultTitleString: PresentationStrings.FormattedString if peerIds.count == 1 { if peerIds[0] == accountPeerId { @@ -551,7 +550,7 @@ public func universalServiceMessageString(presentationData: (PresentationTheme, } else if message.author?.id == accountPeerId { attributedString = NSAttributedString(string: strings.Notification_YouDisabledTheme, font: titleFont, textColor: primaryTextColor) } else { - let attributePeerIds: [(Int, PeerId?)] = [(0, message.author?.id)] + let attributePeerIds: [(Int, EnginePeer.Id?)] = [(0, message.author?.id)] let resultTitleString = strings.Notification_DisabledTheme(authorName) attributedString = addAttributesToStringWithRanges(resultTitleString._tuple, body: bodyAttributes, argumentAttributes: peerMentionsAttributes(primaryTextColor: primaryTextColor, peerIds: attributePeerIds)) } diff --git a/submodules/TelegramUI/BUILD b/submodules/TelegramUI/BUILD index ed1c70045c..0fceea4376 100644 --- a/submodules/TelegramUI/BUILD +++ b/submodules/TelegramUI/BUILD @@ -188,7 +188,6 @@ swift_library( "//submodules/WatchBridge:WatchBridge", "//submodules/ShareItems:ShareItems", "//submodules/ShareItems/Impl:ShareItemsImpl", - "//submodules/ReactionSelectionNode:ReactionSelectionNode", "//submodules/SettingsUI:SettingsUI", "//submodules/UrlHandling:UrlHandling", "//submodules/HexColor:HexColor", diff --git a/submodules/TelegramUI/Sources/ChatController.swift b/submodules/TelegramUI/Sources/ChatController.swift index c560854080..7039e7ea97 100644 --- a/submodules/TelegramUI/Sources/ChatController.swift +++ b/submodules/TelegramUI/Sources/ChatController.swift @@ -44,7 +44,6 @@ import PeerAvatarGalleryUI import PeerInfoUI import RaiseToListen import UrlHandling -import ReactionSelectionNode import AvatarNode import AppBundle import LocalizedPeerData @@ -934,35 +933,6 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G guard let strongSelf = self, !actions.items.isEmpty else { return } - var reactionItems: [ReactionContextItem] = [] - - /*var hasLike = false - let hearts: [String] = ["❤", "❤️"] - for attribute in messages[0].attributes { - if let attribute = attribute as? ReactionsMessageAttribute { - for reaction in attribute.reactions { - if hearts.contains(reaction.value) { - if reaction.isSelected { - hasLike = true - } - } - } - } else if let attribute = attribute as? PendingReactionsMessageAttribute { - if let value = attribute.value, hearts.contains(value) { - hasLike = true - } - } - } - - if hasLike { - reactionItems.append(ReactionContextItem(reaction: .unlike)) - } else { - reactionItems.append(ReactionContextItem(reaction: .like)) - }*/ - - if Namespaces.Message.allScheduled.contains(message.id.namespace) || message.id.peerId.namespace == Namespaces.Peer.SecretChat { - reactionItems = [] - } var tip: ContextController.Tip? @@ -979,47 +949,9 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G actions.tip = tip } - let controller = ContextController(account: strongSelf.context.account, presentationData: strongSelf.presentationData, source: .extracted(ChatMessageContextExtractedContentSource(chatNode: strongSelf.chatDisplayNode, postbox: strongSelf.context.account.postbox, message: message, selectAll: selectAll)), items: .single(actions), reactionItems: reactionItems, recognizer: recognizer, gesture: gesture) + let controller = ContextController(account: strongSelf.context.account, presentationData: strongSelf.presentationData, source: .extracted(ChatMessageContextExtractedContentSource(chatNode: strongSelf.chatDisplayNode, postbox: strongSelf.context.account.postbox, message: message, selectAll: selectAll)), items: .single(actions), recognizer: recognizer, gesture: gesture) strongSelf.currentContextController = controller - controller.reactionSelected = { [weak controller] value in - guard let strongSelf = self, let message = updatedMessages.first else { - return - } - let hearts: [String] = ["❤", "❤️"] - strongSelf.chatDisplayNode.historyNode.forEachItemNode { itemNode in - if let itemNode = itemNode as? ChatMessageItemView, let item = itemNode.item { - if item.message.id == message.id { - switch value { - case .like: - itemNode.awaitingAppliedReaction = (hearts[0], { [weak itemNode] in - guard let controller = controller else { - return - } - if let itemNode = itemNode, let (targetEmptyNode, targetFilledNode) = itemNode.targetReactionNode(value: hearts[0]) { - controller.dismissWithReaction(value: hearts[0], targetEmptyNode: targetEmptyNode, targetFilledNode: targetFilledNode, hideNode: true, completion: { - }) - } else { - controller.dismiss() - } - }) - case .unlike: - itemNode.awaitingAppliedReaction = (nil, { - guard let controller = controller else { - return - } - controller.dismiss() - }) - } - } - } - } - switch value { - case .like: - let _ = updateMessageReactionsInteractively(postbox: strongSelf.context.account.postbox, messageId: message.id, reaction: hearts[0]).start() - case .unlike: - let _ = updateMessageReactionsInteractively(postbox: strongSelf.context.account.postbox, messageId: message.id, reaction: nil).start() - } - } + strongSelf.forEachController({ controller in if let controller = controller as? TooltipScreen { controller.dismiss() @@ -1734,8 +1666,6 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G return self?.navigationController as? NavigationController }, chatControllerNode: { [weak self] in return self?.chatDisplayNode - }, reactionContainerNode: { [weak self] in - return self?.chatDisplayNode.reactionContainerNode }, presentGlobalOverlayController: { [weak self] controller, arguments in self?.presentInGlobalOverlay(controller, with: arguments) }, callPeer: { [weak self] peerId, isVideo in @@ -2162,28 +2092,6 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G if canReplyInChat(strongSelf.presentationInterfaceState) { return .reply } else if let channel = message.peers[message.id.peerId] as? TelegramChannel, case .broadcast = channel.info { - /*var hasLike = false - let hearts: [String] = ["❤", "❤️"] - for attribute in message.attributes { - if let attribute = attribute as? ReactionsMessageAttribute { - for reaction in attribute.reactions { - if hearts.contains(reaction.value) { - if reaction.isSelected { - hasLike = true - } - } - } - } else if let attribute = attribute as? PendingReactionsMessageAttribute { - if let value = attribute.value, hearts.contains(value) { - hasLike = true - } - } - } - if hasLike { - return .unlike - } else { - return .like - }*/ } } return .none @@ -2235,7 +2143,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G } }))) - let controller = ContextController(account: strongSelf.context.account, presentationData: strongSelf.presentationData, source: .extracted(ChatMessageContextExtractedContentSource(chatNode: strongSelf.chatDisplayNode, postbox: strongSelf.context.account.postbox, message: message, selectAll: true)), items: .single(ContextController.Items(items: actions)), reactionItems: [], recognizer: nil) + let controller = ContextController(account: strongSelf.context.account, presentationData: strongSelf.presentationData, source: .extracted(ChatMessageContextExtractedContentSource(chatNode: strongSelf.chatDisplayNode, postbox: strongSelf.context.account.postbox, message: message, selectAll: true)), items: .single(ContextController.Items(items: actions)), recognizer: nil) strongSelf.currentContextController = controller strongSelf.forEachController({ controller in if let controller = controller as? TooltipScreen { @@ -2312,7 +2220,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G f(.dismissWithoutContent) }))) - let controller = ContextController(account: strongSelf.context.account, presentationData: strongSelf.presentationData, source: .extracted(ChatMessageContextExtractedContentSource(chatNode: strongSelf.chatDisplayNode, postbox: strongSelf.context.account.postbox, message: topMessage, selectAll: true)), items: .single(ContextController.Items(items: actions)), reactionItems: [], recognizer: nil) + let controller = ContextController(account: strongSelf.context.account, presentationData: strongSelf.presentationData, source: .extracted(ChatMessageContextExtractedContentSource(chatNode: strongSelf.chatDisplayNode, postbox: strongSelf.context.account.postbox, message: topMessage, selectAll: true)), items: .single(ContextController.Items(items: actions)), recognizer: nil) strongSelf.currentContextController = controller strongSelf.forEachController({ controller in if let controller = controller as? TooltipScreen { @@ -2604,18 +2512,6 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G case .speak: speakText(text.string) } - }, updateMessageLike: { [weak self] messageId, isLiked in - guard let strongSelf = self else { - return - } - - let heart = "❤" - if isLiked { - let _ = updateMessageReactionsInteractively(postbox: strongSelf.context.account.postbox, messageId: messageId, reaction: heart).start() - } else { - let _ = updateMessageReactionsInteractively(postbox: strongSelf.context.account.postbox, messageId: messageId, reaction: nil).start() - } - }, openMessageReactions: { _ in }, displayImportedMessageTooltip: { [weak self] _ in guard let strongSelf = self else { return @@ -2755,7 +2651,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G return items } - let contextController = ContextController(account: strongSelf.context.account, presentationData: strongSelf.presentationData, source: .controller(ContextControllerContentSourceImpl(controller: galleryController, sourceNode: node, passthroughTouches: false)), items: items |> map { ContextController.Items(items: $0) }, reactionItems: [], gesture: gesture) + let contextController = ContextController(account: strongSelf.context.account, presentationData: strongSelf.presentationData, source: .controller(ContextControllerContentSourceImpl(controller: galleryController, sourceNode: node, passthroughTouches: false)), items: items |> map { ContextController.Items(items: $0) }, gesture: gesture) strongSelf.presentInGlobalOverlay(contextController) }) }, openMessageReplies: { [weak self] messageId, isChannelPost, displayModalProgress in @@ -3034,7 +2930,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G return items } - let contextController = ContextController(account: strongSelf.context.account, presentationData: strongSelf.presentationData, source: .controller(ContextControllerContentSourceImpl(controller: galleryController, sourceNode: node, passthroughTouches: false)), items: items |> map { ContextController.Items(items: $0) }, reactionItems: [], gesture: gesture) + let contextController = ContextController(account: strongSelf.context.account, presentationData: strongSelf.presentationData, source: .controller(ContextControllerContentSourceImpl(controller: galleryController, sourceNode: node, passthroughTouches: false)), items: items |> map { ContextController.Items(items: $0) }, gesture: gesture) strongSelf.presentInGlobalOverlay(contextController) } chatInfoButtonItem = UIBarButtonItem(customDisplayNode: avatarNode)! @@ -5841,7 +5737,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G return items } - let contextController = ContextController(account: strongSelf.context.account, presentationData: strongSelf.presentationData, source: .controller(ContextControllerContentSourceImpl(controller: chatController, sourceNode: sourceNode, passthroughTouches: true)), items: items |> map { ContextController.Items(items: $0) }, reactionItems: []) + let contextController = ContextController(account: strongSelf.context.account, presentationData: strongSelf.presentationData, source: .controller(ContextControllerContentSourceImpl(controller: chatController, sourceNode: sourceNode, passthroughTouches: true)), items: items |> map { ContextController.Items(items: $0) }) contextController.dismissedForCancel = { [weak chatController] in if let selectedMessageIds = (chatController as? ChatControllerImpl)?.selectedMessageIds { var forwardMessageIds = strongSelf.presentationInterfaceState.interfaceState.forwardMessageIds ?? [] @@ -7349,7 +7245,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G let chatController = strongSelf.context.sharedContext.makeChatController(context: strongSelf.context, chatLocation: .peer(peerId), subject: .pinnedMessages(id: pinnedMessage.message.id), botStart: nil, mode: .standard(previewing: true)) chatController.canReadHistory.set(false) - let contextController = ContextController(account: strongSelf.context.account, presentationData: strongSelf.presentationData, source: .controller(ContextControllerContentSourceImpl(controller: chatController, sourceNode: node, passthroughTouches: true)), items: .single(ContextController.Items(items: items)), reactionItems: [], gesture: gesture) + let contextController = ContextController(account: strongSelf.context.account, presentationData: strongSelf.presentationData, source: .controller(ContextControllerContentSourceImpl(controller: chatController, sourceNode: node, passthroughTouches: true)), items: .single(ContextController.Items(items: items)), gesture: gesture) strongSelf.presentInGlobalOverlay(contextController) }, joinGroupCall: { [weak self] activeCall in guard let strongSelf = self, let peer = strongSelf.presentationInterfaceState.renderedPeer?.peer else { diff --git a/submodules/TelegramUI/Sources/ChatControllerInteraction.swift b/submodules/TelegramUI/Sources/ChatControllerInteraction.swift index d5836f9602..838237d59b 100644 --- a/submodules/TelegramUI/Sources/ChatControllerInteraction.swift +++ b/submodules/TelegramUI/Sources/ChatControllerInteraction.swift @@ -8,7 +8,6 @@ import Display import TelegramUIPreferences import AccountContext import TextSelectionNode -import ReactionSelectionNode import ContextUI import ChatInterfaceState import UndoUI @@ -45,8 +44,6 @@ struct ChatInterfacePollActionState: Equatable { public enum ChatControllerInteractionSwipeAction { case none case reply - case like - case unlike } public final class ChatControllerInteraction { @@ -83,7 +80,6 @@ public final class ChatControllerInteraction { let presentController: (ViewController, Any?) -> Void let navigationController: () -> NavigationController? let chatControllerNode: () -> ASDisplayNode? - let reactionContainerNode: () -> ReactionSelectionParentNode? let presentGlobalOverlayController: (ViewController, Any?) -> Void let callPeer: (PeerId, Bool) -> Void let longTap: (ChatControllerInteractionLongTapAction, Message?) -> Void @@ -104,8 +100,6 @@ public final class ChatControllerInteraction { let sendScheduledMessagesNow: ([MessageId]) -> Void let editScheduledMessagesTime: ([MessageId]) -> Void let performTextSelectionAction: (UInt32, NSAttributedString, TextSelectionAction) -> Void - let updateMessageLike: (MessageId, Bool) -> Void - let openMessageReactions: (MessageId) -> Void let displayImportedMessageTooltip: (ASDisplayNode) -> Void let displaySwipeToReplyHint: () -> Void let dismissReplyMarkupMessage: (Message) -> Void @@ -180,7 +174,6 @@ public final class ChatControllerInteraction { presentController: @escaping (ViewController, Any?) -> Void, navigationController: @escaping () -> NavigationController?, chatControllerNode: @escaping () -> ASDisplayNode?, - reactionContainerNode: @escaping () -> ReactionSelectionParentNode?, presentGlobalOverlayController: @escaping (ViewController, Any?) -> Void, callPeer: @escaping (PeerId, Bool) -> Void, longTap: @escaping (ChatControllerInteractionLongTapAction, Message?) -> Void, @@ -201,8 +194,6 @@ public final class ChatControllerInteraction { sendScheduledMessagesNow: @escaping ([MessageId]) -> Void, editScheduledMessagesTime: @escaping ([MessageId]) -> Void, performTextSelectionAction: @escaping (UInt32, NSAttributedString, TextSelectionAction) -> Void, - updateMessageLike: @escaping (MessageId, Bool) -> Void, - openMessageReactions: @escaping (MessageId) -> Void, displayImportedMessageTooltip: @escaping (ASDisplayNode) -> Void, displaySwipeToReplyHint: @escaping () -> Void, dismissReplyMarkupMessage: @escaping (Message) -> Void, @@ -263,7 +254,6 @@ public final class ChatControllerInteraction { self.presentController = presentController self.navigationController = navigationController self.chatControllerNode = chatControllerNode - self.reactionContainerNode = reactionContainerNode self.presentGlobalOverlayController = presentGlobalOverlayController self.callPeer = callPeer self.longTap = longTap @@ -287,8 +277,6 @@ public final class ChatControllerInteraction { self.sendScheduledMessagesNow = sendScheduledMessagesNow self.editScheduledMessagesTime = editScheduledMessagesTime self.performTextSelectionAction = performTextSelectionAction - self.updateMessageLike = updateMessageLike - self.openMessageReactions = openMessageReactions self.displayImportedMessageTooltip = displayImportedMessageTooltip self.displaySwipeToReplyHint = displaySwipeToReplyHint self.dismissReplyMarkupMessage = dismissReplyMarkupMessage @@ -324,8 +312,6 @@ public final class ChatControllerInteraction { return nil }, chatControllerNode: { return nil - }, reactionContainerNode: { - return nil }, presentGlobalOverlayController: { _, _ in }, callPeer: { _, _ in }, longTap: { _, _ in }, openCheckoutOrReceipt: { _ in }, openSearch: { }, setupReply: { _ in }, canSetupReply: { _ in return .none @@ -342,8 +328,6 @@ public final class ChatControllerInteraction { }, sendScheduledMessagesNow: { _ in }, editScheduledMessagesTime: { _ in }, performTextSelectionAction: { _, _, _ in - }, updateMessageLike: { _, _ in - }, openMessageReactions: { _ in }, displayImportedMessageTooltip: { _ in }, displaySwipeToReplyHint: { }, dismissReplyMarkupMessage: { _ in diff --git a/submodules/TelegramUI/Sources/ChatControllerNode.swift b/submodules/TelegramUI/Sources/ChatControllerNode.swift index 876092e5f6..4ae7c5aa92 100644 --- a/submodules/TelegramUI/Sources/ChatControllerNode.swift +++ b/submodules/TelegramUI/Sources/ChatControllerNode.swift @@ -10,7 +10,6 @@ import TelegramUIPreferences import TextFormat import AccountContext import TelegramNotices -import ReactionSelectionNode import TelegramUniversalVideoContent import ChatInterfaceState import FastBlur @@ -83,7 +82,6 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate { let backgroundNode: WallpaperBackgroundNode let historyNode: ChatHistoryListNode var blurredHistoryNode: ASImageNode? - let reactionContainerNode: ReactionSelectionParentNode let historyNodeContainer: ASDisplayNode let loadingNode: ChatLoadingNode private var emptyNode: ChatEmptyNode? @@ -336,8 +334,6 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate { onTransitionEventImpl?(transition) }) - self.reactionContainerNode = ReactionSelectionParentNode(account: context.account, theme: chatPresentationInterfaceState.theme) - self.loadingNode = ChatLoadingNode(theme: self.chatPresentationInterfaceState.theme, chatWallpaper: self.chatPresentationInterfaceState.chatWallpaper, bubbleCorners: self.chatPresentationInterfaceState.bubbleCorners) if case let .color(color) = self.chatPresentationInterfaceState.chatWallpaper, UIColor(rgb: color).isEqual(self.chatPresentationInterfaceState.theme.chat.inputPanel.panelBackgroundColorNoWallpaper) { @@ -1178,9 +1174,6 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate { transition.updateFrame(node: emptyNode, frame: contentBounds) } - transition.updateFrame(node: self.reactionContainerNode, frame: contentBounds) - self.reactionContainerNode.updateLayout(size: contentBounds.size, insets: UIEdgeInsets(), transition: transition) - var contentBottomInset: CGFloat = inputPanelsHeight + 4.0 if let scrollContainerNode = self.scrollContainerNode { @@ -1852,10 +1845,6 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate { } else { completion(.immediate) } - - if self.reactionContainerNode.supernode == nil { - self.addSubnode(self.reactionContainerNode) - } } func updateAutomaticMediaDownloadSettings(_ settings: MediaAutoDownloadSettings) { diff --git a/submodules/TelegramUI/Sources/ChatHistoryListNode.swift b/submodules/TelegramUI/Sources/ChatHistoryListNode.swift index f3473e49d1..8d2720b91f 100644 --- a/submodules/TelegramUI/Sources/ChatHistoryListNode.swift +++ b/submodules/TelegramUI/Sources/ChatHistoryListNode.swift @@ -470,7 +470,6 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode { private let messageProcessingManager = ChatMessageThrottledProcessingManager() private let adSeenProcessingManager = ChatMessageThrottledProcessingManager() - private let messageReactionsProcessingManager = ChatMessageThrottledProcessingManager() private let seenLiveLocationProcessingManager = ChatMessageThrottledProcessingManager() private let unsupportedMessageProcessingManager = ChatMessageThrottledProcessingManager() private let refreshMediaProcessingManager = ChatMessageThrottledProcessingManager() @@ -631,9 +630,6 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode { } } } - self.messageReactionsProcessingManager.process = { [weak context] messageIds in - context?.account.viewTracker.updateReactionsForMessageIds(messageIds: messageIds) - } self.seenLiveLocationProcessingManager.process = { [weak context] messageIds in context?.account.viewTracker.updateSeenLiveLocationForMessageIds(messageIds: messageIds) } @@ -1503,7 +1499,6 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode { var messageIdsWithViewCount: [MessageId] = [] var messageIdsWithAds: [MessageId] = [] - var messageIdsWithUpdateableReactions: [MessageId] = [] var messageIdsWithLiveLocation: [MessageId] = [] var messageIdsWithUnsupportedMedia: [MessageId] = [] var messageIdsWithRefreshMedia: [MessageId] = [] @@ -1541,7 +1536,6 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode { contentRequiredValidation = true } } - var isAction = false for media in message.media { if let _ = media as? TelegramMediaUnsupported { contentRequiredValidation = true @@ -1550,8 +1544,6 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode { if message.timestamp + liveBroadcastingTimeout > timestamp { messageIdsWithLiveLocation.append(message.id) } - } else if let _ = media as? TelegramMediaAction { - isAction = true } else if let telegramFile = media as? TelegramMediaFile { if telegramFile.isAnimatedSticker, (message.id.peerId.namespace == Namespaces.Peer.SecretChat || !telegramFile.previewRepresentations.isEmpty), let size = telegramFile.size, size > 0 && size <= 128 * 1024 { if message.id.peerId.namespace == Namespaces.Peer.SecretChat { @@ -1572,9 +1564,6 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode { } } } - if !isAction && message.id.peerId.namespace == Namespaces.Peer.CloudChannel { - messageIdsWithUpdateableReactions.append(message.id) - } if contentRequiredValidation { messageIdsWithUnsupportedMedia.append(message.id) } @@ -1703,9 +1692,6 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode { if !messageIdsWithAds.isEmpty { self.adSeenProcessingManager.add(messageIdsWithAds) } - if !messageIdsWithUpdateableReactions.isEmpty { - self.messageReactionsProcessingManager.add(messageIdsWithUpdateableReactions) - } if !messageIdsWithLiveLocation.isEmpty { self.seenLiveLocationProcessingManager.add(messageIdsWithLiveLocation) } diff --git a/submodules/TelegramUI/Sources/ChatMediaInputNode.swift b/submodules/TelegramUI/Sources/ChatMediaInputNode.swift index b07064aaf4..0363e076a6 100644 --- a/submodules/TelegramUI/Sources/ChatMediaInputNode.swift +++ b/submodules/TelegramUI/Sources/ChatMediaInputNode.swift @@ -1465,7 +1465,7 @@ final class ChatMediaInputNode: ChatInputNode { let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 } - let contextController = ContextController(account: strongSelf.context.account, presentationData: presentationData, source: .controller(ContextControllerContentSourceImpl(controller: gallery, sourceNode: sourceNode, sourceRect: sourceRect)), items: .single(ContextController.Items(items: items)), reactionItems: [], gesture: gesture) + let contextController = ContextController(account: strongSelf.context.account, presentationData: presentationData, source: .controller(ContextControllerContentSourceImpl(controller: gallery, sourceNode: sourceNode, sourceRect: sourceRect)), items: .single(ContextController.Items(items: items)), gesture: gesture) strongSelf.controllerInteraction.presentGlobalOverlayController(contextController, nil) }) } diff --git a/submodules/TelegramUI/Sources/ChatMessageActionItemNode.swift b/submodules/TelegramUI/Sources/ChatMessageActionItemNode.swift index 3fa59cf22c..0559c304d1 100644 --- a/submodules/TelegramUI/Sources/ChatMessageActionItemNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageActionItemNode.swift @@ -19,7 +19,7 @@ import GalleryUI import WallpaperBackgroundNode private func attributedServiceMessageString(theme: ChatPresentationThemeData, strings: PresentationStrings, nameDisplayOrder: PresentationPersonNameOrder, dateTimeFormat: PresentationDateTimeFormat, message: Message, accountPeerId: PeerId) -> NSAttributedString? { - return universalServiceMessageString(presentationData: (theme.theme, theme.wallpaper), strings: strings, nameDisplayOrder: nameDisplayOrder, dateTimeFormat: dateTimeFormat, message: message, accountPeerId: accountPeerId, forChatList: false) + return universalServiceMessageString(presentationData: (theme.theme, theme.wallpaper), strings: strings, nameDisplayOrder: nameDisplayOrder, dateTimeFormat: dateTimeFormat, message: EngineMessage(message), accountPeerId: accountPeerId, forChatList: false) } class ChatMessageActionBubbleContentNode: ChatMessageBubbleContentNode { diff --git a/submodules/TelegramUI/Sources/ChatMessageAnimatedStickerItemNode.swift b/submodules/TelegramUI/Sources/ChatMessageAnimatedStickerItemNode.swift index 2ae27e7385..9170a47ab6 100644 --- a/submodules/TelegramUI/Sources/ChatMessageAnimatedStickerItemNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageAnimatedStickerItemNode.swift @@ -299,13 +299,6 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView { self.messageAccessibilityArea.focused = { [weak self] in self?.accessibilityElementDidBecomeFocused() } - - self.dateAndStatusNode.openReactions = { [weak self] in - guard let strongSelf = self, let item = strongSelf.item else { - return - } - item.controllerInteraction.openMessageReactions(item.message.id) - } } deinit { @@ -352,7 +345,7 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView { guard let strongSelf = self else { return } - //strongSelf.reactionRecognizer?.cancel() + if let action = strongSelf.gestureRecognized(gesture: .longTap, location: point, recognizer: recognizer) { switch action { case let .action(f): @@ -875,27 +868,14 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView { } } - var dateReactions: [MessageReaction] = [] - var dateReactionCount = 0 - if let reactionsAttribute = mergedMessageReactions(attributes: item.message.attributes), !reactionsAttribute.reactions.isEmpty { - for reaction in reactionsAttribute.reactions { - if reaction.isSelected { - dateReactions.insert(reaction, at: 0) - } else { - dateReactions.append(reaction) - } - dateReactionCount += Int(reaction.count) - } - } - - let dateText = stringForMessageTimestampStatus(accountPeerId: item.context.account.peerId, message: item.message, dateTimeFormat: item.presentationData.dateTimeFormat, nameDisplayOrder: item.presentationData.nameDisplayOrder, strings: item.presentationData.strings, format: .regular, reactionCount: dateReactionCount) + let dateText = stringForMessageTimestampStatus(accountPeerId: item.context.account.peerId, message: item.message, dateTimeFormat: item.presentationData.dateTimeFormat, nameDisplayOrder: item.presentationData.nameDisplayOrder, strings: item.presentationData.strings, format: .regular) var isReplyThread = false if case .replyThread = item.chatLocation { isReplyThread = true } - let (dateAndStatusSize, dateAndStatusApply) = makeDateAndStatusLayout(item.context, item.presentationData, edited, viewCount, dateText, statusType, CGSize(width: params.width, height: CGFloat.greatestFiniteMagnitude), dateReactions, dateReplies, item.message.tags.contains(.pinned) && !item.associatedData.isInPinnedListMode && !isReplyThread, item.message.isSelfExpiring) + let (dateAndStatusSize, dateAndStatusApply) = makeDateAndStatusLayout(item.context, item.presentationData, edited, viewCount, dateText, statusType, CGSize(width: params.width, height: CGFloat.greatestFiniteMagnitude), dateReplies, item.message.tags.contains(.pinned) && !item.associatedData.isInPinnedListMode && !isReplyThread, item.message.isSelfExpiring) var viaBotApply: (TextNodeLayout, () -> TextNode)? var replyInfoApply: (CGSize, () -> ChatMessageReplyInfoNode)? @@ -1836,10 +1816,6 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView { break case .reply: item.controllerInteraction.setupReply(item.message.id) - case .like: - item.controllerInteraction.updateMessageLike(item.message.id, true) - case .unlike: - item.controllerInteraction.updateMessageLike(item.message.id, true) } } } diff --git a/submodules/TelegramUI/Sources/ChatMessageAttachedContentNode.swift b/submodules/TelegramUI/Sources/ChatMessageAttachedContentNode.swift index f4cc8e02f3..464453b54c 100644 --- a/submodules/TelegramUI/Sources/ChatMessageAttachedContentNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageAttachedContentNode.swift @@ -329,20 +329,7 @@ final class ChatMessageAttachedContentNode: ASDisplayNode { } } - var dateReactions: [MessageReaction] = [] - var dateReactionCount = 0 - if let reactionsAttribute = mergedMessageReactions(attributes: message.attributes), !reactionsAttribute.reactions.isEmpty { - for reaction in reactionsAttribute.reactions { - if reaction.isSelected { - dateReactions.insert(reaction, at: 0) - } else { - dateReactions.append(reaction) - } - dateReactionCount += Int(reaction.count) - } - } - - let dateText = stringForMessageTimestampStatus(accountPeerId: context.account.peerId, message: message, dateTimeFormat: presentationData.dateTimeFormat, nameDisplayOrder: presentationData.nameDisplayOrder, strings: presentationData.strings, reactionCount: dateReactionCount) + let dateText = stringForMessageTimestampStatus(accountPeerId: context.account.peerId, message: message, dateTimeFormat: presentationData.dateTimeFormat, nameDisplayOrder: presentationData.nameDisplayOrder, strings: presentationData.strings) var webpageGalleryMediaCount: Int? for media in message.media { @@ -506,7 +493,6 @@ final class ChatMessageAttachedContentNode: ASDisplayNode { edited: edited, viewCount: viewCount, dateReplies: dateReplies, - dateReactions: dateReactions, isPinned: message.tags.contains(.pinned) && !associatedData.isInPinnedListMode && !isReplyThread, dateText: dateText ) @@ -626,7 +612,7 @@ final class ChatMessageAttachedContentNode: ASDisplayNode { let textConstrainedSize = CGSize(width: constrainedSize.width - insets.left - insets.right, height: constrainedSize.height - insets.top - insets.bottom) if let textStatusType = textStatusType { - statusSizeAndApply = statusLayout(context, presentationData, edited, viewCount, dateText, textStatusType, textConstrainedSize, dateReactions, dateReplies, message.tags.contains(.pinned) && !associatedData.isInPinnedListMode && !isReplyThread, message.isSelfExpiring) + statusSizeAndApply = statusLayout(context, presentationData, edited, viewCount, dateText, textStatusType, textConstrainedSize, dateReplies, message.tags.contains(.pinned) && !associatedData.isInPinnedListMode && !isReplyThread, message.isSelfExpiring) } var updatedAdditionalImageBadge: ChatMessageInteractiveMediaBadge? @@ -1120,11 +1106,4 @@ final class ChatMessageAttachedContentNode: ASDisplayNode { func playMediaWithSound() -> ((Double?) -> Void, Bool, Bool, Bool, ASDisplayNode?)? { return self.contentImageNode?.playMediaWithSound() } - - func reactionTargetNode(value: String) -> (ASDisplayNode, ASDisplayNode)? { - if !self.statusNode.isHidden { - return self.statusNode.reactionNode(value: value) - } - return nil - } } diff --git a/submodules/TelegramUI/Sources/ChatMessageBubbleContentNode.swift b/submodules/TelegramUI/Sources/ChatMessageBubbleContentNode.swift index 01a062a262..db3775ce12 100644 --- a/submodules/TelegramUI/Sources/ChatMessageBubbleContentNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageBubbleContentNode.swift @@ -210,10 +210,6 @@ class ChatMessageBubbleContentNode: ASDisplayNode { func applyAbsoluteOffsetSpring(value: CGFloat, duration: Double, damping: CGFloat) { } - func reactionTargetNode(value: String) -> (ASDisplayNode, ASDisplayNode)? { - return nil - } - func getStatusNode() -> ASDisplayNode? { return nil } diff --git a/submodules/TelegramUI/Sources/ChatMessageBubbleItemNode.swift b/submodules/TelegramUI/Sources/ChatMessageBubbleItemNode.swift index c195435489..f077acfc5f 100644 --- a/submodules/TelegramUI/Sources/ChatMessageBubbleItemNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageBubbleItemNode.swift @@ -16,7 +16,6 @@ import MosaicLayout import TextSelectionNode import PlatformRestrictionMatching import Emoji -import ReactionSelectionNode import PersistentStringHash import GridMessageSelectionNode import AppBundle @@ -438,7 +437,6 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode private var appliedForwardInfo: (Peer?, String?)? private var tapRecognizer: TapLongTapOrDoubleTapGestureRecognizer? - private var reactionRecognizer: ReactionSwipeGestureRecognizer? private var currentSwipeAction: ChatControllerInteractionSwipeAction? @@ -799,7 +797,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode guard let strongSelf = self else { return } - strongSelf.reactionRecognizer?.cancel() + if let action = strongSelf.gestureRecognized(gesture: .longTap, location: point, recognizer: recognizer) { switch action { case let .action(f): @@ -828,234 +826,35 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode self.tapRecognizer = recognizer self.view.addGestureRecognizer(recognizer) self.view.isExclusiveTouch = true - - if true { - let replyRecognizer = ChatSwipeToReplyRecognizer(target: self, action: #selector(self.swipeToReplyGesture(_:))) - replyRecognizer.shouldBegin = { [weak self] in - if let strongSelf = self, let item = strongSelf.item { - if strongSelf.selectionNode != nil { - return false - } - for media in item.content.firstMessage.media { - if let _ = media as? TelegramMediaExpiredContent { - return false - } - else if let media = media as? TelegramMediaAction { - if case .phoneCall(_, _, _, _) = media.action { - } else { - return false - } - } - } - let action = item.controllerInteraction.canSetupReply(item.message) - strongSelf.currentSwipeAction = action - if case .none = action { - return false - } else { - return true - } - } - return false - } - self.view.addGestureRecognizer(replyRecognizer) - } else { - /*let reactionRecognizer = ReactionSwipeGestureRecognizer(target: nil, action: nil) - self.reactionRecognizer = reactionRecognizer - reactionRecognizer.availableReactions = { [weak self] in - guard let strongSelf = self, let item = strongSelf.item, !item.presentationData.isPreview && !Namespaces.Message.allScheduled.contains(item.message.id.namespace) else { - return [] - } + + let replyRecognizer = ChatSwipeToReplyRecognizer(target: self, action: #selector(self.swipeToReplyGesture(_:))) + replyRecognizer.shouldBegin = { [weak self] in + if let strongSelf = self, let item = strongSelf.item { if strongSelf.selectionNode != nil { - return [] + return false } for media in item.content.firstMessage.media { if let _ = media as? TelegramMediaExpiredContent { - return [] + return false } else if let media = media as? TelegramMediaAction { - if case .phoneCall = media.action { + if case .phoneCall(_, _, _, _) = media.action { } else { - return [] + return false } } } - - let reactions: [(String, String, String)] = [ - ("😔", "Sad", "sad"), - ("😳", "Surprised", "surprised"), - ("😂", "Fun", "lol"), - ("👍", "Like", "thumbsup"), - ("❤", "Love", "heart"), - ] - - var reactionItems: [ReactionGestureItem] = [] - for (value, text, name) in reactions.reversed() { - if let path = getAppBundle().path(forResource: name, ofType: "tgs") { - reactionItems.append(.reaction(value: value, text: text, path: path)) - } - } - if item.controllerInteraction.canSetupReply(item.message) { - //reactionItems.append(.reply) - } - return reactionItems - } - reactionRecognizer.getReactionContainer = { [weak self] in - return self?.item?.controllerInteraction.reactionContainerNode() - } - reactionRecognizer.getAnchorPoint = { [weak self] in - guard let strongSelf = self else { - return nil - } - return CGPoint(x: strongSelf.backgroundNode.frame.maxX, y: strongSelf.backgroundNode.frame.minY) - } - reactionRecognizer.shouldElevateAnchorPoint = { [weak self] in - guard let strongSelf = self, let item = strongSelf.item else { + let action = item.controllerInteraction.canSetupReply(item.message) + strongSelf.currentSwipeAction = action + if case .none = action { return false - } - return item.controllerInteraction.canSetupReply(item.message) - } - reactionRecognizer.began = { [weak self] in - guard let strongSelf = self, let item = strongSelf.item else { - return - } - item.controllerInteraction.cancelInteractiveKeyboardGestures() - } - reactionRecognizer.updateOffset = { [weak self] offset, animated in - guard let strongSelf = self else { - return - } - var bounds = strongSelf.bounds - bounds.origin.x = offset - strongSelf.bounds = bounds - - var shadowBounds = strongSelf.shadowNode.bounds - shadowBounds.origin.x = offset - strongSelf.shadowNode.bounds = shadowBounds - - if animated { - strongSelf.layer.animateBoundsOriginXAdditive(from: -offset, to: 0.0, duration: 0.1, mediaTimingFunction: CAMediaTimingFunction(name: .easeOut)) - strongSelf.shadowNode.layer.animateBoundsOriginXAdditive(from: -offset, to: 0.0, duration: 0.1, mediaTimingFunction: CAMediaTimingFunction(name: .easeOut)) - } - if let swipeToReplyNode = strongSelf.swipeToReplyNode { - swipeToReplyNode.alpha = max(0.0, min(1.0, abs(offset / 40.0))) - } - } - reactionRecognizer.activateReply = { [weak self] in - guard let strongSelf = self, let item = strongSelf.item else { - return - } - var bounds = strongSelf.bounds - let offset = bounds.origin.x - bounds.origin.x = 0.0 - strongSelf.bounds = bounds - - var shadowBounds = strongSelf.shadowNode.bounds - let shadowOffset = shadowBounds.origin.x - shadowBounds.origin.x = 0.0 - strongSelf.shadowNode.bounds = shadowBounds - - if !offset.isZero { - strongSelf.layer.animateBoundsOriginXAdditive(from: offset, to: 0.0, duration: 0.2, timingFunction: kCAMediaTimingFunctionSpring) - } - if !shadowOffset.isZero { - strongSelf.shadowNode.layer.animateBoundsOriginXAdditive(from: shadowOffset, to: 0.0, duration: 0.2, timingFunction: kCAMediaTimingFunctionSpring) - } - if let swipeToReplyNode = strongSelf.swipeToReplyNode { - strongSelf.swipeToReplyNode = nil - swipeToReplyNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, removeOnCompletion: false, completion: { [weak swipeToReplyNode] _ in - swipeToReplyNode?.removeFromSupernode() - }) - swipeToReplyNode.layer.animateScale(from: 1.0, to: 0.2, duration: 0.3, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false) - } - item.controllerInteraction.setupReply(item.message.id) - } - reactionRecognizer.displayReply = { [weak self] offset in - guard let strongSelf = self, let item = strongSelf.item else { - return - } - if !item.controllerInteraction.canSetupReply(item.message) { - return - } - if strongSelf.swipeToReplyFeedback == nil { - strongSelf.swipeToReplyFeedback = HapticFeedback() - } - strongSelf.swipeToReplyFeedback?.tap() - if strongSelf.swipeToReplyNode == nil { - let swipeToReplyNode = ChatMessageSwipeToReplyNode(fillColor: bubbleVariableColor(variableColor: item.presentationData.theme.theme.chat.message.shareButtonFillColor, wallpaper: item.presentationData.theme.wallpaper), strokeColor: bubbleVariableColor(variableColor: item.presentationData.theme.theme.chat.message.shareButtonStrokeColor, wallpaper: item.presentationData.theme.wallpaper), foregroundColor: bubbleVariableColor(variableColor: item.presentationData.theme.theme.chat.message.shareButtonForegroundColor, wallpaper: item.presentationData.theme.wallpaper)) - strongSelf.swipeToReplyNode = swipeToReplyNode - strongSelf.insertSubnode(swipeToReplyNode, belowSubnode: strongSelf.messageAccessibilityArea) - swipeToReplyNode.frame = CGRect(origin: CGPoint(x: strongSelf.bounds.size.width, y: floor((strongSelf.contentSize.height - 33.0) / 2.0)), size: CGSize(width: 33.0, height: 33.0)) - swipeToReplyNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.12) - swipeToReplyNode.layer.animateSpring(from: 0.1 as NSNumber, to: 1.0 as NSNumber, keyPath: "transform.scale", duration: 0.4) - } - } - reactionRecognizer.completed = { [weak self] reaction in - guard let strongSelf = self else { - return - } - if let item = strongSelf.item, let reaction = reaction { - switch reaction { - case let .reaction(value, _, _): - var resolvedValue: String? - if let reactionsAttribute = mergedMessageReactions(attributes: item.message.attributes), reactionsAttribute.reactions.contains(where: { $0.value == value }) { - resolvedValue = nil - } else { - resolvedValue = value - } - strongSelf.awaitingAppliedReaction = (resolvedValue, {}) - item.controllerInteraction.updateMessageReaction(item.message.id, resolvedValue) - case .reply: - strongSelf.reactionRecognizer?.complete(into: nil, hideTarget: false) - var bounds = strongSelf.bounds - let offset = bounds.origin.x - bounds.origin.x = 0.0 - strongSelf.bounds = bounds - var shadowBounds = strongSelf.shadowNode.bounds - let shadowOffset = shadowBounds.origin.x - shadowBounds.origin.x = 0.0 - strongSelf.shadowNode.bounds = shadowBounds - if !offset.isZero { - strongSelf.layer.animateBoundsOriginXAdditive(from: offset, to: 0.0, duration: 0.2, timingFunction: kCAMediaTimingFunctionSpring) - } - if !shadowOffset.isZero { - strongSelf.shadowNode.layer.animateBoundsOriginXAdditive(from: shadowOffset, to: 0.0, duration: 0.2, timingFunction: kCAMediaTimingFunctionSpring) - } - if let swipeToReplyNode = strongSelf.swipeToReplyNode { - strongSelf.swipeToReplyNode = nil - swipeToReplyNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, removeOnCompletion: false, completion: { [weak swipeToReplyNode] _ in - swipeToReplyNode?.removeFromSupernode() - }) - swipeToReplyNode.layer.animateScale(from: 1.0, to: 0.2, duration: 0.3, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false) - } - item.controllerInteraction.setupReply(item.message.id) - } } else { - strongSelf.reactionRecognizer?.complete(into: nil, hideTarget: false) - var bounds = strongSelf.bounds - let offset = bounds.origin.x - bounds.origin.x = 0.0 - strongSelf.bounds = bounds - var shadowBounds = strongSelf.shadowNode.bounds - let shadowOffset = shadowBounds.origin.x - shadowBounds.origin.x = 0.0 - strongSelf.shadowNode.bounds = shadowBounds - if !offset.isZero { - strongSelf.layer.animateBoundsOriginXAdditive(from: offset, to: 0.0, duration: 0.2, timingFunction: kCAMediaTimingFunctionSpring) - } - if !shadowOffset.isZero { - strongSelf.shadowNode.layer.animateBoundsOriginXAdditive(from: shadowOffset, to: 0.0, duration: 0.2, timingFunction: kCAMediaTimingFunctionSpring) - } - if let swipeToReplyNode = strongSelf.swipeToReplyNode { - strongSelf.swipeToReplyNode = nil - swipeToReplyNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, removeOnCompletion: false, completion: { [weak swipeToReplyNode] _ in - swipeToReplyNode?.removeFromSupernode() - }) - swipeToReplyNode.layer.animateScale(from: 1.0, to: 0.2, duration: 0.3, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false) - } + return true } } - self.view.addGestureRecognizer(reactionRecognizer)*/ + return false } + self.view.addGestureRecognizer(replyRecognizer) } override func asyncLayout() -> (_ item: ChatMessageItem, _ params: ListViewItemLayoutParams, _ mergedTop: ChatMessageMerge, _ mergedBottom: ChatMessageMerge, _ dateHeaderAtBottom: Bool) -> (ListViewItemNodeLayout, (ListViewItemUpdateAnimation, ListViewItemApply, Bool) -> Void) { @@ -1110,7 +909,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode forwardInfoLayout: (ChatPresentationData, PresentationStrings, ChatMessageForwardInfoType, Peer?, String?, String?, CGSize) -> (CGSize, (CGFloat) -> ChatMessageForwardInfoNode), replyInfoLayout: (ChatPresentationData, PresentationStrings, AccountContext, ChatMessageReplyInfoType, Message, CGSize) -> (CGSize, () -> ChatMessageReplyInfoNode), actionButtonsLayout: (AccountContext, ChatPresentationThemeData, PresentationChatBubbleCorners, PresentationStrings, ReplyMarkupMessageAttribute, Message, CGFloat) -> (minWidth: CGFloat, layout: (CGFloat) -> (CGSize, (Bool) -> ChatMessageActionButtonsNode)), - mosaicStatusLayout: (AccountContext, ChatPresentationData, Bool, Int?, String, ChatMessageDateAndStatusType, CGSize, [MessageReaction], Int, Bool, Bool) -> (CGSize, (Bool) -> ChatMessageDateAndStatusNode), + mosaicStatusLayout: (AccountContext, ChatPresentationData, Bool, Int?, String, ChatMessageDateAndStatusType, CGSize, Int, Bool, Bool) -> (CGSize, (Bool) -> ChatMessageDateAndStatusNode), layoutConstants: ChatMessageItemLayoutConstants, currentItem: ChatMessageItem?, currentForwardInfo: (Peer?, String?)?, @@ -1678,26 +1477,13 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode } } - var dateReactions: [MessageReaction] = [] - var dateReactionCount = 0 - if let reactionsAttribute = mergedMessageReactions(attributes: item.message.attributes), !reactionsAttribute.reactions.isEmpty { - for reaction in reactionsAttribute.reactions { - if reaction.isSelected { - dateReactions.insert(reaction, at: 0) - } else { - dateReactions.append(reaction) - } - dateReactionCount += Int(reaction.count) - } - } - let dateFormat: MessageTimestampStatusFormat if let subject = item.associatedData.subject, case .forwardedMessages = subject { dateFormat = .minimal } else { dateFormat = .regular } - let dateText = stringForMessageTimestampStatus(accountPeerId: item.context.account.peerId, message: message, dateTimeFormat: item.presentationData.dateTimeFormat, nameDisplayOrder: item.presentationData.nameDisplayOrder, strings: item.presentationData.strings, format: dateFormat, reactionCount: dateReactionCount) + let dateText = stringForMessageTimestampStatus(accountPeerId: item.context.account.peerId, message: message, dateTimeFormat: item.presentationData.dateTimeFormat, nameDisplayOrder: item.presentationData.nameDisplayOrder, strings: item.presentationData.strings, format: dateFormat) let statusType: ChatMessageDateAndStatusType if message.effectivelyIncoming(item.context.account.peerId) { @@ -1717,7 +1503,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode isReplyThread = true } - mosaicStatusSizeAndApply = mosaicStatusLayout(item.context, item.presentationData, edited, viewCount, dateText, statusType, CGSize(width: 200.0, height: CGFloat.greatestFiniteMagnitude), dateReactions, dateReplies, message.tags.contains(.pinned) && !item.associatedData.isInPinnedListMode && !isReplyThread, message.isSelfExpiring) + mosaicStatusSizeAndApply = mosaicStatusLayout(item.context, item.presentationData, edited, viewCount, dateText, statusType, CGSize(width: 200.0, height: CGFloat.greatestFiniteMagnitude), dateReplies, message.tags.contains(.pinned) && !item.associatedData.isInPinnedListMode && !isReplyThread, message.isSelfExpiring) } } @@ -2889,45 +2675,6 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode } strongSelf.updateSearchTextHighlightState() - - /*if let (awaitingAppliedReaction, f) = strongSelf.awaitingAppliedReaction { - var bounds = strongSelf.bounds - let offset = bounds.origin.x - bounds.origin.x = 0.0 - strongSelf.bounds = bounds - var shadowBounds = strongSelf.shadowNode.bounds - let shadowOffset = shadowBounds.origin.x - shadowBounds.origin.x = 0.0 - strongSelf.shadowNode.bounds = shadowBounds - if !offset.isZero { - strongSelf.layer.animateBoundsOriginXAdditive(from: offset, to: 0.0, duration: 0.2, timingFunction: kCAMediaTimingFunctionSpring) - } - if !shadowOffset.isZero { - strongSelf.shadowNode.layer.animateBoundsOriginXAdditive(from: shadowOffset, to: 0.0, duration: 0.2, timingFunction: kCAMediaTimingFunctionSpring) - } - if let swipeToReplyNode = strongSelf.swipeToReplyNode { - strongSelf.swipeToReplyNode = nil - swipeToReplyNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, removeOnCompletion: false, completion: { [weak swipeToReplyNode] _ in - swipeToReplyNode?.removeFromSupernode() - }) - swipeToReplyNode.layer.animateScale(from: 1.0, to: 0.2, duration: 0.3, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false) - } - - strongSelf.awaitingAppliedReaction = nil - /*var targetNode: ASDisplayNode? - var hideTarget = false - if let awaitingAppliedReaction = awaitingAppliedReaction { - for contentNode in strongSelf.contentNodes { - if let (reactionNode, count) = contentNode.reactionTargetNode(value: awaitingAppliedReaction) { - targetNode = reactionNode - hideTarget = count == 1 - break - } - } - } - strongSelf.reactionRecognizer?.complete(into: targetNode, hideTarget: hideTarget)*/ - f() - }*/ } override func updateAccessibilityData(_ accessibilityData: ChatMessageAccessibilityData) { @@ -3766,10 +3513,6 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode break case .reply: item.controllerInteraction.setupReply(item.message.id) - case .like: - item.controllerInteraction.updateMessageLike(item.message.id, true) - case .unlike: - item.controllerInteraction.updateMessageLike(item.message.id, false) } } } @@ -3854,15 +3597,6 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode self.mainContextSourceNode.contentNode.addSubnode(accessoryItemNode) } - override func targetReactionNode(value: String) -> (ASDisplayNode, ASDisplayNode)? { - for contentNode in self.contentNodes { - if let (emptyNode, filledNode) = contentNode.reactionTargetNode(value: value) { - return (emptyNode, filledNode) - } - } - return nil - } - private var backgroundMaskMode: Bool { let hasWallpaper = self.item?.presentationData.theme.wallpaper.hasWallpaper ?? false let isPreview = self.item?.presentationData.isPreview ?? false diff --git a/submodules/TelegramUI/Sources/ChatMessageCallBubbleContentNode.swift b/submodules/TelegramUI/Sources/ChatMessageCallBubbleContentNode.swift index b1dc6ef568..c14d04ee1a 100644 --- a/submodules/TelegramUI/Sources/ChatMessageCallBubbleContentNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageCallBubbleContentNode.swift @@ -167,7 +167,7 @@ class ChatMessageCallBubbleContentNode: ChatMessageBubbleContentNode { } } - let dateText = stringForMessageTimestampStatus(accountPeerId: item.context.account.peerId, message: item.message, dateTimeFormat: item.presentationData.dateTimeFormat, nameDisplayOrder: item.presentationData.nameDisplayOrder, strings: item.presentationData.strings, reactionCount: 0) + let dateText = stringForMessageTimestampStatus(accountPeerId: item.context.account.peerId, message: item.message, dateTimeFormat: item.presentationData.dateTimeFormat, nameDisplayOrder: item.presentationData.nameDisplayOrder, strings: item.presentationData.strings) let statusText: String if let callDuration = callDuration, callDuration > 1 { @@ -265,8 +265,4 @@ class ChatMessageCallBubbleContentNode: ChatMessageBubbleContentNode { return .none } } - - override func reactionTargetNode(value: String) -> (ASDisplayNode, ASDisplayNode)? { - return nil - } } diff --git a/submodules/TelegramUI/Sources/ChatMessageContactBubbleContentNode.swift b/submodules/TelegramUI/Sources/ChatMessageContactBubbleContentNode.swift index fb63b3b837..01024dd50e 100644 --- a/submodules/TelegramUI/Sources/ChatMessageContactBubbleContentNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageContactBubbleContentNode.swift @@ -166,20 +166,7 @@ class ChatMessageContactBubbleContentNode: ChatMessageBubbleContentNode { } } - var dateReactions: [MessageReaction] = [] - var dateReactionCount = 0 - if let reactionsAttribute = mergedMessageReactions(attributes: item.message.attributes), !reactionsAttribute.reactions.isEmpty { - for reaction in reactionsAttribute.reactions { - if reaction.isSelected { - dateReactions.insert(reaction, at: 0) - } else { - dateReactions.append(reaction) - } - dateReactionCount += Int(reaction.count) - } - } - - let dateText = stringForMessageTimestampStatus(accountPeerId: item.context.account.peerId, message: item.message, dateTimeFormat: item.presentationData.dateTimeFormat, nameDisplayOrder: item.presentationData.nameDisplayOrder, strings: item.presentationData.strings, reactionCount: dateReactionCount) + let dateText = stringForMessageTimestampStatus(accountPeerId: item.context.account.peerId, message: item.message, dateTimeFormat: item.presentationData.dateTimeFormat, nameDisplayOrder: item.presentationData.nameDisplayOrder, strings: item.presentationData.strings) let statusType: ChatMessageDateAndStatusType? switch position { @@ -208,7 +195,7 @@ class ChatMessageContactBubbleContentNode: ChatMessageBubbleContentNode { isReplyThread = true } - let (size, apply) = statusLayout(item.context, item.presentationData, edited, viewCount, dateText, statusType, CGSize(width: constrainedSize.width, height: CGFloat.greatestFiniteMagnitude), dateReactions, dateReplies, item.message.tags.contains(.pinned) && !item.associatedData.isInPinnedListMode && !isReplyThread, item.message.isSelfExpiring) + let (size, apply) = statusLayout(item.context, item.presentationData, edited, viewCount, dateText, statusType, CGSize(width: constrainedSize.width, height: CGFloat.greatestFiniteMagnitude), dateReplies, item.message.tags.contains(.pinned) && !item.associatedData.isInPinnedListMode && !isReplyThread, item.message.isSelfExpiring) statusSize = size statusApply = apply } @@ -376,11 +363,4 @@ class ChatMessageContactBubbleContentNode: ChatMessageBubbleContentNode { let _ = item.controllerInteraction.openMessage(item.message, .default) } } - - override func reactionTargetNode(value: String) -> (ASDisplayNode, ASDisplayNode)? { - if !self.dateAndStatusNode.isHidden { - return self.dateAndStatusNode.reactionNode(value: value) - } - return nil - } } diff --git a/submodules/TelegramUI/Sources/ChatMessageDateAndStatusNode.swift b/submodules/TelegramUI/Sources/ChatMessageDateAndStatusNode.swift index bba9996b08..c341a56221 100644 --- a/submodules/TelegramUI/Sources/ChatMessageDateAndStatusNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageDateAndStatusNode.swift @@ -9,8 +9,6 @@ import TelegramPresentationData import AccountContext import AppBundle -private let reactionCountFont = Font.semibold(11.0) - private func maybeAddRotationAnimation(_ layer: CALayer, duration: Double) { if let _ = layer.animation(forKey: "clockFrameAnimation") { return @@ -42,112 +40,6 @@ enum ChatMessageDateAndStatusType: Equatable { case FreeOutgoing(ChatMessageDateAndStatusOutgoingType) } -private let reactionFont = Font.regular(12.0) - -private final class StatusReactionNode: ASDisplayNode { - let emptyImageNode: ASImageNode - let selectedImageNode: ASImageNode - - private var theme: PresentationTheme? - private var isSelected: Bool? - - override init() { - self.emptyImageNode = ASImageNode() - self.emptyImageNode.displaysAsynchronously = false - self.selectedImageNode = ASImageNode() - self.selectedImageNode.displaysAsynchronously = false - - super.init() - - self.addSubnode(self.emptyImageNode) - self.addSubnode(self.selectedImageNode) - } - - func update(type: ChatMessageDateAndStatusType, isSelected: Bool, count: Int, theme: PresentationTheme, wallpaper: TelegramWallpaper, animated: Bool) { - if self.theme !== theme { - self.theme = theme - - let emptyImage: UIImage? - let selectedImage: UIImage? - switch type { - case .BubbleIncoming: - emptyImage = PresentationResourcesChat.chatMessageLike(theme, incoming: true, isSelected: false) - selectedImage = PresentationResourcesChat.chatMessageLike(theme, incoming: true, isSelected: true) - case .BubbleOutgoing: - emptyImage = PresentationResourcesChat.chatMessageLike(theme, incoming: false, isSelected: false) - selectedImage = PresentationResourcesChat.chatMessageLike(theme, incoming: false, isSelected: true) - case .ImageIncoming, .ImageOutgoing: - emptyImage = PresentationResourcesChat.chatMessageMediaLike(theme, isSelected: false) - selectedImage = PresentationResourcesChat.chatMessageMediaLike(theme, isSelected: true) - case .FreeIncoming, .FreeOutgoing: - emptyImage = PresentationResourcesChat.chatMessageFreeLike(theme, wallpaper: wallpaper, isSelected: false) - selectedImage = PresentationResourcesChat.chatMessageFreeLike(theme, wallpaper: wallpaper, isSelected: true) - } - - if let emptyImage = emptyImage, let selectedImage = selectedImage { - self.emptyImageNode.image = emptyImage - self.emptyImageNode.frame = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: emptyImage.size) - - self.selectedImageNode.image = selectedImage - self.selectedImageNode.frame = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: selectedImage.size) - } - } - - if self.isSelected != isSelected { - let wasSelected = self.isSelected - self.isSelected = isSelected - - self.emptyImageNode.isHidden = isSelected && count <= 1 - self.selectedImageNode.isHidden = !isSelected - - if let wasSelected = wasSelected, wasSelected, !isSelected { - if let image = self.selectedImageNode.image { - let leftImage = generateImage(image.size, rotatedContext: { size, context in - context.clear(CGRect(origin: CGPoint(), size: size)) - UIGraphicsPushContext(context) - image.draw(in: CGRect(origin: CGPoint(), size: size)) - UIGraphicsPopContext() - context.clear(CGRect(origin: CGPoint(x: size.width / 2.0, y: 0.0), size: CGSize(width: size.width / 2.0, height: size.height))) - }) - let rightImage = generateImage(image.size, rotatedContext: { size, context in - context.clear(CGRect(origin: CGPoint(), size: size)) - UIGraphicsPushContext(context) - image.draw(in: CGRect(origin: CGPoint(), size: size)) - UIGraphicsPopContext() - context.clear(CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: size.width / 2.0, height: size.height))) - }) - if let leftImage = leftImage, let rightImage = rightImage { - let leftView = UIImageView() - leftView.image = leftImage - leftView.frame = self.selectedImageNode.frame - let rightView = UIImageView() - rightView.image = rightImage - rightView.frame = self.selectedImageNode.frame - self.view.addSubview(leftView) - self.view.addSubview(rightView) - - let duration: Double = 0.3 - - leftView.layer.animateRotation(from: 0.0, to: -CGFloat.pi * 0.7, duration: duration, removeOnCompletion: false) - rightView.layer.animateRotation(from: 0.0, to: CGFloat.pi * 0.7, duration: duration, removeOnCompletion: false) - - leftView.layer.animatePosition(from: CGPoint(), to: CGPoint(x: -6.0, y: 8.0), duration: duration, removeOnCompletion: false, additive: true) - rightView.layer.animatePosition(from: CGPoint(), to: CGPoint(x: 6.0, y: 8.0), duration: duration, removeOnCompletion: false, additive: true) - - leftView.layer.animateAlpha(from: 1.0, to: 0.0, duration: duration, removeOnCompletion: false, completion: { [weak leftView] _ in - leftView?.removeFromSuperview() - }) - - rightView.layer.animateAlpha(from: 1.0, to: 0.0, duration: duration, removeOnCompletion: false, completion: { [weak rightView] _ in - rightView?.removeFromSuperview() - }) - } - } - } - } - } -} - class ChatMessageDateAndStatusNode: ASDisplayNode { private var backgroundNode: ASImageNode? private var blurredBackgroundNode: NavigationBackgroundNode? @@ -157,9 +49,6 @@ class ChatMessageDateAndStatusNode: ASDisplayNode { private var clockMinNode: ASImageNode? private let dateNode: TextNode private var impressionIcon: ASImageNode? - private var reactionNodes: [StatusReactionNode] = [] - private var reactionCountNode: TextNode? - private var reactionButtonNode: HighlightTrackingButtonNode? private var repliesIcon: ASImageNode? private var selfExpiringIcon: ASImageNode? private var replyCountNode: TextNode? @@ -169,8 +58,7 @@ class ChatMessageDateAndStatusNode: ASDisplayNode { private var layoutSize: CGSize? private var tapGestureRecognizer: UITapGestureRecognizer? - - var openReactions: (() -> Void)? + var openReplies: (() -> Void)? var pressed: (() -> Void)? { didSet { @@ -203,7 +91,7 @@ class ChatMessageDateAndStatusNode: ASDisplayNode { } } - func asyncLayout() -> (_ context: AccountContext, _ presentationData: ChatPresentationData, _ edited: Bool, _ impressionCount: Int?, _ dateText: String, _ type: ChatMessageDateAndStatusType, _ constrainedSize: CGSize, _ reactions: [MessageReaction], _ replies: Int, _ isPinned: Bool, _ hasAutoremove: Bool) -> (CGSize, (Bool) -> Void) { + func asyncLayout() -> (_ context: AccountContext, _ presentationData: ChatPresentationData, _ edited: Bool, _ impressionCount: Int?, _ dateText: String, _ type: ChatMessageDateAndStatusType, _ constrainedSize: CGSize, _ replies: Int, _ isPinned: Bool, _ hasAutoremove: Bool) -> (CGSize, (Bool) -> Void) { let dateLayout = TextNode.asyncLayout(self.dateNode) var checkReadNode = self.checkReadNode @@ -217,13 +105,12 @@ class ChatMessageDateAndStatusNode: ASDisplayNode { let currentType = self.type let currentTheme = self.theme - - let makeReactionCountLayout = TextNode.asyncLayout(self.reactionCountNode) + let makeReplyCountLayout = TextNode.asyncLayout(self.replyCountNode) let previousLayoutSize = self.layoutSize - return { context, presentationData, edited, impressionCount, dateText, type, constrainedSize, reactions, replyCount, isPinned, hasAutoremove in + return { context, presentationData, edited, impressionCount, dateText, type, constrainedSize, replyCount, isPinned, hasAutoremove in let dateColor: UIColor var backgroundImage: UIImage? var blurredBackgroundColor: (UIColor, Bool)? @@ -526,35 +413,10 @@ class ChatMessageDateAndStatusNode: ASDisplayNode { } else if blurredBackgroundColor != nil { backgroundInsets = UIEdgeInsets(top: 2.0, left: 7.0, bottom: 2.0, right: 7.0) } - - let reactionSize: CGFloat = 14.0 - var reactionCountLayoutAndApply: (TextNodeLayout, () -> TextNode)? + var replyCountLayoutAndApply: (TextNodeLayout, () -> TextNode)? - - let reactionSpacing: CGFloat = -4.0 - let reactionTrailingSpacing: CGFloat = 4.0 + var reactionInset: CGFloat = 0.0 - if !reactions.isEmpty { - reactionInset = -1.0 + CGFloat(reactions.count) * reactionSize + CGFloat(reactions.count - 1) * reactionSpacing + reactionTrailingSpacing - - var count = 0 - for reaction in reactions { - count += Int(reaction.count) - } - - let countString: String - if count > 1000000 { - countString = "\(count / 1000000)M" - } else if count > 1000 { - countString = "\(count / 1000)K" - } else { - countString = "\(count)" - } - - let layoutAndApply = makeReactionCountLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: countString, font: dateFont, textColor: dateColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: 100.0, height: 100.0))) - reactionInset += max(10.0, layoutAndApply.0.size.width) + 2.0 - reactionCountLayoutAndApply = layoutAndApply - } if replyCount > 0 { let countString: String @@ -737,80 +599,6 @@ class ChatMessageDateAndStatusNode: ASDisplayNode { } var reactionOffset: CGFloat = leftInset - reactionInset + backgroundInsets.left - for i in 0 ..< reactions.count { - let node: StatusReactionNode - if strongSelf.reactionNodes.count > i { - node = strongSelf.reactionNodes[i] - } else { - node = StatusReactionNode() - if strongSelf.reactionNodes.count > i { - let previousNode = strongSelf.reactionNodes[i] - if animated { - previousNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false, completion: { [weak previousNode] _ in - previousNode?.removeFromSupernode() - }) - } else { - previousNode.removeFromSupernode() - } - strongSelf.reactionNodes[i] = node - } else { - strongSelf.reactionNodes.append(node) - } - } - - node.update(type: type, isSelected: reactions[i].isSelected, count: Int(reactions[i].count), theme: presentationData.theme.theme, wallpaper: presentationData.theme.wallpaper, animated: false) - if node.supernode == nil { - strongSelf.addSubnode(node) - if animated { - node.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2) - } - } - node.frame = CGRect(origin: CGPoint(x: reactionOffset, y: backgroundInsets.top + offset + 1.0), size: CGSize(width: reactionSize, height: reactionSize)) - reactionOffset += reactionSize + reactionSpacing - } - if !reactions.isEmpty { - reactionOffset += reactionTrailingSpacing - } - for _ in reactions.count ..< strongSelf.reactionNodes.count { - let node = strongSelf.reactionNodes.removeLast() - if animated { - if let previousLayoutSize = previousLayoutSize { - node.frame = node.frame.offsetBy(dx: layoutSize.width - previousLayoutSize.width, dy: 0.0) - } - node.layer.animateScale(from: 1.0, to: 0.1, duration: 0.2, removeOnCompletion: false) - node.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false, completion: { [weak node] _ in - node?.removeFromSupernode() - }) - } else { - node.removeFromSupernode() - } - } - - if let (layout, apply) = reactionCountLayoutAndApply { - let node = apply() - if strongSelf.reactionCountNode !== node { - strongSelf.reactionCountNode?.removeFromSupernode() - strongSelf.addSubnode(node) - strongSelf.reactionCountNode = node - if animated { - node.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.15) - } - } - node.frame = CGRect(origin: CGPoint(x: reactionOffset + 1.0, y: backgroundInsets.top + 1.0 + offset), size: layout.size) - reactionOffset += 1.0 + layout.size.width - } else if let reactionCountNode = strongSelf.reactionCountNode { - strongSelf.reactionCountNode = nil - if animated { - if let previousLayoutSize = previousLayoutSize { - reactionCountNode.frame = reactionCountNode.frame.offsetBy(dx: layoutSize.width - previousLayoutSize.width, dy: 0.0) - } - reactionCountNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false, completion: { [weak reactionCountNode] _ in - reactionCountNode?.removeFromSupernode() - }) - } else { - reactionCountNode.removeFromSupernode() - } - } if let currentRepliesIcon = currentRepliesIcon { currentRepliesIcon.displaysAsynchronously = !presentationData.isPreview @@ -865,50 +653,22 @@ class ChatMessageDateAndStatusNode: ASDisplayNode { replyCountNode.removeFromSupernode() } } - - /*if !strongSelf.reactionNodes.isEmpty { - if strongSelf.reactionButtonNode == nil { - let reactionButtonNode = HighlightTrackingButtonNode() - strongSelf.reactionButtonNode = reactionButtonNode - strongSelf.addSubnode(reactionButtonNode) - reactionButtonNode.addTarget(strongSelf, action: #selector(strongSelf.reactionButtonPressed), forControlEvents: .touchUpInside) - reactionButtonNode.highligthedChanged = { [weak strongSelf] highlighted in - guard let strongSelf = strongSelf else { - return - } - if highlighted { - for itemNode in strongSelf.reactionNodes { - itemNode.alpha = 0.4 - } - } else { - for itemNode in strongSelf.reactionNodes { - itemNode.alpha = 1.0 - itemNode.layer.animateAlpha(from: 0.4, to: 1.0, duration: 0.3) - } - } - } - } - strongSelf.reactionButtonNode?.frame = CGRect(origin: CGPoint(x: leftInset - reactionInset + backgroundInsets.left - 5.0, y: backgroundInsets.top + 1.0 + offset - 5.0), size: CGSize(width: reactionOffset + 5.0 * 2.0, height: 20.0)) - } else if let reactionButtonNode = strongSelf.reactionButtonNode { - strongSelf.reactionButtonNode = nil - reactionButtonNode.removeFromSupernode() - }*/ } }) } } - static func asyncLayout(_ node: ChatMessageDateAndStatusNode?) -> (_ context: AccountContext, _ presentationData: ChatPresentationData, _ edited: Bool, _ impressionCount: Int?, _ dateText: String, _ type: ChatMessageDateAndStatusType, _ constrainedSize: CGSize, _ reactions: [MessageReaction], _ replies: Int, _ isPinned: Bool, _ hasAutoremove: Bool) -> (CGSize, (Bool) -> ChatMessageDateAndStatusNode) { + static func asyncLayout(_ node: ChatMessageDateAndStatusNode?) -> (_ context: AccountContext, _ presentationData: ChatPresentationData, _ edited: Bool, _ impressionCount: Int?, _ dateText: String, _ type: ChatMessageDateAndStatusType, _ constrainedSize: CGSize, _ replies: Int, _ isPinned: Bool, _ hasAutoremove: Bool) -> (CGSize, (Bool) -> ChatMessageDateAndStatusNode) { let currentLayout = node?.asyncLayout() - return { context, presentationData, edited, impressionCount, dateText, type, constrainedSize, reactions, replies, isPinned, hasAutoremove in + return { context, presentationData, edited, impressionCount, dateText, type, constrainedSize, replies, isPinned, hasAutoremove in let resultNode: ChatMessageDateAndStatusNode let resultSizeAndApply: (CGSize, (Bool) -> Void) if let node = node, let currentLayout = currentLayout { resultNode = node - resultSizeAndApply = currentLayout(context, presentationData, edited, impressionCount, dateText, type, constrainedSize, reactions, replies, isPinned, hasAutoremove) + resultSizeAndApply = currentLayout(context, presentationData, edited, impressionCount, dateText, type, constrainedSize, replies, isPinned, hasAutoremove) } else { resultNode = ChatMessageDateAndStatusNode() - resultSizeAndApply = resultNode.asyncLayout()(context, presentationData, edited, impressionCount, dateText, type, constrainedSize, reactions, replies, isPinned, hasAutoremove) + resultSizeAndApply = resultNode.asyncLayout()(context, presentationData, edited, impressionCount, dateText, type, constrainedSize, replies, isPinned, hasAutoremove) } return (resultSizeAndApply.0, { animated in @@ -918,23 +678,7 @@ class ChatMessageDateAndStatusNode: ASDisplayNode { } } - func reactionNode(value: String) -> (ASDisplayNode, ASDisplayNode)? { - for node in self.reactionNodes { - return (node.emptyImageNode, node.selectedImageNode) - } - return nil - } - - @objc private func reactionButtonPressed() { - self.openReactions?() - } - override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { - if let reactionButtonNode = self.reactionButtonNode { - if reactionButtonNode.frame.contains(point) { - return reactionButtonNode.view - } - } if self.pressed != nil { if self.bounds.contains(point) { return self.view diff --git a/submodules/TelegramUI/Sources/ChatMessageFileBubbleContentNode.swift b/submodules/TelegramUI/Sources/ChatMessageFileBubbleContentNode.swift index 45cbb914ab..66e78959cb 100644 --- a/submodules/TelegramUI/Sources/ChatMessageFileBubbleContentNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageFileBubbleContentNode.swift @@ -160,8 +160,4 @@ class ChatMessageFileBubbleContentNode: ChatMessageBubbleContentNode { override func animateRemoved(_ currentTimestamp: Double, duration: Double) { self.interactiveFileNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false) } - - override func reactionTargetNode(value: String) -> (ASDisplayNode, ASDisplayNode)? { - return self.interactiveFileNode.reactionTargetNode(value: value) - } } diff --git a/submodules/TelegramUI/Sources/ChatMessageGameBubbleContentNode.swift b/submodules/TelegramUI/Sources/ChatMessageGameBubbleContentNode.swift index b17ed19d17..ff96893061 100644 --- a/submodules/TelegramUI/Sources/ChatMessageGameBubbleContentNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageGameBubbleContentNode.swift @@ -139,8 +139,4 @@ final class ChatMessageGameBubbleContentNode: ChatMessageBubbleContentNode { } return self.contentNode.transitionNode(media: media) } - - override func reactionTargetNode(value: String) -> (ASDisplayNode, ASDisplayNode)? { - return self.contentNode.reactionTargetNode(value: value) - } } diff --git a/submodules/TelegramUI/Sources/ChatMessageInstantVideoItemNode.swift b/submodules/TelegramUI/Sources/ChatMessageInstantVideoItemNode.swift index 917c8abe47..7fec802f35 100644 --- a/submodules/TelegramUI/Sources/ChatMessageInstantVideoItemNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageInstantVideoItemNode.swift @@ -980,10 +980,6 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView, UIGestureRecognizerD break case .reply: item.controllerInteraction.setupReply(item.message.id) - case .like: - item.controllerInteraction.updateMessageLike(item.message.id, true) - case .unlike: - item.controllerInteraction.updateMessageLike(item.message.id, true) } } } diff --git a/submodules/TelegramUI/Sources/ChatMessageInteractiveFileNode.swift b/submodules/TelegramUI/Sources/ChatMessageInteractiveFileNode.swift index e3e40ed745..5b425f7342 100644 --- a/submodules/TelegramUI/Sources/ChatMessageInteractiveFileNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageInteractiveFileNode.swift @@ -320,22 +320,9 @@ final class ChatMessageInteractiveFileNode: ASDisplayNode { edited = true } - var dateReactions: [MessageReaction] = [] - var dateReactionCount = 0 - if let reactionsAttribute = mergedMessageReactions(attributes: message.attributes), !reactionsAttribute.reactions.isEmpty { - for reaction in reactionsAttribute.reactions { - if reaction.isSelected { - dateReactions.insert(reaction, at: 0) - } else { - dateReactions.append(reaction) - } - dateReactionCount += Int(reaction.count) - } - } + let dateText = stringForMessageTimestampStatus(accountPeerId: context.account.peerId, message: message, dateTimeFormat: presentationData.dateTimeFormat, nameDisplayOrder: presentationData.nameDisplayOrder, strings: presentationData.strings) - let dateText = stringForMessageTimestampStatus(accountPeerId: context.account.peerId, message: message, dateTimeFormat: presentationData.dateTimeFormat, nameDisplayOrder: presentationData.nameDisplayOrder, strings: presentationData.strings, reactionCount: dateReactionCount) - - let (size, apply) = statusLayout(context, presentationData, edited, viewCount, dateText, statusType, constrainedSize, dateReactions, dateReplies, isPinned && !associatedData.isInPinnedListMode, message.isSelfExpiring) + let (size, apply) = statusLayout(context, presentationData, edited, viewCount, dateText, statusType, constrainedSize, dateReplies, isPinned && !associatedData.isInPinnedListMode, message.isSelfExpiring) statusSize = size statusApply = apply } @@ -1137,13 +1124,6 @@ final class ChatMessageInteractiveFileNode: ASDisplayNode { self.playerUpdateTimer?.invalidate() self.playerUpdateTimer = nil } - - func reactionTargetNode(value: String) -> (ASDisplayNode, ASDisplayNode)? { - if !self.dateAndStatusNode.isHidden { - return self.dateAndStatusNode.reactionNode(value: value) - } - return nil - } } diff --git a/submodules/TelegramUI/Sources/ChatMessageInteractiveInstantVideoNode.swift b/submodules/TelegramUI/Sources/ChatMessageInteractiveInstantVideoNode.swift index f21aa256bd..cfc01ba572 100644 --- a/submodules/TelegramUI/Sources/ChatMessageInteractiveInstantVideoNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageInteractiveInstantVideoNode.swift @@ -274,20 +274,7 @@ class ChatMessageInteractiveInstantVideoNode: ASDisplayNode { } } - var dateReactions: [MessageReaction] = [] - var dateReactionCount = 0 - if let reactionsAttribute = mergedMessageReactions(attributes: item.message.attributes), !reactionsAttribute.reactions.isEmpty { - for reaction in reactionsAttribute.reactions { - if reaction.isSelected { - dateReactions.insert(reaction, at: 0) - } else { - dateReactions.append(reaction) - } - dateReactionCount += Int(reaction.count) - } - } - - let dateText = stringForMessageTimestampStatus(accountPeerId: item.context.account.peerId, message: item.message, dateTimeFormat: item.presentationData.dateTimeFormat, nameDisplayOrder: item.presentationData.nameDisplayOrder, strings: item.presentationData.strings, format: .regular, reactionCount: dateReactionCount) + let dateText = stringForMessageTimestampStatus(accountPeerId: item.context.account.peerId, message: item.message, dateTimeFormat: item.presentationData.dateTimeFormat, nameDisplayOrder: item.presentationData.nameDisplayOrder, strings: item.presentationData.strings, format: .regular) let maxDateAndStatusWidth: CGFloat if case .bubble = statusDisplayType { @@ -301,7 +288,7 @@ class ChatMessageInteractiveInstantVideoNode: ASDisplayNode { isReplyThread = true } - let (dateAndStatusSize, dateAndStatusApply) = makeDateAndStatusLayout(item.context, item.presentationData, edited && !sentViaBot, viewCount, dateText, statusType, CGSize(width: max(1.0, maxDateAndStatusWidth), height: CGFloat.greatestFiniteMagnitude), dateReactions, dateReplies, item.message.tags.contains(.pinned) && !item.associatedData.isInPinnedListMode && !isReplyThread, item.message.isSelfExpiring) + let (dateAndStatusSize, dateAndStatusApply) = makeDateAndStatusLayout(item.context, item.presentationData, edited && !sentViaBot, viewCount, dateText, statusType, CGSize(width: max(1.0, maxDateAndStatusWidth), height: CGFloat.greatestFiniteMagnitude), dateReplies, item.message.tags.contains(.pinned) && !item.associatedData.isInPinnedListMode && !isReplyThread, item.message.isSelfExpiring) var displayVideoFrame = videoFrame displayVideoFrame.size.width *= imageScale diff --git a/submodules/TelegramUI/Sources/ChatMessageInteractiveMediaNode.swift b/submodules/TelegramUI/Sources/ChatMessageInteractiveMediaNode.swift index 5b7b0e5f30..323e38ba2e 100644 --- a/submodules/TelegramUI/Sources/ChatMessageInteractiveMediaNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageInteractiveMediaNode.swift @@ -69,7 +69,6 @@ struct ChatMessageDateAndStatus { var edited: Bool var viewCount: Int? var dateReplies: Int - var dateReactions: [MessageReaction] var isPinned: Bool var dateText: String } @@ -468,7 +467,7 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTransitio var statusApply: ((Bool) -> Void)? if let dateAndStatus = dateAndStatus { - let (size, apply) = statusLayout(context, presentationData, dateAndStatus.edited, dateAndStatus.viewCount, dateAndStatus.dateText, dateAndStatus.type, CGSize(width: nativeSize.width - 30.0, height: CGFloat.greatestFiniteMagnitude), dateAndStatus.dateReactions, dateAndStatus.dateReplies, dateAndStatus.isPinned, message.isSelfExpiring) + let (size, apply) = statusLayout(context, presentationData, dateAndStatus.edited, dateAndStatus.viewCount, dateAndStatus.dateText, dateAndStatus.type, CGSize(width: nativeSize.width - 30.0, height: CGFloat.greatestFiniteMagnitude), dateAndStatus.dateReplies, dateAndStatus.isPinned, message.isSelfExpiring) statusSize = size statusApply = apply } diff --git a/submodules/TelegramUI/Sources/ChatMessageInvoiceBubbleContentNode.swift b/submodules/TelegramUI/Sources/ChatMessageInvoiceBubbleContentNode.swift index e8f5830a2f..fef2e5cd0d 100644 --- a/submodules/TelegramUI/Sources/ChatMessageInvoiceBubbleContentNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageInvoiceBubbleContentNode.swift @@ -135,8 +135,4 @@ final class ChatMessageInvoiceBubbleContentNode: ChatMessageBubbleContentNode { } return self.contentNode.transitionNode(media: media) } - - override func reactionTargetNode(value: String) -> (ASDisplayNode, ASDisplayNode)? { - return self.contentNode.reactionTargetNode(value: value) - } } diff --git a/submodules/TelegramUI/Sources/ChatMessageMapBubbleContentNode.swift b/submodules/TelegramUI/Sources/ChatMessageMapBubbleContentNode.swift index 6655607b0f..ef18419e76 100644 --- a/submodules/TelegramUI/Sources/ChatMessageMapBubbleContentNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageMapBubbleContentNode.swift @@ -195,26 +195,13 @@ class ChatMessageMapBubbleContentNode: ChatMessageBubbleContentNode { } } - var dateReactions: [MessageReaction] = [] - var dateReactionCount = 0 - if let reactionsAttribute = mergedMessageReactions(attributes: item.message.attributes), !reactionsAttribute.reactions.isEmpty { - for reaction in reactionsAttribute.reactions { - if reaction.isSelected { - dateReactions.insert(reaction, at: 0) - } else { - dateReactions.append(reaction) - } - dateReactionCount += Int(reaction.count) - } - } - if let selectedMedia = selectedMedia { if selectedMedia.liveBroadcastingTimeout != nil { edited = false } } - let dateText = stringForMessageTimestampStatus(accountPeerId: item.context.account.peerId, message: item.message, dateTimeFormat: item.presentationData.dateTimeFormat, nameDisplayOrder: item.presentationData.nameDisplayOrder, strings: item.presentationData.strings, reactionCount: dateReactionCount) + let dateText = stringForMessageTimestampStatus(accountPeerId: item.context.account.peerId, message: item.message, dateTimeFormat: item.presentationData.dateTimeFormat, nameDisplayOrder: item.presentationData.nameDisplayOrder, strings: item.presentationData.strings) let statusType: ChatMessageDateAndStatusType? switch position { @@ -257,7 +244,7 @@ class ChatMessageMapBubbleContentNode: ChatMessageBubbleContentNode { isReplyThread = true } - let (size, apply) = statusLayout(item.context, item.presentationData, edited, viewCount, dateText, statusType, CGSize(width: constrainedSize.width, height: CGFloat.greatestFiniteMagnitude), dateReactions, dateReplies, item.message.tags.contains(.pinned) && !item.associatedData.isInPinnedListMode && !isReplyThread, item.message.isSelfExpiring) + let (size, apply) = statusLayout(item.context, item.presentationData, edited, viewCount, dateText, statusType, CGSize(width: constrainedSize.width, height: CGFloat.greatestFiniteMagnitude), dateReplies, item.message.tags.contains(.pinned) && !item.associatedData.isInPinnedListMode && !isReplyThread, item.message.isSelfExpiring) statusSize = size statusApply = apply } @@ -498,11 +485,4 @@ class ChatMessageMapBubbleContentNode: ChatMessageBubbleContentNode { } } } - - override func reactionTargetNode(value: String) -> (ASDisplayNode, ASDisplayNode)? { - if !self.dateAndStatusNode.isHidden { - return self.dateAndStatusNode.reactionNode(value: value) - } - return nil - } } diff --git a/submodules/TelegramUI/Sources/ChatMessageMediaBubbleContentNode.swift b/submodules/TelegramUI/Sources/ChatMessageMediaBubbleContentNode.swift index e5d284ab45..5477264c9c 100644 --- a/submodules/TelegramUI/Sources/ChatMessageMediaBubbleContentNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageMediaBubbleContentNode.swift @@ -167,20 +167,7 @@ class ChatMessageMediaBubbleContentNode: ChatMessageBubbleContentNode { } } - var dateReactions: [MessageReaction] = [] - var dateReactionCount = 0 - if let reactionsAttribute = mergedMessageReactions(attributes: item.message.attributes), !reactionsAttribute.reactions.isEmpty { - for reaction in reactionsAttribute.reactions { - if reaction.isSelected { - dateReactions.insert(reaction, at: 0) - } else { - dateReactions.append(reaction) - } - dateReactionCount += Int(reaction.count) - } - } - - let dateText = stringForMessageTimestampStatus(accountPeerId: item.context.account.peerId, message: item.message, dateTimeFormat: item.presentationData.dateTimeFormat, nameDisplayOrder: item.presentationData.nameDisplayOrder, strings: item.presentationData.strings, reactionCount: dateReactionCount) + let dateText = stringForMessageTimestampStatus(accountPeerId: item.context.account.peerId, message: item.message, dateTimeFormat: item.presentationData.dateTimeFormat, nameDisplayOrder: item.presentationData.nameDisplayOrder, strings: item.presentationData.strings) let statusType: ChatMessageDateAndStatusType? switch preparePosition { @@ -213,7 +200,6 @@ class ChatMessageMediaBubbleContentNode: ChatMessageBubbleContentNode { edited: edited, viewCount: viewCount, dateReplies: dateReplies, - dateReactions: dateReactions, isPinned: item.message.tags.contains(.pinned) && !item.associatedData.isInPinnedListMode && !isReplyThread, dateText: dateText ) @@ -399,11 +385,4 @@ class ChatMessageMediaBubbleContentNode: ChatMessageBubbleContentNode { return false } - - override func reactionTargetNode(value: String) -> (ASDisplayNode, ASDisplayNode)? { - /*if !self.dateAndStatusNode.isHidden { - return self.dateAndStatusNode.reactionNode(value: value) - }*/ - return nil - } } diff --git a/submodules/TelegramUI/Sources/ChatMessageNotificationItem.swift b/submodules/TelegramUI/Sources/ChatMessageNotificationItem.swift index d1c8e94fd8..3333e967ff 100644 --- a/submodules/TelegramUI/Sources/ChatMessageNotificationItem.swift +++ b/submodules/TelegramUI/Sources/ChatMessageNotificationItem.swift @@ -112,31 +112,31 @@ final class ChatMessageNotificationItemNode: NotificationItemNode { var isReminder = false var isScheduled = false var title: String? - if let firstMessage = item.messages.first, let peer = messageMainPeer(firstMessage) { - if let channel = peer as? TelegramChannel, case .broadcast = channel.info { - title = EnginePeer(peer).displayTitle(strings: item.strings, displayOrder: item.nameDisplayOrder) + if let firstMessage = item.messages.first, let peer = messageMainPeer(EngineMessage(firstMessage)) { + if case let .channel(channel) = peer, case .broadcast = channel.info { + title = peer.displayTitle(strings: item.strings, displayOrder: item.nameDisplayOrder) } else if let author = firstMessage.author { if firstMessage.id.peerId.isReplies, let _ = firstMessage.sourceReference, let effectiveAuthor = firstMessage.forwardInfo?.author { - title = EnginePeer(effectiveAuthor).displayTitle(strings: item.strings, displayOrder: item.nameDisplayOrder) + "@" + EnginePeer(peer).displayTitle(strings: item.strings, displayOrder: item.nameDisplayOrder) + title = EnginePeer(effectiveAuthor).displayTitle(strings: item.strings, displayOrder: item.nameDisplayOrder) + "@" + peer.displayTitle(strings: item.strings, displayOrder: item.nameDisplayOrder) } else if author.id != peer.id { if author.id == item.context.account.peerId { - title = presentationData.strings.DialogList_You + "@" + EnginePeer(peer).displayTitle(strings: item.strings, displayOrder: item.nameDisplayOrder) + title = presentationData.strings.DialogList_You + "@" + peer.displayTitle(strings: item.strings, displayOrder: item.nameDisplayOrder) } else { - title = EnginePeer(author).displayTitle(strings: item.strings, displayOrder: item.nameDisplayOrder) + "@" + EnginePeer(peer).displayTitle(strings: item.strings, displayOrder: item.nameDisplayOrder) + title = EnginePeer(author).displayTitle(strings: item.strings, displayOrder: item.nameDisplayOrder) + "@" + peer.displayTitle(strings: item.strings, displayOrder: item.nameDisplayOrder) } } else { - title = EnginePeer(peer).displayTitle(strings: item.strings, displayOrder: item.nameDisplayOrder) + title = peer.displayTitle(strings: item.strings, displayOrder: item.nameDisplayOrder) for attribute in firstMessage.attributes { if let attribute = attribute as? SourceReferenceMessageAttribute { if let sourcePeer = firstMessage.peers[attribute.messageId.peerId] { - title = EnginePeer(sourcePeer).displayTitle(strings: item.strings, displayOrder: item.nameDisplayOrder) + "@" + EnginePeer(peer).displayTitle(strings: item.strings, displayOrder: item.nameDisplayOrder) + title = EnginePeer(sourcePeer).displayTitle(strings: item.strings, displayOrder: item.nameDisplayOrder) + "@" + peer.displayTitle(strings: item.strings, displayOrder: item.nameDisplayOrder) } break } } } } else { - title = EnginePeer(peer).displayTitle(strings: item.strings, displayOrder: item.nameDisplayOrder) + title = peer.displayTitle(strings: item.strings, displayOrder: item.nameDisplayOrder) } if let _ = title, firstMessage.flags.contains(.WasScheduled) { @@ -148,9 +148,9 @@ final class ChatMessageNotificationItemNode: NotificationItemNode { } var avatarPeer = peer if firstMessage.id.peerId.isReplies, let author = firstMessage.forwardInfo?.author { - avatarPeer = author + avatarPeer = EnginePeer(author) } - self.avatarNode.setPeer(context: item.context, theme: presentationData.theme, peer: EnginePeer(avatarPeer), overrideImage: peer.id == item.context.account.peerId ? .savedMessagesIcon : nil, emptyColor: presentationData.theme.list.mediaPlaceholderColor) + self.avatarNode.setPeer(context: item.context, theme: presentationData.theme, peer: avatarPeer, overrideImage: peer.id == item.context.account.peerId ? .savedMessagesIcon : nil, emptyColor: presentationData.theme.list.mediaPlaceholderColor) } var updatedMedia: Media? @@ -180,7 +180,7 @@ final class ChatMessageNotificationItemNode: NotificationItemNode { if message.containsSecretMedia { imageDimensions = nil } - messageText = descriptionStringForMessage(contentSettings: item.context.currentContentSettings.with { $0 }, message: message, strings: item.strings, nameDisplayOrder: item.nameDisplayOrder, dateTimeFormat: item.dateTimeFormat, accountPeerId: item.context.account.peerId).0 + messageText = descriptionStringForMessage(contentSettings: item.context.currentContentSettings.with { $0 }, message: EngineMessage(message), strings: item.strings, nameDisplayOrder: item.nameDisplayOrder, dateTimeFormat: item.dateTimeFormat, accountPeerId: item.context.account.peerId).0 } else if item.messages.count > 1, let peer = item.messages[0].peers[item.messages[0].id.peerId] { var displayAuthor = true if let channel = peer as? TelegramChannel { @@ -205,9 +205,9 @@ final class ChatMessageNotificationItemNode: NotificationItemNode { messageText = presentationData.strings.PUSH_MESSAGE_FWDS_TEXT(Int32(item.messages.count)) } } else if item.messages[0].groupingKey != nil { - var kind = messageContentKind(contentSettings: item.context.currentContentSettings.with { $0 }, message: item.messages[0], strings: presentationData.strings, nameDisplayOrder: presentationData.nameDisplayOrder, dateTimeFormat: presentationData.dateTimeFormat, accountPeerId: item.context.account.peerId).key + var kind = messageContentKind(contentSettings: item.context.currentContentSettings.with { $0 }, message: EngineMessage(item.messages[0]), strings: presentationData.strings, nameDisplayOrder: presentationData.nameDisplayOrder, dateTimeFormat: presentationData.dateTimeFormat, accountPeerId: item.context.account.peerId).key for i in 1 ..< item.messages.count { - let nextKind = messageContentKind(contentSettings: item.context.currentContentSettings.with { $0 }, message: item.messages[i], strings: presentationData.strings, nameDisplayOrder: presentationData.nameDisplayOrder, dateTimeFormat: presentationData.dateTimeFormat, accountPeerId: item.context.account.peerId) + let nextKind = messageContentKind(contentSettings: item.context.currentContentSettings.with { $0 }, message: EngineMessage(item.messages[i]), strings: presentationData.strings, nameDisplayOrder: presentationData.nameDisplayOrder, dateTimeFormat: presentationData.dateTimeFormat, accountPeerId: item.context.account.peerId) if kind != nextKind.key { kind = .text break diff --git a/submodules/TelegramUI/Sources/ChatMessagePollBubbleContentNode.swift b/submodules/TelegramUI/Sources/ChatMessagePollBubbleContentNode.swift index 324af61074..232f5e0137 100644 --- a/submodules/TelegramUI/Sources/ChatMessagePollBubbleContentNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessagePollBubbleContentNode.swift @@ -1036,20 +1036,7 @@ class ChatMessagePollBubbleContentNode: ChatMessageBubbleContentNode { } } - var dateReactions: [MessageReaction] = [] - var dateReactionCount = 0 - if let reactionsAttribute = mergedMessageReactions(attributes: item.message.attributes), !reactionsAttribute.reactions.isEmpty { - for reaction in reactionsAttribute.reactions { - if reaction.isSelected { - dateReactions.insert(reaction, at: 0) - } else { - dateReactions.append(reaction) - } - dateReactionCount += Int(reaction.count) - } - } - - let dateText = stringForMessageTimestampStatus(accountPeerId: item.context.account.peerId, message: item.message, dateTimeFormat: item.presentationData.dateTimeFormat, nameDisplayOrder: item.presentationData.nameDisplayOrder, strings: item.presentationData.strings, reactionCount: dateReactionCount) + let dateText = stringForMessageTimestampStatus(accountPeerId: item.context.account.peerId, message: item.message, dateTimeFormat: item.presentationData.dateTimeFormat, nameDisplayOrder: item.presentationData.nameDisplayOrder, strings: item.presentationData.strings) let statusType: ChatMessageDateAndStatusType? switch position { @@ -1078,7 +1065,7 @@ class ChatMessagePollBubbleContentNode: ChatMessageBubbleContentNode { isReplyThread = true } - let (size, apply) = statusLayout(item.context, item.presentationData, edited, viewCount, dateText, statusType, textConstrainedSize, dateReactions, dateReplies, item.message.tags.contains(.pinned) && !item.associatedData.isInPinnedListMode && !isReplyThread, item.message.isSelfExpiring) + let (size, apply) = statusLayout(item.context, item.presentationData, edited, viewCount, dateText, statusType, textConstrainedSize, dateReplies, item.message.tags.contains(.pinned) && !item.associatedData.isInPinnedListMode && !isReplyThread, item.message.isSelfExpiring) statusSize = size statusApply = apply } @@ -1744,13 +1731,6 @@ class ChatMessagePollBubbleContentNode: ChatMessageBubbleContentNode { } } - override func reactionTargetNode(value: String) -> (ASDisplayNode, ASDisplayNode)? { - if !self.statusNode.isHidden { - return self.statusNode.reactionNode(value: value) - } - return nil - } - func updatePollTooltipMessageState(animated: Bool) { guard let item = self.item else { return diff --git a/submodules/TelegramUI/Sources/ChatMessageReplyInfoNode.swift b/submodules/TelegramUI/Sources/ChatMessageReplyInfoNode.swift index 3c5ead8db0..b196e018eb 100644 --- a/submodules/TelegramUI/Sources/ChatMessageReplyInfoNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageReplyInfoNode.swift @@ -64,7 +64,7 @@ class ChatMessageReplyInfoNode: ASDisplayNode { } } - let (textString, isMedia) = descriptionStringForMessage(contentSettings: context.currentContentSettings.with { $0 }, message: message, strings: strings, nameDisplayOrder: presentationData.nameDisplayOrder, dateTimeFormat: presentationData.dateTimeFormat, accountPeerId: context.account.peerId) + let (textString, isMedia) = descriptionStringForMessage(contentSettings: context.currentContentSettings.with { $0 }, message: EngineMessage(message), strings: strings, nameDisplayOrder: presentationData.nameDisplayOrder, dateTimeFormat: presentationData.dateTimeFormat, accountPeerId: context.account.peerId) let placeholderColor: UIColor = message.effectivelyIncoming(context.account.peerId) ? presentationData.theme.theme.chat.message.incoming.mediaPlaceholderColor : presentationData.theme.theme.chat.message.outgoing.mediaPlaceholderColor let titleColor: UIColor diff --git a/submodules/TelegramUI/Sources/ChatMessageRestrictedBubbleContentNode.swift b/submodules/TelegramUI/Sources/ChatMessageRestrictedBubbleContentNode.swift index 9aafc15d13..dac61792fd 100644 --- a/submodules/TelegramUI/Sources/ChatMessageRestrictedBubbleContentNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageRestrictedBubbleContentNode.swift @@ -67,20 +67,7 @@ class ChatMessageRestrictedBubbleContentNode: ChatMessageBubbleContentNode { } } - var dateReactions: [MessageReaction] = [] - var dateReactionCount = 0 - if let reactionsAttribute = mergedMessageReactions(attributes: item.message.attributes), !reactionsAttribute.reactions.isEmpty { - for reaction in reactionsAttribute.reactions { - if reaction.isSelected { - dateReactions.insert(reaction, at: 0) - } else { - dateReactions.append(reaction) - } - dateReactionCount += Int(reaction.count) - } - } - - let dateText = stringForMessageTimestampStatus(accountPeerId: item.context.account.peerId, message: item.message, dateTimeFormat: item.presentationData.dateTimeFormat, nameDisplayOrder: item.presentationData.nameDisplayOrder, strings: item.presentationData.strings, reactionCount: dateReactionCount) + let dateText = stringForMessageTimestampStatus(accountPeerId: item.context.account.peerId, message: item.message, dateTimeFormat: item.presentationData.dateTimeFormat, nameDisplayOrder: item.presentationData.nameDisplayOrder, strings: item.presentationData.strings) let statusType: ChatMessageDateAndStatusType? switch position { @@ -109,7 +96,7 @@ class ChatMessageRestrictedBubbleContentNode: ChatMessageBubbleContentNode { isReplyThread = true } - let (size, apply) = statusLayout(item.context, item.presentationData, edited, viewCount, dateText, statusType, textConstrainedSize, dateReactions, dateReplies, item.message.tags.contains(.pinned) && !item.associatedData.isInPinnedListMode && isReplyThread, item.message.isSelfExpiring) + let (size, apply) = statusLayout(item.context, item.presentationData, edited, viewCount, dateText, statusType, textConstrainedSize, dateReplies, item.message.tags.contains(.pinned) && !item.associatedData.isInPinnedListMode && isReplyThread, item.message.isSelfExpiring) statusSize = size statusApply = apply } @@ -252,11 +239,4 @@ class ChatMessageRestrictedBubbleContentNode: ChatMessageBubbleContentNode { self.textNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false) self.statusNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false) } - - override func reactionTargetNode(value: String) -> (ASDisplayNode, ASDisplayNode)? { - if !self.statusNode.isHidden { - return self.statusNode.reactionNode(value: value) - } - return nil - } } diff --git a/submodules/TelegramUI/Sources/ChatMessageStickerItemNode.swift b/submodules/TelegramUI/Sources/ChatMessageStickerItemNode.swift index a90140af01..2faae669fb 100644 --- a/submodules/TelegramUI/Sources/ChatMessageStickerItemNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageStickerItemNode.swift @@ -140,13 +140,6 @@ class ChatMessageStickerItemNode: ChatMessageItemView { self.messageAccessibilityArea.focused = { [weak self] in self?.accessibilityElementDidBecomeFocused() } - - self.dateAndStatusNode.openReactions = { [weak self] in - guard let strongSelf = self, let item = strongSelf.item else { - return - } - item.controllerInteraction.openMessageReactions(item.message.id) - } } required init?(coder aDecoder: NSCoder) { @@ -191,7 +184,7 @@ class ChatMessageStickerItemNode: ChatMessageItemView { guard let strongSelf = self else { return } - //strongSelf.reactionRecognizer?.cancel() + if let action = strongSelf.gestureRecognized(gesture: .longTap, location: point, recognizer: recognizer) { switch action { case let .action(f): @@ -478,27 +471,14 @@ class ChatMessageStickerItemNode: ChatMessageItemView { } } - var dateReactions: [MessageReaction] = [] - var dateReactionCount = 0 - if let reactionsAttribute = mergedMessageReactions(attributes: item.message.attributes), !reactionsAttribute.reactions.isEmpty { - for reaction in reactionsAttribute.reactions { - if reaction.isSelected { - dateReactions.insert(reaction, at: 0) - } else { - dateReactions.append(reaction) - } - dateReactionCount += Int(reaction.count) - } - } - - let dateText = stringForMessageTimestampStatus(accountPeerId: item.context.account.peerId, message: item.message, dateTimeFormat: item.presentationData.dateTimeFormat, nameDisplayOrder: item.presentationData.nameDisplayOrder, strings: item.presentationData.strings, format: .regular, reactionCount: dateReactionCount) + let dateText = stringForMessageTimestampStatus(accountPeerId: item.context.account.peerId, message: item.message, dateTimeFormat: item.presentationData.dateTimeFormat, nameDisplayOrder: item.presentationData.nameDisplayOrder, strings: item.presentationData.strings, format: .regular) var isReplyThread = false if case .replyThread = item.chatLocation { isReplyThread = true } - let (dateAndStatusSize, dateAndStatusApply) = makeDateAndStatusLayout(item.context, item.presentationData, edited, viewCount, dateText, statusType, CGSize(width: params.width, height: CGFloat.greatestFiniteMagnitude), dateReactions, dateReplies, item.message.tags.contains(.pinned) && !item.associatedData.isInPinnedListMode && !isReplyThread, item.message.isSelfExpiring) + let (dateAndStatusSize, dateAndStatusApply) = makeDateAndStatusLayout(item.context, item.presentationData, edited, viewCount, dateText, statusType, CGSize(width: params.width, height: CGFloat.greatestFiniteMagnitude), dateReplies, item.message.tags.contains(.pinned) && !item.associatedData.isInPinnedListMode && !isReplyThread, item.message.isSelfExpiring) var viaBotApply: (TextNodeLayout, () -> TextNode)? var replyInfoApply: (CGSize, () -> ChatMessageReplyInfoNode)? @@ -1153,10 +1133,6 @@ class ChatMessageStickerItemNode: ChatMessageItemView { break case .reply: item.controllerInteraction.setupReply(item.message.id) - case .like: - item.controllerInteraction.updateMessageLike(item.message.id, true) - case .unlike: - item.controllerInteraction.updateMessageLike(item.message.id, true) } } } diff --git a/submodules/TelegramUI/Sources/ChatMessageSwipeToReplyNode.swift b/submodules/TelegramUI/Sources/ChatMessageSwipeToReplyNode.swift index 6ba2ffb591..bbdee19c02 100644 --- a/submodules/TelegramUI/Sources/ChatMessageSwipeToReplyNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageSwipeToReplyNode.swift @@ -73,10 +73,6 @@ extension ChatMessageSwipeToReplyNode.Action { self = .reply case .reply: self = .reply - case .like: - self = .like - case .unlike: - self = .unlike } } else { self = .reply diff --git a/submodules/TelegramUI/Sources/ChatMessageTextBubbleContentNode.swift b/submodules/TelegramUI/Sources/ChatMessageTextBubbleContentNode.swift index 098a079fd0..1f146f8991 100644 --- a/submodules/TelegramUI/Sources/ChatMessageTextBubbleContentNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageTextBubbleContentNode.swift @@ -65,13 +65,6 @@ class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode { self.textAccessibilityOverlayNode.openUrl = { [weak self] url in self?.item?.controllerInteraction.openUrl(url, false, false, nil) } - - self.statusNode.openReactions = { [weak self] in - guard let strongSelf = self, let item = strongSelf.item else { - return - } - item.controllerInteraction.openMessageReactions(item.message.id) - } } required init?(coder aDecoder: NSCoder) { @@ -126,26 +119,13 @@ class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode { } } - var dateReactions: [MessageReaction] = [] - var dateReactionCount = 0 - if let reactionsAttribute = mergedMessageReactions(attributes: item.message.attributes), !reactionsAttribute.reactions.isEmpty { - for reaction in reactionsAttribute.reactions { - if reaction.isSelected { - dateReactions.insert(reaction, at: 0) - } else { - dateReactions.append(reaction) - } - dateReactionCount += Int(reaction.count) - } - } - let dateFormat: MessageTimestampStatusFormat if let subject = item.associatedData.subject, case .forwardedMessages = subject { dateFormat = .minimal } else { dateFormat = .regular } - let dateText = stringForMessageTimestampStatus(accountPeerId: item.context.account.peerId, message: item.message, dateTimeFormat: item.presentationData.dateTimeFormat, nameDisplayOrder: item.presentationData.nameDisplayOrder, strings: item.presentationData.strings, format: dateFormat, reactionCount: dateReactionCount) + let dateText = stringForMessageTimestampStatus(accountPeerId: item.context.account.peerId, message: item.message, dateTimeFormat: item.presentationData.dateTimeFormat, nameDisplayOrder: item.presentationData.nameDisplayOrder, strings: item.presentationData.strings, format: dateFormat) let statusType: ChatMessageDateAndStatusType? var displayStatus = false @@ -184,7 +164,7 @@ class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode { isReplyThread = true } - let (size, apply) = statusLayout(item.context, item.presentationData, edited, viewCount, dateText, statusType, textConstrainedSize, dateReactions, dateReplies, item.message.tags.contains(.pinned) && !item.associatedData.isInPinnedListMode && !isReplyThread, item.message.isSelfExpiring) + let (size, apply) = statusLayout(item.context, item.presentationData, edited, viewCount, dateText, statusType, textConstrainedSize, dateReplies, item.message.tags.contains(.pinned) && !item.associatedData.isInPinnedListMode && !isReplyThread, item.message.isSelfExpiring) statusSize = size statusApply = apply } @@ -636,13 +616,6 @@ class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode { } } - override func reactionTargetNode(value: String) -> (ASDisplayNode, ASDisplayNode)? { - if !self.statusNode.isHidden { - return self.statusNode.reactionNode(value: value) - } - return nil - } - override func getStatusNode() -> ASDisplayNode? { return self.statusNode } diff --git a/submodules/TelegramUI/Sources/ChatMessageWebpageBubbleContentNode.swift b/submodules/TelegramUI/Sources/ChatMessageWebpageBubbleContentNode.swift index 4af2ea14f0..aaf9f53ee6 100644 --- a/submodules/TelegramUI/Sources/ChatMessageWebpageBubbleContentNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageWebpageBubbleContentNode.swift @@ -526,8 +526,4 @@ final class ChatMessageWebpageBubbleContentNode: ChatMessageBubbleContentNode { let contentNodeFrame = self.contentNode.frame self.contentNode.updateTouchesAtPoint(point.flatMap { $0.offsetBy(dx: -contentNodeFrame.minX, dy: -contentNodeFrame.minY) }) } - - override func reactionTargetNode(value: String) -> (ASDisplayNode, ASDisplayNode)? { - return self.contentNode.reactionTargetNode(value: value) - } } diff --git a/submodules/TelegramUI/Sources/ChatPinnedMessageTitlePanelNode.swift b/submodules/TelegramUI/Sources/ChatPinnedMessageTitlePanelNode.swift index 701bea9fad..d4158f8c69 100644 --- a/submodules/TelegramUI/Sources/ChatPinnedMessageTitlePanelNode.swift +++ b/submodules/TelegramUI/Sources/ChatPinnedMessageTitlePanelNode.swift @@ -451,7 +451,7 @@ final class ChatPinnedMessageTitlePanelNode: ChatTitleAccessoryPanelNode { } let (titleLayout, titleApply) = makeTitleLayout(CGSize(width: width - textLineInset - contentLeftInset - rightInset - textRightInset, height: CGFloat.greatestFiniteMagnitude), titleStrings) - let (textLayout, textApply) = makeTextLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: foldLineBreaks(descriptionStringForMessage(contentSettings: context.currentContentSettings.with { $0 }, message: message, strings: strings, nameDisplayOrder: nameDisplayOrder, dateTimeFormat: dateTimeFormat, accountPeerId: accountPeerId).0), font: Font.regular(15.0), textColor: message.media.isEmpty || message.media.first is TelegramMediaWebpage ? theme.chat.inputPanel.primaryTextColor : theme.chat.inputPanel.secondaryTextColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: width - textLineInset - contentLeftInset - rightInset - textRightInset, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets(top: 2.0, left: 0.0, bottom: 2.0, right: 0.0))) + let (textLayout, textApply) = makeTextLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: foldLineBreaks(descriptionStringForMessage(contentSettings: context.currentContentSettings.with { $0 }, message: EngineMessage(message), strings: strings, nameDisplayOrder: nameDisplayOrder, dateTimeFormat: dateTimeFormat, accountPeerId: accountPeerId).0), font: Font.regular(15.0), textColor: message.media.isEmpty || message.media.first is TelegramMediaWebpage ? theme.chat.inputPanel.primaryTextColor : theme.chat.inputPanel.secondaryTextColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: width - textLineInset - contentLeftInset - rightInset - textRightInset, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets(top: 2.0, left: 0.0, bottom: 2.0, right: 0.0))) Queue.mainQueue().async { if let strongSelf = self { diff --git a/submodules/TelegramUI/Sources/ChatRecentActionsControllerNode.swift b/submodules/TelegramUI/Sources/ChatRecentActionsControllerNode.swift index 39c5dd6072..06ab336719 100644 --- a/submodules/TelegramUI/Sources/ChatRecentActionsControllerNode.swift +++ b/submodules/TelegramUI/Sources/ChatRecentActionsControllerNode.swift @@ -298,8 +298,6 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode { return self?.getNavigationController() }, chatControllerNode: { [weak self] in return self - }, reactionContainerNode: { - return nil }, presentGlobalOverlayController: { _, _ in }, callPeer: { _, _ in }, longTap: { [weak self] action, message in if let strongSelf = self { switch action { @@ -507,8 +505,6 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode { }, sendScheduledMessagesNow: { _ in }, editScheduledMessagesTime: { _ in }, performTextSelectionAction: { _, _, _ in - }, updateMessageLike: { _, _ in - }, openMessageReactions: { _ in }, displayImportedMessageTooltip: { _ in }, displaySwipeToReplyHint: { }, dismissReplyMarkupMessage: { _ in diff --git a/submodules/TelegramUI/Sources/ChatSearchResultsContollerNode.swift b/submodules/TelegramUI/Sources/ChatSearchResultsContollerNode.swift index 18fd8322f8..781e849d67 100644 --- a/submodules/TelegramUI/Sources/ChatSearchResultsContollerNode.swift +++ b/submodules/TelegramUI/Sources/ChatSearchResultsContollerNode.swift @@ -207,7 +207,7 @@ class ChatSearchResultsControllerNode: ViewControllerTracingNode, UIScrollViewDe if let message = messages.first { let chatController = strongSelf.context.sharedContext.makeChatController(context: strongSelf.context, chatLocation: .peer(peer.peerId), subject: .message(id: message.id, highlight: true, timecode: nil), botStart: nil, mode: .standard(previewing: true)) chatController.canReadHistory.set(false) - let contextController = ContextController(account: strongSelf.context.account, presentationData: strongSelf.presentationData, source: .controller(ContextControllerContentSourceImpl(controller: chatController, sourceNode: node)), items: .single(ContextController.Items(items: [])), reactionItems: [], gesture: gesture) + let contextController = ContextController(account: strongSelf.context.account, presentationData: strongSelf.presentationData, source: .controller(ContextControllerContentSourceImpl(controller: chatController, sourceNode: node)), items: .single(ContextController.Items(items: [])), gesture: gesture) presentInGlobalOverlay(contextController) } else { gesture?.cancel() diff --git a/submodules/TelegramUI/Sources/DrawingStickersScreen.swift b/submodules/TelegramUI/Sources/DrawingStickersScreen.swift index 4f869e21fb..5421794303 100644 --- a/submodules/TelegramUI/Sources/DrawingStickersScreen.swift +++ b/submodules/TelegramUI/Sources/DrawingStickersScreen.swift @@ -115,8 +115,6 @@ private final class DrawingStickersScreenNode: ViewControllerTracingNode { return nil }, chatControllerNode: { return nil - }, reactionContainerNode: { - return nil }, presentGlobalOverlayController: { _, _ in }, callPeer: { _, _ in }, longTap: { _, _ in }, openCheckoutOrReceipt: { _ in }, openSearch: { }, setupReply: { _ in }, canSetupReply: { _ in return .none @@ -133,8 +131,6 @@ private final class DrawingStickersScreenNode: ViewControllerTracingNode { }, sendScheduledMessagesNow: { _ in }, editScheduledMessagesTime: { _ in }, performTextSelectionAction: { _, _, _ in - }, updateMessageLike: { _, _ in - }, openMessageReactions: { _ in }, displayImportedMessageTooltip: { _ in }, displaySwipeToReplyHint: { }, dismissReplyMarkupMessage: { _ in diff --git a/submodules/TelegramUI/Sources/EditAccessoryPanelNode.swift b/submodules/TelegramUI/Sources/EditAccessoryPanelNode.swift index ba008e578c..15a1315d92 100644 --- a/submodules/TelegramUI/Sources/EditAccessoryPanelNode.swift +++ b/submodules/TelegramUI/Sources/EditAccessoryPanelNode.swift @@ -169,7 +169,7 @@ final class EditAccessoryPanelNode: AccessoryPanelNode { if let currentEditMediaReference = self.currentEditMediaReference { effectiveMessage = effectiveMessage.withUpdatedMedia([currentEditMediaReference.media]) } - (text, _) = descriptionStringForMessage(contentSettings: context.currentContentSettings.with { $0 }, message: effectiveMessage, strings: self.strings, nameDisplayOrder: self.nameDisplayOrder, dateTimeFormat: self.dateTimeFormat, accountPeerId: self.context.account.peerId) + (text, _) = descriptionStringForMessage(contentSettings: context.currentContentSettings.with { $0 }, message: EngineMessage(effectiveMessage), strings: self.strings, nameDisplayOrder: self.nameDisplayOrder, dateTimeFormat: self.dateTimeFormat, accountPeerId: self.context.account.peerId) } var updatedMediaReference: AnyMediaReference? @@ -242,7 +242,7 @@ final class EditAccessoryPanelNode: AccessoryPanelNode { effectiveMessage = effectiveMessage.withUpdatedMedia([currentEditMediaReference.media]) } let presentationData = self.context.sharedContext.currentPresentationData.with { $0 } - switch messageContentKind(contentSettings: self.context.currentContentSettings.with { $0 }, message: effectiveMessage, strings: strings, nameDisplayOrder: nameDisplayOrder, dateTimeFormat: presentationData.dateTimeFormat, accountPeerId: self.context.account.peerId) { + switch messageContentKind(contentSettings: self.context.currentContentSettings.with { $0 }, message: EngineMessage(effectiveMessage), strings: strings, nameDisplayOrder: nameDisplayOrder, dateTimeFormat: presentationData.dateTimeFormat, accountPeerId: self.context.account.peerId) { case .text: isMedia = false default: diff --git a/submodules/TelegramUI/Sources/OverlayAudioPlayerControllerNode.swift b/submodules/TelegramUI/Sources/OverlayAudioPlayerControllerNode.swift index a3c4762728..a7f50a0d69 100644 --- a/submodules/TelegramUI/Sources/OverlayAudioPlayerControllerNode.swift +++ b/submodules/TelegramUI/Sources/OverlayAudioPlayerControllerNode.swift @@ -102,8 +102,6 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, UIGestu return nil }, chatControllerNode: { return nil - }, reactionContainerNode: { - return nil }, presentGlobalOverlayController: { _, _ in }, callPeer: { _, _ in }, longTap: { _, _ in @@ -125,8 +123,6 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, UIGestu }, sendScheduledMessagesNow: { _ in }, editScheduledMessagesTime: { _ in }, performTextSelectionAction: { _, _, _ in - }, updateMessageLike: { _, _ in - }, openMessageReactions: { _ in }, displayImportedMessageTooltip: { _ in }, displaySwipeToReplyHint: { }, dismissReplyMarkupMessage: { _ in diff --git a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift index db08ed5776..2d2c62ba9f 100644 --- a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift +++ b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift @@ -1866,7 +1866,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD }))) } - let controller = ContextController(account: strongSelf.context.account, presentationData: strongSelf.presentationData, source: .extracted(MessageContextExtractedContentSource(sourceNode: node)), items: .single(ContextController.Items(items: items)), reactionItems: [], recognizer: nil, gesture: gesture) + let controller = ContextController(account: strongSelf.context.account, presentationData: strongSelf.presentationData, source: .extracted(MessageContextExtractedContentSource(sourceNode: node)), items: .single(ContextController.Items(items: items)), recognizer: nil, gesture: gesture) strongSelf.controller?.window?.presentInGlobalOverlay(controller) }) }, activateMessagePinch: { _ in @@ -2006,7 +2006,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD switch previewData { case let .gallery(gallery): gallery.setHintWillBePresentedInPreviewingContext(true) - let contextController = ContextController(account: strongSelf.context.account, presentationData: strongSelf.presentationData, source: .controller(ContextControllerContentSourceImpl(controller: gallery, sourceNode: node)), items: items |> map { ContextController.Items(items: $0) }, reactionItems: [], gesture: gesture) + let contextController = ContextController(account: strongSelf.context.account, presentationData: strongSelf.presentationData, source: .controller(ContextControllerContentSourceImpl(controller: gallery, sourceNode: node)), items: items |> map { ContextController.Items(items: $0) }, gesture: gesture) strongSelf.controller?.presentInGlobalOverlay(contextController) case .instantPage: break @@ -2090,8 +2090,6 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD return self?.controller?.navigationController as? NavigationController }, chatControllerNode: { return nil - }, reactionContainerNode: { - return nil }, presentGlobalOverlayController: { _, _ in }, callPeer: { _, _ in }, longTap: { [weak self] content, _ in guard let strongSelf = self else { @@ -2160,8 +2158,6 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD }, sendScheduledMessagesNow: { _ in }, editScheduledMessagesTime: { _ in }, performTextSelectionAction: { _, _, _ in - }, updateMessageLike: { _, _ in - }, openMessageReactions: { _ in }, displayImportedMessageTooltip: { _ in }, displaySwipeToReplyHint: { }, dismissReplyMarkupMessage: { _ in @@ -2230,7 +2226,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD self?.chatInterfaceInteraction.openPeer(peer.id, .default, nil) })) ] - let contextController = ContextController(account: strongSelf.context.account, presentationData: presentationData, source: .controller(ContextControllerContentSourceImpl(controller: chatController, sourceNode: node)), items: .single(ContextController.Items(items: items)), reactionItems: [], gesture: gesture) + let contextController = ContextController(account: strongSelf.context.account, presentationData: presentationData, source: .controller(ContextControllerContentSourceImpl(controller: chatController, sourceNode: node)), items: .single(ContextController.Items(items: items)), gesture: gesture) controller.presentInGlobalOverlay(contextController) } @@ -2829,7 +2825,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD }, synchronousLoad: true) galleryController.setHintWillBePresentedInPreviewingContext(true) - let contextController = ContextController(account: strongSelf.context.account, presentationData: strongSelf.presentationData, source: .controller(ContextControllerContentSourceImpl(controller: galleryController, sourceNode: node)), items: .single(ContextController.Items(items: items)), reactionItems: [], gesture: gesture) + let contextController = ContextController(account: strongSelf.context.account, presentationData: strongSelf.presentationData, source: .controller(ContextControllerContentSourceImpl(controller: galleryController, sourceNode: node)), items: .single(ContextController.Items(items: items)), gesture: gesture) strongSelf.controller?.presentInGlobalOverlay(contextController) } @@ -3455,7 +3451,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD self.view.endEditing(true) if let sourceNode = self.headerNode.buttonNodes[.mute]?.referenceNode { - let contextController = ContextController(account: self.context.account, presentationData: self.presentationData, source: .reference(PeerInfoContextReferenceContentSource(controller: controller, sourceNode: sourceNode)), items: .single(ContextController.Items(items: items)), reactionItems: [], gesture: gesture) + let contextController = ContextController(account: self.context.account, presentationData: self.presentationData, source: .reference(PeerInfoContextReferenceContentSource(controller: controller, sourceNode: sourceNode)), items: .single(ContextController.Items(items: items)), gesture: gesture) contextController.dismissed = { [weak self] in if let strongSelf = self { strongSelf.state = strongSelf.state.withHighlightedButton(nil) @@ -3771,7 +3767,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD if let sourceNode = self.headerNode.buttonNodes[.more]?.referenceNode { let items = mainItemsImpl?() ?? .single([]) - let contextController = ContextController(account: self.context.account, presentationData: self.presentationData, source: .reference(PeerInfoContextReferenceContentSource(controller: controller, sourceNode: sourceNode)), items: items |> map { ContextController.Items(items: $0) }, reactionItems: [], gesture: gesture) + let contextController = ContextController(account: self.context.account, presentationData: self.presentationData, source: .reference(PeerInfoContextReferenceContentSource(controller: controller, sourceNode: sourceNode)), items: items |> map { ContextController.Items(items: $0) }, gesture: gesture) contextController.dismissed = { [weak self] in if let strongSelf = self { strongSelf.state = strongSelf.state.withHighlightedButton(nil) @@ -4440,7 +4436,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD } if let sourceNode = strongSelf.headerNode.buttonNodes[.voiceChat]?.referenceNode, let controller = strongSelf.controller { - let contextController = ContextController(account: strongSelf.context.account, presentationData: strongSelf.presentationData, source: .reference(PeerInfoContextReferenceContentSource(controller: controller, sourceNode: sourceNode)), items: .single(ContextController.Items(items: items)), reactionItems: [], gesture: gesture) + let contextController = ContextController(account: strongSelf.context.account, presentationData: strongSelf.presentationData, source: .reference(PeerInfoContextReferenceContentSource(controller: controller, sourceNode: sourceNode)), items: .single(ContextController.Items(items: items)), gesture: gesture) contextController.dismissed = { [weak self] in if let strongSelf = self { strongSelf.state = strongSelf.state.withHighlightedButton(nil) @@ -4536,7 +4532,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD } if let sourceNode = strongSelf.headerNode.buttonNodes[.voiceChat]?.referenceNode, let controller = strongSelf.controller { - let contextController = ContextController(account: strongSelf.context.account, presentationData: strongSelf.presentationData, source: .reference(PeerInfoContextReferenceContentSource(controller: controller, sourceNode: sourceNode)), items: .single(ContextController.Items(items: items)), reactionItems: [], gesture: gesture) + let contextController = ContextController(account: strongSelf.context.account, presentationData: strongSelf.presentationData, source: .reference(PeerInfoContextReferenceContentSource(controller: controller, sourceNode: sourceNode)), items: .single(ContextController.Items(items: items)), gesture: gesture) contextController.dismissed = { [weak self] in if let strongSelf = self { strongSelf.state = strongSelf.state.withHighlightedButton(nil) @@ -5609,7 +5605,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD let contextController = ContextController(account: accountContext.account, presentationData: self.presentationData, source: .controller(ContextControllerContentSourceImpl(controller: chatListController, sourceNode: node)), items: accountContextMenuItems(context: accountContext, logout: { [weak self] in self?.logoutAccount(id: id) - }) |> map { ContextController.Items(items: $0) }, reactionItems: [], gesture: gesture) + }) |> map { ContextController.Items(items: $0) }, gesture: gesture) self.controller?.presentInGlobalOverlay(contextController) } else { gesture?.cancel() @@ -6908,7 +6904,7 @@ public final class PeerInfoScreenImpl: ViewController, PeerInfoScreen { }))) } - let controller = ContextController(account: primary.0.account, presentationData: self.presentationData, source: .extracted(SettingsTabBarContextExtractedContentSource(controller: self, sourceNode: sourceNode)), items: .single(ContextController.Items(items: items)), reactionItems: [], recognizer: nil, gesture: gesture) + let controller = ContextController(account: primary.0.account, presentationData: self.presentationData, source: .extracted(SettingsTabBarContextExtractedContentSource(controller: self, sourceNode: sourceNode)), items: .single(ContextController.Items(items: items)), recognizer: nil, gesture: gesture) self.context.sharedContext.mainWindow?.presentInGlobalOverlay(controller) } } diff --git a/submodules/TelegramUI/Sources/ReplyAccessoryPanelNode.swift b/submodules/TelegramUI/Sources/ReplyAccessoryPanelNode.swift index 02db078c90..2cff35dd92 100644 --- a/submodules/TelegramUI/Sources/ReplyAccessoryPanelNode.swift +++ b/submodules/TelegramUI/Sources/ReplyAccessoryPanelNode.swift @@ -106,7 +106,7 @@ final class ReplyAccessoryPanelNode: AccessoryPanelNode { authorName = EnginePeer(author).displayTitle(strings: strings, displayOrder: nameDisplayOrder) } if let message = message { - (text, _) = descriptionStringForMessage(contentSettings: context.currentContentSettings.with { $0 }, message: message, strings: strings, nameDisplayOrder: nameDisplayOrder, dateTimeFormat: dateTimeFormat, accountPeerId: context.account.peerId) + (text, _) = descriptionStringForMessage(contentSettings: context.currentContentSettings.with { $0 }, message: EngineMessage(message), strings: strings, nameDisplayOrder: nameDisplayOrder, dateTimeFormat: dateTimeFormat, accountPeerId: context.account.peerId) } var updatedMediaReference: AnyMediaReference? @@ -172,7 +172,7 @@ final class ReplyAccessoryPanelNode: AccessoryPanelNode { let isMedia: Bool if let message = message { - switch messageContentKind(contentSettings: context.currentContentSettings.with { $0 }, message: message, strings: strings, nameDisplayOrder: nameDisplayOrder, dateTimeFormat: dateTimeFormat, accountPeerId: context.account.peerId) { + switch messageContentKind(contentSettings: context.currentContentSettings.with { $0 }, message: EngineMessage(message), strings: strings, nameDisplayOrder: nameDisplayOrder, dateTimeFormat: dateTimeFormat, accountPeerId: context.account.peerId) { case .text: isMedia = false default: diff --git a/submodules/TelegramUI/Sources/SharedAccountContext.swift b/submodules/TelegramUI/Sources/SharedAccountContext.swift index d66ce27f67..9b79c3e0ea 100644 --- a/submodules/TelegramUI/Sources/SharedAccountContext.swift +++ b/submodules/TelegramUI/Sources/SharedAccountContext.swift @@ -1254,8 +1254,6 @@ public final class SharedAccountContextImpl: SharedAccountContext { return nil }, chatControllerNode: { return nil - }, reactionContainerNode: { - return nil }, presentGlobalOverlayController: { _, _ in }, callPeer: { _, _ in }, longTap: { _, _ in }, openCheckoutOrReceipt: { _ in }, openSearch: { }, setupReply: { _ in }, canSetupReply: { _ in return .none @@ -1272,8 +1270,6 @@ public final class SharedAccountContextImpl: SharedAccountContext { }, sendScheduledMessagesNow: { _ in }, editScheduledMessagesTime: { _ in }, performTextSelectionAction: { _, _, _ in - }, updateMessageLike: { _, _ in - }, openMessageReactions: { _ in }, displayImportedMessageTooltip: { _ in }, displaySwipeToReplyHint: { }, dismissReplyMarkupMessage: { _ in diff --git a/submodules/TelegramUI/Sources/StringForMessageTimestampStatus.swift b/submodules/TelegramUI/Sources/StringForMessageTimestampStatus.swift index c3ba9fb771..79b793522b 100644 --- a/submodules/TelegramUI/Sources/StringForMessageTimestampStatus.swift +++ b/submodules/TelegramUI/Sources/StringForMessageTimestampStatus.swift @@ -28,7 +28,7 @@ private func dateStringForDay(strings: PresentationStrings, dateTimeFormat: Pres } } -func stringForMessageTimestampStatus(accountPeerId: PeerId, message: Message, dateTimeFormat: PresentationDateTimeFormat, nameDisplayOrder: PresentationPersonNameOrder, strings: PresentationStrings, format: MessageTimestampStatusFormat = .regular, reactionCount: Int) -> String { +func stringForMessageTimestampStatus(accountPeerId: PeerId, message: Message, dateTimeFormat: PresentationDateTimeFormat, nameDisplayOrder: PresentationPersonNameOrder, strings: PresentationStrings, format: MessageTimestampStatusFormat = .regular) -> String { if message.adAttribute != nil { return strings.Message_SponsoredLabel } diff --git a/submodules/TelegramUI/Sources/WebpagePreviewAccessoryPanelNode.swift b/submodules/TelegramUI/Sources/WebpagePreviewAccessoryPanelNode.swift index e8c472d253..3ea6d8a12c 100644 --- a/submodules/TelegramUI/Sources/WebpagePreviewAccessoryPanelNode.swift +++ b/submodules/TelegramUI/Sources/WebpagePreviewAccessoryPanelNode.swift @@ -128,7 +128,7 @@ final class WebpagePreviewAccessoryPanelNode: AccessoryPanelNode { if let contentText = content.text { text = contentText } else { - if let file = content.file, let mediaKind = mediaContentKind(file) { + if let file = content.file, let mediaKind = mediaContentKind(EngineMedia(file)) { if content.type == "telegram_background" { text = strings.Message_Wallpaper } else if content.type == "telegram_theme" { From e658555ef43a2055f6578c570ee1f5eabbb6e882 Mon Sep 17 00:00:00 2001 From: Ali <> Date: Tue, 21 Sep 2021 00:23:29 +0300 Subject: [PATCH 14/30] Refactoring --- Telegram/BUILD | 23 ++++++ Telegram/SiriIntents/IntentHandler.swift | 4 +- Telegram/SiriIntents/IntentMessages.swift | 8 +-- .../WidgetKitWidget/TodayViewController.swift | 2 +- .../TelegramEngine/Messages/Media.swift | 12 ++++ .../Sources/WidgetDataContext.swift | 2 +- submodules/TelegramUpdateUI/BUILD | 1 - .../Sources/UpdateInfoController.swift | 1 - .../Sources/GroupCallContext.swift | 1 - submodules/WallpaperBackgroundNode/BUILD | 1 - .../Sources/WallpaperBackgroundNode.swift | 14 ++-- submodules/WidgetItemsUtils/BUILD | 1 - .../Sources/WidgetItemsUtils.swift | 4 +- .../Sources/NBAsYouTypeFormatter.m | 18 ++--- .../Sources/NBPhoneMetaDataGenerator.m | 72 +++++++++---------- .../Sources/NBPhoneNumberDesc.m | 10 +-- 16 files changed, 96 insertions(+), 78 deletions(-) diff --git a/Telegram/BUILD b/Telegram/BUILD index 803f6deadc..66da047e93 100644 --- a/Telegram/BUILD +++ b/Telegram/BUILD @@ -698,6 +698,7 @@ ios_framework( ":VersionInfoPlist", ], minimum_os_version = "9.0", + extension_safe = True, ipa_post_processor = strip_framework, deps = [ "//submodules/MtProtoKit:MtProtoKit", @@ -737,6 +738,7 @@ ios_framework( ":VersionInfoPlist", ], minimum_os_version = "9.0", + extension_safe = True, ipa_post_processor = strip_framework, deps = [ "//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit", @@ -779,6 +781,7 @@ ios_framework( ":SwiftSignalKitFramework", ], minimum_os_version = "9.0", + extension_safe = True, ipa_post_processor = strip_framework, deps = [ "//submodules/Postbox:Postbox", @@ -818,6 +821,7 @@ ios_framework( ":VersionInfoPlist", ], minimum_os_version = "9.0", + extension_safe = True, ipa_post_processor = strip_framework, deps = [ "//submodules/TelegramApi:TelegramApi", @@ -862,6 +866,7 @@ ios_framework( ":PostboxFramework", ], minimum_os_version = "9.0", + extension_safe = True, ipa_post_processor = strip_framework, deps = [ "//submodules/TelegramCore:TelegramCore", @@ -901,6 +906,7 @@ ios_framework( ":VersionInfoPlist", ], minimum_os_version = "9.0", + extension_safe = True, ipa_post_processor = strip_framework, deps = [ "//submodules/AsyncDisplayKit:AsyncDisplayKit", @@ -987,6 +993,7 @@ ios_framework( ":AsyncDisplayKitFramework", ], minimum_os_version = "9.0", + extension_safe = True, ipa_post_processor = strip_framework, deps = [ "//submodules/Display:Display", @@ -1034,6 +1041,7 @@ ios_framework( ":DisplayFramework", ], minimum_os_version = "9.0", + extension_safe = True, ipa_post_processor = strip_framework, deps = [ "//submodules/TelegramUI:TelegramUI", @@ -1096,6 +1104,9 @@ swift_library( srcs = glob([ "Share/**/*.swift", ]), + copts = [ + "-warnings-as-errors", + ], deps = [ "//submodules/TelegramUI:TelegramUI" ], @@ -1178,6 +1189,9 @@ swift_library( srcs = glob([ "NotificationContent/**/*.swift", ]), + copts = [ + "-warnings-as-errors", + ], deps = [ "//submodules/TelegramUI:TelegramUI", ":NotificationContentExtensionLink", @@ -1269,6 +1283,9 @@ swift_library( srcs = glob([ "WidgetKitWidget/**/*.swift", ]), + copts = [ + "-warnings-as-errors", + ], data = [ ":WidgetAssets", ], @@ -1397,6 +1414,9 @@ swift_library( srcs = glob([ "SiriIntents/**/*.swift", ]), + copts = [ + "-warnings-as-errors", + ], data = glob([ "SiriIntents/*.lproj/Intents.intentdefinition" ]) + [ @@ -1496,6 +1516,9 @@ swift_library( srcs = glob([ "BroadcastUpload/**/*.swift", ]), + copts = [ + "-warnings-as-errors", + ], deps = [ "//submodules/TelegramUI:TelegramUI", "//submodules/TelegramVoip:TelegramVoip", diff --git a/Telegram/SiriIntents/IntentHandler.swift b/Telegram/SiriIntents/IntentHandler.swift index ed260d7bcb..8362b55ec1 100644 --- a/Telegram/SiriIntents/IntentHandler.swift +++ b/Telegram/SiriIntents/IntentHandler.swift @@ -37,7 +37,7 @@ private struct ApplicationSettings { private func applicationSettings(accountManager: AccountManager) -> Signal { return accountManager.transaction { transaction -> ApplicationSettings in let loggingSettings: LoggingSettings - if let value = transaction.getSharedData(SharedDataKeys.loggingSettings) as? LoggingSettings { + if let value = transaction.getSharedData(SharedDataKeys.loggingSettings)?.get(LoggingSettings.self) { loggingSettings = value } else { loggingSettings = LoggingSettings.defaultSettings @@ -943,7 +943,7 @@ private final class WidgetIntentHandler { if let data = try? Data(contentsOf: URL(fileURLWithPath: appLockStatePath(rootPath: rootPath))), let state = try? JSONDecoder().decode(LockState.self, from: data), isAppLocked(state: state) { - let presentationData = WidgetPresentationData.getForExtension() + //let presentationData = WidgetPresentationData.getForExtension() let error = NSError(domain: "Locked", code: 1, userInfo: [ NSLocalizedDescriptionKey: "Open Telegram and enter passcode to edit widget." diff --git a/Telegram/SiriIntents/IntentMessages.swift b/Telegram/SiriIntents/IntentMessages.swift index fc3287b7ae..f08d7e076d 100644 --- a/Telegram/SiriIntents/IntentMessages.swift +++ b/Telegram/SiriIntents/IntentMessages.swift @@ -36,7 +36,7 @@ func unreadMessages(account: Account) -> Signal<[INMessage], NoError> { |> mapToSignal { view -> Signal<[INMessage], NoError> in var signals: [Signal<[INMessage], NoError>] = [] for entry in view.0.entries { - if case let .MessageEntry(index, _, readState, notificationSettings, _, _, _, _, _, _) = entry { + if case let .MessageEntry(index, _, readState, isMuted, _, _, _, _, _, _) = entry { if index.messageIndex.id.peerId.namespace != Namespaces.Peer.CloudUser { continue } @@ -47,12 +47,6 @@ func unreadMessages(account: Account) -> Signal<[INMessage], NoError> { hasUnread = readState.count != 0 fixedCombinedReadStates = .peer([index.messageIndex.id.peerId: readState]) } - var isMuted = false - if let notificationSettings = notificationSettings as? TelegramPeerNotificationSettings { - if case let .muted(until) = notificationSettings.muteState, until >= Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970) { - isMuted = true - } - } if !isMuted && hasUnread { signals.append(account.postbox.aroundMessageHistoryViewForLocation(.peer(index.messageIndex.id.peerId), anchor: .upperBound, count: 10, fixedCombinedReadStates: fixedCombinedReadStates, topTaggedMessageIdNamespaces: Set(), tagMask: nil, appendMessagesFromTheSameGroup: false, namespaces: .not(Namespaces.Message.allScheduled), orderStatistics: .combinedLocation) diff --git a/Telegram/WidgetKitWidget/TodayViewController.swift b/Telegram/WidgetKitWidget/TodayViewController.swift index 11ce25c07c..059ae8c119 100644 --- a/Telegram/WidgetKitWidget/TodayViewController.swift +++ b/Telegram/WidgetKitWidget/TodayViewController.swift @@ -171,7 +171,7 @@ private func getCommonTimeline(friends: [Friend]?, in context: TimelineProviderC var mappedMessage: WidgetDataPeer.Message? if let index = transaction.getTopPeerMessageIndex(peerId: peer.id) { if let message = transaction.getMessage(index.id) { - mappedMessage = WidgetDataPeer.Message(accountPeerId: state.peerId, message: message) + mappedMessage = WidgetDataPeer.Message(accountPeerId: state.peerId, message: EngineMessage(message)) } } diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Messages/Media.swift b/submodules/TelegramCore/Sources/TelegramEngine/Messages/Media.swift index b83f597780..a1d8d9a14f 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Messages/Media.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Messages/Media.swift @@ -1,5 +1,17 @@ import Postbox +public final class EngineMediaResource { + private let resource: MediaResource + + public init(_ resource: MediaResource) { + self.resource = resource + } + + public func _asResource() -> MediaResource { + return self.resource + } +} + public enum EngineMedia { public typealias Id = MediaId diff --git a/submodules/TelegramUI/Sources/WidgetDataContext.swift b/submodules/TelegramUI/Sources/WidgetDataContext.swift index 95add664e7..f172bb7ff6 100644 --- a/submodules/TelegramUI/Sources/WidgetDataContext.swift +++ b/submodules/TelegramUI/Sources/WidgetDataContext.swift @@ -227,7 +227,7 @@ final class WidgetDataContext { name = peer.debugDisplayTitle } - result.append(WidgetDataPeer(id: peerId.toInt64(), name: name, lastName: lastName, letters: [], avatarPath: nil, badge: nil, message: WidgetDataPeer.Message(accountPeerId: account.peerId, message: message))) + result.append(WidgetDataPeer(id: peerId.toInt64(), name: name, lastName: lastName, letters: [], avatarPath: nil, badge: nil, message: WidgetDataPeer.Message(accountPeerId: account.peerId, message: EngineMessage(message)))) } result.sort(by: { lhs, rhs in return lhs.id < rhs.id diff --git a/submodules/TelegramUpdateUI/BUILD b/submodules/TelegramUpdateUI/BUILD index cea001af4c..2a82a25c16 100644 --- a/submodules/TelegramUpdateUI/BUILD +++ b/submodules/TelegramUpdateUI/BUILD @@ -13,7 +13,6 @@ swift_library( "//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit", "//submodules/AsyncDisplayKit:AsyncDisplayKit", "//submodules/Display:Display", - "//submodules/Postbox:Postbox", "//submodules/TelegramCore:TelegramCore", "//submodules/TelegramPresentationData:TelegramPresentationData", "//submodules/ItemListUI:ItemListUI", diff --git a/submodules/TelegramUpdateUI/Sources/UpdateInfoController.swift b/submodules/TelegramUpdateUI/Sources/UpdateInfoController.swift index f219a6e120..3af24efa21 100644 --- a/submodules/TelegramUpdateUI/Sources/UpdateInfoController.swift +++ b/submodules/TelegramUpdateUI/Sources/UpdateInfoController.swift @@ -2,7 +2,6 @@ import Foundation import UIKit import Display import SwiftSignalKit -import Postbox import TelegramCore import TelegramPresentationData import AccountContext diff --git a/submodules/TelegramVoip/Sources/GroupCallContext.swift b/submodules/TelegramVoip/Sources/GroupCallContext.swift index 7ab35eaf4e..33e3504bca 100644 --- a/submodules/TelegramVoip/Sources/GroupCallContext.swift +++ b/submodules/TelegramVoip/Sources/GroupCallContext.swift @@ -1,7 +1,6 @@ import Foundation import SwiftSignalKit import TgVoipWebrtc -import Postbox import TelegramCore private final class ContextQueueImpl: NSObject, OngoingCallThreadLocalContextQueueWebrtc { diff --git a/submodules/WallpaperBackgroundNode/BUILD b/submodules/WallpaperBackgroundNode/BUILD index 1dbe792985..574f61d5db 100644 --- a/submodules/WallpaperBackgroundNode/BUILD +++ b/submodules/WallpaperBackgroundNode/BUILD @@ -15,7 +15,6 @@ swift_library( "//submodules/GradientBackground:GradientBackground", "//submodules/TelegramPresentationData:TelegramPresentationData", "//submodules/TelegramCore:TelegramCore", - "//submodules/Postbox:Postbox", "//submodules/AccountContext:AccountContext", "//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit", "//submodules/WallpaperResources:WallpaperResources", diff --git a/submodules/WallpaperBackgroundNode/Sources/WallpaperBackgroundNode.swift b/submodules/WallpaperBackgroundNode/Sources/WallpaperBackgroundNode.swift index 5afc0c891d..c150c744e9 100644 --- a/submodules/WallpaperBackgroundNode/Sources/WallpaperBackgroundNode.swift +++ b/submodules/WallpaperBackgroundNode/Sources/WallpaperBackgroundNode.swift @@ -8,7 +8,6 @@ import TelegramCore import AccountContext import SwiftSignalKit import WallpaperResources -import Postbox import FastBlur private let motionAmount: CGFloat = 32.0 @@ -395,7 +394,7 @@ public final class WallpaperBackgroundNode: ASDisplayNode { } private struct PatternKey: Equatable { - var mediaId: MediaId + var mediaId: EngineMedia.Id var isLight: Bool } private static var cachedSharedPattern: (PatternKey, UIImage)? @@ -626,19 +625,16 @@ public final class WallpaperBackgroundNode: ASDisplayNode { if let cachedValidPatternImage = WallpaperBackgroundNode.cachedValidPatternImage, cachedValidPatternImage.generated.wallpaper == wallpaper { self.validPatternImage = ValidPatternImage(wallpaper: cachedValidPatternImage.generated.wallpaper, generate: cachedValidPatternImage.generate) } else { - func reference(for resource: MediaResource, media: Media, message: Message?) -> MediaResourceReference { - if let message = message { - return .media(media: .message(message: MessageReference(message), media: media), resource: resource) - } - return .wallpaper(wallpaper: .slug(file.slug), resource: resource) + func reference(for resource: EngineMediaResource, media: EngineMedia) -> MediaResourceReference { + return .wallpaper(wallpaper: .slug(file.slug), resource: resource._asResource()) } var convertedRepresentations: [ImageRepresentationWithReference] = [] for representation in file.file.previewRepresentations { - convertedRepresentations.append(ImageRepresentationWithReference(representation: representation, reference: reference(for: representation.resource, media: file.file, message: nil))) + convertedRepresentations.append(ImageRepresentationWithReference(representation: representation, reference: reference(for: EngineMediaResource(representation.resource), media: EngineMedia(file.file)))) } let dimensions = file.file.dimensions ?? PixelDimensions(width: 2000, height: 4000) - convertedRepresentations.append(ImageRepresentationWithReference(representation: .init(dimensions: dimensions, resource: file.file.resource, progressiveSizes: [], immediateThumbnailData: nil), reference: reference(for: file.file.resource, media: file.file, message: nil))) + convertedRepresentations.append(ImageRepresentationWithReference(representation: .init(dimensions: dimensions, resource: file.file.resource, progressiveSizes: [], immediateThumbnailData: nil), reference: reference(for: EngineMediaResource(file.file.resource), media: EngineMedia(file.file)))) let signal = patternWallpaperImage(account: self.context.account, accountManager: self.context.sharedContext.accountManager, representations: convertedRepresentations, mode: .screen, autoFetchFullSize: true) self.patternImageDisposable.set((signal diff --git a/submodules/WidgetItemsUtils/BUILD b/submodules/WidgetItemsUtils/BUILD index 95ae41d81e..f9bef45747 100644 --- a/submodules/WidgetItemsUtils/BUILD +++ b/submodules/WidgetItemsUtils/BUILD @@ -11,7 +11,6 @@ swift_library( ], deps = [ "//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit", - "//submodules/Postbox:Postbox", "//submodules/TelegramCore:TelegramCore", "//submodules/WidgetItems:WidgetItems", ], diff --git a/submodules/WidgetItemsUtils/Sources/WidgetItemsUtils.swift b/submodules/WidgetItemsUtils/Sources/WidgetItemsUtils.swift index c5c1c11359..64d45a51e4 100644 --- a/submodules/WidgetItemsUtils/Sources/WidgetItemsUtils.swift +++ b/submodules/WidgetItemsUtils/Sources/WidgetItemsUtils.swift @@ -1,11 +1,9 @@ import Foundation - -import Postbox import TelegramCore import WidgetItems public extension WidgetDataPeer.Message { - init(accountPeerId: PeerId, message: Message) { + init(accountPeerId: EnginePeer.Id, message: EngineMessage) { var content: WidgetDataPeer.Message.Content = .text for media in message.media { switch media { diff --git a/submodules/libphonenumber/Sources/NBAsYouTypeFormatter.m b/submodules/libphonenumber/Sources/NBAsYouTypeFormatter.m index 32a5824c43..0f7a039b83 100755 --- a/submodules/libphonenumber/Sources/NBAsYouTypeFormatter.m +++ b/submodules/libphonenumber/Sources/NBAsYouTypeFormatter.m @@ -16,11 +16,11 @@ @interface NSArray (NBAdditions) -- (id)safeObjectAtIndex:(NSUInteger)index; +- (id)customSafeObjectAtIndex:(NSUInteger)index; @end @implementation NSArray (NBAdditions) -- (id)safeObjectAtIndex:(NSUInteger)index { +- (id)customSafeObjectAtIndex:(NSUInteger)index { @synchronized(self) { if (index >= [self count]) return nil; id res = [self objectAtIndex:index]; @@ -376,7 +376,7 @@ for (unsigned int i = 0; i < possibleFormatsLength; ++i) { /** @type {i18n.phonenumbers.NumberFormat} */ - NBNumberFormat *numberFormat = [self.possibleFormats_ safeObjectAtIndex:i]; + NBNumberFormat *numberFormat = [self.possibleFormats_ customSafeObjectAtIndex:i]; /** @type {string} */ NSString *pattern = numberFormat.pattern; @@ -424,7 +424,7 @@ for (unsigned int i = 0; i < formatListLength; ++i) { /** @type {i18n.phonenumbers.NumberFormat} */ - NBNumberFormat *format = [formatList safeObjectAtIndex:i]; + NBNumberFormat *format = [formatList customSafeObjectAtIndex:i]; /** @type {BOOL} */ BOOL nationalPrefixIsUsedByCountry = (self.currentMetaData_.nationalPrefix && self.currentMetaData_.nationalPrefix.length > 0); @@ -473,7 +473,7 @@ for (NSUInteger i = 0; i < possibleFormatsLength; ++i) { /** @type {i18n.phonenumbers.NumberFormat} */ - NBNumberFormat *format = [self.possibleFormats_ safeObjectAtIndex:i]; + NBNumberFormat *format = [self.possibleFormats_ customSafeObjectAtIndex:i]; if (format.leadingDigitsPatterns.count == 0) { // Keep everything that isn't restricted by leading digits. @@ -485,7 +485,7 @@ NSInteger lastLeadingDigitsPattern = MIN(indexOfLeadingDigitsPattern, format.leadingDigitsPatterns.count - 1); /** @type {string} */ - NSString *leadingDigitsPattern = [format.leadingDigitsPatterns safeObjectAtIndex:lastLeadingDigitsPattern]; + NSString *leadingDigitsPattern = [format.leadingDigitsPatterns customSafeObjectAtIndex:lastLeadingDigitsPattern]; if ([self.phoneUtil_ stringPositionByRegex:leadingDigits regex:leadingDigitsPattern] == 0) { [possibleFormats addObject:format]; @@ -554,7 +554,7 @@ // this match will always succeed /** @type {string} */ - NSString *aPhoneNumber = [m safeObjectAtIndex:0]; + NSString *aPhoneNumber = [m customSafeObjectAtIndex:0]; // No formatting template can be created if the number of digits entered so // far is longer than the maximum the current formatting rule can accommodate. if (aPhoneNumber.length < self.nationalNumber_.length) { @@ -1101,7 +1101,7 @@ NSString *nationalPrefixForParsing = [NSString stringWithFormat:@"^(?:%@)", self.currentMetaData_.nationalPrefixForParsing]; /** @type {Array.} */ NSArray *m = [self.phoneUtil_ matchedStringByRegex:nationalNumber regex:nationalPrefixForParsing]; - NSString *firstString = [m safeObjectAtIndex:0]; + NSString *firstString = [m customSafeObjectAtIndex:0]; if (m != nil && firstString != nil && firstString.length > 0) { // When the national prefix is detected, we use international formatting // rules instead of national ones, because national formatting rules could @@ -1135,7 +1135,7 @@ /** @type {Array.} */ NSArray *m = [self.phoneUtil_ matchedStringByRegex:accruedInputWithoutFormatting regex:internationalPrefix]; - NSString *firstString = [m safeObjectAtIndex:0]; + NSString *firstString = [m customSafeObjectAtIndex:0]; if (m != nil && firstString != nil && firstString.length > 0) { self.isCompleteNumber_ = YES; diff --git a/submodules/libphonenumber/Sources/NBPhoneMetaDataGenerator.m b/submodules/libphonenumber/Sources/NBPhoneMetaDataGenerator.m index 21078e89c1..de37b66221 100755 --- a/submodules/libphonenumber/Sources/NBPhoneMetaDataGenerator.m +++ b/submodules/libphonenumber/Sources/NBPhoneMetaDataGenerator.m @@ -8,11 +8,11 @@ #import "NBPhoneMetaData.h" @interface NSArray (NBAdditions) -- (id)safeObjectAtIndex:(NSUInteger)index; +- (id)customSafeObjectAtIndex:(NSUInteger)index; @end @implementation NSArray (NBAdditions) -- (id)safeObjectAtIndex:(NSUInteger)index { +- (id)customSafeObjectAtIndex:(NSUInteger)index { @synchronized(self) { if (index >= [self count]) return nil; id res = [self objectAtIndex:index]; @@ -228,34 +228,34 @@ NSString *letters = @"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; [contents appendString:@" self = [super init];\n"]; [contents appendString:@" if (self) {\n"]; - /* 1 */ [contents appendString:[self phoneNumberDescWithData:[currentMetadata safeObjectAtIndex:1] name:@"self.generalDesc"]]; - /* 2 */ [contents appendString:[self phoneNumberDescWithData:[currentMetadata safeObjectAtIndex:2] name:@"self.fixedLine"]]; - /* 3 */ [contents appendString:[self phoneNumberDescWithData:[currentMetadata safeObjectAtIndex:3] name:@"self.mobile"]]; - /* 4 */ [contents appendString:[self phoneNumberDescWithData:[currentMetadata safeObjectAtIndex:4] name:@"self.tollFree"]]; - /* 5 */ [contents appendString:[self phoneNumberDescWithData:[currentMetadata safeObjectAtIndex:5] name:@"self.premiumRate"]]; - /* 6 */ [contents appendString:[self phoneNumberDescWithData:[currentMetadata safeObjectAtIndex:6] name:@"self.sharedCost"]]; - /* 7 */ [contents appendString:[self phoneNumberDescWithData:[currentMetadata safeObjectAtIndex:7] name:@"self.personalNumber"]]; - /* 8 */ [contents appendString:[self phoneNumberDescWithData:[currentMetadata safeObjectAtIndex:8] name:@"self.voip"]]; + /* 1 */ [contents appendString:[self phoneNumberDescWithData:[currentMetadata customSafeObjectAtIndex:1] name:@"self.generalDesc"]]; + /* 2 */ [contents appendString:[self phoneNumberDescWithData:[currentMetadata customSafeObjectAtIndex:2] name:@"self.fixedLine"]]; + /* 3 */ [contents appendString:[self phoneNumberDescWithData:[currentMetadata customSafeObjectAtIndex:3] name:@"self.mobile"]]; + /* 4 */ [contents appendString:[self phoneNumberDescWithData:[currentMetadata customSafeObjectAtIndex:4] name:@"self.tollFree"]]; + /* 5 */ [contents appendString:[self phoneNumberDescWithData:[currentMetadata customSafeObjectAtIndex:5] name:@"self.premiumRate"]]; + /* 6 */ [contents appendString:[self phoneNumberDescWithData:[currentMetadata customSafeObjectAtIndex:6] name:@"self.sharedCost"]]; + /* 7 */ [contents appendString:[self phoneNumberDescWithData:[currentMetadata customSafeObjectAtIndex:7] name:@"self.personalNumber"]]; + /* 8 */ [contents appendString:[self phoneNumberDescWithData:[currentMetadata customSafeObjectAtIndex:8] name:@"self.voip"]]; - /* 21 */ [contents appendString:[self phoneNumberDescWithData:[currentMetadata safeObjectAtIndex:21] name:@"self.pager"]]; - /* 25 */ [contents appendString:[self phoneNumberDescWithData:[currentMetadata safeObjectAtIndex:25] name:@"self.uan"]]; - /* 27 */ [contents appendString:[self phoneNumberDescWithData:[currentMetadata safeObjectAtIndex:27] name:@"self.emergency"]]; - /* 28 */ [contents appendString:[self phoneNumberDescWithData:[currentMetadata safeObjectAtIndex:28] name:@"self.voicemail"]]; - /* 24 */ [contents appendString:[self phoneNumberDescWithData:[currentMetadata safeObjectAtIndex:24] name:@"self.noInternationalDialling"]]; - /* 9 */ [contents appendFormat:@" self.codeID = %@;\n", STR_VAL([currentMetadata safeObjectAtIndex:9])]; - /* 10 */ [contents appendFormat:@" self.countryCode = %@;\n", NUM_VAL([currentMetadata safeObjectAtIndex:10])]; - /* 11 */ [contents appendFormat:@" self.internationalPrefix = %@;\n", STR_VAL([currentMetadata safeObjectAtIndex:11])]; - /* 17 */ [contents appendFormat:@" self.preferredInternationalPrefix = %@;\n", STR_VAL([currentMetadata safeObjectAtIndex:17])]; - /* 12 */ [contents appendFormat:@" self.nationalPrefix = %@;\n", STR_VAL([currentMetadata safeObjectAtIndex:12])]; - /* 13 */ [contents appendFormat:@" self.preferredExtnPrefix = %@;\n", STR_VAL([currentMetadata safeObjectAtIndex:13])]; - /* 15 */ [contents appendFormat:@" self.nationalPrefixForParsing = %@;\n", STR_VAL([currentMetadata safeObjectAtIndex:15])]; - /* 16 */ [contents appendFormat:@" self.nationalPrefixTransformRule = %@;\n", STR_VAL([currentMetadata safeObjectAtIndex:16])]; - /* 18 */ [contents appendFormat:@" self.sameMobileAndFixedLinePattern = %@;\n", [[currentMetadata safeObjectAtIndex:18] boolValue] ? @"YES":@"NO"]; - /* 19 */ [contents appendString:[self phoneNumberFormatArrayWithData:[currentMetadata safeObjectAtIndex:19] name:@"self.numberFormats"]]; // NBNumberFormat array - /* 20 */ [contents appendString:[self phoneNumberFormatArrayWithData:[currentMetadata safeObjectAtIndex:20] name:@"self.intlNumberFormats"]]; // NBNumberFormat array - /* 22 */ [contents appendFormat:@" self.mainCountryForCode = %@;\n", [[currentMetadata safeObjectAtIndex:22] boolValue] ? @"YES":@"NO"]; - /* 23 */ [contents appendFormat:@" self.leadingDigits = %@;\n", STR_VAL([currentMetadata safeObjectAtIndex:23])]; - /* 26 */ [contents appendFormat:@" self.leadingZeroPossible = %@;\n", [[currentMetadata safeObjectAtIndex:26] boolValue] ? @"YES":@"NO"]; + /* 21 */ [contents appendString:[self phoneNumberDescWithData:[currentMetadata customSafeObjectAtIndex:21] name:@"self.pager"]]; + /* 25 */ [contents appendString:[self phoneNumberDescWithData:[currentMetadata customSafeObjectAtIndex:25] name:@"self.uan"]]; + /* 27 */ [contents appendString:[self phoneNumberDescWithData:[currentMetadata customSafeObjectAtIndex:27] name:@"self.emergency"]]; + /* 28 */ [contents appendString:[self phoneNumberDescWithData:[currentMetadata customSafeObjectAtIndex:28] name:@"self.voicemail"]]; + /* 24 */ [contents appendString:[self phoneNumberDescWithData:[currentMetadata customSafeObjectAtIndex:24] name:@"self.noInternationalDialling"]]; + /* 9 */ [contents appendFormat:@" self.codeID = %@;\n", STR_VAL([currentMetadata customSafeObjectAtIndex:9])]; + /* 10 */ [contents appendFormat:@" self.countryCode = %@;\n", NUM_VAL([currentMetadata customSafeObjectAtIndex:10])]; + /* 11 */ [contents appendFormat:@" self.internationalPrefix = %@;\n", STR_VAL([currentMetadata customSafeObjectAtIndex:11])]; + /* 17 */ [contents appendFormat:@" self.preferredInternationalPrefix = %@;\n", STR_VAL([currentMetadata customSafeObjectAtIndex:17])]; + /* 12 */ [contents appendFormat:@" self.nationalPrefix = %@;\n", STR_VAL([currentMetadata customSafeObjectAtIndex:12])]; + /* 13 */ [contents appendFormat:@" self.preferredExtnPrefix = %@;\n", STR_VAL([currentMetadata customSafeObjectAtIndex:13])]; + /* 15 */ [contents appendFormat:@" self.nationalPrefixForParsing = %@;\n", STR_VAL([currentMetadata customSafeObjectAtIndex:15])]; + /* 16 */ [contents appendFormat:@" self.nationalPrefixTransformRule = %@;\n", STR_VAL([currentMetadata customSafeObjectAtIndex:16])]; + /* 18 */ [contents appendFormat:@" self.sameMobileAndFixedLinePattern = %@;\n", [[currentMetadata customSafeObjectAtIndex:18] boolValue] ? @"YES":@"NO"]; + /* 19 */ [contents appendString:[self phoneNumberFormatArrayWithData:[currentMetadata customSafeObjectAtIndex:19] name:@"self.numberFormats"]]; // NBNumberFormat array + /* 20 */ [contents appendString:[self phoneNumberFormatArrayWithData:[currentMetadata customSafeObjectAtIndex:20] name:@"self.intlNumberFormats"]]; // NBNumberFormat array + /* 22 */ [contents appendFormat:@" self.mainCountryForCode = %@;\n", [[currentMetadata customSafeObjectAtIndex:22] boolValue] ? @"YES":@"NO"]; + /* 23 */ [contents appendFormat:@" self.leadingDigits = %@;\n", STR_VAL([currentMetadata customSafeObjectAtIndex:23])]; + /* 26 */ [contents appendFormat:@" self.leadingZeroPossible = %@;\n", [[currentMetadata customSafeObjectAtIndex:26] boolValue] ? @"YES":@"NO"]; [contents appendString:@" }\n"]; [contents appendString:@" return self;\n"]; @@ -346,7 +346,7 @@ NSString *letters = @"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; - (NSString *)phoneNumberDescWithData:(id)value { NSString *initSentance = [NSString stringWithFormat:@"[[NBPhoneNumberDesc alloc] initWithNationalNumberPattern:%@ withPossibleNumberPattern:%@ withExample:%@]", - STR_VAL([value safeObjectAtIndex:2]), STR_VAL([value safeObjectAtIndex:3]), STR_VAL([value safeObjectAtIndex:6])]; + STR_VAL([value customSafeObjectAtIndex:2]), STR_VAL([value customSafeObjectAtIndex:3]), STR_VAL([value customSafeObjectAtIndex:6])]; return initSentance; } @@ -359,15 +359,15 @@ NSString *letters = @"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; NSString *arrayName = [NSString stringWithFormat:@"%@_patternArray", cleanName]; if (value != nil && [value isKindOfClass:[NSArray class]]) { - /* 1 */ NSString *pattern = [value safeObjectAtIndex:1]; - /* 2 */ NSString *format = [value safeObjectAtIndex:2]; - /* 4 */ NSString *nationalPrefixFormattingRule = [value safeObjectAtIndex:4]; - /* 6 */ BOOL nationalPrefixOptionalWhenFormatting = [[value safeObjectAtIndex:6] boolValue]; - /* 5 */ NSString *domesticCarrierCodeFormattingRule = [value safeObjectAtIndex:5]; + /* 1 */ NSString *pattern = [value customSafeObjectAtIndex:1]; + /* 2 */ NSString *format = [value customSafeObjectAtIndex:2]; + /* 4 */ NSString *nationalPrefixFormattingRule = [value customSafeObjectAtIndex:4]; + /* 6 */ BOOL nationalPrefixOptionalWhenFormatting = [[value customSafeObjectAtIndex:6] boolValue]; + /* 5 */ NSString *domesticCarrierCodeFormattingRule = [value customSafeObjectAtIndex:5]; [contents appendFormat:@"\n NSMutableArray *%@ = [[NSMutableArray alloc] init];\n", arrayName]; - /* 3 */ id tmpData = [value safeObjectAtIndex:3]; + /* 3 */ id tmpData = [value customSafeObjectAtIndex:3]; if (tmpData != nil && [tmpData isKindOfClass:[NSArray class]]) { for (id numFormat in tmpData) { diff --git a/submodules/libphonenumber/Sources/NBPhoneNumberDesc.m b/submodules/libphonenumber/Sources/NBPhoneNumberDesc.m index 731cde861c..cbc3d0947e 100755 --- a/submodules/libphonenumber/Sources/NBPhoneNumberDesc.m +++ b/submodules/libphonenumber/Sources/NBPhoneNumberDesc.m @@ -7,11 +7,11 @@ #import "NBPhoneNumberDesc.h" @interface NSArray (NBAdditions) -- (id)safeObjectAtIndex:(NSUInteger)index; +- (id)customSafeObjectAtIndex:(NSUInteger)index; @end @implementation NSArray (NBAdditions) -- (id)safeObjectAtIndex:(NSUInteger)index { +- (id)customSafeObjectAtIndex:(NSUInteger)index { @synchronized(self) { if (index >= [self count]) return nil; id res = [self objectAtIndex:index]; @@ -33,9 +33,9 @@ NSString *exp = nil; if (data != nil && [data isKindOfClass:[NSArray class]]) { - /* 2 */ nnp = [data safeObjectAtIndex:2]; - /* 3 */ pnp = [data safeObjectAtIndex:3]; - /* 6 */ exp = [data safeObjectAtIndex:6]; + /* 2 */ nnp = [data customSafeObjectAtIndex:2]; + /* 3 */ pnp = [data customSafeObjectAtIndex:3]; + /* 6 */ exp = [data customSafeObjectAtIndex:6]; } return [self initWithNationalNumberPattern:nnp withPossibleNumberPattern:pnp withExample:exp]; From 54e3543a6f29623475c999da9e47a41a8ed9e1d7 Mon Sep 17 00:00:00 2001 From: Ali <> Date: Tue, 21 Sep 2021 01:14:05 +0300 Subject: [PATCH 15/30] Cleanup --- .../Sources/NBPhoneMetaDataGenerator.m | 13 ------------- .../libphonenumber/Sources/NBPhoneNumberDesc.m | 14 -------------- 2 files changed, 27 deletions(-) diff --git a/submodules/libphonenumber/Sources/NBPhoneMetaDataGenerator.m b/submodules/libphonenumber/Sources/NBPhoneMetaDataGenerator.m index de37b66221..12c1f0575f 100755 --- a/submodules/libphonenumber/Sources/NBPhoneMetaDataGenerator.m +++ b/submodules/libphonenumber/Sources/NBPhoneMetaDataGenerator.m @@ -11,19 +11,6 @@ - (id)customSafeObjectAtIndex:(NSUInteger)index; @end -@implementation NSArray (NBAdditions) -- (id)customSafeObjectAtIndex:(NSUInteger)index { - @synchronized(self) { - if (index >= [self count]) return nil; - id res = [self objectAtIndex:index]; - if (res == nil || (NSNull*)res == [NSNull null]) { - return nil; - } - return res; - } -} -@end - #define kNBSRCDirectoryName @"src" #define INDENT_TAB @" " diff --git a/submodules/libphonenumber/Sources/NBPhoneNumberDesc.m b/submodules/libphonenumber/Sources/NBPhoneNumberDesc.m index cbc3d0947e..ca92a84e1a 100755 --- a/submodules/libphonenumber/Sources/NBPhoneNumberDesc.m +++ b/submodules/libphonenumber/Sources/NBPhoneNumberDesc.m @@ -10,20 +10,6 @@ - (id)customSafeObjectAtIndex:(NSUInteger)index; @end -@implementation NSArray (NBAdditions) -- (id)customSafeObjectAtIndex:(NSUInteger)index { - @synchronized(self) { - if (index >= [self count]) return nil; - id res = [self objectAtIndex:index]; - if (res == nil || (NSNull*)res == [NSNull null]) { - return nil; - } - return res; - } -} -@end - - @implementation NBPhoneNumberDesc - (id)initWithData:(id)data From c90f551614a52fa1baf50d36800e49f6d34268ad Mon Sep 17 00:00:00 2001 From: Ali <> Date: Tue, 21 Sep 2021 18:45:59 +0300 Subject: [PATCH 16/30] Fix mp3 playback --- submodules/ffmpeg/Sources/FFMpeg/build-ffmpeg-bazel.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/ffmpeg/Sources/FFMpeg/build-ffmpeg-bazel.sh b/submodules/ffmpeg/Sources/FFMpeg/build-ffmpeg-bazel.sh index 8b4aff7cf7..3f2f119e19 100755 --- a/submodules/ffmpeg/Sources/FFMpeg/build-ffmpeg-bazel.sh +++ b/submodules/ffmpeg/Sources/FFMpeg/build-ffmpeg-bazel.sh @@ -47,7 +47,7 @@ CONFIGURE_FLAGS="--enable-cross-compile --disable-programs \ --enable-libopus \ --enable-audiotoolbox \ --enable-bsf=aac_adtstoasc \ - --enable-decoder=h264,hevc,libopus,mp3_at,aac,flac,alac_at,pcm_s16le,pcm_s24le,gsm_ms_at \ + --enable-decoder=h264,hevc,libopus,mp3,aac,flac,alac_at,pcm_s16le,pcm_s24le,gsm_ms_at \ --enable-demuxer=aac,mov,m4v,mp3,ogg,libopus,flac,wav,aiff,matroska \ --enable-parser=aac,h264,mp3,libopus \ --enable-protocol=file \ From f55ba47e74cfb5f6eafd4208458bddbc66067cb6 Mon Sep 17 00:00:00 2001 From: Ali <> Date: Tue, 21 Sep 2021 18:46:49 +0300 Subject: [PATCH 17/30] Update webrtc --- submodules/TgVoipWebrtc/tgcalls | 2 +- third-party/webrtc/BUILD | 140 +- .../third_party/abseil-cpp/BUILD.gn | 77 - .../abseil-cpp/CMake/AbseilDll.cmake | 61 +- .../abseil-cpp/CMake/AbseilHelpers.cmake | 135 +- .../abseil-cpp/CMake/AbseilInstallDirs.cmake | 20 - .../CMake/Googletest/CMakeLists.txt.in | 30 +- .../third_party/abseil-cpp/CMake/README.md | 96 +- .../abseil-cpp/CMake/abslConfig.cmake.in | 5 +- .../CMake/install_test_project/CMakeLists.txt | 4 +- .../CMake/install_test_project/simple.cc | 9 + .../CMake/install_test_project/test.sh | 164 +- .../third_party/abseil-cpp/CMakeLists.txt | 136 +- .../third_party/abseil-cpp/FAQ.md | 5 +- .../third_party/abseil-cpp/LTS.md | 16 - .../third_party/abseil-cpp/OWNERS | 6 - .../third_party/abseil-cpp/README.chromium | 36 - .../third_party/abseil-cpp/README.md | 42 +- .../third_party/abseil-cpp/WORKSPACE | 45 - .../third_party/abseil-cpp/absl.gni | 80 - .../abseil-cpp/absl/CMakeLists.txt | 2 + .../abseil-cpp/absl/abseil.podspec.gen.py | 4 +- .../abseil-cpp/absl/algorithm/BUILD.gn | 19 - .../abseil-cpp/absl/algorithm/CMakeLists.txt | 4 +- .../abseil-cpp/absl/algorithm/container.h | 279 +-- .../absl/algorithm/container_test.cc | 133 +- .../third_party/abseil-cpp/absl/base/BUILD.gn | 304 --- .../abseil-cpp/absl/base/CMakeLists.txt | 105 +- .../abseil-cpp/absl/base/attributes.h | 212 +- .../abseil-cpp/absl/base/call_once.h | 13 +- .../third_party/abseil-cpp/absl/base/casts.h | 15 +- .../third_party/abseil-cpp/absl/base/config.h | 177 +- .../absl/base/dynamic_annotations.cc | 129 -- .../absl/base/dynamic_annotations.h | 796 +++---- .../abseil-cpp/absl/base/internal/bits.h | 218 -- .../absl/base/internal/bits_test.cc | 97 - .../absl/base/internal/direct_mmap.h | 10 +- .../absl/base/internal/dynamic_annotations.h | 398 ++++ .../abseil-cpp/absl/base/internal/endian.h | 61 + .../absl/base/internal/endian_test.cc | 24 +- .../base/internal/exception_safety_testing.h | 26 +- .../absl/base/internal/exponential_biased.cc | 2 +- .../absl/base/internal/exponential_biased.h | 2 +- .../base/internal/exponential_biased_test.cc | 2 +- .../abseil-cpp/absl/base/internal/invoke.h | 8 +- .../base/internal/low_level_alloc_test.cc | 23 +- .../absl/base/internal/low_level_scheduling.h | 35 +- .../absl/base/internal/raw_logging.cc | 70 +- .../absl/base/internal/raw_logging.h | 22 +- .../abseil-cpp/absl/base/internal/spinlock.cc | 57 +- .../abseil-cpp/absl/base/internal/spinlock.h | 50 +- .../absl/base/internal/spinlock_akaros.inc | 4 +- .../absl/base/internal/spinlock_linux.inc | 14 +- .../absl/base/internal/spinlock_posix.inc | 4 +- .../absl/base/internal/spinlock_wait.h | 22 +- .../absl/base/internal/spinlock_win32.inc | 10 +- .../abseil-cpp/absl/base/internal/strerror.cc | 39 +- .../absl/base/internal/strerror_benchmark.cc | 9 - .../absl/base/internal/strerror_test.cc | 6 +- .../abseil-cpp/absl/base/internal/sysinfo.cc | 93 +- .../abseil-cpp/absl/base/internal/sysinfo.h | 8 + .../absl/base/internal/sysinfo_test.cc | 23 +- .../absl/base/internal/thread_annotations.h | 271 +++ .../absl/base/internal/thread_identity.cc | 15 +- .../absl/base/internal/thread_identity.h | 110 +- .../base/internal/thread_identity_test.cc | 11 +- .../absl/base/internal/throw_delegate.cc | 118 +- .../absl/base/internal/tsan_mutex_interface.h | 4 +- .../absl/base/internal/unaligned_access.h | 76 - .../base/internal/unique_small_name_test.cc | 77 + .../absl/base/internal/unscaledcycleclock.cc | 16 +- .../absl/base/internal/unscaledcycleclock.h | 14 +- .../abseil-cpp/absl/base/invoke_test.cc | 128 +- .../abseil-cpp/absl/base/log_severity.h | 8 +- .../abseil-cpp/absl/base/log_severity_test.cc | 6 +- .../third_party/abseil-cpp/absl/base/macros.h | 120 +- .../abseil-cpp/absl/base/optimization.h | 75 +- .../abseil-cpp/absl/base/optimization_test.cc | 129 ++ .../abseil-cpp/absl/base/policy_checks.h | 2 +- .../third_party/abseil-cpp/absl/base/port.h | 1 - .../absl/base/spinlock_test_common.cc | 21 +- .../abseil-cpp/absl/base/thread_annotations.h | 145 +- .../abseil-cpp/absl/cleanup/CMakeLists.txt | 55 + .../abseil-cpp/absl/cleanup/cleanup.h | 140 ++ .../abseil-cpp/absl/cleanup/cleanup_test.cc | 311 +++ .../absl/cleanup/internal/cleanup.h | 100 + .../absl/compiler_config_setting.bzl | 38 - .../abseil-cpp/absl/container/BUILD.gn | 352 ---- .../abseil-cpp/absl/container/CMakeLists.txt | 79 +- .../absl/container/btree_benchmark.cc | 36 +- .../abseil-cpp/absl/container/btree_map.h | 91 +- .../abseil-cpp/absl/container/btree_set.h | 72 +- .../abseil-cpp/absl/container/btree_test.cc | 652 +++++- .../abseil-cpp/absl/container/fixed_array.h | 48 +- .../fixed_array_exception_safety_test.cc | 3 +- .../absl/container/fixed_array_test.cc | 103 +- .../abseil-cpp/absl/container/flat_hash_map.h | 8 +- .../absl/container/flat_hash_map_test.cc | 55 + .../abseil-cpp/absl/container/flat_hash_set.h | 5 +- .../absl/container/flat_hash_set_test.cc | 12 + .../absl/container/inlined_vector.h | 203 +- .../container/inlined_vector_benchmark.cc | 22 + .../absl/container/inlined_vector_test.cc | 36 +- .../absl/container/internal/btree.h | 1004 ++++----- .../absl/container/internal/btree_container.h | 313 +-- .../absl/container/internal/common.h | 7 +- .../container/internal/compressed_tuple.h | 2 +- .../container/internal/container_memory.h | 65 +- .../internal/container_memory_test.cc | 5 +- .../container/internal/counting_allocator.h | 69 +- .../internal/hash_function_defaults.h | 32 +- .../internal/hash_function_defaults_test.cc | 4 +- .../internal/hash_generator_testing.cc | 6 +- .../internal/hash_generator_testing.h | 21 + .../container/internal/hash_policy_traits.h | 31 +- .../container/internal/hashtablez_sampler.cc | 112 +- .../container/internal/hashtablez_sampler.h | 153 +- ...ashtablez_sampler_force_weak_definition.cc | 3 +- .../internal/hashtablez_sampler_test.cc | 44 +- .../absl/container/internal/inlined_vector.h | 829 ++++---- .../absl/container/internal/layout.h | 20 +- .../container/internal/layout_benchmark.cc | 122 ++ .../absl/container/internal/layout_test.cc | 604 +++--- .../absl/container/internal/raw_hash_map.h | 5 +- .../absl/container/internal/raw_hash_set.cc | 23 +- .../absl/container/internal/raw_hash_set.h | 665 +++--- .../internal/raw_hash_set_allocator_test.cc | 75 + .../internal/raw_hash_set_benchmark.cc | 431 ++++ .../internal/raw_hash_set_probe_benchmark.cc | 590 ++++++ .../container/internal/raw_hash_set_test.cc | 444 +++- .../internal/unordered_map_constructor_test.h | 39 +- .../internal/unordered_map_modifiers_test.h | 41 +- .../internal/unordered_set_modifiers_test.h | 35 +- .../abseil-cpp/absl/container/node_hash_map.h | 14 +- .../absl/container/node_hash_map_test.cc | 15 + .../abseil-cpp/absl/container/node_hash_set.h | 39 +- .../absl/copts/AbseilConfigureCopts.cmake | 18 +- .../absl/copts/GENERATED_AbseilCopts.cmake | 117 +- .../abseil-cpp/absl/copts/GENERATED_copts.bzl | 117 +- .../abseil-cpp/absl/copts/configure_copts.bzl | 16 +- .../abseil-cpp/absl/copts/copts.py | 128 +- .../abseil-cpp/absl/copts/generate_copts.py | 2 +- .../abseil-cpp/absl/debugging/BUILD.gn | 164 -- .../abseil-cpp/absl/debugging/CMakeLists.txt | 22 +- .../absl/debugging/failure_signal_handler.cc | 44 +- .../absl/debugging/failure_signal_handler.h | 2 +- .../debugging/failure_signal_handler_test.cc | 12 +- .../debugging/internal/address_is_readable.cc | 9 +- .../absl/debugging/internal/demangle.cc | 120 +- .../absl/debugging/internal/demangle_test.cc | 38 +- .../absl/debugging/internal/examine_stack.cc | 48 +- .../debugging/internal/stack_consumption.cc | 3 +- .../debugging/internal/stack_consumption.h | 5 +- .../internal/stacktrace_aarch64-inl.inc | 7 +- .../debugging/internal/stacktrace_arm-inl.inc | 17 +- .../debugging/internal/stacktrace_config.h | 64 +- .../internal/stacktrace_emscripten-inl.inc | 110 + .../internal/stacktrace_generic-inl.inc | 15 +- .../internal/stacktrace_powerpc-inl.inc | 7 +- .../internal/stacktrace_riscv-inl.inc | 234 +++ .../debugging/internal/stacktrace_x86-inl.inc | 7 +- .../absl/debugging/internal/symbolize.h | 41 +- .../absl/debugging/internal/vdso_support.cc | 21 - .../abseil-cpp/absl/debugging/leak_check.cc | 16 + .../abseil-cpp/absl/debugging/leak_check.h | 22 +- .../absl/debugging/leak_check_test.cc | 2 + .../abseil-cpp/absl/debugging/stacktrace.cc | 2 + .../abseil-cpp/absl/debugging/symbolize.cc | 15 +- .../absl/debugging/symbolize_darwin.inc | 101 + .../absl/debugging/symbolize_elf.inc | 124 +- .../absl/debugging/symbolize_emscripten.inc | 72 + .../absl/debugging/symbolize_test.cc | 80 +- .../abseil-cpp/absl/flags/BUILD.gn | 205 -- .../abseil-cpp/absl/flags/CMakeLists.txt | 198 +- .../abseil-cpp/absl/flags/commandlineflag.cc | 34 + .../abseil-cpp/absl/flags/commandlineflag.h | 200 ++ .../{internal => }/commandlineflag_test.cc | 152 +- .../abseil-cpp/absl/flags/config.h | 31 +- .../abseil-cpp/absl/flags/declare.h | 1 - .../third_party/abseil-cpp/absl/flags/flag.cc | 2 - .../third_party/abseil-cpp/absl/flags/flag.h | 199 +- .../abseil-cpp/absl/flags/flag_benchmark.cc | 153 +- .../abseil-cpp/absl/flags/flag_benchmark.lds | 13 + .../abseil-cpp/absl/flags/flag_test.cc | 629 ++++-- .../abseil-cpp/absl/flags/flag_test_defs.cc | 4 +- .../absl/flags/internal/commandlineflag.cc | 4 - .../absl/flags/internal/commandlineflag.h | 139 +- .../abseil-cpp/absl/flags/internal/flag.cc | 276 ++- .../abseil-cpp/absl/flags/internal/flag.h | 501 +++-- .../abseil-cpp/absl/flags/internal/parse.h | 8 + .../absl/flags/internal/path_util.h | 1 - .../flags/internal/private_handle_accessor.cc | 65 + .../flags/internal/private_handle_accessor.h | 61 + .../absl/flags/internal/program_name_test.cc | 4 +- .../absl/flags/internal/registry.cc | 351 ---- .../abseil-cpp/absl/flags/internal/registry.h | 55 +- .../absl/flags/internal/sequence_lock.h | 187 ++ .../absl/flags/internal/sequence_lock_test.cc | 169 ++ .../absl/flags/internal/type_erased.cc | 90 - .../absl/flags/internal/type_erased.h | 90 - .../absl/flags/internal/type_erased_test.cc | 157 -- .../abseil-cpp/absl/flags/internal/usage.cc | 353 ++-- .../abseil-cpp/absl/flags/internal/usage.h | 47 +- .../absl/flags/internal/usage_test.cc | 138 +- .../abseil-cpp/absl/flags/marshalling.cc | 21 +- .../abseil-cpp/absl/flags/marshalling.h | 4 +- .../abseil-cpp/absl/flags/parse.cc | 111 +- .../third_party/abseil-cpp/absl/flags/parse.h | 1 - .../abseil-cpp/absl/flags/parse_test.cc | 129 +- .../abseil-cpp/absl/flags/reflection.cc | 354 ++++ .../abseil-cpp/absl/flags/reflection.h | 90 + .../abseil-cpp/absl/flags/reflection_test.cc | 265 +++ .../abseil-cpp/absl/flags/usage_config.cc | 6 +- .../abseil-cpp/absl/flags/usage_config.h | 3 +- .../abseil-cpp/absl/functional/BUILD.gn | 25 - .../abseil-cpp/absl/functional/CMakeLists.txt | 5 +- .../abseil-cpp/absl/functional/function_ref.h | 7 +- .../absl/functional/internal/front_binder.h | 16 +- .../absl/functional/internal/function_ref.h | 4 +- .../third_party/abseil-cpp/absl/hash/BUILD.gn | 75 - .../abseil-cpp/absl/hash/CMakeLists.txt | 41 +- .../third_party/abseil-cpp/absl/hash/hash.h | 32 +- .../abseil-cpp/absl/hash/hash_benchmark.cc | 254 +++ .../abseil-cpp/absl/hash/hash_test.cc | 63 +- .../abseil-cpp/absl/hash/internal/city.cc | 27 +- .../abseil-cpp/absl/hash/internal/city.h | 20 +- .../abseil-cpp/absl/hash/internal/hash.cc | 34 +- .../abseil-cpp/absl/hash/internal/hash.h | 276 +-- .../absl/hash/internal/low_level_hash.cc | 123 ++ .../absl/hash/internal/low_level_hash.h | 50 + .../absl/hash/internal/low_level_hash_test.cc | 532 +++++ .../abseil-cpp/absl/memory/BUILD.gn | 13 - .../abseil-cpp/absl/memory/CMakeLists.txt | 4 +- .../abseil-cpp/absl/memory/memory.h | 4 + .../abseil-cpp/absl/memory/memory_test.cc | 38 +- .../third_party/abseil-cpp/absl/meta/BUILD.gn | 10 - .../abseil-cpp/absl/meta/CMakeLists.txt | 2 +- .../abseil-cpp/absl/meta/type_traits.h | 49 +- .../abseil-cpp/absl/meta/type_traits_test.cc | 28 + .../abseil-cpp/absl/numeric/BUILD.gn | 18 - .../abseil-cpp/absl/numeric/CMakeLists.txt | 42 +- .../abseil-cpp/absl/numeric/bits.h | 177 ++ .../abseil-cpp/absl/numeric/bits_test.cc | 573 +++++ .../abseil-cpp/absl/numeric/int128.cc | 53 +- .../abseil-cpp/absl/numeric/int128.h | 219 +- .../absl/numeric/int128_benchmark.cc | 161 +- .../absl/numeric/int128_have_intrinsic.inc | 44 +- .../absl/numeric/int128_no_intrinsic.inc | 129 +- .../abseil-cpp/absl/numeric/int128_test.cc | 18 + .../abseil-cpp/absl/numeric/internal/bits.h | 358 ++++ .../absl/numeric/internal/representation.h | 55 + .../abseil-cpp/absl/profiling/CMakeLists.txt | 39 + .../absl/profiling/internal/sample_recorder.h | 230 ++ .../internal/sample_recorder_test.cc | 171 ++ .../abseil-cpp/absl/random/BUILD.gn | 84 - .../abseil-cpp/absl/random/CMakeLists.txt | 197 +- .../random/bernoulli_distribution_test.cc | 6 +- .../absl/random/beta_distribution_test.cc | 66 +- .../abseil-cpp/absl/random/bit_gen_ref.h | 111 +- .../absl/random/bit_gen_ref_test.cc | 25 +- .../absl/random/discrete_distribution_test.cc | 13 +- .../abseil-cpp/absl/random/distributions.h | 12 +- .../absl/random/distributions_test.cc | 152 +- .../random/exponential_distribution_test.cc | 48 +- .../absl/random/gaussian_distribution_test.cc | 40 +- .../abseil-cpp/absl/random/internal/BUILD.gn | 268 --- .../random/internal/distribution_caller.h | 53 +- .../absl/random/internal/distributions.h | 52 - .../absl/random/internal/explicit_seed_seq.h | 3 +- .../absl/random/internal/fast_uniform_bits.h | 226 +- .../random/internal/fast_uniform_bits_test.cc | 322 +-- .../absl/random/internal/fastmath.h | 23 +- .../absl/random/internal/fastmath_test.cc | 13 - .../gaussian_distribution_gentables.cc | 16 +- .../absl/random/internal/generate_real.h | 10 +- .../random/internal/generate_real_test.cc | 9 +- .../random/internal/iostream_state_saver.h | 4 +- .../internal/iostream_state_saver_test.cc | 5 +- .../absl/random/internal/mock_helpers.h | 134 ++ .../absl/random/internal/mock_overload_set.h | 39 +- .../random/internal/mocking_bit_gen_base.h | 85 - .../random/internal/nanobenchmark_test.cc | 2 +- .../absl/random/internal/pcg_engine.h | 7 +- .../absl/random/internal/pool_urbg.cc | 7 +- .../absl/random/internal/randen-keys.inc | 207 -- .../abseil-cpp/absl/random/internal/randen.cc | 2 +- .../abseil-cpp/absl/random/internal/randen.h | 2 +- .../absl/random/internal/randen_detect.cc | 4 +- .../absl/random/internal/randen_engine.h | 8 +- .../absl/random/internal/randen_hwaes.cc | 420 ++-- .../absl/random/internal/randen_hwaes.h | 2 +- .../absl/random/internal/randen_hwaes_test.cc | 12 +- .../absl/random/internal/randen_round_keys.cc | 462 +++++ .../absl/random/internal/randen_slow.cc | 646 +++--- .../absl/random/internal/randen_slow.h | 9 +- .../absl/random/internal/randen_slow_test.cc | 11 +- .../absl/random/internal/randen_traits.h | 33 +- .../absl/random/internal/seed_material.cc | 50 +- .../absl/random/internal/uniform_helper.h | 68 +- .../random/internal/uniform_helper_test.cc | 279 +++ .../absl/random/internal/wide_multiply.h | 12 +- .../random/internal/wide_multiply_test.cc | 3 +- .../random/log_uniform_int_distribution.h | 7 +- .../log_uniform_int_distribution_test.cc | 7 +- .../absl/random/mock_distributions.h | 5 + .../abseil-cpp/absl/random/mocking_bit_gen.h | 206 +- .../absl/random/mocking_bit_gen_test.cc | 51 +- .../absl/random/poisson_distribution_test.cc | 12 +- .../abseil-cpp/absl/random/random.h | 2 +- .../absl/random/seed_sequences_test.cc | 1 - .../absl/random/uniform_int_distribution.h | 2 +- .../random/uniform_int_distribution_test.cc | 13 +- .../random/uniform_real_distribution_test.cc | 38 +- .../absl/random/zipf_distribution_test.cc | 6 +- .../abseil-cpp/absl/status/BUILD.gn | 28 - .../abseil-cpp/absl/status/CMakeLists.txt | 39 +- .../absl/status/internal/status_internal.h | 69 + .../absl/status/internal/statusor_internal.h | 396 ++++ .../abseil-cpp/absl/status/status.cc | 59 +- .../abseil-cpp/absl/status/status.h | 689 ++++-- .../absl/status/status_payload_printer.cc | 15 +- .../abseil-cpp/absl/status/status_test.cc | 36 +- .../abseil-cpp/absl/status/statusor.cc | 103 + .../abseil-cpp/absl/status/statusor.h | 770 +++++++ .../abseil-cpp/absl/status/statusor_test.cc | 1847 +++++++++++++++++ .../abseil-cpp/absl/strings/BUILD.gn | 174 -- .../abseil-cpp/absl/strings/CMakeLists.txt | 535 ++++- .../abseil-cpp/absl/strings/ascii_test.cc | 4 + .../abseil-cpp/absl/strings/charconv.cc | 16 +- .../abseil-cpp/absl/strings/charconv_test.cc | 4 +- .../abseil-cpp/absl/strings/cord.cc | 1441 ++++++------- .../abseil-cpp/absl/strings/cord.h | 798 +++---- .../absl/strings/cord_ring_reader_test.cc | 180 ++ .../abseil-cpp/absl/strings/cord_ring_test.cc | 1495 +++++++++++++ .../abseil-cpp/absl/strings/cord_test.cc | 530 +++-- .../absl/strings/cord_test_helpers.h | 62 + .../abseil-cpp/absl/strings/cordz_test.cc | 466 +++++ .../absl/strings/cordz_test_helpers.h | 151 ++ .../abseil-cpp/absl/strings/escaping.cc | 8 +- .../strings/internal/charconv_bigint_test.cc | 55 + .../absl/strings/internal/charconv_parse.cc | 14 +- .../absl/strings/internal/cord_internal.cc | 89 + .../absl/strings/internal/cord_internal.h | 539 ++++- .../absl/strings/internal/cord_rep_btree.cc | 955 +++++++++ .../absl/strings/internal/cord_rep_btree.h | 870 ++++++++ .../internal/cord_rep_btree_navigator.cc | 185 ++ .../internal/cord_rep_btree_navigator.h | 265 +++ .../internal/cord_rep_btree_navigator_test.cc | 325 +++ .../strings/internal/cord_rep_btree_reader.cc | 68 + .../strings/internal/cord_rep_btree_reader.h | 211 ++ .../internal/cord_rep_btree_reader_test.cc | 293 +++ .../strings/internal/cord_rep_btree_test.cc | 1395 +++++++++++++ .../absl/strings/internal/cord_rep_consume.cc | 129 ++ .../absl/strings/internal/cord_rep_consume.h | 50 + .../strings/internal/cord_rep_consume_test.cc | 173 ++ .../absl/strings/internal/cord_rep_flat.h | 146 ++ .../absl/strings/internal/cord_rep_ring.cc | 771 +++++++ .../absl/strings/internal/cord_rep_ring.h | 607 ++++++ .../strings/internal/cord_rep_ring_reader.h | 118 ++ .../strings/internal/cord_rep_test_util.h | 185 ++ .../absl/strings/internal/cordz_functions.cc | 96 + .../absl/strings/internal/cordz_functions.h | 85 + .../strings/internal/cordz_functions_test.cc | 149 ++ .../absl/strings/internal/cordz_handle.cc | 139 ++ .../absl/strings/internal/cordz_handle.h | 131 ++ .../strings/internal/cordz_handle_test.cc | 265 +++ .../absl/strings/internal/cordz_info.cc | 445 ++++ .../absl/strings/internal/cordz_info.h | 298 +++ .../internal/cordz_info_statistics_test.cc | 625 ++++++ .../absl/strings/internal/cordz_info_test.cc | 341 +++ .../strings/internal/cordz_sample_token.cc | 64 + .../strings/internal/cordz_sample_token.h | 97 + .../internal/cordz_sample_token_test.cc | 208 ++ .../absl/strings/internal/cordz_statistics.h | 87 + .../strings/internal/cordz_update_scope.h | 71 + .../internal/cordz_update_scope_test.cc | 49 + .../strings/internal/cordz_update_tracker.h | 119 ++ .../internal/cordz_update_tracker_test.cc | 143 ++ .../strings/internal/resize_uninitialized.h | 23 + .../internal/resize_uninitialized_test.cc | 23 + .../absl/strings/internal/str_format/arg.cc | 374 ++-- .../absl/strings/internal/str_format/arg.h | 218 +- .../strings/internal/str_format/arg_test.cc | 21 +- .../absl/strings/internal/str_format/bind.cc | 23 +- .../absl/strings/internal/str_format/bind.h | 48 +- .../strings/internal/str_format/bind_test.cc | 14 + .../strings/internal/str_format/checker.h | 35 +- .../internal/str_format/checker_test.cc | 24 +- .../internal/str_format/convert_test.cc | 700 ++++++- .../strings/internal/str_format/extension.cc | 50 +- .../strings/internal/str_format/extension.h | 306 +-- .../internal/str_format/extension_test.cc | 36 +- .../internal/str_format/float_conversion.cc | 1079 +++++++++- .../internal/str_format/float_conversion.h | 20 +- .../absl/strings/internal/str_format/output.h | 16 +- .../internal/str_format/output_test.cc | 8 +- .../strings/internal/str_format/parser.cc | 159 +- .../absl/strings/internal/str_format/parser.h | 74 +- .../internal/str_format/parser_test.cc | 72 +- .../strings/internal/str_split_internal.h | 121 +- .../absl/strings/internal/string_constant.h | 64 + .../strings/internal/string_constant_test.cc | 60 + .../abseil-cpp/absl/strings/match.cc | 9 +- .../abseil-cpp/absl/strings/match.h | 22 +- .../abseil-cpp/absl/strings/match_test.cc | 17 + .../abseil-cpp/absl/strings/numbers.cc | 136 +- .../abseil-cpp/absl/strings/numbers.h | 20 +- .../abseil-cpp/absl/strings/numbers_test.cc | 108 +- .../abseil-cpp/absl/strings/str_cat.cc | 16 +- .../absl/strings/str_cat_benchmark.cc | 47 + .../abseil-cpp/absl/strings/str_format.h | 303 ++- .../absl/strings/str_format_test.cc | 171 +- .../abseil-cpp/absl/strings/str_join.h | 2 +- .../abseil-cpp/absl/strings/str_split.h | 43 +- .../abseil-cpp/absl/strings/str_split_test.cc | 40 +- .../abseil-cpp/absl/strings/string_view.cc | 37 +- .../abseil-cpp/absl/strings/string_view.h | 165 +- .../absl/strings/string_view_test.cc | 56 +- .../abseil-cpp/absl/strings/substitute.h | 188 +- .../absl/strings/testdata/getline-1.txt | 3 - .../absl/strings/testdata/getline-2.txt | 1 - .../abseil-cpp/absl/synchronization/BUILD.gn | 91 - .../absl/synchronization/CMakeLists.txt | 18 +- .../absl/synchronization/blocking_counter.cc | 40 +- .../absl/synchronization/blocking_counter.h | 8 +- .../blocking_counter_benchmark.cc | 83 + .../synchronization/blocking_counter_test.cc | 12 + .../internal/create_thread_identity.cc | 6 +- .../absl/synchronization/internal/futex.h | 154 ++ .../synchronization/internal/graphcycles.cc | 7 +- .../synchronization/internal/kernel_timeout.h | 57 +- .../synchronization/internal/mutex_nonprod.cc | 320 --- .../internal/mutex_nonprod.inc | 261 --- .../internal/per_thread_sem.cc | 4 +- .../synchronization/internal/per_thread_sem.h | 10 +- .../internal/per_thread_sem_test.cc | 3 +- .../absl/synchronization/internal/waiter.cc | 60 +- .../absl/synchronization/internal/waiter.h | 12 +- .../abseil-cpp/absl/synchronization/mutex.cc | 238 ++- .../abseil-cpp/absl/synchronization/mutex.h | 146 +- .../absl/synchronization/mutex_benchmark.cc | 227 +- .../absl/synchronization/mutex_test.cc | 49 +- .../third_party/abseil-cpp/absl/time/BUILD.gn | 50 - .../abseil-cpp/absl/time/CMakeLists.txt | 5 +- .../abseil-cpp/absl/time/civil_time.cc | 16 +- .../third_party/abseil-cpp/absl/time/clock.cc | 276 +-- .../third_party/abseil-cpp/absl/time/clock.h | 4 +- .../abseil-cpp/absl/time/duration.cc | 152 +- .../absl/time/duration_benchmark.cc | 16 + .../abseil-cpp/absl/time/duration_test.cc | 31 +- .../abseil-cpp/absl/time/format.cc | 77 +- .../abseil-cpp/absl/time/format_benchmark.cc | 2 +- .../absl/time/internal/cctz/BUILD.gn | 46 - .../cctz/include/cctz/civil_time_detail.h | 60 +- .../internal/cctz/include/cctz/time_zone.h | 4 +- .../time/internal/cctz/src/cctz_benchmark.cc | 17 +- .../time/internal/cctz/src/civil_time_test.cc | 10 + .../time/internal/cctz/src/time_zone_fixed.cc | 2 +- .../internal/cctz/src/time_zone_format.cc | 161 +- .../cctz/src/time_zone_format_test.cc | 115 +- .../time/internal/cctz/src/time_zone_impl.cc | 34 +- .../time/internal/cctz/src/time_zone_info.cc | 298 +-- .../time/internal/cctz/src/time_zone_info.h | 9 +- .../time/internal/cctz/src/time_zone_libc.cc | 23 +- .../cctz/src/time_zone_lookup_test.cc | 29 +- .../internal/cctz/src/zone_info_source.cc | 3 +- .../absl/time/internal/cctz/testdata/version | 2 +- .../cctz/testdata/zoneinfo/Africa/Abidjan | Bin 148 -> 130 bytes .../cctz/testdata/zoneinfo/Africa/Accra | Bin 816 -> 700 bytes .../cctz/testdata/zoneinfo/Africa/Addis_Ababa | Bin 251 -> 191 bytes .../cctz/testdata/zoneinfo/Africa/Algiers | Bin 735 -> 470 bytes .../cctz/testdata/zoneinfo/Africa/Asmara | Bin 251 -> 191 bytes .../cctz/testdata/zoneinfo/Africa/Asmera | Bin 251 -> 191 bytes .../cctz/testdata/zoneinfo/Africa/Bamako | Bin 148 -> 130 bytes .../cctz/testdata/zoneinfo/Africa/Bangui | Bin 149 -> 180 bytes .../cctz/testdata/zoneinfo/Africa/Banjul | Bin 148 -> 130 bytes .../cctz/testdata/zoneinfo/Africa/Bissau | Bin 194 -> 149 bytes .../cctz/testdata/zoneinfo/Africa/Blantyre | Bin 149 -> 131 bytes .../cctz/testdata/zoneinfo/Africa/Brazzaville | Bin 149 -> 180 bytes .../cctz/testdata/zoneinfo/Africa/Bujumbura | Bin 149 -> 131 bytes .../cctz/testdata/zoneinfo/Africa/Cairo | Bin 1955 -> 1276 bytes .../cctz/testdata/zoneinfo/Africa/Casablanca | Bin 2429 -> 1919 bytes .../cctz/testdata/zoneinfo/Africa/Ceuta | Bin 2036 -> 562 bytes .../cctz/testdata/zoneinfo/Africa/Conakry | Bin 148 -> 130 bytes .../cctz/testdata/zoneinfo/Africa/Dakar | Bin 148 -> 130 bytes .../testdata/zoneinfo/Africa/Dar_es_Salaam | Bin 251 -> 191 bytes .../cctz/testdata/zoneinfo/Africa/Djibouti | Bin 251 -> 191 bytes .../cctz/testdata/zoneinfo/Africa/Douala | Bin 149 -> 180 bytes .../cctz/testdata/zoneinfo/Africa/El_Aaiun | Bin 2295 -> 1830 bytes .../cctz/testdata/zoneinfo/Africa/Freetown | Bin 148 -> 130 bytes .../cctz/testdata/zoneinfo/Africa/Gaborone | Bin 149 -> 131 bytes .../cctz/testdata/zoneinfo/Africa/Harare | Bin 149 -> 131 bytes .../testdata/zoneinfo/Africa/Johannesburg | Bin 246 -> 190 bytes .../cctz/testdata/zoneinfo/Africa/Juba | Bin 653 -> 458 bytes .../cctz/testdata/zoneinfo/Africa/Kampala | Bin 251 -> 191 bytes .../cctz/testdata/zoneinfo/Africa/Khartoum | Bin 679 -> 458 bytes .../cctz/testdata/zoneinfo/Africa/Kigali | Bin 149 -> 131 bytes .../cctz/testdata/zoneinfo/Africa/Kinshasa | Bin 149 -> 180 bytes .../cctz/testdata/zoneinfo/Africa/Lagos | Bin 149 -> 180 bytes .../cctz/testdata/zoneinfo/Africa/Libreville | Bin 149 -> 180 bytes .../cctz/testdata/zoneinfo/Africa/Lome | Bin 148 -> 130 bytes .../cctz/testdata/zoneinfo/Africa/Luanda | Bin 149 -> 180 bytes .../cctz/testdata/zoneinfo/Africa/Lubumbashi | Bin 149 -> 131 bytes .../cctz/testdata/zoneinfo/Africa/Lusaka | Bin 149 -> 131 bytes .../cctz/testdata/zoneinfo/Africa/Malabo | Bin 149 -> 180 bytes .../cctz/testdata/zoneinfo/Africa/Maputo | Bin 149 -> 131 bytes .../cctz/testdata/zoneinfo/Africa/Maseru | Bin 246 -> 190 bytes .../cctz/testdata/zoneinfo/Africa/Mbabane | Bin 246 -> 190 bytes .../cctz/testdata/zoneinfo/Africa/Mogadishu | Bin 251 -> 191 bytes .../cctz/testdata/zoneinfo/Africa/Monrovia | Bin 208 -> 164 bytes .../cctz/testdata/zoneinfo/Africa/Nairobi | Bin 251 -> 191 bytes .../cctz/testdata/zoneinfo/Africa/Ndjamena | Bin 199 -> 160 bytes .../cctz/testdata/zoneinfo/Africa/Niamey | Bin 149 -> 180 bytes .../cctz/testdata/zoneinfo/Africa/Nouakchott | Bin 148 -> 130 bytes .../cctz/testdata/zoneinfo/Africa/Ouagadougou | Bin 148 -> 130 bytes .../cctz/testdata/zoneinfo/Africa/Porto-Novo | Bin 149 -> 180 bytes .../cctz/testdata/zoneinfo/Africa/Sao_Tome | Bin 254 -> 173 bytes .../cctz/testdata/zoneinfo/Africa/Timbuktu | Bin 148 -> 130 bytes .../cctz/testdata/zoneinfo/Africa/Tripoli | Bin 625 -> 431 bytes .../cctz/testdata/zoneinfo/Africa/Tunis | Bin 689 -> 449 bytes .../cctz/testdata/zoneinfo/Africa/Windhoek | Bin 955 -> 638 bytes .../cctz/testdata/zoneinfo/America/Adak | Bin 2356 -> 969 bytes .../cctz/testdata/zoneinfo/America/Anchorage | Bin 2371 -> 977 bytes .../cctz/testdata/zoneinfo/America/Anguilla | Bin 148 -> 130 bytes .../cctz/testdata/zoneinfo/America/Antigua | Bin 148 -> 130 bytes .../cctz/testdata/zoneinfo/America/Araguaina | Bin 884 -> 592 bytes .../zoneinfo/America/Argentina/Buenos_Aires | Bin 1076 -> 708 bytes .../zoneinfo/America/Argentina/Catamarca | Bin 1076 -> 708 bytes .../zoneinfo/America/Argentina/ComodRivadavia | Bin 1076 -> 708 bytes .../zoneinfo/America/Argentina/Cordoba | Bin 1076 -> 708 bytes .../testdata/zoneinfo/America/Argentina/Jujuy | Bin 1048 -> 690 bytes .../zoneinfo/America/Argentina/La_Rioja | Bin 1090 -> 717 bytes .../zoneinfo/America/Argentina/Mendoza | Bin 1076 -> 708 bytes .../zoneinfo/America/Argentina/Rio_Gallegos | Bin 1076 -> 708 bytes .../testdata/zoneinfo/America/Argentina/Salta | Bin 1048 -> 690 bytes .../zoneinfo/America/Argentina/San_Juan | Bin 1090 -> 717 bytes .../zoneinfo/America/Argentina/San_Luis | Bin 1102 -> 717 bytes .../zoneinfo/America/Argentina/Tucuman | Bin 1104 -> 726 bytes .../zoneinfo/America/Argentina/Ushuaia | Bin 1076 -> 708 bytes .../cctz/testdata/zoneinfo/America/Aruba | Bin 186 -> 151 bytes .../cctz/testdata/zoneinfo/America/Asuncion | Bin 2044 -> 884 bytes .../cctz/testdata/zoneinfo/America/Atikokan | Bin 336 -> 224 bytes .../cctz/testdata/zoneinfo/America/Atka | Bin 2356 -> 969 bytes .../cctz/testdata/zoneinfo/America/Bahia | Bin 1024 -> 682 bytes .../testdata/zoneinfo/America/Bahia_Banderas | Bin 1546 -> 530 bytes .../cctz/testdata/zoneinfo/America/Barbados | Bin 314 -> 231 bytes .../cctz/testdata/zoneinfo/America/Belem | Bin 576 -> 394 bytes .../cctz/testdata/zoneinfo/America/Belize | Bin 948 -> 1045 bytes .../testdata/zoneinfo/America/Blanc-Sablon | Bin 298 -> 205 bytes .../cctz/testdata/zoneinfo/America/Boa_Vista | Bin 632 -> 430 bytes .../cctz/testdata/zoneinfo/America/Bogota | Bin 246 -> 179 bytes .../cctz/testdata/zoneinfo/America/Boise | Bin 2394 -> 999 bytes .../testdata/zoneinfo/America/Buenos_Aires | Bin 1076 -> 708 bytes .../testdata/zoneinfo/America/Cambridge_Bay | Bin 2084 -> 768 bytes .../testdata/zoneinfo/America/Campo_Grande | Bin 1444 -> 952 bytes .../cctz/testdata/zoneinfo/America/Cancun | Bin 782 -> 529 bytes .../cctz/testdata/zoneinfo/America/Caracas | Bin 264 -> 190 bytes .../cctz/testdata/zoneinfo/America/Catamarca | Bin 1076 -> 708 bytes .../cctz/testdata/zoneinfo/America/Cayenne | Bin 198 -> 151 bytes .../cctz/testdata/zoneinfo/America/Cayman | Bin 182 -> 149 bytes .../cctz/testdata/zoneinfo/America/Chicago | Bin 3576 -> 1754 bytes .../cctz/testdata/zoneinfo/America/Chihuahua | Bin 1484 -> 340 bytes .../testdata/zoneinfo/America/Coral_Harbour | Bin 336 -> 224 bytes .../cctz/testdata/zoneinfo/America/Cordoba | Bin 1076 -> 708 bytes .../cctz/testdata/zoneinfo/America/Costa_Rica | Bin 316 -> 232 bytes .../cctz/testdata/zoneinfo/America/Creston | Bin 208 -> 158 bytes .../cctz/testdata/zoneinfo/America/Cuiaba | Bin 1416 -> 934 bytes .../cctz/testdata/zoneinfo/America/Curacao | Bin 186 -> 151 bytes .../testdata/zoneinfo/America/Danmarkshavn | Bin 698 -> 447 bytes .../cctz/testdata/zoneinfo/America/Dawson | Bin 2084 -> 1029 bytes .../testdata/zoneinfo/America/Dawson_Creek | Bin 1050 -> 683 bytes .../cctz/testdata/zoneinfo/America/Denver | Bin 2444 -> 1042 bytes .../cctz/testdata/zoneinfo/America/Detroit | Bin 2230 -> 899 bytes .../cctz/testdata/zoneinfo/America/Dominica | Bin 148 -> 130 bytes .../cctz/testdata/zoneinfo/America/Edmonton | Bin 2332 -> 970 bytes .../cctz/testdata/zoneinfo/America/Eirunepe | Bin 656 -> 436 bytes .../testdata/zoneinfo/America/El_Salvador | Bin 224 -> 176 bytes .../cctz/testdata/zoneinfo/America/Ensenada | Bin 2342 -> 1025 bytes .../testdata/zoneinfo/America/Fort_Nelson | Bin 2240 -> 1448 bytes .../cctz/testdata/zoneinfo/America/Fort_Wayne | Bin 1666 -> 531 bytes .../cctz/testdata/zoneinfo/America/Fortaleza | Bin 716 -> 484 bytes .../cctz/testdata/zoneinfo/America/Glace_Bay | Bin 2192 -> 880 bytes .../cctz/testdata/zoneinfo/America/Godthab | Bin 1878 -> 465 bytes .../cctz/testdata/zoneinfo/America/Goose_Bay | Bin 3210 -> 1580 bytes .../cctz/testdata/zoneinfo/America/Grand_Turk | Bin 1848 -> 853 bytes .../cctz/testdata/zoneinfo/America/Grenada | Bin 148 -> 130 bytes .../cctz/testdata/zoneinfo/America/Guadeloupe | Bin 148 -> 130 bytes .../cctz/testdata/zoneinfo/America/Guatemala | Bin 280 -> 212 bytes .../cctz/testdata/zoneinfo/America/Guayaquil | Bin 246 -> 179 bytes .../cctz/testdata/zoneinfo/America/Guyana | Bin 236 -> 172 bytes .../cctz/testdata/zoneinfo/America/Halifax | Bin 3424 -> 1672 bytes .../cctz/testdata/zoneinfo/America/Havana | Bin 2416 -> 1117 bytes .../cctz/testdata/zoneinfo/America/Hermosillo | Bin 416 -> 286 bytes .../zoneinfo/America/Indiana/Indianapolis | Bin 1666 -> 531 bytes .../testdata/zoneinfo/America/Indiana/Knox | Bin 2428 -> 1016 bytes .../testdata/zoneinfo/America/Indiana/Marengo | Bin 1722 -> 567 bytes .../zoneinfo/America/Indiana/Petersburg | Bin 1904 -> 683 bytes .../zoneinfo/America/Indiana/Tell_City | Bin 1684 -> 522 bytes .../testdata/zoneinfo/America/Indiana/Vevay | Bin 1414 -> 369 bytes .../zoneinfo/America/Indiana/Vincennes | Bin 1694 -> 558 bytes .../testdata/zoneinfo/America/Indiana/Winamac | Bin 1778 -> 612 bytes .../testdata/zoneinfo/America/Indianapolis | Bin 1666 -> 531 bytes .../cctz/testdata/zoneinfo/America/Inuvik | Bin 1894 -> 701 bytes .../cctz/testdata/zoneinfo/America/Iqaluit | Bin 2032 -> 740 bytes .../cctz/testdata/zoneinfo/America/Jamaica | Bin 482 -> 339 bytes .../cctz/testdata/zoneinfo/America/Jujuy | Bin 1048 -> 690 bytes .../cctz/testdata/zoneinfo/America/Juneau | Bin 2353 -> 966 bytes .../zoneinfo/America/Kentucky/Louisville | Bin 2772 -> 1242 bytes .../zoneinfo/America/Kentucky/Monticello | Bin 2352 -> 972 bytes .../cctz/testdata/zoneinfo/America/Knox_IN | Bin 2428 -> 1016 bytes .../cctz/testdata/zoneinfo/America/Kralendijk | Bin 186 -> 151 bytes .../cctz/testdata/zoneinfo/America/La_Paz | Bin 232 -> 170 bytes .../cctz/testdata/zoneinfo/America/Lima | Bin 406 -> 283 bytes .../testdata/zoneinfo/America/Los_Angeles | Bin 2836 -> 1294 bytes .../cctz/testdata/zoneinfo/America/Louisville | Bin 2772 -> 1242 bytes .../testdata/zoneinfo/America/Lower_Princes | Bin 186 -> 151 bytes .../cctz/testdata/zoneinfo/America/Maceio | Bin 744 -> 502 bytes .../cctz/testdata/zoneinfo/America/Managua | Bin 430 -> 295 bytes .../cctz/testdata/zoneinfo/America/Manaus | Bin 604 -> 412 bytes .../cctz/testdata/zoneinfo/America/Marigot | Bin 148 -> 130 bytes .../cctz/testdata/zoneinfo/America/Martinique | Bin 232 -> 178 bytes .../cctz/testdata/zoneinfo/America/Matamoros | Bin 1390 -> 437 bytes .../cctz/testdata/zoneinfo/America/Mazatlan | Bin 1526 -> 367 bytes .../cctz/testdata/zoneinfo/America/Mendoza | Bin 1076 -> 708 bytes .../cctz/testdata/zoneinfo/America/Menominee | Bin 2274 -> 917 bytes .../cctz/testdata/zoneinfo/America/Merida | Bin 1422 -> 303 bytes .../cctz/testdata/zoneinfo/America/Metlakatla | Bin 1423 -> 595 bytes .../testdata/zoneinfo/America/Mexico_City | Bin 1584 -> 412 bytes .../cctz/testdata/zoneinfo/America/Miquelon | Bin 1666 -> 550 bytes .../cctz/testdata/zoneinfo/America/Moncton | Bin 3154 -> 1493 bytes .../cctz/testdata/zoneinfo/America/Monterrey | Bin 1390 -> 293 bytes .../cctz/testdata/zoneinfo/America/Montevideo | Bin 1510 -> 969 bytes .../cctz/testdata/zoneinfo/America/Montreal | Bin 3494 -> 1717 bytes .../cctz/testdata/zoneinfo/America/Montserrat | Bin 148 -> 130 bytes .../cctz/testdata/zoneinfo/America/Nassau | Bin 2258 -> 1006 bytes .../cctz/testdata/zoneinfo/America/New_York | Bin 3536 -> 1744 bytes .../cctz/testdata/zoneinfo/America/Nipigon | Bin 2122 -> 835 bytes .../cctz/testdata/zoneinfo/America/Nome | Bin 2367 -> 975 bytes .../cctz/testdata/zoneinfo/America/Noronha | Bin 716 -> 484 bytes .../zoneinfo/America/North_Dakota/Beulah | Bin 2380 -> 1043 bytes .../zoneinfo/America/North_Dakota/Center | Bin 2380 -> 990 bytes .../zoneinfo/America/North_Dakota/New_Salem | Bin 2380 -> 990 bytes .../cctz/testdata/zoneinfo/America/Nuuk | Bin 0 -> 465 bytes .../cctz/testdata/zoneinfo/America/Ojinaga | Bin 1484 -> 484 bytes .../cctz/testdata/zoneinfo/America/Panama | Bin 182 -> 149 bytes .../testdata/zoneinfo/America/Pangnirtung | Bin 2094 -> 769 bytes .../cctz/testdata/zoneinfo/America/Paramaribo | Bin 262 -> 187 bytes .../cctz/testdata/zoneinfo/America/Phoenix | Bin 328 -> 240 bytes .../testdata/zoneinfo/America/Port-au-Prince | Bin 1434 -> 565 bytes .../testdata/zoneinfo/America/Port_of_Spain | Bin 148 -> 130 bytes .../cctz/testdata/zoneinfo/America/Porto_Acre | Bin 628 -> 418 bytes .../testdata/zoneinfo/America/Porto_Velho | Bin 576 -> 394 bytes .../testdata/zoneinfo/America/Puerto_Rico | Bin 246 -> 177 bytes .../testdata/zoneinfo/America/Punta_Arenas | Bin 1902 -> 1209 bytes .../testdata/zoneinfo/America/Rainy_River | Bin 2122 -> 835 bytes .../testdata/zoneinfo/America/Rankin_Inlet | Bin 1892 -> 692 bytes .../cctz/testdata/zoneinfo/America/Recife | Bin 716 -> 484 bytes .../cctz/testdata/zoneinfo/America/Regina | Bin 980 -> 638 bytes .../cctz/testdata/zoneinfo/America/Resolute | Bin 1892 -> 692 bytes .../cctz/testdata/zoneinfo/America/Rio_Branco | Bin 628 -> 418 bytes .../cctz/testdata/zoneinfo/America/Rosario | Bin 1076 -> 708 bytes .../testdata/zoneinfo/America/Santa_Isabel | Bin 2342 -> 1025 bytes .../cctz/testdata/zoneinfo/America/Santarem | Bin 602 -> 409 bytes .../cctz/testdata/zoneinfo/America/Santiago | Bin 2529 -> 1282 bytes .../testdata/zoneinfo/America/Santo_Domingo | Bin 458 -> 317 bytes .../cctz/testdata/zoneinfo/America/Sao_Paulo | Bin 1444 -> 952 bytes .../testdata/zoneinfo/America/Scoresbysund | Bin 1916 -> 479 bytes .../cctz/testdata/zoneinfo/America/Shiprock | Bin 2444 -> 1042 bytes .../cctz/testdata/zoneinfo/America/Sitka | Bin 2329 -> 956 bytes .../testdata/zoneinfo/America/St_Barthelemy | Bin 148 -> 130 bytes .../cctz/testdata/zoneinfo/America/St_Johns | Bin 3655 -> 1878 bytes .../cctz/testdata/zoneinfo/America/St_Kitts | Bin 148 -> 130 bytes .../cctz/testdata/zoneinfo/America/St_Lucia | Bin 148 -> 130 bytes .../cctz/testdata/zoneinfo/America/St_Thomas | Bin 148 -> 130 bytes .../cctz/testdata/zoneinfo/America/St_Vincent | Bin 148 -> 130 bytes .../testdata/zoneinfo/America/Swift_Current | Bin 560 -> 368 bytes .../testdata/zoneinfo/America/Tegucigalpa | Bin 252 -> 194 bytes .../cctz/testdata/zoneinfo/America/Thule | Bin 1502 -> 455 bytes .../testdata/zoneinfo/America/Thunder_Bay | Bin 2202 -> 881 bytes .../cctz/testdata/zoneinfo/America/Tijuana | Bin 2342 -> 1025 bytes .../cctz/testdata/zoneinfo/America/Toronto | Bin 3494 -> 1717 bytes .../cctz/testdata/zoneinfo/America/Tortola | Bin 148 -> 130 bytes .../cctz/testdata/zoneinfo/America/Vancouver | Bin 2892 -> 1330 bytes .../cctz/testdata/zoneinfo/America/Virgin | Bin 148 -> 130 bytes .../cctz/testdata/zoneinfo/America/Whitehorse | Bin 2084 -> 1029 bytes .../cctz/testdata/zoneinfo/America/Winnipeg | Bin 2868 -> 1294 bytes .../cctz/testdata/zoneinfo/America/Yakutat | Bin 2305 -> 946 bytes .../testdata/zoneinfo/America/Yellowknife | Bin 1966 -> 729 bytes .../cctz/testdata/zoneinfo/Antarctica/Casey | Bin 297 -> 243 bytes .../cctz/testdata/zoneinfo/Antarctica/Davis | Bin 297 -> 197 bytes .../zoneinfo/Antarctica/DumontDUrville | Bin 194 -> 152 bytes .../testdata/zoneinfo/Antarctica/Macquarie | Bin 1520 -> 976 bytes .../cctz/testdata/zoneinfo/Antarctica/Mawson | Bin 199 -> 152 bytes .../cctz/testdata/zoneinfo/Antarctica/McMurdo | Bin 2437 -> 1043 bytes .../cctz/testdata/zoneinfo/Antarctica/Palmer | Bin 1418 -> 887 bytes .../cctz/testdata/zoneinfo/Antarctica/Rothera | Bin 164 -> 132 bytes .../testdata/zoneinfo/Antarctica/South_Pole | Bin 2437 -> 1043 bytes .../cctz/testdata/zoneinfo/Antarctica/Syowa | Bin 165 -> 133 bytes .../cctz/testdata/zoneinfo/Antarctica/Troll | Bin 1162 -> 177 bytes .../cctz/testdata/zoneinfo/Antarctica/Vostok | Bin 165 -> 133 bytes .../testdata/zoneinfo/Arctic/Longyearbyen | Bin 2228 -> 676 bytes .../internal/cctz/testdata/zoneinfo/Asia/Aden | Bin 165 -> 133 bytes .../cctz/testdata/zoneinfo/Asia/Almaty | Bin 997 -> 609 bytes .../cctz/testdata/zoneinfo/Asia/Amman | Bin 1853 -> 787 bytes .../cctz/testdata/zoneinfo/Asia/Anadyr | Bin 1188 -> 743 bytes .../cctz/testdata/zoneinfo/Asia/Aqtau | Bin 983 -> 606 bytes .../cctz/testdata/zoneinfo/Asia/Aqtobe | Bin 1011 -> 615 bytes .../cctz/testdata/zoneinfo/Asia/Ashgabat | Bin 619 -> 375 bytes .../cctz/testdata/zoneinfo/Asia/Ashkhabad | Bin 619 -> 375 bytes .../cctz/testdata/zoneinfo/Asia/Atyrau | Bin 991 -> 616 bytes .../cctz/testdata/zoneinfo/Asia/Baghdad | Bin 983 -> 630 bytes .../cctz/testdata/zoneinfo/Asia/Bahrain | Bin 199 -> 152 bytes .../internal/cctz/testdata/zoneinfo/Asia/Baku | Bin 1227 -> 744 bytes .../cctz/testdata/zoneinfo/Asia/Bangkok | Bin 199 -> 152 bytes .../cctz/testdata/zoneinfo/Asia/Barnaul | Bin 1221 -> 753 bytes .../cctz/testdata/zoneinfo/Asia/Beirut | Bin 2154 -> 732 bytes .../cctz/testdata/zoneinfo/Asia/Bishkek | Bin 983 -> 618 bytes .../cctz/testdata/zoneinfo/Asia/Brunei | Bin 203 -> 154 bytes .../cctz/testdata/zoneinfo/Asia/Calcutta | Bin 285 -> 220 bytes .../cctz/testdata/zoneinfo/Asia/Chita | Bin 1221 -> 750 bytes .../cctz/testdata/zoneinfo/Asia/Choibalsan | Bin 949 -> 619 bytes .../cctz/testdata/zoneinfo/Asia/Chongqing | Bin 533 -> 393 bytes .../cctz/testdata/zoneinfo/Asia/Chungking | Bin 533 -> 393 bytes .../cctz/testdata/zoneinfo/Asia/Colombo | Bin 372 -> 247 bytes .../cctz/testdata/zoneinfo/Asia/Dacca | Bin 337 -> 231 bytes .../cctz/testdata/zoneinfo/Asia/Damascus | Bin 2294 -> 1047 bytes .../cctz/testdata/zoneinfo/Asia/Dhaka | Bin 337 -> 231 bytes .../internal/cctz/testdata/zoneinfo/Asia/Dili | Bin 227 -> 170 bytes .../cctz/testdata/zoneinfo/Asia/Dubai | Bin 165 -> 133 bytes .../cctz/testdata/zoneinfo/Asia/Dushanbe | Bin 591 -> 366 bytes .../cctz/testdata/zoneinfo/Asia/Famagusta | Bin 2028 -> 940 bytes .../internal/cctz/testdata/zoneinfo/Asia/Gaza | Bin 2316 -> 1213 bytes .../cctz/testdata/zoneinfo/Asia/Harbin | Bin 533 -> 393 bytes .../cctz/testdata/zoneinfo/Asia/Hebron | Bin 2344 -> 1231 bytes .../cctz/testdata/zoneinfo/Asia/Ho_Chi_Minh | Bin 351 -> 236 bytes .../cctz/testdata/zoneinfo/Asia/Hong_Kong | Bin 1203 -> 775 bytes .../internal/cctz/testdata/zoneinfo/Asia/Hovd | Bin 891 -> 594 bytes .../cctz/testdata/zoneinfo/Asia/Irkutsk | Bin 1243 -> 760 bytes .../cctz/testdata/zoneinfo/Asia/Istanbul | Bin 1947 -> 1200 bytes .../cctz/testdata/zoneinfo/Asia/Jakarta | Bin 355 -> 248 bytes .../cctz/testdata/zoneinfo/Asia/Jayapura | Bin 221 -> 171 bytes .../cctz/testdata/zoneinfo/Asia/Jerusalem | Bin 2288 -> 1074 bytes .../cctz/testdata/zoneinfo/Asia/Kabul | Bin 208 -> 159 bytes .../cctz/testdata/zoneinfo/Asia/Kamchatka | Bin 1166 -> 727 bytes .../cctz/testdata/zoneinfo/Asia/Karachi | Bin 379 -> 266 bytes .../cctz/testdata/zoneinfo/Asia/Kashgar | Bin 165 -> 133 bytes .../cctz/testdata/zoneinfo/Asia/Kathmandu | Bin 212 -> 161 bytes .../cctz/testdata/zoneinfo/Asia/Katmandu | Bin 212 -> 161 bytes .../cctz/testdata/zoneinfo/Asia/Khandyga | Bin 1271 -> 775 bytes .../cctz/testdata/zoneinfo/Asia/Kolkata | Bin 285 -> 220 bytes .../cctz/testdata/zoneinfo/Asia/Krasnoyarsk | Bin 1207 -> 741 bytes .../cctz/testdata/zoneinfo/Asia/Kuala_Lumpur | Bin 383 -> 256 bytes .../cctz/testdata/zoneinfo/Asia/Kuching | Bin 483 -> 320 bytes .../cctz/testdata/zoneinfo/Asia/Kuwait | Bin 165 -> 133 bytes .../cctz/testdata/zoneinfo/Asia/Macao | Bin 1227 -> 791 bytes .../cctz/testdata/zoneinfo/Asia/Macau | Bin 1227 -> 791 bytes .../cctz/testdata/zoneinfo/Asia/Magadan | Bin 1222 -> 751 bytes .../cctz/testdata/zoneinfo/Asia/Makassar | Bin 254 -> 190 bytes .../cctz/testdata/zoneinfo/Asia/Manila | Bin 328 -> 238 bytes .../cctz/testdata/zoneinfo/Asia/Muscat | Bin 165 -> 133 bytes .../cctz/testdata/zoneinfo/Asia/Nicosia | Bin 2002 -> 597 bytes .../cctz/testdata/zoneinfo/Asia/Novokuznetsk | Bin 1165 -> 726 bytes .../cctz/testdata/zoneinfo/Asia/Novosibirsk | Bin 1221 -> 753 bytes .../internal/cctz/testdata/zoneinfo/Asia/Omsk | Bin 1207 -> 741 bytes .../internal/cctz/testdata/zoneinfo/Asia/Oral | Bin 1005 -> 625 bytes .../cctz/testdata/zoneinfo/Asia/Phnom_Penh | Bin 199 -> 152 bytes .../cctz/testdata/zoneinfo/Asia/Pontianak | Bin 353 -> 247 bytes .../cctz/testdata/zoneinfo/Asia/Pyongyang | Bin 237 -> 183 bytes .../cctz/testdata/zoneinfo/Asia/Qatar | Bin 199 -> 152 bytes .../cctz/testdata/zoneinfo/Asia/Qostanay | Bin 1011 -> 615 bytes .../cctz/testdata/zoneinfo/Asia/Qyzylorda | Bin 1025 -> 624 bytes .../cctz/testdata/zoneinfo/Asia/Rangoon | Bin 268 -> 187 bytes .../cctz/testdata/zoneinfo/Asia/Riyadh | Bin 165 -> 133 bytes .../cctz/testdata/zoneinfo/Asia/Saigon | Bin 351 -> 236 bytes .../cctz/testdata/zoneinfo/Asia/Sakhalin | Bin 1202 -> 755 bytes .../cctz/testdata/zoneinfo/Asia/Samarkand | Bin 577 -> 366 bytes .../cctz/testdata/zoneinfo/Asia/Seoul | Bin 617 -> 415 bytes .../cctz/testdata/zoneinfo/Asia/Shanghai | Bin 533 -> 393 bytes .../cctz/testdata/zoneinfo/Asia/Singapore | Bin 383 -> 256 bytes .../cctz/testdata/zoneinfo/Asia/Srednekolymsk | Bin 1208 -> 742 bytes .../cctz/testdata/zoneinfo/Asia/Taipei | Bin 761 -> 511 bytes .../cctz/testdata/zoneinfo/Asia/Tashkent | Bin 591 -> 366 bytes .../cctz/testdata/zoneinfo/Asia/Tbilisi | Bin 1035 -> 629 bytes .../cctz/testdata/zoneinfo/Asia/Tehran | Bin 2582 -> 2004 bytes .../cctz/testdata/zoneinfo/Asia/Tel_Aviv | Bin 2288 -> 1074 bytes .../cctz/testdata/zoneinfo/Asia/Thimbu | Bin 203 -> 154 bytes .../cctz/testdata/zoneinfo/Asia/Thimphu | Bin 203 -> 154 bytes .../cctz/testdata/zoneinfo/Asia/Tokyo | Bin 309 -> 213 bytes .../cctz/testdata/zoneinfo/Asia/Tomsk | Bin 1221 -> 753 bytes .../cctz/testdata/zoneinfo/Asia/Ujung_Pandang | Bin 254 -> 190 bytes .../cctz/testdata/zoneinfo/Asia/Ulaanbaatar | Bin 891 -> 594 bytes .../cctz/testdata/zoneinfo/Asia/Ulan_Bator | Bin 891 -> 594 bytes .../cctz/testdata/zoneinfo/Asia/Urumqi | Bin 165 -> 133 bytes .../cctz/testdata/zoneinfo/Asia/Ust-Nera | Bin 1252 -> 771 bytes .../cctz/testdata/zoneinfo/Asia/Vientiane | Bin 199 -> 152 bytes .../cctz/testdata/zoneinfo/Asia/Vladivostok | Bin 1208 -> 742 bytes .../cctz/testdata/zoneinfo/Asia/Yakutsk | Bin 1207 -> 741 bytes .../cctz/testdata/zoneinfo/Asia/Yangon | Bin 268 -> 187 bytes .../cctz/testdata/zoneinfo/Asia/Yekaterinburg | Bin 1243 -> 760 bytes .../cctz/testdata/zoneinfo/Asia/Yerevan | Bin 1151 -> 708 bytes .../cctz/testdata/zoneinfo/Atlantic/Azores | Bin 3484 -> 1435 bytes .../cctz/testdata/zoneinfo/Atlantic/Bermuda | Bin 1978 -> 1024 bytes .../cctz/testdata/zoneinfo/Atlantic/Canary | Bin 1897 -> 478 bytes .../testdata/zoneinfo/Atlantic/Cape_Verde | Bin 270 -> 175 bytes .../cctz/testdata/zoneinfo/Atlantic/Faeroe | Bin 1815 -> 441 bytes .../cctz/testdata/zoneinfo/Atlantic/Faroe | Bin 1815 -> 441 bytes .../cctz/testdata/zoneinfo/Atlantic/Jan_Mayen | Bin 2228 -> 676 bytes .../cctz/testdata/zoneinfo/Atlantic/Madeira | Bin 3475 -> 1435 bytes .../cctz/testdata/zoneinfo/Atlantic/Reykjavik | Bin 1162 -> 753 bytes .../testdata/zoneinfo/Atlantic/South_Georgia | Bin 164 -> 132 bytes .../cctz/testdata/zoneinfo/Atlantic/St_Helena | Bin 148 -> 130 bytes .../cctz/testdata/zoneinfo/Atlantic/Stanley | Bin 1214 -> 789 bytes .../cctz/testdata/zoneinfo/Australia/ACT | Bin 2204 -> 904 bytes .../cctz/testdata/zoneinfo/Australia/Adelaide | Bin 2222 -> 921 bytes .../cctz/testdata/zoneinfo/Australia/Brisbane | Bin 433 -> 289 bytes .../testdata/zoneinfo/Australia/Broken_Hill | Bin 2243 -> 941 bytes .../cctz/testdata/zoneinfo/Australia/Canberra | Bin 2204 -> 904 bytes .../cctz/testdata/zoneinfo/Australia/Currie | Bin 2204 -> 1003 bytes .../cctz/testdata/zoneinfo/Australia/Darwin | Bin 304 -> 234 bytes .../cctz/testdata/zoneinfo/Australia/Eucla | Bin 484 -> 314 bytes .../cctz/testdata/zoneinfo/Australia/Hobart | Bin 2316 -> 1003 bytes .../cctz/testdata/zoneinfo/Australia/LHI | Bin 1860 -> 692 bytes .../cctz/testdata/zoneinfo/Australia/Lindeman | Bin 489 -> 325 bytes .../testdata/zoneinfo/Australia/Lord_Howe | Bin 1860 -> 692 bytes .../testdata/zoneinfo/Australia/Melbourne | Bin 2204 -> 904 bytes .../cctz/testdata/zoneinfo/Australia/NSW | Bin 2204 -> 904 bytes .../cctz/testdata/zoneinfo/Australia/North | Bin 304 -> 234 bytes .../cctz/testdata/zoneinfo/Australia/Perth | Bin 460 -> 306 bytes .../testdata/zoneinfo/Australia/Queensland | Bin 433 -> 289 bytes .../cctz/testdata/zoneinfo/Australia/South | Bin 2222 -> 921 bytes .../cctz/testdata/zoneinfo/Australia/Sydney | Bin 2204 -> 904 bytes .../cctz/testdata/zoneinfo/Australia/Tasmania | Bin 2316 -> 1003 bytes .../cctz/testdata/zoneinfo/Australia/Victoria | Bin 2204 -> 904 bytes .../cctz/testdata/zoneinfo/Australia/West | Bin 460 -> 306 bytes .../testdata/zoneinfo/Australia/Yancowinna | Bin 2243 -> 941 bytes .../cctz/testdata/zoneinfo/Brazil/Acre | Bin 628 -> 418 bytes .../cctz/testdata/zoneinfo/Brazil/DeNoronha | Bin 716 -> 484 bytes .../cctz/testdata/zoneinfo/Brazil/East | Bin 1444 -> 952 bytes .../cctz/testdata/zoneinfo/Brazil/West | Bin 604 -> 412 bytes .../time/internal/cctz/testdata/zoneinfo/CET | Bin 2094 -> 621 bytes .../internal/cctz/testdata/zoneinfo/CST6CDT | Bin 2310 -> 951 bytes .../cctz/testdata/zoneinfo/Canada/Atlantic | Bin 3424 -> 1672 bytes .../cctz/testdata/zoneinfo/Canada/Central | Bin 2868 -> 1294 bytes .../cctz/testdata/zoneinfo/Canada/Eastern | Bin 3494 -> 1717 bytes .../cctz/testdata/zoneinfo/Canada/Mountain | Bin 2332 -> 970 bytes .../testdata/zoneinfo/Canada/Newfoundland | Bin 3655 -> 1878 bytes .../cctz/testdata/zoneinfo/Canada/Pacific | Bin 2892 -> 1330 bytes .../testdata/zoneinfo/Canada/Saskatchewan | Bin 980 -> 638 bytes .../cctz/testdata/zoneinfo/Canada/Yukon | Bin 2084 -> 1029 bytes .../cctz/testdata/zoneinfo/Chile/Continental | Bin 2529 -> 1282 bytes .../cctz/testdata/zoneinfo/Chile/EasterIsland | Bin 2233 -> 1102 bytes .../time/internal/cctz/testdata/zoneinfo/Cuba | Bin 2416 -> 1117 bytes .../time/internal/cctz/testdata/zoneinfo/EET | Bin 1908 -> 497 bytes .../time/internal/cctz/testdata/zoneinfo/EST | Bin 114 -> 111 bytes .../internal/cctz/testdata/zoneinfo/EST5EDT | Bin 2310 -> 951 bytes .../internal/cctz/testdata/zoneinfo/Egypt | Bin 1955 -> 1276 bytes .../time/internal/cctz/testdata/zoneinfo/Eire | Bin 3492 -> 1496 bytes .../internal/cctz/testdata/zoneinfo/Etc/GMT | Bin 114 -> 111 bytes .../internal/cctz/testdata/zoneinfo/Etc/GMT+0 | Bin 114 -> 111 bytes .../internal/cctz/testdata/zoneinfo/Etc/GMT+1 | Bin 116 -> 113 bytes .../cctz/testdata/zoneinfo/Etc/GMT+10 | Bin 117 -> 114 bytes .../cctz/testdata/zoneinfo/Etc/GMT+11 | Bin 117 -> 114 bytes .../cctz/testdata/zoneinfo/Etc/GMT+12 | Bin 117 -> 114 bytes .../internal/cctz/testdata/zoneinfo/Etc/GMT+2 | Bin 116 -> 113 bytes .../internal/cctz/testdata/zoneinfo/Etc/GMT+3 | Bin 116 -> 113 bytes .../internal/cctz/testdata/zoneinfo/Etc/GMT+4 | Bin 116 -> 113 bytes .../internal/cctz/testdata/zoneinfo/Etc/GMT+5 | Bin 116 -> 113 bytes .../internal/cctz/testdata/zoneinfo/Etc/GMT+6 | Bin 116 -> 113 bytes .../internal/cctz/testdata/zoneinfo/Etc/GMT+7 | Bin 116 -> 113 bytes .../internal/cctz/testdata/zoneinfo/Etc/GMT+8 | Bin 116 -> 113 bytes .../internal/cctz/testdata/zoneinfo/Etc/GMT+9 | Bin 116 -> 113 bytes .../internal/cctz/testdata/zoneinfo/Etc/GMT-0 | Bin 114 -> 111 bytes .../internal/cctz/testdata/zoneinfo/Etc/GMT-1 | Bin 117 -> 114 bytes .../cctz/testdata/zoneinfo/Etc/GMT-10 | Bin 118 -> 115 bytes .../cctz/testdata/zoneinfo/Etc/GMT-11 | Bin 118 -> 115 bytes .../cctz/testdata/zoneinfo/Etc/GMT-12 | Bin 118 -> 115 bytes .../cctz/testdata/zoneinfo/Etc/GMT-13 | Bin 118 -> 115 bytes .../cctz/testdata/zoneinfo/Etc/GMT-14 | Bin 118 -> 115 bytes .../internal/cctz/testdata/zoneinfo/Etc/GMT-2 | Bin 117 -> 114 bytes .../internal/cctz/testdata/zoneinfo/Etc/GMT-3 | Bin 117 -> 114 bytes .../internal/cctz/testdata/zoneinfo/Etc/GMT-4 | Bin 117 -> 114 bytes .../internal/cctz/testdata/zoneinfo/Etc/GMT-5 | Bin 117 -> 114 bytes .../internal/cctz/testdata/zoneinfo/Etc/GMT-6 | Bin 117 -> 114 bytes .../internal/cctz/testdata/zoneinfo/Etc/GMT-7 | Bin 117 -> 114 bytes .../internal/cctz/testdata/zoneinfo/Etc/GMT-8 | Bin 117 -> 114 bytes .../internal/cctz/testdata/zoneinfo/Etc/GMT-9 | Bin 117 -> 114 bytes .../internal/cctz/testdata/zoneinfo/Etc/GMT0 | Bin 114 -> 111 bytes .../cctz/testdata/zoneinfo/Etc/Greenwich | Bin 114 -> 111 bytes .../internal/cctz/testdata/zoneinfo/Etc/UCT | Bin 114 -> 111 bytes .../internal/cctz/testdata/zoneinfo/Etc/UTC | Bin 114 -> 111 bytes .../cctz/testdata/zoneinfo/Etc/Universal | Bin 114 -> 111 bytes .../internal/cctz/testdata/zoneinfo/Etc/Zulu | Bin 114 -> 111 bytes .../cctz/testdata/zoneinfo/Europe/Amsterdam | Bin 2910 -> 1071 bytes .../cctz/testdata/zoneinfo/Europe/Andorra | Bin 1742 -> 389 bytes .../cctz/testdata/zoneinfo/Europe/Astrakhan | Bin 1165 -> 726 bytes .../cctz/testdata/zoneinfo/Europe/Athens | Bin 2262 -> 682 bytes .../cctz/testdata/zoneinfo/Europe/Belfast | Bin 3648 -> 1599 bytes .../cctz/testdata/zoneinfo/Europe/Belgrade | Bin 1920 -> 478 bytes .../cctz/testdata/zoneinfo/Europe/Berlin | Bin 2298 -> 705 bytes .../cctz/testdata/zoneinfo/Europe/Bratislava | Bin 2301 -> 723 bytes .../cctz/testdata/zoneinfo/Europe/Brussels | Bin 2933 -> 1103 bytes .../cctz/testdata/zoneinfo/Europe/Bucharest | Bin 2184 -> 661 bytes .../cctz/testdata/zoneinfo/Europe/Budapest | Bin 2368 -> 766 bytes .../cctz/testdata/zoneinfo/Europe/Busingen | Bin 1909 -> 497 bytes .../cctz/testdata/zoneinfo/Europe/Chisinau | Bin 2390 -> 755 bytes .../cctz/testdata/zoneinfo/Europe/Copenhagen | Bin 2137 -> 623 bytes .../cctz/testdata/zoneinfo/Europe/Dublin | Bin 3492 -> 1496 bytes .../cctz/testdata/zoneinfo/Europe/Gibraltar | Bin 3052 -> 1220 bytes .../cctz/testdata/zoneinfo/Europe/Guernsey | Bin 3648 -> 1599 bytes .../cctz/testdata/zoneinfo/Europe/Helsinki | Bin 1900 -> 481 bytes .../cctz/testdata/zoneinfo/Europe/Isle_of_Man | Bin 3648 -> 1599 bytes .../cctz/testdata/zoneinfo/Europe/Istanbul | Bin 1947 -> 1200 bytes .../cctz/testdata/zoneinfo/Europe/Jersey | Bin 3648 -> 1599 bytes .../cctz/testdata/zoneinfo/Europe/Kaliningrad | Bin 1493 -> 904 bytes .../cctz/testdata/zoneinfo/Europe/Kiev | Bin 2088 -> 549 bytes .../cctz/testdata/zoneinfo/Europe/Kirov | Bin 1153 -> 717 bytes .../cctz/testdata/zoneinfo/Europe/Lisbon | Bin 3469 -> 1436 bytes .../cctz/testdata/zoneinfo/Europe/Ljubljana | Bin 1920 -> 478 bytes .../cctz/testdata/zoneinfo/Europe/London | Bin 3648 -> 1599 bytes .../cctz/testdata/zoneinfo/Europe/Luxembourg | Bin 2946 -> 1087 bytes .../cctz/testdata/zoneinfo/Europe/Madrid | Bin 2614 -> 897 bytes .../cctz/testdata/zoneinfo/Europe/Malta | Bin 2620 -> 928 bytes .../cctz/testdata/zoneinfo/Europe/Mariehamn | Bin 1900 -> 481 bytes .../cctz/testdata/zoneinfo/Europe/Minsk | Bin 1321 -> 808 bytes .../cctz/testdata/zoneinfo/Europe/Monaco | Bin 2944 -> 1114 bytes .../cctz/testdata/zoneinfo/Europe/Moscow | Bin 1535 -> 908 bytes .../cctz/testdata/zoneinfo/Europe/Nicosia | Bin 2002 -> 597 bytes .../cctz/testdata/zoneinfo/Europe/Oslo | Bin 2228 -> 676 bytes .../cctz/testdata/zoneinfo/Europe/Paris | Bin 2962 -> 1105 bytes .../cctz/testdata/zoneinfo/Europe/Podgorica | Bin 1920 -> 478 bytes .../cctz/testdata/zoneinfo/Europe/Prague | Bin 2301 -> 723 bytes .../cctz/testdata/zoneinfo/Europe/Riga | Bin 2198 -> 694 bytes .../cctz/testdata/zoneinfo/Europe/Rome | Bin 2641 -> 947 bytes .../cctz/testdata/zoneinfo/Europe/Samara | Bin 1215 -> 732 bytes .../cctz/testdata/zoneinfo/Europe/San_Marino | Bin 2641 -> 947 bytes .../cctz/testdata/zoneinfo/Europe/Sarajevo | Bin 1920 -> 478 bytes .../cctz/testdata/zoneinfo/Europe/Saratov | Bin 1183 -> 726 bytes .../cctz/testdata/zoneinfo/Europe/Simferopol | Bin 1453 -> 865 bytes .../cctz/testdata/zoneinfo/Europe/Skopje | Bin 1920 -> 478 bytes .../cctz/testdata/zoneinfo/Europe/Sofia | Bin 2077 -> 592 bytes .../cctz/testdata/zoneinfo/Europe/Stockholm | Bin 1909 -> 497 bytes .../cctz/testdata/zoneinfo/Europe/Tallinn | Bin 2148 -> 675 bytes .../cctz/testdata/zoneinfo/Europe/Tirane | Bin 2084 -> 604 bytes .../cctz/testdata/zoneinfo/Europe/Tiraspol | Bin 2390 -> 755 bytes .../cctz/testdata/zoneinfo/Europe/Ulyanovsk | Bin 1267 -> 760 bytes .../cctz/testdata/zoneinfo/Europe/Uzhgorod | Bin 2050 -> 530 bytes .../cctz/testdata/zoneinfo/Europe/Vaduz | Bin 1909 -> 497 bytes .../cctz/testdata/zoneinfo/Europe/Vatican | Bin 2641 -> 947 bytes .../cctz/testdata/zoneinfo/Europe/Vienna | Bin 2200 -> 658 bytes .../cctz/testdata/zoneinfo/Europe/Vilnius | Bin 2162 -> 676 bytes .../cctz/testdata/zoneinfo/Europe/Volgograd | Bin 1165 -> 735 bytes .../cctz/testdata/zoneinfo/Europe/Warsaw | Bin 2654 -> 923 bytes .../cctz/testdata/zoneinfo/Europe/Zagreb | Bin 1920 -> 478 bytes .../cctz/testdata/zoneinfo/Europe/Zaporozhye | Bin 2106 -> 560 bytes .../cctz/testdata/zoneinfo/Europe/Zurich | Bin 1909 -> 497 bytes .../internal/cctz/testdata/zoneinfo/Factory | Bin 116 -> 113 bytes .../time/internal/cctz/testdata/zoneinfo/GB | Bin 3648 -> 1599 bytes .../internal/cctz/testdata/zoneinfo/GB-Eire | Bin 3648 -> 1599 bytes .../time/internal/cctz/testdata/zoneinfo/GMT | Bin 114 -> 111 bytes .../internal/cctz/testdata/zoneinfo/GMT+0 | Bin 114 -> 111 bytes .../internal/cctz/testdata/zoneinfo/GMT-0 | Bin 114 -> 111 bytes .../time/internal/cctz/testdata/zoneinfo/GMT0 | Bin 114 -> 111 bytes .../internal/cctz/testdata/zoneinfo/Greenwich | Bin 114 -> 111 bytes .../time/internal/cctz/testdata/zoneinfo/HST | Bin 115 -> 112 bytes .../internal/cctz/testdata/zoneinfo/Hongkong | Bin 1203 -> 775 bytes .../internal/cctz/testdata/zoneinfo/Iceland | Bin 1162 -> 753 bytes .../testdata/zoneinfo/Indian/Antananarivo | Bin 251 -> 191 bytes .../cctz/testdata/zoneinfo/Indian/Chagos | Bin 199 -> 152 bytes .../cctz/testdata/zoneinfo/Indian/Christmas | Bin 165 -> 133 bytes .../cctz/testdata/zoneinfo/Indian/Cocos | Bin 174 -> 140 bytes .../cctz/testdata/zoneinfo/Indian/Comoro | Bin 251 -> 191 bytes .../cctz/testdata/zoneinfo/Indian/Kerguelen | Bin 165 -> 133 bytes .../cctz/testdata/zoneinfo/Indian/Mahe | Bin 165 -> 133 bytes .../cctz/testdata/zoneinfo/Indian/Maldives | Bin 199 -> 152 bytes .../cctz/testdata/zoneinfo/Indian/Mauritius | Bin 241 -> 179 bytes .../cctz/testdata/zoneinfo/Indian/Mayotte | Bin 251 -> 191 bytes .../cctz/testdata/zoneinfo/Indian/Reunion | Bin 165 -> 133 bytes .../time/internal/cctz/testdata/zoneinfo/Iran | Bin 2582 -> 2004 bytes .../internal/cctz/testdata/zoneinfo/Israel | Bin 2288 -> 1074 bytes .../internal/cctz/testdata/zoneinfo/Jamaica | Bin 482 -> 339 bytes .../internal/cctz/testdata/zoneinfo/Japan | Bin 309 -> 213 bytes .../internal/cctz/testdata/zoneinfo/Kwajalein | Bin 316 -> 219 bytes .../internal/cctz/testdata/zoneinfo/Libya | Bin 625 -> 431 bytes .../time/internal/cctz/testdata/zoneinfo/MET | Bin 2094 -> 621 bytes .../time/internal/cctz/testdata/zoneinfo/MST | Bin 114 -> 111 bytes .../internal/cctz/testdata/zoneinfo/MST7MDT | Bin 2310 -> 951 bytes .../cctz/testdata/zoneinfo/Mexico/BajaNorte | Bin 2342 -> 1025 bytes .../cctz/testdata/zoneinfo/Mexico/BajaSur | Bin 1526 -> 367 bytes .../cctz/testdata/zoneinfo/Mexico/General | Bin 1584 -> 412 bytes .../time/internal/cctz/testdata/zoneinfo/NZ | Bin 2437 -> 1043 bytes .../internal/cctz/testdata/zoneinfo/NZ-CHAT | Bin 2068 -> 808 bytes .../internal/cctz/testdata/zoneinfo/Navajo | Bin 2444 -> 1042 bytes .../time/internal/cctz/testdata/zoneinfo/PRC | Bin 533 -> 393 bytes .../internal/cctz/testdata/zoneinfo/PST8PDT | Bin 2310 -> 951 bytes .../cctz/testdata/zoneinfo/Pacific/Apia | Bin 1097 -> 268 bytes .../cctz/testdata/zoneinfo/Pacific/Auckland | Bin 2437 -> 1043 bytes .../testdata/zoneinfo/Pacific/Bougainville | Bin 268 -> 201 bytes .../cctz/testdata/zoneinfo/Pacific/Chatham | Bin 2068 -> 808 bytes .../cctz/testdata/zoneinfo/Pacific/Chuuk | Bin 269 -> 195 bytes .../cctz/testdata/zoneinfo/Pacific/Easter | Bin 2233 -> 1102 bytes .../cctz/testdata/zoneinfo/Pacific/Efate | Bin 466 -> 342 bytes .../cctz/testdata/zoneinfo/Pacific/Enderbury | Bin 234 -> 172 bytes .../cctz/testdata/zoneinfo/Pacific/Fakaofo | Bin 200 -> 153 bytes .../cctz/testdata/zoneinfo/Pacific/Fiji | Bin 1077 -> 419 bytes .../cctz/testdata/zoneinfo/Pacific/Funafuti | Bin 166 -> 134 bytes .../cctz/testdata/zoneinfo/Pacific/Galapagos | Bin 238 -> 175 bytes .../cctz/testdata/zoneinfo/Pacific/Gambier | Bin 164 -> 132 bytes .../testdata/zoneinfo/Pacific/Guadalcanal | Bin 166 -> 134 bytes .../cctz/testdata/zoneinfo/Pacific/Guam | Bin 494 -> 350 bytes .../cctz/testdata/zoneinfo/Pacific/Honolulu | Bin 329 -> 221 bytes .../cctz/testdata/zoneinfo/Pacific/Johnston | Bin 329 -> 221 bytes .../cctz/testdata/zoneinfo/Pacific/Kiritimati | Bin 238 -> 174 bytes .../cctz/testdata/zoneinfo/Pacific/Kosrae | Bin 351 -> 242 bytes .../cctz/testdata/zoneinfo/Pacific/Kwajalein | Bin 316 -> 219 bytes .../cctz/testdata/zoneinfo/Pacific/Majuro | Bin 310 -> 218 bytes .../cctz/testdata/zoneinfo/Pacific/Marquesas | Bin 173 -> 139 bytes .../cctz/testdata/zoneinfo/Pacific/Midway | Bin 175 -> 146 bytes .../cctz/testdata/zoneinfo/Pacific/Nauru | Bin 252 -> 183 bytes .../cctz/testdata/zoneinfo/Pacific/Niue | Bin 241 -> 175 bytes .../cctz/testdata/zoneinfo/Pacific/Norfolk | Bin 880 -> 247 bytes .../cctz/testdata/zoneinfo/Pacific/Noumea | Bin 304 -> 198 bytes .../cctz/testdata/zoneinfo/Pacific/Pago_Pago | Bin 175 -> 146 bytes .../cctz/testdata/zoneinfo/Pacific/Palau | Bin 180 -> 148 bytes .../cctz/testdata/zoneinfo/Pacific/Pitcairn | Bin 202 -> 153 bytes .../cctz/testdata/zoneinfo/Pacific/Pohnpei | Bin 303 -> 214 bytes .../cctz/testdata/zoneinfo/Pacific/Ponape | Bin 303 -> 214 bytes .../testdata/zoneinfo/Pacific/Port_Moresby | Bin 186 -> 154 bytes .../cctz/testdata/zoneinfo/Pacific/Rarotonga | Bin 577 -> 391 bytes .../cctz/testdata/zoneinfo/Pacific/Saipan | Bin 494 -> 350 bytes .../cctz/testdata/zoneinfo/Pacific/Samoa | Bin 175 -> 146 bytes .../cctz/testdata/zoneinfo/Pacific/Tahiti | Bin 165 -> 133 bytes .../cctz/testdata/zoneinfo/Pacific/Tarawa | Bin 166 -> 134 bytes .../cctz/testdata/zoneinfo/Pacific/Tongatapu | Bin 372 -> 237 bytes .../cctz/testdata/zoneinfo/Pacific/Truk | Bin 269 -> 195 bytes .../cctz/testdata/zoneinfo/Pacific/Wake | Bin 166 -> 134 bytes .../cctz/testdata/zoneinfo/Pacific/Wallis | Bin 166 -> 134 bytes .../cctz/testdata/zoneinfo/Pacific/Yap | Bin 269 -> 195 bytes .../internal/cctz/testdata/zoneinfo/Poland | Bin 2654 -> 923 bytes .../internal/cctz/testdata/zoneinfo/Portugal | Bin 3469 -> 1436 bytes .../time/internal/cctz/testdata/zoneinfo/ROC | Bin 761 -> 511 bytes .../time/internal/cctz/testdata/zoneinfo/ROK | Bin 617 -> 415 bytes .../internal/cctz/testdata/zoneinfo/Singapore | Bin 383 -> 256 bytes .../internal/cctz/testdata/zoneinfo/Turkey | Bin 1947 -> 1200 bytes .../time/internal/cctz/testdata/zoneinfo/UCT | Bin 114 -> 111 bytes .../internal/cctz/testdata/zoneinfo/US/Alaska | Bin 2371 -> 977 bytes .../cctz/testdata/zoneinfo/US/Aleutian | Bin 2356 -> 969 bytes .../cctz/testdata/zoneinfo/US/Arizona | Bin 328 -> 240 bytes .../cctz/testdata/zoneinfo/US/Central | Bin 3576 -> 1754 bytes .../cctz/testdata/zoneinfo/US/East-Indiana | Bin 1666 -> 531 bytes .../cctz/testdata/zoneinfo/US/Eastern | Bin 3536 -> 1744 bytes .../internal/cctz/testdata/zoneinfo/US/Hawaii | Bin 329 -> 221 bytes .../cctz/testdata/zoneinfo/US/Indiana-Starke | Bin 2428 -> 1016 bytes .../cctz/testdata/zoneinfo/US/Michigan | Bin 2230 -> 899 bytes .../cctz/testdata/zoneinfo/US/Mountain | Bin 2444 -> 1042 bytes .../cctz/testdata/zoneinfo/US/Pacific | Bin 2836 -> 1294 bytes .../internal/cctz/testdata/zoneinfo/US/Samoa | Bin 175 -> 146 bytes .../time/internal/cctz/testdata/zoneinfo/UTC | Bin 114 -> 111 bytes .../internal/cctz/testdata/zoneinfo/Universal | Bin 114 -> 111 bytes .../time/internal/cctz/testdata/zoneinfo/W-SU | Bin 1535 -> 908 bytes .../time/internal/cctz/testdata/zoneinfo/WET | Bin 1905 -> 494 bytes .../time/internal/cctz/testdata/zoneinfo/Zulu | Bin 114 -> 111 bytes .../cctz/testdata/zoneinfo/zone1970.tab | 17 +- .../absl/time/internal/test_util.cc | 1 + .../third_party/abseil-cpp/absl/time/time.cc | 7 +- .../third_party/abseil-cpp/absl/time/time.h | 182 +- .../abseil-cpp/absl/time/time_test.cc | 56 +- .../abseil-cpp/absl/types/BUILD.gn | 119 -- .../abseil-cpp/absl/types/CMakeLists.txt | 39 +- .../third_party/abseil-cpp/absl/types/any.h | 31 +- .../absl/types/bad_optional_access.h | 2 +- .../absl/types/bad_variant_access.h | 4 +- .../abseil-cpp/absl/types/compare.h | 6 +- .../absl/types/internal/conformance_profile.h | 599 +++++- .../absl/types/internal/conformance_testing.h | 1386 +++++++++++++ .../internal/conformance_testing_helpers.h | 391 ++++ .../internal/conformance_testing_test.cc | 372 +++- .../absl/types/internal/parentheses.h | 34 + .../absl/types/internal/transform_args.h | 246 +++ .../abseil-cpp/absl/types/internal/variant.h | 10 +- .../abseil-cpp/absl/types/optional_test.cc | 2 +- .../third_party/abseil-cpp/absl/types/span.h | 41 +- .../abseil-cpp/absl/types/span_test.cc | 2 + .../abseil-cpp/absl/types/variant.h | 13 +- .../abseil-cpp/absl/types/variant_test.cc | 8 +- .../abseil-cpp/absl/utility/BUILD.gn | 14 - .../abseil-cpp/absl/utility/CMakeLists.txt | 2 +- .../abseil-cpp/absl/utility/utility.h | 4 +- .../abseil-cpp/ci/absl_alternate_options.h | 29 + .../third_party/abseil-cpp/ci/cmake_common.sh | 25 + .../abseil-cpp/ci/cmake_install_test.sh | 46 + .../linux_clang-latest_libcxx_asan_bazel.sh | 100 + .../ci/linux_clang-latest_libcxx_bazel.sh | 98 + .../linux_clang-latest_libcxx_tsan_bazel.sh | 96 + .../ci/linux_clang-latest_libstdcxx_bazel.sh | 92 + .../abseil-cpp/ci/linux_docker_containers.sh | 21 + .../ci/linux_gcc-floor_libstdcxx_bazel.sh | 90 + .../ci/linux_gcc-latest_libstdcxx_bazel.sh | 96 + .../ci/linux_gcc-latest_libstdcxx_cmake.sh | 65 + .../abseil-cpp/ci/linux_gcc_alpine_cmake.sh | 64 + .../abseil-cpp/ci/macos_xcode_bazel.sh | 54 + .../abseil-cpp/ci/macos_xcode_cmake.sh | 56 + .../third_party/abseil-cpp/conanfile.py | 51 + .../third_party/abseil-cpp/create_lts.py | 133 ++ .../abseil-cpp/rename_annotations.sh | 165 -- third-party/webrtc/webrtc | 2 +- 1105 files changed, 48591 insertions(+), 15472 deletions(-) delete mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/BUILD.gn delete mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/CMake/AbseilInstallDirs.cmake delete mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/LTS.md delete mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/OWNERS delete mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/README.chromium delete mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/WORKSPACE delete mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl.gni delete mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/algorithm/BUILD.gn delete mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/BUILD.gn delete mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/dynamic_annotations.cc delete mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/bits.h delete mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/bits_test.cc create mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/dynamic_annotations.h create mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/thread_annotations.h create mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/unique_small_name_test.cc create mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/optimization_test.cc create mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/cleanup/CMakeLists.txt create mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/cleanup/cleanup.h create mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/cleanup/cleanup_test.cc create mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/cleanup/internal/cleanup.h delete mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/compiler_config_setting.bzl delete mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/BUILD.gn create mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/layout_benchmark.cc create mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/raw_hash_set_benchmark.cc create mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/raw_hash_set_probe_benchmark.cc delete mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/BUILD.gn create mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/internal/stacktrace_emscripten-inl.inc create mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/internal/stacktrace_riscv-inl.inc create mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/symbolize_darwin.inc create mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/symbolize_emscripten.inc delete mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/BUILD.gn create mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/commandlineflag.cc create mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/commandlineflag.h rename third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/{internal => }/commandlineflag_test.cc (50%) create mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/flag_benchmark.lds create mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/internal/private_handle_accessor.cc create mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/internal/private_handle_accessor.h delete mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/internal/registry.cc create mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/internal/sequence_lock.h create mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/internal/sequence_lock_test.cc delete mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/internal/type_erased.cc delete mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/internal/type_erased.h delete mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/internal/type_erased_test.cc create mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/reflection.cc create mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/reflection.h create mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/reflection_test.cc delete mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/functional/BUILD.gn delete mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/hash/BUILD.gn create mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/hash/hash_benchmark.cc create mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/hash/internal/low_level_hash.cc create mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/hash/internal/low_level_hash.h create mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/hash/internal/low_level_hash_test.cc delete mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/memory/BUILD.gn delete mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/meta/BUILD.gn delete mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/numeric/BUILD.gn create mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/numeric/bits.h create mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/numeric/bits_test.cc create mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/numeric/internal/bits.h create mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/numeric/internal/representation.h create mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/profiling/CMakeLists.txt create mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/profiling/internal/sample_recorder.h create mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/profiling/internal/sample_recorder_test.cc delete mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/random/BUILD.gn delete mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/random/internal/BUILD.gn delete mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/random/internal/distributions.h create mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/random/internal/mock_helpers.h delete mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/random/internal/mocking_bit_gen_base.h delete mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/random/internal/randen-keys.inc create mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/random/internal/randen_round_keys.cc create mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/random/internal/uniform_helper_test.cc delete mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/status/BUILD.gn create mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/status/internal/status_internal.h create mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/status/internal/statusor_internal.h create mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/status/statusor.cc create mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/status/statusor.h create mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/status/statusor_test.cc delete mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/strings/BUILD.gn create mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/strings/cord_ring_reader_test.cc create mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/strings/cord_ring_test.cc create mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/strings/cordz_test.cc create mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/strings/cordz_test_helpers.h create mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/strings/internal/cord_internal.cc create mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/strings/internal/cord_rep_btree.cc create mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/strings/internal/cord_rep_btree.h create mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/strings/internal/cord_rep_btree_navigator.cc create mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/strings/internal/cord_rep_btree_navigator.h create mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/strings/internal/cord_rep_btree_navigator_test.cc create mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/strings/internal/cord_rep_btree_reader.cc create mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/strings/internal/cord_rep_btree_reader.h create mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/strings/internal/cord_rep_btree_reader_test.cc create mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/strings/internal/cord_rep_btree_test.cc create mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/strings/internal/cord_rep_consume.cc create mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/strings/internal/cord_rep_consume.h create mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/strings/internal/cord_rep_consume_test.cc create mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/strings/internal/cord_rep_flat.h create mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/strings/internal/cord_rep_ring.cc create mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/strings/internal/cord_rep_ring.h create mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/strings/internal/cord_rep_ring_reader.h create mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/strings/internal/cord_rep_test_util.h create mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/strings/internal/cordz_functions.cc create mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/strings/internal/cordz_functions.h create mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/strings/internal/cordz_functions_test.cc create mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/strings/internal/cordz_handle.cc create mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/strings/internal/cordz_handle.h create mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/strings/internal/cordz_handle_test.cc create mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/strings/internal/cordz_info.cc create mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/strings/internal/cordz_info.h create mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/strings/internal/cordz_info_statistics_test.cc create mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/strings/internal/cordz_info_test.cc create mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/strings/internal/cordz_sample_token.cc create mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/strings/internal/cordz_sample_token.h create mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/strings/internal/cordz_sample_token_test.cc create mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/strings/internal/cordz_statistics.h create mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/strings/internal/cordz_update_scope.h create mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/strings/internal/cordz_update_scope_test.cc create mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/strings/internal/cordz_update_tracker.h create mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/strings/internal/cordz_update_tracker_test.cc create mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/strings/internal/string_constant.h create mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/strings/internal/string_constant_test.cc delete mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/strings/testdata/getline-1.txt delete mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/strings/testdata/getline-2.txt delete mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/synchronization/BUILD.gn create mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/synchronization/blocking_counter_benchmark.cc create mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/synchronization/internal/futex.h delete mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/synchronization/internal/mutex_nonprod.cc delete mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/synchronization/internal/mutex_nonprod.inc delete mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/time/BUILD.gn delete mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/time/internal/cctz/BUILD.gn create mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Nuuk delete mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/types/BUILD.gn create mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/types/internal/conformance_testing.h create mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/types/internal/conformance_testing_helpers.h create mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/types/internal/parentheses.h create mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/types/internal/transform_args.h delete mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/absl/utility/BUILD.gn create mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/ci/absl_alternate_options.h create mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/ci/cmake_common.sh create mode 100755 third-party/webrtc/dependencies/third_party/abseil-cpp/ci/cmake_install_test.sh create mode 100755 third-party/webrtc/dependencies/third_party/abseil-cpp/ci/linux_clang-latest_libcxx_asan_bazel.sh create mode 100755 third-party/webrtc/dependencies/third_party/abseil-cpp/ci/linux_clang-latest_libcxx_bazel.sh create mode 100755 third-party/webrtc/dependencies/third_party/abseil-cpp/ci/linux_clang-latest_libcxx_tsan_bazel.sh create mode 100755 third-party/webrtc/dependencies/third_party/abseil-cpp/ci/linux_clang-latest_libstdcxx_bazel.sh create mode 100644 third-party/webrtc/dependencies/third_party/abseil-cpp/ci/linux_docker_containers.sh create mode 100755 third-party/webrtc/dependencies/third_party/abseil-cpp/ci/linux_gcc-floor_libstdcxx_bazel.sh create mode 100755 third-party/webrtc/dependencies/third_party/abseil-cpp/ci/linux_gcc-latest_libstdcxx_bazel.sh create mode 100755 third-party/webrtc/dependencies/third_party/abseil-cpp/ci/linux_gcc-latest_libstdcxx_cmake.sh create mode 100755 third-party/webrtc/dependencies/third_party/abseil-cpp/ci/linux_gcc_alpine_cmake.sh create mode 100755 third-party/webrtc/dependencies/third_party/abseil-cpp/ci/macos_xcode_bazel.sh create mode 100755 third-party/webrtc/dependencies/third_party/abseil-cpp/ci/macos_xcode_cmake.sh create mode 100755 third-party/webrtc/dependencies/third_party/abseil-cpp/conanfile.py create mode 100755 third-party/webrtc/dependencies/third_party/abseil-cpp/create_lts.py delete mode 100755 third-party/webrtc/dependencies/third_party/abseil-cpp/rename_annotations.sh diff --git a/submodules/TgVoipWebrtc/tgcalls b/submodules/TgVoipWebrtc/tgcalls index f76a9290fa..0f0ba327d6 160000 --- a/submodules/TgVoipWebrtc/tgcalls +++ b/submodules/TgVoipWebrtc/tgcalls @@ -1 +1 @@ -Subproject commit f76a9290fa502a8df473dd872aedf9a553b089cc +Subproject commit 0f0ba327d636ab3f933624f11b5ef5678841c548 diff --git a/third-party/webrtc/BUILD b/third-party/webrtc/BUILD index f7319e2cb1..958f1394da 100644 --- a/third-party/webrtc/BUILD +++ b/third-party/webrtc/BUILD @@ -9,8 +9,11 @@ config_setting( ) optimization_flags = select({ - ":debug_build": ["-O2", "-DNDEBUG"], - #":debug_build": [], + ":debug_build": [ + #"-O2", + #"-DNDEBUG", + "-DRTC_DCHECK_IS_ON", + ], "//conditions:default": ["-DNDEBUG"], }) @@ -32,7 +35,6 @@ absl_sources = [ "dependencies/third_party/abseil-cpp/" + x for x in [ "absl/container/internal/hashtable_debug_hooks.h", "absl/strings/internal/cord_internal.h", "absl/base/internal/inline_variable.h", - "absl/base/dynamic_annotations.cc", "absl/base/internal/cycleclock.cc", "absl/base/internal/exponential_biased.cc", "absl/base/internal/low_level_alloc.cc", @@ -68,8 +70,6 @@ absl_sources = [ "dependencies/third_party/abseil-cpp/" + x for x in [ "absl/flags/internal/commandlineflag.cc", "absl/flags/internal/flag.cc", "absl/flags/internal/program_name.cc", - "absl/flags/internal/registry.cc", - "absl/flags/internal/type_erased.cc", "absl/flags/internal/usage.cc", "absl/flags/marshalling.cc", "absl/flags/parse.cc", @@ -201,7 +201,6 @@ absl_sources = [ "dependencies/third_party/abseil-cpp/" + x for x in [ "absl/numeric/int128.h", "absl/flags/marshalling.h", "absl/flags/parse.h", - "absl/flags/internal/type_erased.h", "absl/flags/internal/commandlineflag.h", "absl/flags/internal/program_name.h", "absl/flags/internal/usage.h", @@ -260,7 +259,6 @@ absl_sources = [ "dependencies/third_party/abseil-cpp/" + x for x in [ "absl/base/call_once.h", "absl/base/const_init.h", "absl/base/internal/atomic_hook.h", - "absl/base/internal/bits.h", "absl/base/internal/endian.h", "absl/base/internal/errno_saver.h", "absl/base/internal/fast_type_id.h", @@ -301,7 +299,6 @@ absl_sources = [ "dependencies/third_party/abseil-cpp/" + x for x in [ "absl/hash/hash.h", "absl/random/internal/generate_real.h", "absl/random/internal/iostream_state_saver.h", - "absl/random/internal/randen-keys.inc", "absl/random/internal/randen_engine.h", "absl/random/internal/randen_traits.h", "absl/strings/internal/resize_uninitialized.h", @@ -607,7 +604,6 @@ webrtc_sources = [ "api/neteq/neteq.cc", "api/neteq/tick_timer.cc", "api/peer_connection_interface.cc", - "api/proxy.cc", "api/rtc_error.cc", "api/rtc_event_log/rtc_event.cc", "api/rtc_event_log/rtc_event_log.cc", @@ -653,7 +649,6 @@ webrtc_sources = [ "api/video_codecs/sdp_video_format.cc", "api/video_codecs/video_codec.cc", "api/video_codecs/video_decoder.cc", - "api/video_codecs/video_decoder_factory.cc", "api/video_codecs/video_decoder_software_fallback_wrapper.cc", "api/video_codecs/video_encoder.cc", "api/video_codecs/video_encoder_config.cc", @@ -726,16 +721,13 @@ webrtc_sources = [ "media/base/media_constants.cc", "media/base/media_engine.cc", "media/base/rid_description.cc", - "media/base/rtp_data_engine.cc", "media/base/rtp_utils.cc", - "media/base/sdp_fmtp_utils.cc", "media/base/stream_params.cc", "media/base/turn_utils.cc", "media/base/video_adapter.cc", "media/base/video_broadcaster.cc", "media/base/video_common.cc", "media/base/video_source_base.cc", - "media/base/vp9_profile.cc", "media/base/adapted_video_track_source.h", "media/engine/adm_helpers.cc", "media/engine/encoder_simulcast_proxy.cc", @@ -753,8 +745,6 @@ webrtc_sources = [ "media/engine/webrtc_video_engine.cc", "media/engine/webrtc_voice_engine.h", "media/engine/webrtc_voice_engine.cc", - "media/sctp/noop.cc", - "media/sctp/sctp_transport.cc", "system_wrappers/source/clock.cc", "system_wrappers/source/cpu_features.cc", "system_wrappers/source/cpu_info.cc", @@ -1165,7 +1155,6 @@ webrtc_sources = [ "modules/pacing/task_queue_paced_sender.cc", "modules/rtp_rtcp/include/report_block_data.cc", "modules/rtp_rtcp/include/rtp_rtcp_defines.cc", - "modules/rtp_rtcp/source/absolute_capture_time_receiver.cc", "modules/rtp_rtcp/source/absolute_capture_time_sender.cc", "modules/rtp_rtcp/source/create_video_rtp_depacketizer.cc", "modules/rtp_rtcp/source/dtmf_queue.cc", @@ -1218,7 +1207,6 @@ webrtc_sources = [ "modules/rtp_rtcp/source/rtp_descriptor_authentication.cc", "modules/rtp_rtcp/source/rtp_format.cc", "modules/rtp_rtcp/source/rtp_format_h264.cc", - "modules/rtp_rtcp/source/rtp_format_h265.cc", "modules/rtp_rtcp/source/rtp_format_video_generic.cc", "modules/rtp_rtcp/source/rtp_format_vp8.cc", "modules/rtp_rtcp/source/rtp_format_vp9.cc", @@ -1239,7 +1227,6 @@ webrtc_sources = [ "modules/rtp_rtcp/source/rtp_sender_video.cc", "modules/rtp_rtcp/source/rtp_sender_video_frame_transformer_delegate.cc", "modules/rtp_rtcp/source/rtp_sequence_number_map.cc", - "modules/rtp_rtcp/source/rtp_utility.cc", "modules/rtp_rtcp/source/rtp_video_header.cc", "modules/rtp_rtcp/source/source_tracker.cc", "modules/rtp_rtcp/source/time_util.cc", @@ -1251,7 +1238,6 @@ webrtc_sources = [ "modules/rtp_rtcp/source/video_rtp_depacketizer_av1.cc", "modules/rtp_rtcp/source/video_rtp_depacketizer_generic.cc", "modules/rtp_rtcp/source/video_rtp_depacketizer_h264.cc", - "modules/rtp_rtcp/source/video_rtp_depacketizer_h265.cc", "modules/rtp_rtcp/source/video_rtp_depacketizer_raw.cc", "modules/rtp_rtcp/source/video_rtp_depacketizer_vp8.cc", "modules/rtp_rtcp/source/video_rtp_depacketizer_vp9.cc", @@ -1285,7 +1271,6 @@ webrtc_sources = [ "modules/video_coding/generic_decoder.cc", "modules/video_coding/h264_sprop_parameter_sets.cc", "modules/video_coding/h264_sps_pps_tracker.cc", - "modules/video_coding/h265_vps_sps_pps_tracker.cc", "modules/video_coding/histogram.cc", "modules/video_coding/include/video_codec_interface.cc", "modules/video_coding/inter_frame_delay.cc", @@ -1418,14 +1403,8 @@ webrtc_sources = [ "common_video/h264/h264_bitstream_parser.cc", "common_video/h264/h264_common.cc", "common_video/h264/pps_parser.cc", - "common_video/h264/prefix_parser.cc", "common_video/h264/sps_parser.cc", "common_video/h264/sps_vui_rewriter.cc", - "common_video/h265/h265_bitstream_parser.cc", - "common_video/h265/h265_common.cc", - "common_video/h265/h265_pps_parser.cc", - "common_video/h265/h265_sps_parser.cc", - "common_video/h265/h265_vps_parser.cc", "common_video/incoming_video_stream.cc", "common_video/libyuv/webrtc_libyuv.cc", "common_video/video_frame_buffer.cc", @@ -1442,7 +1421,6 @@ webrtc_sources = [ "p2p/base/ice_controller_interface.cc", "p2p/base/ice_credentials_iterator.cc", "p2p/base/ice_transport_internal.cc", - "p2p/base/mdns_message.cc", "p2p/base/p2p_constants.cc", "p2p/base/p2p_transport_channel.cc", "p2p/base/packet_transport_internal.cc", @@ -1608,7 +1586,6 @@ webrtc_sources = [ "api/neteq/neteq.h", "api/neteq/tick_timer.h", "api/peer_connection_interface.h", - "api/proxy.h", "api/rtc_error.h", "api/rtc_event_log/rtc_event.h", "api/rtc_event_log/rtc_event_log.h", @@ -1728,12 +1705,8 @@ webrtc_sources = [ "common_video/h264/h264_bitstream_parser.h", "common_video/h264/h264_common.h", "common_video/h264/pps_parser.h", - "common_video/h264/prefix_parser.h", "common_video/h264/sps_parser.h", "common_video/h264/sps_vui_rewriter.h", - "common_video/h265/h265_bitstream_parser.h", - "common_video/h265/h265_common.h", - "common_video/h265/h265_pps_parser.h", "common_video/include/bitrate_adjuster.h", "common_video/include/incoming_video_stream.h", "common_video/include/video_frame_buffer.h", @@ -1778,9 +1751,7 @@ webrtc_sources = [ "media/base/media_constants.h", "media/base/media_engine.h", "media/base/rid_description.h", - "media/base/rtp_data_engine.h", "media/base/rtp_utils.h", - "media/base/sdp_fmtp_utils.h", "media/base/stream_params.h", "media/base/turn_utils.h", "media/base/video_adapter.h", @@ -2121,7 +2092,6 @@ webrtc_sources = [ "modules/rtp_rtcp/include/report_block_data.h", "modules/rtp_rtcp/include/rtp_header_extension_map.h", "modules/rtp_rtcp/include/rtp_rtcp_defines.h", - "modules/rtp_rtcp/source/absolute_capture_time_receiver.h", "modules/rtp_rtcp/source/absolute_capture_time_sender.h", "modules/rtp_rtcp/source/create_video_rtp_depacketizer.h", "modules/rtp_rtcp/source/dtmf_queue.h", @@ -2191,7 +2161,6 @@ webrtc_sources = [ "modules/rtp_rtcp/source/rtp_sender_video.h", "modules/rtp_rtcp/source/rtp_sender_video_frame_transformer_delegate.h", "modules/rtp_rtcp/source/rtp_sequence_number_map.h", - "modules/rtp_rtcp/source/rtp_utility.h", "modules/rtp_rtcp/source/rtp_video_header.h", "modules/rtp_rtcp/source/source_tracker.h", "modules/rtp_rtcp/source/time_util.h", @@ -2203,7 +2172,6 @@ webrtc_sources = [ "modules/rtp_rtcp/source/video_rtp_depacketizer_av1.h", "modules/rtp_rtcp/source/video_rtp_depacketizer_generic.h", "modules/rtp_rtcp/source/video_rtp_depacketizer_h264.h", - "modules/rtp_rtcp/source/video_rtp_depacketizer_h265.h", "modules/rtp_rtcp/source/video_rtp_depacketizer_raw.h", "modules/rtp_rtcp/source/video_rtp_depacketizer_vp8.h", "modules/rtp_rtcp/source/video_rtp_depacketizer_vp9.h", @@ -2229,7 +2197,6 @@ webrtc_sources = [ "modules/video_coding/codecs/vp8/screenshare_layers.h", "modules/video_coding/codecs/vp9/include/vp9.h", "modules/video_coding/codecs/vp9/svc_config.h", - "modules/video_coding/codecs/vp9/svc_rate_allocator.h", "modules/video_coding/codecs/vp9/vp9_frame_buffer_pool.h", "modules/video_coding/decoder_database.h", "modules/video_coding/decoding_state.h", @@ -2243,7 +2210,6 @@ webrtc_sources = [ "modules/video_coding/generic_decoder.h", "modules/video_coding/h264_sprop_parameter_sets.h", "modules/video_coding/h264_sps_pps_tracker.h", - "modules/video_coding/h265_vps_sps_pps_tracker.h", "modules/video_coding/histogram.h", "modules/video_coding/include/video_codec_initializer.h", "modules/video_coding/include/video_codec_interface.h", @@ -2293,7 +2259,6 @@ webrtc_sources = [ "p2p/base/ice_controller_interface.h", "p2p/base/ice_credentials_iterator.h", "p2p/base/ice_transport_internal.h", - "p2p/base/mdns_message.h", "p2p/base/p2p_constants.h", "p2p/base/p2p_transport_channel.h", "p2p/base/packet_transport_internal.h", @@ -2482,9 +2447,6 @@ webrtc_sources = [ "audio/remix_resample.h", "audio/utility/audio_frame_operations.h", "common_audio/fir_filter.h", - "common_video/h264/profile_level_id.h", - "common_video/h265/h265_sps_parser.h", - "common_video/h265/h265_vps_parser.h", "common_video/include/quality_limitation_reason.h", "modules/audio_coding/codecs/ilbc/abs_quant.h", "modules/audio_coding/codecs/ilbc/abs_quant_loop.h", @@ -2533,7 +2495,6 @@ webrtc_sources = [ "modules/video_coding/codecs/vp9/include/vp9_globals.h", "pc/rtp_transport_internal.h", "rtc_base/mdns_responder_interface.h", - "rtc_base/message_buffer_reader.h", "rtc_base/numerics/running_statistics.h", "rtc_base/numerics/sequence_number_util.h", "rtc_base/openssl.h", @@ -2564,7 +2525,6 @@ webrtc_sources = [ "api/video_codecs/bitstream_parser.h", "api/video_codecs/vp8_frame_buffer_controller.h", "media/base/delayable.h", - "media/sctp/sctp_transport.h", "media/sctp/sctp_transport_internal.h", "modules/audio_coding/audio_network_adaptor/include/audio_network_adaptor.h", "modules/audio_coding/codecs/ilbc/decoder_interpolate_lsf.h", @@ -2597,7 +2557,6 @@ webrtc_sources = [ "modules/remote_bitrate_estimator/include/remote_bitrate_estimator.h", "modules/rtp_rtcp/include/rtcp_statistics.h", "modules/rtp_rtcp/include/rtp_rtcp.h", - "modules/rtp_rtcp/source/rtp_format_h265.h", "modules/video_capture/video_capture_defines.h", "modules/video_coding/fec_rate_table.h", "p2p/base/candidate_pair_interface.h", @@ -2614,7 +2573,6 @@ webrtc_sources = [ "api/audio_codecs/isac/audio_encoder_isac.h", "api/task_queue/default_task_queue_factory.h", "api/video/video_stream_encoder_settings.h", - "api/video_track_source_proxy.h", "call/audio_sender.h", "call/rtp_transport_controller_send_interface.h", "call/rtp_video_sender_interface.h", @@ -2629,10 +2587,8 @@ webrtc_sources = [ "modules/audio_coding/codecs/isac/audio_encoder_isac_t_impl.h", "modules/audio_processing/agc/gain_map_internal.h", "modules/video_capture/video_capture_config.h", - "modules/video_coding/codecs/h265/include/h265_globals.h", "modules/video_coding/codecs/vp8/include/vp8.h", "p2p/base/p2p_transport_channel_ice_field_trials.h", - "pc/jitter_buffer_delay_interface.h", "rtc_base/swap_queue.h", "rtc_base/system/ignore_warnings.h", "logging/rtc_event_log/encoder/rtc_event_log_encoder.h", @@ -2660,7 +2616,6 @@ webrtc_sources = [ "modules/audio_coding/codecs/ilbc/enhancer_interface.h", "modules/rtp_rtcp/include/rtp_cvo.h", "call/simulated_packet_receiver.h", - "api/media_stream_proxy.h", "logging/rtc_event_log/encoder/rtc_event_log_encoder_legacy.h", "modules/audio_coding/codecs/ilbc/cb_search.h", "modules/audio_coding/codecs/ilbc/decode.h", @@ -2682,17 +2637,13 @@ webrtc_sources = [ "modules/audio_coding/codecs/ilbc/cb_mem_energy_augmentation.h", "modules/audio_coding/codecs/ilbc/unpack_bits.h", "modules/audio_coding/codecs/ilbc/index_conv_enc.h", - "api/media_stream_track_proxy.h", "pc/stream_collection.h", - "api/peer_connection_factory_proxy.h", "api/uma_metrics.h", "logging/rtc_event_log/encoder/rtc_event_log_encoder_new_format.h", "modules/audio_coding/codecs/ilbc/cb_search_core.h", "modules/audio_coding/codecs/ilbc/pack_bits.h", "modules/audio_coding/codecs/ilbc/swap_bytes.h", "modules/audio_processing/common.h", - "pc/jitter_buffer_delay_proxy.h", - "api/peer_connection_proxy.h", "modules/audio_coding/codecs/ilbc/hp_input.h", "api/adaptation/resource.h", "api/adaptation/resource.cc", @@ -2770,8 +2721,6 @@ webrtc_sources = [ "pc/connection_context.cc", "pc/data_channel_utils.h", "pc/data_channel_utils.cc", - "pc/rtp_data_channel.h", - "pc/rtp_data_channel.cc", "rtc_base/boringssl_certificate.h", "rtc_base/boringssl_certificate.cc", "rtc_base/strings/string_format.h", @@ -2859,8 +2808,6 @@ webrtc_sources = [ "video/rtp_video_stream_receiver2.cc", "video/video_stream_decoder2.h", "video/video_stream_decoder2.cc", - "modules/video_coding/nack_module2.h", - "modules/video_coding/nack_module2.cc", "api/sequence_checker.h", "common_audio/third_party/ooura/fft_size_128/ooura_fft_tables_common.h", "common_audio/third_party/ooura/fft_size_128/ooura_fft_tables_neon_sse2.h", @@ -2891,6 +2838,59 @@ webrtc_sources = [ "modules/audio_processing/capture_levels_adjuster/audio_samples_scaler.cc", "rtc_base/system/gcd_helpers.h", "rtc_base/system/gcd_helpers.m", + "modules/rtp_rtcp/source/rtp_util.h", + "modules/rtp_rtcp/source/rtp_util.cc", + "pc/jsep_transport_collection.h", + "pc/jsep_transport_collection.cc", + "modules/video_coding/nack_requester.h", + "modules/video_coding/nack_requester.cc", + "modules/congestion_controller/remb_throttler.h", + "modules/congestion_controller/remb_throttler.cc", + "modules/congestion_controller/goog_cc/loss_based_bwe_v2.h", + "modules/congestion_controller/goog_cc/loss_based_bwe_v2.cc", + "system_wrappers/include/denormal_disabler.h", + "system_wrappers/source/denormal_disabler.cc", + "api/video_codecs/vp9_profile.h", + "api/video_codecs/vp9_profile.cc", + "api/video_codecs/h264_profile_level_id.h", + "api/video_codecs/h264_profile_level_id.cc", + "modules/remote_bitrate_estimator/packet_arrival_map.h", + "modules/remote_bitrate_estimator/packet_arrival_map.cc", + "modules/audio_processing/agc/clipping_predictor.h", + "modules/audio_processing/agc/clipping_predictor.cc", + "modules/rtp_rtcp/source/capture_clock_offset_updater.h", + "modules/rtp_rtcp/source/capture_clock_offset_updater.cc", + "pc/video_track_source_proxy.h", + "pc/video_track_source_proxy.cc", + "modules/rtp_rtcp/source/absolute_capture_time_interpolator.h", + "modules/rtp_rtcp/source/absolute_capture_time_interpolator.cc", + "media/base/sdp_video_format_utils.h", + "media/base/sdp_video_format_utils.cc", + "modules/audio_processing/agc/clipping_predictor_evaluator.h", + "modules/audio_processing/agc/clipping_predictor_evaluator.cc", + "modules/audio_processing/agc/clipping_predictor_level_buffer.h", + "modules/audio_processing/agc/clipping_predictor_level_buffer.cc", + "modules/rtp_rtcp/source/rtp_format_h265.cc", + "modules/rtp_rtcp/source/video_rtp_depacketizer_h265.cc", + "modules/video_coding/h265_vps_sps_pps_tracker.cc", + "common_video/h265/h265_bitstream_parser.cc", + "common_video/h265/h265_common.cc", + "common_video/h265/h265_pps_parser.cc", + "common_video/h265/h265_sps_parser.cc", + "common_video/h265/h265_vps_parser.cc", + "common_video/h265/h265_bitstream_parser.h", + "common_video/h265/h265_common.h", + "common_video/h265/h265_pps_parser.h", + "modules/rtp_rtcp/source/video_rtp_depacketizer_h265.h", + "modules/video_coding/h265_vps_sps_pps_tracker.h", + "common_video/h265/h265_sps_parser.h", + "common_video/h265/h265_vps_parser.h", + "modules/rtp_rtcp/source/rtp_format_h265.h", + "modules/video_coding/codecs/h265/include/h265_globals.h", + "media/sctp/sctp_transport_factory.h", + "media/sctp/sctp_transport_factory.cc", + "media/sctp/usrsctp_transport.h", + "media/sctp/usrsctp_transport.cc", ] ios_objc_sources = [ @@ -2916,6 +2916,15 @@ ios_objc_sources = [ "objc/components/video_codec/RTCVideoEncoderFactoryH264.m", "objc/components/video_codec/RTCVideoDecoderFactoryH264.h", "objc/components/video_codec/RTCVideoDecoderFactoryH264.m", + "objc/components/video_codec/RTCCodecSpecificInfoH265.h", + "objc/components/video_codec/RTCCodecSpecificInfoH265.mm", + "objc/components/video_codec/RTCH265ProfileLevelId.h", + "objc/components/video_codec/RTCH265ProfileLevelId.mm", + "objc/components/video_codec/RTCVideoDecoderH265.h", + "objc/components/video_codec/RTCVideoDecoderH265.mm", + "objc/components/video_codec/RTCVideoEncoderH265.h", + "objc/components/video_codec/RTCVideoEncoderH265.mm", + "objc/components/video_codec/RTCCodecSpecificInfoH265+Private.h", ] ios_sources = [ @@ -2983,18 +2992,10 @@ ios_sources = [ "objc/components/video_codec/RTCCodecSpecificInfoH264.mm", "objc/components/video_codec/RTCH264ProfileLevelId.h", "objc/components/video_codec/RTCH264ProfileLevelId.mm", - "objc/components/video_codec/RTCCodecSpecificInfoH265.h", - "objc/components/video_codec/RTCCodecSpecificInfoH265.mm", - "objc/components/video_codec/RTCH265ProfileLevelId.h", - "objc/components/video_codec/RTCH265ProfileLevelId.mm", "objc/components/video_codec/RTCVideoDecoderH264.h", "objc/components/video_codec/RTCVideoDecoderH264.mm", "objc/components/video_codec/RTCVideoEncoderH264.h", "objc/components/video_codec/RTCVideoEncoderH264.mm", - "objc/components/video_codec/RTCVideoDecoderH265.h", - "objc/components/video_codec/RTCVideoDecoderH265.mm", - "objc/components/video_codec/RTCVideoEncoderH265.h", - "objc/components/video_codec/RTCVideoEncoderH265.mm", "objc/api/video_codec/RTCVideoCodecConstants.h", "objc/api/video_codec/RTCVideoCodecConstants.mm", "objc/components/video_codec/helpers.cc", @@ -3050,7 +3051,6 @@ ios_sources = [ "objc/api/peerconnection/RTCAudioSource+Private.h", "objc/api/peerconnection/RTCAudioTrack+Private.h", "objc/api/peerconnection/RTCCertificate.h", - "objc/components/video_codec/RTCCodecSpecificInfoH265+Private.h", "objc/api/peerconnection/RTCConfiguration+Private.h", "objc/api/peerconnection/RTCCryptoOptions.h", "objc/api/peerconnection/RTCDataChannel+Private.h", @@ -3221,6 +3221,7 @@ common_flags = [ "-DRTC_ENABLE_VP9", "-DWEBRTC_USE_H264", "-DHAVE_SCTP", + "-DWEBRTC_HAVE_USRSCTP", "-Ithird-party/openh264", "-DWEBRTC_NS_FLOAT", "-DRTC_DISABLE_TRACE_EVENTS", @@ -3229,7 +3230,7 @@ common_flags = [ "-DBWE_TEST_LOGGING_COMPILE_TIME_ENABLE=0", "-DABSL_ALLOCATOR_NOTHROW=1", "-DDYNAMIC_ANNOTATIONS_ENABLED=0", - "-DNS_BLOCK_ASSERTIONS=1", + #"-DNS_BLOCK_ASSERTIONS=1", "-DWEBRTC_ENABLE_PROTOBUF=0", "-DWEBRTC_ENABLE_AVX2", "-DWEBRTC_NON_STATIC_TRACE_EVENT_HANDLERS=0", @@ -3353,6 +3354,7 @@ cc_library( "-D__Userspace_os_Darwin", "-DPACKAGE_VERSION=''", "-DHAVE_SCTP", + "-DWEBRTC_HAVE_USRSCTP", "-DNON_WINDOWS_DEFINE", ] + arch_specific_cflags + optimization_flags, visibility = ["//visibility:public"], @@ -3432,6 +3434,7 @@ cc_library( "-DHAVE_UNISTD_H", "-DPACKAGE_STRING='\"\"'", "-DHAVE_SCTP", + "-DWEBRTC_HAVE_USRSCTP", ] + arch_specific_cflags + optimization_flags, deps = [ "//third-party/boringssl:crypto", @@ -3481,6 +3484,7 @@ objc_library( "-D__Userspace_os_Darwin", "-DPACKAGE_VERSION='\"\"'", "-DHAVE_SCTP", + "-DWEBRTC_HAVE_USRSCTP", "-DNO_MAIN_THREAD_WRAPPING", "-DRTC_DISABLE_TRACE_EVENTS", "-DRTC_DISABLE_METRICS", diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/BUILD.gn b/third-party/webrtc/dependencies/third_party/abseil-cpp/BUILD.gn deleted file mode 100644 index 8e39203f9b..0000000000 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/BUILD.gn +++ /dev/null @@ -1,77 +0,0 @@ -# Copyright (c) 2018 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -# Flags specified here must not impact ABI. Code compiled with and without these -# opts will be linked together, and in some cases headers compiled with and -# without these options will be part of the same program. - -import("//build/toolchain/toolchain.gni") - -group("default") { - deps = [ - "absl/types:any", - "absl/types:bad_any_cast", - "absl/types:bad_optional_access", - "absl/types:optional", - "absl/types:span", - ] -} - -config("absl_include_config") { - include_dirs = [ "." ] -} - -config("absl_define_config") { - defines = [ "ABSL_ALLOCATOR_NOTHROW=1" ] -} - -config("absl_default_cflags_cc") { - cflags_cc = [] - if (is_clang) { - cflags_cc += [ - # TODO(crbug.com/588506): Explicitly enable conversion warnings. - "-Wbool-conversion", - "-Wconstant-conversion", - "-Wenum-conversion", - "-Wint-conversion", - "-Wliteral-conversion", - "-Wnon-literal-null-conversion", - "-Wnull-conversion", - "-Wobjc-literal-conversion", - "-Wno-sign-conversion", - "-Wstring-conversion", - ] - if (!is_nacl && !use_xcode_clang) { - cflags_cc += [ "-Wbitfield-enum-conversion" ] - } - } - if (is_win) { - cflags_cc += [ - "/wd4005", # macro-redefinition - "/wd4018", # sign-compare - "/wd4068", # unknown pragma - "/wd4702", # unreachable code - ] - } -} - -config("absl_test_cflags_cc") { - cflags_cc = [] - if (is_clang || !is_win) { - cflags_cc += [ - "-Wno-conversion-null", - "-Wno-missing-declarations", - "-Wno-sign-compare", - "-Wno-unused-function", - "-Wno-unused-parameter", - "-Wno-unused-private-field", - ] - } - if (is_win) { - cflags_cc += [ - "/wd4018", # signed/unsigned mismatch - "/wd4101", # unreferenced local variable - ] - } -} diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/CMake/AbseilDll.cmake b/third-party/webrtc/dependencies/third_party/abseil-cpp/CMake/AbseilDll.cmake index 7646c154ef..056343e59c 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/CMake/AbseilDll.cmake +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/CMake/AbseilDll.cmake @@ -1,4 +1,5 @@ include(CMakeParseArguments) +include(GNUInstallDirs) set(ABSL_INTERNAL_DLL_FILES "algorithm/algorithm.h" @@ -8,13 +9,12 @@ set(ABSL_INTERNAL_DLL_FILES "base/casts.h" "base/config.h" "base/const_init.h" - "base/dynamic_annotations.cc" "base/dynamic_annotations.h" "base/internal/atomic_hook.h" - "base/internal/bits.h" "base/internal/cycleclock.cc" "base/internal/cycleclock.h" "base/internal/direct_mmap.h" + "base/internal/dynamic_annotations.h" "base/internal/endian.h" "base/internal/errno_saver.h" "base/internal/exponential_biased.cc" @@ -61,6 +61,8 @@ set(ABSL_INTERNAL_DLL_FILES "base/policy_checks.h" "base/port.h" "base/thread_annotations.h" + "cleanup/cleanup.h" + "cleanup/internal/cleanup.h" "container/btree_map.h" "container/btree_set.h" "container/fixed_array.h" @@ -122,10 +124,16 @@ set(ABSL_INTERNAL_DLL_FILES "hash/internal/hash.h" "hash/internal/hash.cc" "hash/internal/spy_hash_state.h" + "hash/internal/low_level_hash.h" + "hash/internal/low_level_hash.cc" "memory/memory.h" "meta/type_traits.h" + "numeric/bits.h" "numeric/int128.cc" "numeric/int128.h" + "numeric/internal/bits.h" + "numeric/internal/representation.h" + "profiling/internal/sample_recorder.h" "random/bernoulli_distribution.h" "random/beta_distribution.h" "random/bit_gen_ref.h" @@ -135,13 +143,12 @@ set(ABSL_INTERNAL_DLL_FILES "random/exponential_distribution.h" "random/gaussian_distribution.cc" "random/gaussian_distribution.h" - "random/internal/distributions.h" "random/internal/distribution_caller.h" - "random/internal/fast_uniform_bits.h" "random/internal/fastmath.h" - "random/internal/gaussian_distribution_gentables.cc" + "random/internal/fast_uniform_bits.h" "random/internal/generate_real.h" "random/internal/iostream_state_saver.h" + "random/internal/mock_helpers.h" "random/internal/nonsecure_base.h" "random/internal/pcg_engine.h" "random/internal/platform.h" @@ -154,6 +161,7 @@ set(ABSL_INTERNAL_DLL_FILES "random/internal/randen_engine.h" "random/internal/randen_hwaes.cc" "random/internal/randen_hwaes.h" + "random/internal/randen_round_keys.cc" "random/internal/randen_slow.cc" "random/internal/randen_slow.h" "random/internal/randen_traits.h" @@ -174,8 +182,12 @@ set(ABSL_INTERNAL_DLL_FILES "random/uniform_int_distribution.h" "random/uniform_real_distribution.h" "random/zipf_distribution.h" + "status/internal/status_internal.h" + "status/internal/statusor_internal.h" "status/status.h" "status/status.cc" + "status/statusor.h" + "status/statusor.cc" "status/status_payload_printer.h" "status/status_payload_printer.cc" "strings/ascii.cc" @@ -186,12 +198,37 @@ set(ABSL_INTERNAL_DLL_FILES "strings/cord.h" "strings/escaping.cc" "strings/escaping.h" - "strings/internal/cord_internal.h" "strings/internal/charconv_bigint.cc" "strings/internal/charconv_bigint.h" "strings/internal/charconv_parse.cc" "strings/internal/charconv_parse.h" + "strings/internal/cord_internal.cc" + "strings/internal/cord_internal.h" + "strings/internal/cord_rep_consume.h" + "strings/internal/cord_rep_consume.cc" + "strings/internal/cord_rep_btree.cc" + "strings/internal/cord_rep_btree.h" + "strings/internal/cord_rep_btree_navigator.cc" + "strings/internal/cord_rep_btree_navigator.h" + "strings/internal/cord_rep_btree_reader.cc" + "strings/internal/cord_rep_btree_reader.h" + "strings/internal/cord_rep_flat.h" + "strings/internal/cord_rep_ring.cc" + "strings/internal/cord_rep_ring.h" + "strings/internal/cord_rep_ring_reader.h" + "strings/internal/cordz_functions.cc" + "strings/internal/cordz_functions.h" + "strings/internal/cordz_handle.cc" + "strings/internal/cordz_handle.h" + "strings/internal/cordz_info.cc" + "strings/internal/cordz_info.h" + "strings/internal/cordz_sample_token.cc" + "strings/internal/cordz_sample_token.h" + "strings/internal/cordz_statistics.h" + "strings/internal/cordz_update_scope.h" + "strings/internal/cordz_update_tracker.h" "strings/internal/stl_type_traits.h" + "strings/internal/string_constant.h" "strings/match.cc" "strings/match.h" "strings/numbers.cc" @@ -246,6 +283,7 @@ set(ABSL_INTERNAL_DLL_FILES "synchronization/notification.h" "synchronization/internal/create_thread_identity.cc" "synchronization/internal/create_thread_identity.h" + "synchronization/internal/futex.h" "synchronization/internal/graphcycles.cc" "synchronization/internal/graphcycles.h" "synchronization/internal/kernel_timeout.h" @@ -294,6 +332,8 @@ set(ABSL_INTERNAL_DLL_FILES "types/internal/conformance_aliases.h" "types/internal/conformance_archetype.h" "types/internal/conformance_profile.h" + "types/internal/parentheses.h" + "types/internal/transform_args.h" "types/internal/variant.h" "types/optional.h" "types/internal/optional.h" @@ -418,6 +458,7 @@ set(ABSL_INTERNAL_DLL_TARGETS "raw_hash_set" "layout" "tracked" + "sample_recorder" ) function(absl_internal_dll_contains) @@ -481,7 +522,7 @@ function(absl_make_dll) abseil_dll PUBLIC "$" - $ + $ ) target_compile_options( @@ -499,8 +540,8 @@ function(absl_make_dll) ${ABSL_CC_LIB_DEFINES} ) install(TARGETS abseil_dll EXPORT ${PROJECT_NAME}Targets - RUNTIME DESTINATION ${ABSL_INSTALL_BINDIR} - LIBRARY DESTINATION ${ABSL_INSTALL_LIBDIR} - ARCHIVE DESTINATION ${ABSL_INSTALL_LIBDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} ) endfunction() diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/CMake/AbseilHelpers.cmake b/third-party/webrtc/dependencies/third_party/abseil-cpp/CMake/AbseilHelpers.cmake index 86ff9eba2a..17c4f4499c 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/CMake/AbseilHelpers.cmake +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/CMake/AbseilHelpers.cmake @@ -17,13 +17,14 @@ include(CMakeParseArguments) include(AbseilConfigureCopts) include(AbseilDll) -include(AbseilInstallDirs) # The IDE folder for Abseil that will be used if Abseil is included in a CMake # project that sets # set_property(GLOBAL PROPERTY USE_FOLDERS ON) # For example, Visual Studio supports folders. -set(ABSL_IDE_FOLDER Abseil) +if(NOT DEFINED ABSL_IDE_FOLDER) + set(ABSL_IDE_FOLDER Abseil) +endif() # absl_cc_library() # @@ -39,7 +40,7 @@ set(ABSL_IDE_FOLDER Abseil) # LINKOPTS: List of link options # PUBLIC: Add this so that this library will be exported under absl:: # Also in IDE, target will appear in Abseil folder while non PUBLIC will be in Abseil/internal. -# TESTONLY: When added, this target will only be built if user passes -DABSL_RUN_TESTS=ON to CMake. +# TESTONLY: When added, this target will only be built if BUILD_TESTING=ON. # # Note: # By default, absl_cc_library will always create a library named absl_${NAME}, @@ -81,7 +82,7 @@ function(absl_cc_library) ${ARGN} ) - if(ABSL_CC_LIB_TESTONLY AND NOT ABSL_RUN_TESTS) + if(ABSL_CC_LIB_TESTONLY AND NOT BUILD_TESTING) return() endif() @@ -102,7 +103,7 @@ function(absl_cc_library) endif() endforeach() - if("${ABSL_CC_SRCS}" STREQUAL "") + if(ABSL_CC_SRCS STREQUAL "") set(ABSL_CC_LIB_IS_INTERFACE 1) else() set(ABSL_CC_LIB_IS_INTERFACE 0) @@ -120,7 +121,11 @@ function(absl_cc_library) # 4. "static" -- This target does not depend on the DLL and should be built # statically. if (${ABSL_BUILD_DLL}) - absl_internal_dll_contains(TARGET ${_NAME} OUTPUT _in_dll) + if(ABSL_ENABLE_INSTALL) + absl_internal_dll_contains(TARGET ${_NAME} OUTPUT _in_dll) + else() + absl_internal_dll_contains(TARGET ${ABSL_CC_LIB_NAME} OUTPUT _in_dll) + endif() if (${_in_dll}) # This target should be replaced by the DLL set(_build_type "dll") @@ -135,8 +140,54 @@ function(absl_cc_library) set(_build_type "static") endif() + # Generate a pkg-config file for every library: + if((_build_type STREQUAL "static" OR _build_type STREQUAL "shared") + AND ABSL_ENABLE_INSTALL) + if(NOT ABSL_CC_LIB_TESTONLY) + if(absl_VERSION) + set(PC_VERSION "${absl_VERSION}") + else() + set(PC_VERSION "head") + endif() + foreach(dep ${ABSL_CC_LIB_DEPS}) + if(${dep} MATCHES "^absl::(.*)") + # Join deps with commas. + if(PC_DEPS) + set(PC_DEPS "${PC_DEPS},") + endif() + set(PC_DEPS "${PC_DEPS} absl_${CMAKE_MATCH_1} = ${PC_VERSION}") + endif() + endforeach() + foreach(cflag ${ABSL_CC_LIB_COPTS}) + if(${cflag} MATCHES "^(-Wno|/wd)") + # These flags are needed to suppress warnings that might fire in our headers. + set(PC_CFLAGS "${PC_CFLAGS} ${cflag}") + elseif(${cflag} MATCHES "^(-W|/w[1234eo])") + # Don't impose our warnings on others. + else() + set(PC_CFLAGS "${PC_CFLAGS} ${cflag}") + endif() + endforeach() + FILE(GENERATE OUTPUT "${CMAKE_BINARY_DIR}/lib/pkgconfig/absl_${_NAME}.pc" CONTENT "\ +prefix=${CMAKE_INSTALL_PREFIX}\n\ +exec_prefix=\${prefix}\n\ +libdir=${CMAKE_INSTALL_FULL_LIBDIR}\n\ +includedir=${CMAKE_INSTALL_FULL_INCLUDEDIR}\n\ +\n\ +Name: absl_${_NAME}\n\ +Description: Abseil ${_NAME} library\n\ +URL: https://abseil.io/\n\ +Version: ${PC_VERSION}\n\ +Requires:${PC_DEPS}\n\ +Libs: -L\${libdir} $ $<$>:-labsl_${_NAME}>\n\ +Cflags: -I\${includedir}${PC_CFLAGS}\n") + INSTALL(FILES "${CMAKE_BINARY_DIR}/lib/pkgconfig/absl_${_NAME}.pc" + DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig") + endif() + endif() + if(NOT ABSL_CC_LIB_IS_INTERFACE) - if(${_build_type} STREQUAL "dll_dep") + if(_build_type STREQUAL "dll_dep") # This target depends on the DLL. When adding dependencies to this target, # any depended-on-target which is contained inside the DLL is replaced # with a dependency on the DLL. @@ -165,7 +216,7 @@ function(absl_cc_library) "${_gtest_link_define}" ) - elseif(${_build_type} STREQUAL "static" OR ${_build_type} STREQUAL "shared") + elseif(_build_type STREQUAL "static" OR _build_type STREQUAL "shared") add_library(${_NAME} "") target_sources(${_NAME} PRIVATE ${ABSL_CC_LIB_SRCS} ${ABSL_CC_LIB_HDRS}) target_link_libraries(${_NAME} @@ -188,7 +239,7 @@ function(absl_cc_library) target_include_directories(${_NAME} PUBLIC "$" - $ + $ ) target_compile_options(${_NAME} PRIVATE ${ABSL_CC_LIB_COPTS}) @@ -203,9 +254,23 @@ function(absl_cc_library) set_property(TARGET ${_NAME} PROPERTY FOLDER ${ABSL_IDE_FOLDER}/internal) endif() - # INTERFACE libraries can't have the CXX_STANDARD property set - set_property(TARGET ${_NAME} PROPERTY CXX_STANDARD ${ABSL_CXX_STANDARD}) - set_property(TARGET ${_NAME} PROPERTY CXX_STANDARD_REQUIRED ON) + if(ABSL_PROPAGATE_CXX_STD) + # Abseil libraries require C++11 as the current minimum standard. + # Top-level application CMake projects should ensure a consistent C++ + # standard for all compiled sources by setting CMAKE_CXX_STANDARD. + target_compile_features(${_NAME} PUBLIC cxx_std_11) + else() + # Note: This is legacy (before CMake 3.8) behavior. Setting the + # target-level CXX_STANDARD property to ABSL_CXX_STANDARD (which is + # initialized by CMAKE_CXX_STANDARD) should have no real effect, since + # that is the default value anyway. + # + # CXX_STANDARD_REQUIRED does guard against the top-level CMake project + # not having enabled CMAKE_CXX_STANDARD_REQUIRED (which prevents + # "decaying" to an older standard if the requested one isn't available). + set_property(TARGET ${_NAME} PROPERTY CXX_STANDARD ${ABSL_CXX_STANDARD}) + set_property(TARGET ${_NAME} PROPERTY CXX_STANDARD_REQUIRED ON) + endif() # When being installed, we lose the absl_ prefix. We want to put it back # to have properly named lib files. This is a no-op when we are not being @@ -213,6 +278,7 @@ function(absl_cc_library) if(ABSL_ENABLE_INSTALL) set_target_properties(${_NAME} PROPERTIES OUTPUT_NAME "absl_${_NAME}" + SOVERSION 0 ) endif() else() @@ -221,10 +287,10 @@ function(absl_cc_library) target_include_directories(${_NAME} INTERFACE "$" - $ + $ ) - if (${_build_type} STREQUAL "dll") + if (_build_type STREQUAL "dll") set(ABSL_CC_LIB_DEPS abseil_dll) endif() @@ -235,15 +301,25 @@ function(absl_cc_library) ${ABSL_DEFAULT_LINKOPTS} ) target_compile_definitions(${_NAME} INTERFACE ${ABSL_CC_LIB_DEFINES}) + + if(ABSL_PROPAGATE_CXX_STD) + # Abseil libraries require C++11 as the current minimum standard. + # Top-level application CMake projects should ensure a consistent C++ + # standard for all compiled sources by setting CMAKE_CXX_STANDARD. + target_compile_features(${_NAME} INTERFACE cxx_std_11) + + # (INTERFACE libraries can't have the CXX_STANDARD property set, so there + # is no legacy behavior else case). + endif() endif() # TODO currently we don't install googletest alongside abseil sources, so # installed abseil can't be tested. if(NOT ABSL_CC_LIB_TESTONLY AND ABSL_ENABLE_INSTALL) install(TARGETS ${_NAME} EXPORT ${PROJECT_NAME}Targets - RUNTIME DESTINATION ${ABSL_INSTALL_BINDIR} - LIBRARY DESTINATION ${ABSL_INSTALL_LIBDIR} - ARCHIVE DESTINATION ${ABSL_INSTALL_LIBDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} ) endif() @@ -284,11 +360,11 @@ endfunction() # "awesome_test.cc" # DEPS # absl::awesome -# gmock -# gtest_main +# GTest::gmock +# GTest::gtest_main # ) function(absl_cc_test) - if(NOT ABSL_RUN_TESTS) + if(NOT BUILD_TESTING) return() endif() @@ -338,8 +414,23 @@ function(absl_cc_test) # Add all Abseil targets to a folder in the IDE for organization. set_property(TARGET ${_NAME} PROPERTY FOLDER ${ABSL_IDE_FOLDER}/test) - set_property(TARGET ${_NAME} PROPERTY CXX_STANDARD ${ABSL_CXX_STANDARD}) - set_property(TARGET ${_NAME} PROPERTY CXX_STANDARD_REQUIRED ON) + if(ABSL_PROPAGATE_CXX_STD) + # Abseil libraries require C++11 as the current minimum standard. + # Top-level application CMake projects should ensure a consistent C++ + # standard for all compiled sources by setting CMAKE_CXX_STANDARD. + target_compile_features(${_NAME} PUBLIC cxx_std_11) + else() + # Note: This is legacy (before CMake 3.8) behavior. Setting the + # target-level CXX_STANDARD property to ABSL_CXX_STANDARD (which is + # initialized by CMAKE_CXX_STANDARD) should have no real effect, since + # that is the default value anyway. + # + # CXX_STANDARD_REQUIRED does guard against the top-level CMake project + # not having enabled CMAKE_CXX_STANDARD_REQUIRED (which prevents + # "decaying" to an older standard if the requested one isn't available). + set_property(TARGET ${_NAME} PROPERTY CXX_STANDARD ${ABSL_CXX_STANDARD}) + set_property(TARGET ${_NAME} PROPERTY CXX_STANDARD_REQUIRED ON) + endif() add_test(NAME ${_NAME} COMMAND ${_NAME}) endfunction() diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/CMake/AbseilInstallDirs.cmake b/third-party/webrtc/dependencies/third_party/abseil-cpp/CMake/AbseilInstallDirs.cmake deleted file mode 100644 index b67272f830..0000000000 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/CMake/AbseilInstallDirs.cmake +++ /dev/null @@ -1,20 +0,0 @@ -include(GNUInstallDirs) - -# absl_VERSION is only set if we are an LTS release being installed, in which -# case it may be into a system directory and so we need to make subdirectories -# for each installed version of Abseil. This mechanism is implemented in -# Abseil's internal Copybara (https://github.com/google/copybara) workflows and -# isn't visible in the CMake buildsystem itself. - -if(absl_VERSION) - set(ABSL_SUBDIR "${PROJECT_NAME}_${PROJECT_VERSION}") - set(ABSL_INSTALL_BINDIR "${CMAKE_INSTALL_BINDIR}/${ABSL_SUBDIR}") - set(ABSL_INSTALL_CONFIGDIR "${CMAKE_INSTALL_LIBDIR}/cmake/${ABSL_SUBDIR}") - set(ABSL_INSTALL_INCLUDEDIR "${CMAKE_INSTALL_INCLUDEDIR}/{ABSL_SUBDIR}") - set(ABSL_INSTALL_LIBDIR "${CMAKE_INSTALL_LIBDIR}/${ABSL_SUBDIR}") -else() - set(ABSL_INSTALL_BINDIR "${CMAKE_INSTALL_BINDIR}") - set(ABSL_INSTALL_CONFIGDIR "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}") - set(ABSL_INSTALL_INCLUDEDIR "${CMAKE_INSTALL_INCLUDEDIR}") - set(ABSL_INSTALL_LIBDIR "${CMAKE_INSTALL_LIBDIR}") -endif() \ No newline at end of file diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/CMake/Googletest/CMakeLists.txt.in b/third-party/webrtc/dependencies/third_party/abseil-cpp/CMake/Googletest/CMakeLists.txt.in index 994dac0bf7..5769e3a97b 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/CMake/Googletest/CMakeLists.txt.in +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/CMake/Googletest/CMakeLists.txt.in @@ -3,24 +3,12 @@ cmake_minimum_required(VERSION 2.8.2) project(googletest-external NONE) include(ExternalProject) -if(${ABSL_USE_GOOGLETEST_HEAD}) - ExternalProject_Add(googletest - GIT_REPOSITORY https://github.com/google/googletest.git - GIT_TAG master - SOURCE_DIR "${absl_gtest_src_dir}" - BINARY_DIR "${absl_gtest_build_dir}" - CONFIGURE_COMMAND "" - BUILD_COMMAND "" - INSTALL_COMMAND "" - TEST_COMMAND "" - ) -else() - ExternalProject_Add(googletest - SOURCE_DIR "${absl_gtest_src_dir}" - BINARY_DIR "${absl_gtest_build_dir}" - CONFIGURE_COMMAND "" - BUILD_COMMAND "" - INSTALL_COMMAND "" - TEST_COMMAND "" - ) -endif() \ No newline at end of file +ExternalProject_Add(googletest + URL "${absl_gtest_download_url}" # May be empty + SOURCE_DIR "${absl_gtest_src_dir}" + BINARY_DIR "${absl_gtest_build_dir}" + CONFIGURE_COMMAND "" + BUILD_COMMAND "" + INSTALL_COMMAND "" + TEST_COMMAND "" +) diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/CMake/README.md b/third-party/webrtc/dependencies/third_party/abseil-cpp/CMake/README.md index 04d5df3ab0..f8b27e63f6 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/CMake/README.md +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/CMake/README.md @@ -34,15 +34,16 @@ to include Abseil directly in your CMake project. 4. Add the **absl::** target you wish to use to the [`target_link_libraries()`](https://cmake.org/cmake/help/latest/command/target_link_libraries.html) section of your executable or of your library.
-Here is a short CMakeLists.txt example of a project file using Abseil. +Here is a short CMakeLists.txt example of an application project using Abseil. ```cmake -cmake_minimum_required(VERSION 3.5) -project(my_project) +cmake_minimum_required(VERSION 3.8.2) +project(my_app_project) # Pick the C++ standard to compile with. # Abseil currently supports C++11, C++14, and C++17. set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_STANDARD_REQUIRED ON) add_subdirectory(abseil-cpp) @@ -50,9 +51,47 @@ add_executable(my_exe source.cpp) target_link_libraries(my_exe absl::base absl::synchronization absl::strings) ``` +Note that if you are developing a library designed for use by other clients, you +should instead leave `CMAKE_CXX_STANDARD` unset (or only set if being built as +the current top-level CMake project) and configure the minimum required C++ +standard at the target level. If you require a later minimum C++ standard than +Abseil does, it's a good idea to also enforce that `CMAKE_CXX_STANDARD` (which +will control Abseil library targets) is set to at least that minimum. For +example: + +```cmake +cmake_minimum_required(VERSION 3.8.2) +project(my_lib_project) + +# Leave C++ standard up to the root application, so set it only if this is the +# current top-level CMake project. +if(CMAKE_SOURCE_DIR STREQUAL my_lib_project_SOURCE_DIR) + set(CMAKE_CXX_STANDARD 17) + set(CMAKE_CXX_STANDARD_REQUIRED ON) +endif() + +add_subdirectory(abseil-cpp) + +add_library(my_lib source.cpp) +target_link_libraries(my_lib absl::base absl::synchronization absl::strings) + +# Enforce that my_lib requires C++17. Important to document for clients that they +# must set CMAKE_CXX_STANDARD to 17 or higher for proper Abseil ABI compatibility +# (since otherwise, Abseil library targets could be compiled with a lower C++ +# standard than my_lib). +target_compile_features(my_lib PUBLIC cxx_std_17) +if(CMAKE_CXX_STANDARD LESS 17) + message(FATAL_ERROR + "my_lib_project requires CMAKE_CXX_STANDARD >= 17 (got: ${CMAKE_CXX_STANDARD})") +endif() +``` + +Then the top-level application project that uses your library is responsible for +setting a consistent `CMAKE_CXX_STANDARD` that is sufficiently high. + ### Running Abseil Tests with CMake -Use the `-DABSL_RUN_TESTS=ON` flag to run Abseil tests. Note that if the `-DBUILD_TESTING=OFF` flag is passed then Abseil tests will not be run. +Use the `-DBUILD_TESTING=ON` flag to run Abseil tests. You will need to provide Abseil with a Googletest dependency. There are two options for how to do this: @@ -70,7 +109,7 @@ For example, to run just the Abseil tests, you could use this script: cd path/to/abseil-cpp mkdir build cd build -cmake -DABSL_USE_GOOGLETEST_HEAD=ON -DABSL_RUN_TESTS=ON .. +cmake -DBUILD_TESTING=ON -DABSL_USE_GOOGLETEST_HEAD=ON .. make -j ctest ``` @@ -93,9 +132,54 @@ absl::flags absl::memory absl::meta absl::numeric -absl::random +absl::random_random absl::strings absl::synchronization absl::time absl::utility ``` + +## Traditional CMake Set-Up + +For larger projects, it may make sense to use the traditional CMake set-up where you build and install projects separately. + +First, you'd need to build and install Google Test: +``` +cmake -S /source/googletest -B /build/googletest -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/installation/dir -DBUILD_GMOCK=ON +cmake --build /build/googletest --target install +``` + +Then you need to configure and build Abseil. Make sure you enable `ABSL_USE_EXTERNAL_GOOGLETEST` and `ABSL_FIND_GOOGLETEST`. You also need to enable `ABSL_ENABLE_INSTALL` so that you can install Abseil itself. +``` +cmake -S /source/abseil-cpp -B /build/abseil-cpp -DCMAKE_PREFIX_PATH=/installation/dir -DCMAKE_INSTALL_PREFIX=/installation/dir -DABSL_ENABLE_INSTALL=ON -DABSL_USE_EXTERNAL_GOOGLETEST=ON -DABSL_FIND_GOOGLETEST=ON +cmake --build /temporary/build/abseil-cpp +``` + +(`CMAKE_PREFIX_PATH` is where you already have Google Test installed; `CMAKE_INSTALL_PREFIX` is where you want to have Abseil installed; they can be different.) + +Run the tests: +``` +ctest --test-dir /temporary/build/abseil-cpp +``` + +And finally install: +``` +cmake --build /temporary/build/abseil-cpp --target install +``` + +# CMake Option Synposis + +## Enable Standard CMake Installation + +`-DABSL_ENABLE_INSTALL=ON` + +## Google Test Options + +`-DBUILD_TESTING=ON` must be set to enable testing + +- Have Abseil download and build Google Test for you: `-DABSL_USE_EXTERNAL_GOOGLETEST=OFF` (default) + - Download and build latest Google Test: `-DABSL_USE_GOOGLETEST_HEAD=ON` + - Download specific Google Test version (ZIP archive): `-DABSL_GOOGLETEST_DOWNLOAD_URL=https://.../version.zip` + - Use Google Test from specific local directory: `-DABSL_LOCAL_GOOGLETEST_DIR=/path/to/googletest` +- Use Google Test included elsewhere in your project: `-DABSL_USE_EXTERNAL_GOOGLETEST=ON` +- Use standard CMake `find_package(CTest)` to find installed Google Test: `-DABSL_USE_EXTERNAL_GOOGLETEST=ON -DABSL_FIND_GOOGLETEST=ON` diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/CMake/abslConfig.cmake.in b/third-party/webrtc/dependencies/third_party/abseil-cpp/CMake/abslConfig.cmake.in index 60847fa772..62d246d01e 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/CMake/abslConfig.cmake.in +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/CMake/abslConfig.cmake.in @@ -1,7 +1,8 @@ # absl CMake configuration file. -include(FindThreads) +include(CMakeFindDependencyMacro) +find_dependency(Threads) @PACKAGE_INIT@ -include ("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake") \ No newline at end of file +include ("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake") diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/CMake/install_test_project/CMakeLists.txt b/third-party/webrtc/dependencies/third_party/abseil-cpp/CMake/install_test_project/CMakeLists.txt index 06b797e9ed..b865b2ec50 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/CMake/install_test_project/CMakeLists.txt +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/CMake/install_test_project/CMakeLists.txt @@ -18,10 +18,8 @@ cmake_minimum_required(VERSION 3.5) project(absl_cmake_testing CXX) -set(CMAKE_CXX_STANDARD 11) - add_executable(simple simple.cc) find_package(absl REQUIRED) -target_link_libraries(simple absl::strings) +target_link_libraries(simple absl::strings absl::config) diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/CMake/install_test_project/simple.cc b/third-party/webrtc/dependencies/third_party/abseil-cpp/CMake/install_test_project/simple.cc index e9e352912b..7daa7f0901 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/CMake/install_test_project/simple.cc +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/CMake/install_test_project/simple.cc @@ -14,8 +14,17 @@ // limitations under the License. #include +#include "absl/base/config.h" #include "absl/strings/substitute.h" +#if !defined(ABSL_LTS_RELEASE_VERSION) || ABSL_LTS_RELEASE_VERSION != 99998877 +#error ABSL_LTS_RELEASE_VERSION is not set correctly. +#endif + +#if !defined(ABSL_LTS_RELEASE_PATCH_LEVEL) || ABSL_LTS_RELEASE_PATCH_LEVEL != 0 +#error ABSL_LTS_RELEASE_PATCH_LEVEL is not set correctly. +#endif + int main(int argc, char** argv) { for (int i = 0; i < argc; ++i) { std::cout << absl::Substitute("Arg $0: $1\n", i, argv[i]); diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/CMake/install_test_project/test.sh b/third-party/webrtc/dependencies/third_party/abseil-cpp/CMake/install_test_project/test.sh index 99989b031d..5a78c92cd1 100755 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/CMake/install_test_project/test.sh +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/CMake/install_test_project/test.sh @@ -13,70 +13,60 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - -# "Unit" and integration tests for Absl CMake installation - -# TODO(absl-team): This script isn't fully hermetic because -# -DABSL_USE_GOOGLETEST_HEAD=ON means that this script isn't pinned to a fixed -# version of GoogleTest. This means that an upstream change to GoogleTest could -# break this test. Fix this by allowing this script to pin to a known-good -# version of GoogleTest. +# +# Unit and integration tests for Abseil LTS CMake installation # Fail on any error. Treat unset variables an error. Print commands as executed. set -euox pipefail -install_absl() { - pushd "${absl_build_dir}" - if [[ "${#}" -eq 1 ]]; then - cmake -DCMAKE_INSTALL_PREFIX="${1}" "${absl_dir}" - else - cmake "${absl_dir}" - fi - cmake --build . --target install -- -j - popd -} - -uninstall_absl() { - xargs rm < "${absl_build_dir}"/install_manifest.txt - rm -rf "${absl_build_dir}" - mkdir -p "${absl_build_dir}" -} - -lts_install="" - -while getopts ":l" lts; do - case "${lts}" in - l ) - lts_install="true" - ;; - esac -done - absl_dir=/abseil-cpp -absl_build_dir=/buildfs/absl-build +absl_build_dir=/buildfs +googletest_builddir=/googletest_builddir project_dir="${absl_dir}"/CMake/install_test_project project_build_dir=/buildfs/project-build -mkdir -p "${absl_build_dir}" +build_shared_libs="OFF" +if [ "${LINK_TYPE:-}" = "DYNAMIC" ]; then + build_shared_libs="ON" +fi + +# Build and install GoogleTest +mkdir "${googletest_builddir}" +pushd "${googletest_builddir}" +curl -L "${ABSL_GOOGLETEST_DOWNLOAD_URL}" --output "${ABSL_GOOGLETEST_COMMIT}".zip +unzip "${ABSL_GOOGLETEST_COMMIT}".zip +pushd "googletest-${ABSL_GOOGLETEST_COMMIT}" +mkdir build +pushd build +cmake -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS="${build_shared_libs}" .. +make -j $(nproc) +make install +ldconfig +popd +popd +popd + +# Run the LTS transformations +./create_lts.py 99998877 + +# Build and install Abseil +pushd "${absl_build_dir}" +cmake "${absl_dir}" \ + -DABSL_USE_EXTERNAL_GOOGLETEST=ON \ + -DABSL_FIND_GOOGLETEST=ON \ + -DCMAKE_BUILD_TYPE=Release \ + -DBUILD_TESTING=ON \ + -DBUILD_SHARED_LIBS="${build_shared_libs}" +make -j $(nproc) +ctest -j $(nproc) +make install +ldconfig +popd + +# Test the project against the installed Abseil mkdir -p "${project_build_dir}" - -if [[ "${lts_install}" ]]; then - install_dir="/usr/local" -else - install_dir="${project_build_dir}"/install -fi -mkdir -p "${install_dir}" - -# Test build, install, and link against installed abseil pushd "${project_build_dir}" -if [[ "${lts_install}" ]]; then - install_absl - cmake "${project_dir}" -else - install_absl "${install_dir}" - cmake "${project_dir}" -DCMAKE_PREFIX_PATH="${install_dir}" -fi - +cmake "${project_dir}" cmake --build . --target simple output="$(${project_build_dir}/simple "printme" 2>&1)" @@ -88,57 +78,35 @@ fi popd -# Test that we haven't accidentally made absl::abslblah -pushd "${install_dir}" - -# Starting in CMake 3.12 the default install dir is lib$bit_width -if [[ -d lib64 ]]; then - libdir="lib64" -elif [[ -d lib ]]; then - libdir="lib" -else - echo "ls *, */*, */*/*:" - ls * - ls */* - ls */*/* - echo "unknown lib dir" -fi - -if [[ "${lts_install}" ]]; then - # LTS versions append the date of the release to the subdir. - # 9999/99/99 is the dummy date used in the local_lts workflow. - absl_subdir="absl_99999999" -else - absl_subdir="absl" -fi - -if ! grep absl::strings "${libdir}/cmake/${absl_subdir}/abslTargets.cmake"; then - cat "${libdir}"/cmake/absl/abslTargets.cmake +if ! grep absl::strings "/usr/local/lib/cmake/absl/abslTargets.cmake"; then + cat "/usr/local/lib/cmake/absl/abslTargets.cmake" echo "CMake targets named incorrectly" exit 1 fi -uninstall_absl -popd +pushd "${HOME}" +cat > hello-abseil.cc << EOF +#include -if [[ ! "${lts_install}" ]]; then - # Test that we warn if installed without a prefix or a system prefix - output="$(install_absl 2>&1)" - if [[ "${output}" != *"Please set CMAKE_INSTALL_PREFIX"* ]]; then - echo "Install without prefix didn't warn as expected. Output:" - echo "${output}" - exit 1 - fi - uninstall_absl +#include "absl/strings/str_format.h" - output="$(install_absl /usr 2>&1)" - if [[ "${output}" != *"Please set CMAKE_INSTALL_PREFIX"* ]]; then - echo "Install with /usr didn't warn as expected. Output:" - echo "${output}" - exit 1 - fi - uninstall_absl +int main(int argc, char **argv) { + absl::PrintF("Hello Abseil!\n"); + return EXIT_SUCCESS; +} +EOF + +if [ "${LINK_TYPE:-}" != "DYNAMIC" ]; then + pc_args=($(pkg-config --cflags --libs --static absl_str_format)) + g++ -static -o hello-abseil hello-abseil.cc "${pc_args[@]}" +else + pc_args=($(pkg-config --cflags --libs absl_str_format)) + g++ -o hello-abseil hello-abseil.cc "${pc_args[@]}" fi +hello="$(./hello-abseil)" +[[ "${hello}" == "Hello Abseil!" ]] + +popd echo "Install test complete!" exit 0 diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/CMakeLists.txt b/third-party/webrtc/dependencies/third_party/abseil-cpp/CMakeLists.txt index e94dcd3f90..7c8bfff4c5 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/CMakeLists.txt +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/CMakeLists.txt @@ -22,15 +22,36 @@ cmake_minimum_required(VERSION 3.5) # Compiler id for Apple Clang is now AppleClang. -cmake_policy(SET CMP0025 NEW) +if (POLICY CMP0025) + cmake_policy(SET CMP0025 NEW) +endif (POLICY CMP0025) # if command can use IN_LIST -cmake_policy(SET CMP0057 NEW) +if (POLICY CMP0057) + cmake_policy(SET CMP0057 NEW) +endif (POLICY CMP0057) # Project version variables are the empty string if version is unspecified -cmake_policy(SET CMP0048 NEW) +if (POLICY CMP0048) + cmake_policy(SET CMP0048 NEW) +endif (POLICY CMP0048) -project(absl CXX) +# option() honor variables +if (POLICY CMP0077) + cmake_policy(SET CMP0077 NEW) +endif (POLICY CMP0077) + +# Allow the user to specify the MSVC runtime +if (POLICY CMP0091) + cmake_policy(SET CMP0091 NEW) +endif (POLICY CMP0091) + +# Set BUILD_TESTING to OFF by default. +# This must come before the project() and include(CTest) lines. +OPTION(BUILD_TESTING "Build tests" OFF) + +project(absl LANGUAGES CXX) +include(CTest) # Output directory is correct by default for most build setups. However, when # building Abseil as a DLL, it is important to have the DLL in the same @@ -40,10 +61,17 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) # when absl is included as subproject (i.e. using add_subdirectory(abseil-cpp)) # in the source tree of a project that uses it, install rules are disabled. -if(NOT "^${CMAKE_SOURCE_DIR}$" STREQUAL "^${PROJECT_SOURCE_DIR}$") - set(ABSL_ENABLE_INSTALL FALSE) +if(NOT CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR) + option(ABSL_ENABLE_INSTALL "Enable install rule" OFF) else() - set(ABSL_ENABLE_INSTALL TRUE) + option(ABSL_ENABLE_INSTALL "Enable install rule" ON) +endif() + +option(ABSL_PROPAGATE_CXX_STD + "Use CMake C++ standard meta features (e.g. cxx_std_11) that propagate to targets that link to Abseil" + OFF) # TODO: Default to ON for CMake 3.8 and greater. +if((${CMAKE_VERSION} VERSION_GREATER_EQUAL 3.8) AND (NOT ABSL_PROPAGATE_CXX_STD)) + message(WARNING "A future Abseil release will default ABSL_PROPAGATE_CXX_STD to ON for CMake 3.8 and up. We recommend enabling this option to ensure your project still builds correctly.") endif() list(APPEND CMAKE_MODULE_PATH @@ -51,8 +79,8 @@ list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}/absl/copts ) -include(AbseilInstallDirs) include(CMakePackageConfigHelpers) +include(GNUInstallDirs) include(AbseilDll) include(AbseilHelpers) @@ -81,41 +109,71 @@ endif() ## pthread find_package(Threads REQUIRED) +include(CMakeDependentOption) + +option(ABSL_USE_EXTERNAL_GOOGLETEST + "If ON, Abseil will assume that the targets for GoogleTest are already provided by the including project. This makes sense when Abseil is used with add_subproject." OFF) + +cmake_dependent_option(ABSL_FIND_GOOGLETEST + "If ON, Abseil will use find_package(GTest) rather than assuming that GoogleTest is already provided by the including project." + ON + "ABSL_USE_EXTERNAL_GOOGLETEST" + OFF) + + option(ABSL_USE_GOOGLETEST_HEAD - "If ON, abseil will download HEAD from googletest at config time." OFF) + "If ON, abseil will download HEAD from GoogleTest at config time." OFF) + +set(ABSL_GOOGLETEST_DOWNLOAD_URL "" CACHE STRING "If set, download GoogleTest from this URL") set(ABSL_LOCAL_GOOGLETEST_DIR "/usr/src/googletest" CACHE PATH - "If ABSL_USE_GOOGLETEST_HEAD is OFF, specifies the directory of a local googletest checkout." + "If ABSL_USE_GOOGLETEST_HEAD is OFF and ABSL_GOOGLETEST_URL is not set, specifies the directory of a local GoogleTest checkout." ) -option(ABSL_RUN_TESTS "If ON, Abseil tests will be run." OFF) - -if(${ABSL_RUN_TESTS}) - # enable CTest. This will set BUILD_TESTING to ON unless otherwise specified - # on the command line - include(CTest) - enable_testing() -endif() - -## check targets if(BUILD_TESTING) - - set(absl_gtest_build_dir ${CMAKE_BINARY_DIR}/googletest-build) - if(${ABSL_USE_GOOGLETEST_HEAD}) - set(absl_gtest_src_dir ${CMAKE_BINARY_DIR}/googletest-src) + ## check targets + if (ABSL_USE_EXTERNAL_GOOGLETEST) + if (ABSL_FIND_GOOGLETEST) + find_package(GTest REQUIRED) + else() + if (NOT TARGET gtest AND NOT TARGET GTest::gtest) + message(FATAL_ERROR "ABSL_USE_EXTERNAL_GOOGLETEST is ON and ABSL_FIND_GOOGLETEST is OFF, which means that the top-level project must build the Google Test project. However, the target gtest was not found.") + endif() + endif() else() - set(absl_gtest_src_dir ${ABSL_LOCAL_GOOGLETEST_DIR}) + set(absl_gtest_build_dir ${CMAKE_BINARY_DIR}/googletest-build) + if(ABSL_USE_GOOGLETEST_HEAD AND ABSL_GOOGLETEST_DOWNLOAD_URL) + message(FATAL_ERROR "Do not set both ABSL_USE_GOOGLETEST_HEAD and ABSL_GOOGLETEST_DOWNLOAD_URL") + endif() + if(ABSL_USE_GOOGLETEST_HEAD) + set(absl_gtest_download_url "https://github.com/google/googletest/archive/master.zip") + elseif(ABSL_GOOGLETEST_DOWNLOAD_URL) + set(absl_gtest_download_url ${ABSL_GOOGLETEST_DOWNLOAD_URL}) + endif() + if(absl_gtest_download_url) + set(absl_gtest_src_dir ${CMAKE_BINARY_DIR}/googletest-src) + else() + set(absl_gtest_src_dir ${ABSL_LOCAL_GOOGLETEST_DIR}) + endif() + include(CMake/Googletest/DownloadGTest.cmake) endif() - include(CMake/Googletest/DownloadGTest.cmake) - check_target(gtest) - check_target(gtest_main) - check_target(gmock) + if (NOT ABSL_FIND_GOOGLETEST) + # When Google Test is included directly rather than through find_package, the aliases are missing. + add_library(GTest::gtest_main ALIAS gtest_main) + add_library(GTest::gtest ALIAS gtest) + add_library(GTest::gmock ALIAS gmock) + endif() + + check_target(GTest::gtest) + check_target(GTest::gtest_main) + check_target(GTest::gmock) + check_target(GTest::gmock_main) list(APPEND ABSL_TEST_COMMON_LIBRARIES - gtest_main - gtest - gmock + GTest::gtest_main + GTest::gtest + GTest::gmock ${CMAKE_THREAD_LIBS_INIT} ) endif() @@ -138,16 +196,16 @@ if(ABSL_ENABLE_INSTALL) # install as a subdirectory only install(EXPORT ${PROJECT_NAME}Targets NAMESPACE absl:: - DESTINATION "${ABSL_INSTALL_CONFIGDIR}" + DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}" ) configure_package_config_file( CMake/abslConfig.cmake.in "${PROJECT_BINARY_DIR}/${PROJECT_NAME}Config.cmake" - INSTALL_DESTINATION "${ABSL_INSTALL_CONFIGDIR}" + INSTALL_DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}" ) install(FILES "${PROJECT_BINARY_DIR}/${PROJECT_NAME}Config.cmake" - DESTINATION "${ABSL_INSTALL_CONFIGDIR}" + DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}" ) # Abseil only has a version in LTS releases. This mechanism is accomplished @@ -160,14 +218,16 @@ if(ABSL_ENABLE_INSTALL) ) install(FILES "${PROJECT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake" - DESTINATION ${ABSL_INSTALL_CONFIGDIR} + DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}" ) endif() # absl_VERSION install(DIRECTORY absl - DESTINATION ${ABSL_INSTALL_INCLUDEDIR} + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} FILES_MATCHING PATTERN "*.inc" PATTERN "*.h" - ) + PATTERN "copts" EXCLUDE + PATTERN "testdata" EXCLUDE + ) endif() # ABSL_ENABLE_INSTALL diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/FAQ.md b/third-party/webrtc/dependencies/third_party/abseil-cpp/FAQ.md index 78028fc09f..fbd92ce975 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/FAQ.md +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/FAQ.md @@ -27,7 +27,10 @@ compiler, there several ways to do this: file](https://docs.bazel.build/versions/master/guide.html#bazelrc) If you are using CMake as the build system, you'll need to add a line like -`set(CMAKE_CXX_STANDARD 17)` to your top level `CMakeLists.txt` file. See the +`set(CMAKE_CXX_STANDARD 17)` to your top level `CMakeLists.txt` file. If you +are developing a library designed to be used by other clients, you should +instead leave `CMAKE_CXX_STANDARD` unset and configure the minimum C++ standard +required by each of your library targets via `target_compile_features`. See the [CMake build instructions](https://github.com/abseil/abseil-cpp/blob/master/CMake/README.md) for more information. diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/LTS.md b/third-party/webrtc/dependencies/third_party/abseil-cpp/LTS.md deleted file mode 100644 index ade8b17c73..0000000000 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/LTS.md +++ /dev/null @@ -1,16 +0,0 @@ -# Long Term Support (LTS) Branches - -This repository contains periodic snapshots of the Abseil codebase that are -Long Term Support (LTS) branches. An LTS branch allows you to use a known -version of Abseil without interfering with other projects which may also, in -turn, use Abseil. (For more information about our releases, see the -[Abseil Release Management](https://abseil.io/about/releases) guide.) - -## LTS Branches - -The following lists LTS branches and the dates on which they have been released: - -* [LTS Branch December 18, 2018](https://github.com/abseil/abseil-cpp/tree/lts_2018_12_18/) -* [LTS Branch June 20, 2018](https://github.com/abseil/abseil-cpp/tree/lts_2018_06_20/) -* [LTS Branch August 8, 2019](https://github.com/abseil/abseil-cpp/tree/lts_2019_08_08/) -* [LTS Branch February 25, 2020](https://github.com/abseil/abseil-cpp/tree/lts_2020_02_25/) diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/OWNERS b/third-party/webrtc/dependencies/third_party/abseil-cpp/OWNERS deleted file mode 100644 index 68650639fd..0000000000 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/OWNERS +++ /dev/null @@ -1,6 +0,0 @@ -danilchap@chromium.org -kwiberg@chromium.org -mbonadei@chromium.org -phoglund@chromium.org - -# COMPONENT: Internals>Core diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/README.chromium b/third-party/webrtc/dependencies/third_party/abseil-cpp/README.chromium deleted file mode 100644 index 142914f978..0000000000 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/README.chromium +++ /dev/null @@ -1,36 +0,0 @@ -Name: Abseil -Short Name: absl -URL: https://github.com/abseil/abseil-cpp -License: Apache 2.0 -License File: LICENSE -Version: 0 -Revision: fba8a316c30690097de5d6127ad307d84a1b74ca -Security Critical: yes - -Description: -This directory contains the source code of Abseil for C++. This can be used by -Chromium's dependencies, but shouldn't be used by Chromium itself. -See: https://goo.gl/TgnJb8. - -How to update Abseil: - -1. Download the code from the Abseil git repository (see URL). - -2. Copy the content of the Abseil git repo to //third_party/abseil-cpp. - -3. From //third_party/abseil-cpp/ launch ./rename_annotations.sh. - This script will rewrite dynamic_annotations and thread_annotations - macros and function inside Abseil in order to avoid ODR violations - and macro clashing with Chromium - (see: https://github.com/abseil/abseil-cpp/issues/122). - -Local Modifications: - -* absl/copts.bzl has been translated to //third_party/absl-cpp/BUILD.gn. Both - files contain lists of compiler flags in order to reduce duplication. - -* All the BUILD.bazel files has been translated to BUILD.gn files. - -* Functions and macros in absl/base/dynamic_annotations.{h,cc} and - absl/base/thread_annotations.h have been renamed to avoid ODR - violations and macro clashes with Chromium (see step 3). diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/README.md b/third-party/webrtc/dependencies/third_party/abseil-cpp/README.md index 85de569658..db3a7b447a 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/README.md +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/README.md @@ -9,7 +9,9 @@ standard library. - [About Abseil](#about) - [Quickstart](#quickstart) - [Building Abseil](#build) +- [Support](#support) - [Codemap](#codemap) +- [Releases](#releases) - [License](#license) - [Links](#links) @@ -42,14 +44,22 @@ the Abseil code, running tests, and getting a simple binary working. ## Building Abseil -[Bazel](https://bazel.build) is the official build system for Abseil, -which is supported on most major platforms (Linux, Windows, macOS, for example) -and compilers. See the [quickstart](https://abseil.io/docs/cpp/quickstart) for -more information on building Abseil using the Bazel build system. +[Bazel](https://bazel.build) and [CMake](https://cmake.org/) are the official +build systems for Abseil. - -If you require CMake support, please check the -[CMake build instructions](CMake/README.md). +See the [quickstart](https://abseil.io/docs/cpp/quickstart) for more information +on building Abseil using the Bazel build system. + +If you require CMake support, please check the [CMake build +instructions](CMake/README.md) and [CMake +Quickstart](https://abseil.io/docs/cpp/quickstart-cmake). + +## Support + +Abseil is officially supported on many platforms. See the [Abseil +platform support +guide](https://abseil.io/docs/cpp/platforms/platforms) for details on +supported operating systems, compilers, CPUs, etc. ## Codemap @@ -62,6 +72,9 @@ Abseil contains the following C++ library components: * [`algorithm`](absl/algorithm/)
The `algorithm` library contains additions to the C++ `` library and container-based versions of such algorithms. +* [`cleanup`](absl/cleanup/) +
The `cleanup` library contains the control-flow-construct-like type + `absl::Cleanup` which is used for executing a callback on scope exit. * [`container`](absl/container/)
The `container` library contains additional STL-style containers, including Abseil's unordered "Swiss table" containers. @@ -79,6 +92,12 @@ Abseil contains the following C++ library components: available within C++14 and C++17 versions of the C++ `` library. * [`numeric`](absl/numeric/)
The `numeric` library contains C++11-compatible 128-bit integers. +* [`profiling`](absl/profiling/) +
The `profiling` library contains utility code for profiling C++ + entities. It is currently a private dependency of other Abseil libraries. +* [`status`](absl/status/) +
The `status` contains abstractions for error handling, specifically + `absl::Status` and `absl::StatusOr`. * [`strings`](absl/strings/)
The `strings` library contains a variety of strings routines and utilities, including a C++11-compatible version of the C++17 @@ -97,6 +116,15 @@ Abseil contains the following C++ library components: * [`utility`](absl/utility/)
The `utility` library contains utility and helper code. +## Releases + +Abseil recommends users "live-at-head" (update to the latest commit from the +master branch as often as possible). However, we realize this philosophy doesn't +work for every project, so we also provide [Long Term Support +Releases](https://github.com/abseil/abseil-cpp/releases) to which we backport +fixes for severe bugs. See our [release +management](https://abseil.io/about/releases) document for more details. + ## License The Abseil C++ library is licensed under the terms of the Apache diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/WORKSPACE b/third-party/webrtc/dependencies/third_party/abseil-cpp/WORKSPACE deleted file mode 100644 index f2b1046446..0000000000 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/WORKSPACE +++ /dev/null @@ -1,45 +0,0 @@ -# -# Copyright 2019 The Abseil Authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -workspace(name = "com_google_absl") -load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") - -# GoogleTest/GoogleMock framework. Used by most unit-tests. -http_archive( - name = "com_google_googletest", - urls = ["https://github.com/google/googletest/archive/b6cd405286ed8635ece71c72f118e659f4ade3fb.zip"], # 2019-01-07 - strip_prefix = "googletest-b6cd405286ed8635ece71c72f118e659f4ade3fb", - sha256 = "ff7a82736e158c077e76188232eac77913a15dac0b22508c390ab3f88e6d6d86", -) - -# Google benchmark. -http_archive( - name = "com_github_google_benchmark", - urls = ["https://github.com/google/benchmark/archive/16703ff83c1ae6d53e5155df3bb3ab0bc96083be.zip"], - strip_prefix = "benchmark-16703ff83c1ae6d53e5155df3bb3ab0bc96083be", - sha256 = "59f918c8ccd4d74b6ac43484467b500f1d64b40cc1010daa055375b322a43ba3", -) - -# C++ rules for Bazel. -http_archive( - name = "rules_cc", - sha256 = "9a446e9dd9c1bb180c86977a8dc1e9e659550ae732ae58bd2e8fd51e15b2c91d", - strip_prefix = "rules_cc-262ebec3c2296296526740db4aefce68c80de7fa", - urls = [ - "https://mirror.bazel.build/github.com/bazelbuild/rules_cc/archive/262ebec3c2296296526740db4aefce68c80de7fa.zip", - "https://github.com/bazelbuild/rules_cc/archive/262ebec3c2296296526740db4aefce68c80de7fa.zip", - ], -) diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl.gni b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl.gni deleted file mode 100644 index 1edf61ae52..0000000000 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl.gni +++ /dev/null @@ -1,80 +0,0 @@ -# Copyright 2020 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -# This file contains the definition of the template absl_source_set which -# should be the only type of target needed in abseil's BUILD.gn files. -# This template will correctly set "configs" and "public_configs" in order -# to correctly compile abseil in Chromium. -# -# Targets that set visibility should set it to something more restrictive than -# `absl_visibility` (defined below). -# -# Usage: -# Most of the times its usage will be similar to the example below but all -# the arguments avilable in source_set are also available for absl_source_set. -# -# absl_source_set("foo") { -# sources = [ "foo.cc" ] -# public = [ "foo.h" ] -# deps = [ ":bar" ] -# } - -import("//build_overrides/build.gni") - -# Usage of Abseil in Chromium is guarded by an explicit opt-in list, before -# adding projects to this list please reach out to cxx@chromium.org and CC: -# - https://cs.chromium.org/chromium/src/third_party/abseil-cpp/OWNERS -# -# More information can be found at: -# https://docs.google.com/document/d/1DgS1-A3rzboTLjpf4m1sqkJgWjnY_Ru2dokk1X1vBDU -declare_args() { - # Additional targets that can depend on absl. - # ** DISCLAIMER ** - # - # Using "additional_absl_clients" is highly discouraged because it will break - # the component build since Abseil doesn't have export annotations and WebRTC - # is already depending on it. Any CL that use "additional_absl_clients" will - # have a really high probability of being reverted. - additional_absl_clients = [] -} -assert(!is_component_build || additional_absl_clients == []) - -_chromium_absl_clients = [ - "//libassistant/*", - "//third_party/webrtc/*", - "//third_party/abseil-cpp/*", - "//third_party/googletest:gtest", -] - -absl_visibility = _chromium_absl_clients + additional_absl_clients - -template("absl_source_set") { - source_set(target_name) { - forward_variables_from(invoker, "*") - configs -= [ "//build/config/compiler:chromium_code" ] - configs += [ - "//build/config/compiler:no_chromium_code", - "//third_party/abseil-cpp:absl_default_cflags_cc", - ] - - if (!defined(public_configs)) { - public_configs = [] - } - public_configs += [ "//third_party/abseil-cpp:absl_include_config" ] - - # Usage of Abseil in Chromium is guarded by an explicit opt-in list, before - # adding projects to this list please reach out to cxx@chromium.org and CC: - # - https://cs.chromium.org/chromium/src/third_party/abseil-cpp/OWNERS - # - # More information can be found at: - # https://docs.google.com/document/d/1DgS1-A3rzboTLjpf4m1sqkJgWjnY_Ru2dokk1X1vBDU - if (!defined(visibility)) { - if (build_with_chromium) { - visibility = absl_visibility - } else { - visibility = [ "*" ] - } - } - } -} diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/CMakeLists.txt b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/CMakeLists.txt index fbfa7822b5..b1715846f0 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/CMakeLists.txt +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/CMakeLists.txt @@ -16,6 +16,7 @@ add_subdirectory(base) add_subdirectory(algorithm) +add_subdirectory(cleanup) add_subdirectory(container) add_subdirectory(debugging) add_subdirectory(flags) @@ -24,6 +25,7 @@ add_subdirectory(hash) add_subdirectory(memory) add_subdirectory(meta) add_subdirectory(numeric) +add_subdirectory(profiling) add_subdirectory(random) add_subdirectory(status) add_subdirectory(strings) diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/abseil.podspec.gen.py b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/abseil.podspec.gen.py index 6aefb794df..63752980d0 100755 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/abseil.podspec.gen.py +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/abseil.podspec.gen.py @@ -40,8 +40,8 @@ Pod::Spec.new do |s| 'USE_HEADERMAP' => 'NO', 'ALWAYS_SEARCH_USER_PATHS' => 'NO', } - s.ios.deployment_target = '7.0' - s.osx.deployment_target = '10.9' + s.ios.deployment_target = '9.0' + s.osx.deployment_target = '10.10' s.tvos.deployment_target = '9.0' s.watchos.deployment_target = '2.0' """ diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/algorithm/BUILD.gn b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/algorithm/BUILD.gn deleted file mode 100644 index 1c7b7e9123..0000000000 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/algorithm/BUILD.gn +++ /dev/null @@ -1,19 +0,0 @@ -# Copyright 2018 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -import("//third_party/abseil-cpp/absl.gni") - -absl_source_set("algorithm") { - public = [ "algorithm.h" ] - deps = [ "../base:config" ] -} - -absl_source_set("container") { - public = [ "container.h" ] - deps = [ - ":algorithm", - "../base:core_headers", - "../meta:type_traits", - ] -} diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/algorithm/CMakeLists.txt b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/algorithm/CMakeLists.txt index 56cd0fb85b..609d858946 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/algorithm/CMakeLists.txt +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/algorithm/CMakeLists.txt @@ -35,7 +35,7 @@ absl_cc_test( ${ABSL_TEST_COPTS} DEPS absl::algorithm - gmock_main + GTest::gmock_main ) absl_cc_library( @@ -65,5 +65,5 @@ absl_cc_test( absl::core_headers absl::memory absl::span - gmock_main + GTest::gmock_main ) diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/algorithm/container.h b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/algorithm/container.h index d72532decf..c38a4a63db 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/algorithm/container.h +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/algorithm/container.h @@ -90,10 +90,10 @@ using ContainerPointerType = // lookup of std::begin and std::end, i.e. // using std::begin; // using std::end; -// std::foo(begin(c), end(c); +// std::foo(begin(c), end(c)); // becomes // std::foo(container_algorithm_internal::begin(c), -// container_algorithm_internal::end(c)); +// container_algorithm_internal::end(c)); // These are meant for internal use only. template @@ -188,7 +188,7 @@ bool c_any_of(const C& c, Pred&& pred) { // c_none_of() // // Container-based version of the `std::none_of()` function to -// test if no elements in a container fulfil a condition. +// test if no elements in a container fulfill a condition. template bool c_none_of(const C& c, Pred&& pred) { return std::none_of(container_algorithm_internal::c_begin(c), @@ -340,24 +340,45 @@ container_algorithm_internal::ContainerDifferenceType c_count_if( // c_mismatch() // // Container-based version of the `std::mismatch()` function to -// return the first element where two ordered containers differ. +// return the first element where two ordered containers differ. Applies `==` to +// the first N elements of `c1` and `c2`, where N = min(size(c1), size(c2)). template container_algorithm_internal::ContainerIterPairType c_mismatch(C1& c1, C2& c2) { - return std::mismatch(container_algorithm_internal::c_begin(c1), - container_algorithm_internal::c_end(c1), - container_algorithm_internal::c_begin(c2)); + auto first1 = container_algorithm_internal::c_begin(c1); + auto last1 = container_algorithm_internal::c_end(c1); + auto first2 = container_algorithm_internal::c_begin(c2); + auto last2 = container_algorithm_internal::c_end(c2); + + for (; first1 != last1 && first2 != last2; ++first1, (void)++first2) { + // Negates equality because Cpp17EqualityComparable doesn't require clients + // to overload both `operator==` and `operator!=`. + if (!(*first1 == *first2)) { + break; + } + } + + return std::make_pair(first1, first2); } // Overload of c_mismatch() for using a predicate evaluation other than `==` as -// the function's test condition. +// the function's test condition. Applies `pred`to the first N elements of `c1` +// and `c2`, where N = min(size(c1), size(c2)). template container_algorithm_internal::ContainerIterPairType -c_mismatch(C1& c1, C2& c2, BinaryPredicate&& pred) { - return std::mismatch(container_algorithm_internal::c_begin(c1), - container_algorithm_internal::c_end(c1), - container_algorithm_internal::c_begin(c2), - std::forward(pred)); +c_mismatch(C1& c1, C2& c2, BinaryPredicate pred) { + auto first1 = container_algorithm_internal::c_begin(c1); + auto last1 = container_algorithm_internal::c_end(c1); + auto first2 = container_algorithm_internal::c_begin(c2); + auto last2 = container_algorithm_internal::c_end(c2); + + for (; first1 != last1 && first2 != last2; ++first1, (void)++first2) { + if (!pred(*first1, *first2)) { + break; + } + } + + return std::make_pair(first1, first2); } // c_equal() @@ -539,12 +560,20 @@ BidirectionalIterator c_move_backward(C&& src, BidirectionalIterator dest) { // c_swap_ranges() // // Container-based version of the `std::swap_ranges()` function to -// swap a container's elements with another container's elements. +// swap a container's elements with another container's elements. Swaps the +// first N elements of `c1` and `c2`, where N = min(size(c1), size(c2)). template container_algorithm_internal::ContainerIter c_swap_ranges(C1& c1, C2& c2) { - return std::swap_ranges(container_algorithm_internal::c_begin(c1), - container_algorithm_internal::c_end(c1), - container_algorithm_internal::c_begin(c2)); + auto first1 = container_algorithm_internal::c_begin(c1); + auto last1 = container_algorithm_internal::c_end(c1); + auto first2 = container_algorithm_internal::c_begin(c2); + auto last2 = container_algorithm_internal::c_end(c2); + + using std::swap; + for (; first1 != last1 && first2 != last2; ++first1, (void)++first2) { + swap(*first1, *first2); + } + return first2; } // c_transform() @@ -562,16 +591,23 @@ OutputIterator c_transform(const InputSequence& input, OutputIterator output, } // Overload of c_transform() for performing a transformation using a binary -// predicate. +// predicate. Applies `binary_op` to the first N elements of `c1` and `c2`, +// where N = min(size(c1), size(c2)). template OutputIterator c_transform(const InputSequence1& input1, const InputSequence2& input2, OutputIterator output, BinaryOp&& binary_op) { - return std::transform(container_algorithm_internal::c_begin(input1), - container_algorithm_internal::c_end(input1), - container_algorithm_internal::c_begin(input2), output, - std::forward(binary_op)); + auto first1 = container_algorithm_internal::c_begin(input1); + auto last1 = container_algorithm_internal::c_end(input1); + auto first2 = container_algorithm_internal::c_begin(input2); + auto last2 = container_algorithm_internal::c_end(input2); + for (; first1 != last1 && first2 != last2; + ++first1, (void)++first2, ++output) { + *output = binary_op(*first1, *first2); + } + + return output; } // c_replace() @@ -869,11 +905,11 @@ void c_sort(C& c) { // Overload of c_sort() for performing a `comp` comparison other than the // default `operator<`. -template -void c_sort(C& c, Compare&& comp) { +template +void c_sort(C& c, LessThan&& comp) { std::sort(container_algorithm_internal::c_begin(c), container_algorithm_internal::c_end(c), - std::forward(comp)); + std::forward(comp)); } // c_stable_sort() @@ -889,11 +925,11 @@ void c_stable_sort(C& c) { // Overload of c_stable_sort() for performing a `comp` comparison other than the // default `operator<`. -template -void c_stable_sort(C& c, Compare&& comp) { +template +void c_stable_sort(C& c, LessThan&& comp) { std::stable_sort(container_algorithm_internal::c_begin(c), container_algorithm_internal::c_end(c), - std::forward(comp)); + std::forward(comp)); } // c_is_sorted() @@ -908,11 +944,11 @@ bool c_is_sorted(const C& c) { // c_is_sorted() overload for performing a `comp` comparison other than the // default `operator<`. -template -bool c_is_sorted(const C& c, Compare&& comp) { +template +bool c_is_sorted(const C& c, LessThan&& comp) { return std::is_sorted(container_algorithm_internal::c_begin(c), container_algorithm_internal::c_end(c), - std::forward(comp)); + std::forward(comp)); } // c_partial_sort() @@ -930,22 +966,23 @@ void c_partial_sort( // Overload of c_partial_sort() for performing a `comp` comparison other than // the default `operator<`. -template +template void c_partial_sort( RandomAccessContainer& sequence, container_algorithm_internal::ContainerIter middle, - Compare&& comp) { + LessThan&& comp) { std::partial_sort(container_algorithm_internal::c_begin(sequence), middle, container_algorithm_internal::c_end(sequence), - std::forward(comp)); + std::forward(comp)); } // c_partial_sort_copy() // // Container-based version of the `std::partial_sort_copy()` -// function to sort elements within a container such that elements before -// `middle` are sorted in ascending order, and return the result within an -// iterator. +// function to sort the elements in the given range `result` within the larger +// `sequence` in ascending order (and using `result` as the output parameter). +// At most min(result.last - result.first, sequence.last - sequence.first) +// elements from the sequence will be stored in the result. template container_algorithm_internal::ContainerIter c_partial_sort_copy(const C& sequence, RandomAccessContainer& result) { @@ -957,15 +994,15 @@ c_partial_sort_copy(const C& sequence, RandomAccessContainer& result) { // Overload of c_partial_sort_copy() for performing a `comp` comparison other // than the default `operator<`. -template +template container_algorithm_internal::ContainerIter c_partial_sort_copy(const C& sequence, RandomAccessContainer& result, - Compare&& comp) { + LessThan&& comp) { return std::partial_sort_copy(container_algorithm_internal::c_begin(sequence), container_algorithm_internal::c_end(sequence), container_algorithm_internal::c_begin(result), container_algorithm_internal::c_end(result), - std::forward(comp)); + std::forward(comp)); } // c_is_sorted_until() @@ -981,12 +1018,12 @@ container_algorithm_internal::ContainerIter c_is_sorted_until(C& c) { // Overload of c_is_sorted_until() for performing a `comp` comparison other than // the default `operator<`. -template +template container_algorithm_internal::ContainerIter c_is_sorted_until( - C& c, Compare&& comp) { + C& c, LessThan&& comp) { return std::is_sorted_until(container_algorithm_internal::c_begin(c), container_algorithm_internal::c_end(c), - std::forward(comp)); + std::forward(comp)); } // c_nth_element() @@ -1006,14 +1043,14 @@ void c_nth_element( // Overload of c_nth_element() for performing a `comp` comparison other than // the default `operator<`. -template +template void c_nth_element( RandomAccessContainer& sequence, container_algorithm_internal::ContainerIter nth, - Compare&& comp) { + LessThan&& comp) { std::nth_element(container_algorithm_internal::c_begin(sequence), nth, container_algorithm_internal::c_end(sequence), - std::forward(comp)); + std::forward(comp)); } //------------------------------------------------------------------------------ @@ -1035,12 +1072,12 @@ container_algorithm_internal::ContainerIter c_lower_bound( // Overload of c_lower_bound() for performing a `comp` comparison other than // the default `operator<`. -template +template container_algorithm_internal::ContainerIter c_lower_bound( - Sequence& sequence, T&& value, Compare&& comp) { + Sequence& sequence, T&& value, LessThan&& comp) { return std::lower_bound(container_algorithm_internal::c_begin(sequence), container_algorithm_internal::c_end(sequence), - std::forward(value), std::forward(comp)); + std::forward(value), std::forward(comp)); } // c_upper_bound() @@ -1058,12 +1095,12 @@ container_algorithm_internal::ContainerIter c_upper_bound( // Overload of c_upper_bound() for performing a `comp` comparison other than // the default `operator<`. -template +template container_algorithm_internal::ContainerIter c_upper_bound( - Sequence& sequence, T&& value, Compare&& comp) { + Sequence& sequence, T&& value, LessThan&& comp) { return std::upper_bound(container_algorithm_internal::c_begin(sequence), container_algorithm_internal::c_end(sequence), - std::forward(value), std::forward(comp)); + std::forward(value), std::forward(comp)); } // c_equal_range() @@ -1081,12 +1118,12 @@ c_equal_range(Sequence& sequence, T&& value) { // Overload of c_equal_range() for performing a `comp` comparison other than // the default `operator<`. -template +template container_algorithm_internal::ContainerIterPairType -c_equal_range(Sequence& sequence, T&& value, Compare&& comp) { +c_equal_range(Sequence& sequence, T&& value, LessThan&& comp) { return std::equal_range(container_algorithm_internal::c_begin(sequence), container_algorithm_internal::c_end(sequence), - std::forward(value), std::forward(comp)); + std::forward(value), std::forward(comp)); } // c_binary_search() @@ -1103,12 +1140,12 @@ bool c_binary_search(Sequence&& sequence, T&& value) { // Overload of c_binary_search() for performing a `comp` comparison other than // the default `operator<`. -template -bool c_binary_search(Sequence&& sequence, T&& value, Compare&& comp) { +template +bool c_binary_search(Sequence&& sequence, T&& value, LessThan&& comp) { return std::binary_search(container_algorithm_internal::c_begin(sequence), container_algorithm_internal::c_end(sequence), std::forward(value), - std::forward(comp)); + std::forward(comp)); } //------------------------------------------------------------------------------ @@ -1129,14 +1166,14 @@ OutputIterator c_merge(const C1& c1, const C2& c2, OutputIterator result) { // Overload of c_merge() for performing a `comp` comparison other than // the default `operator<`. -template +template OutputIterator c_merge(const C1& c1, const C2& c2, OutputIterator result, - Compare&& comp) { + LessThan&& comp) { return std::merge(container_algorithm_internal::c_begin(c1), container_algorithm_internal::c_end(c1), container_algorithm_internal::c_begin(c2), container_algorithm_internal::c_end(c2), result, - std::forward(comp)); + std::forward(comp)); } // c_inplace_merge() @@ -1152,13 +1189,13 @@ void c_inplace_merge(C& c, // Overload of c_inplace_merge() for performing a merge using a `comp` other // than `operator<`. -template +template void c_inplace_merge(C& c, container_algorithm_internal::ContainerIter middle, - Compare&& comp) { + LessThan&& comp) { std::inplace_merge(container_algorithm_internal::c_begin(c), middle, container_algorithm_internal::c_end(c), - std::forward(comp)); + std::forward(comp)); } // c_includes() @@ -1176,13 +1213,13 @@ bool c_includes(const C1& c1, const C2& c2) { // Overload of c_includes() for performing a merge using a `comp` other than // `operator<`. -template -bool c_includes(const C1& c1, const C2& c2, Compare&& comp) { +template +bool c_includes(const C1& c1, const C2& c2, LessThan&& comp) { return std::includes(container_algorithm_internal::c_begin(c1), container_algorithm_internal::c_end(c1), container_algorithm_internal::c_begin(c2), container_algorithm_internal::c_end(c2), - std::forward(comp)); + std::forward(comp)); } // c_set_union() @@ -1206,7 +1243,7 @@ OutputIterator c_set_union(const C1& c1, const C2& c2, OutputIterator output) { // Overload of c_set_union() for performing a merge using a `comp` other than // `operator<`. -template ::value, void>::type, @@ -1214,18 +1251,18 @@ template ::value, void>::type> OutputIterator c_set_union(const C1& c1, const C2& c2, OutputIterator output, - Compare&& comp) { + LessThan&& comp) { return std::set_union(container_algorithm_internal::c_begin(c1), container_algorithm_internal::c_end(c1), container_algorithm_internal::c_begin(c2), container_algorithm_internal::c_end(c2), output, - std::forward(comp)); + std::forward(comp)); } // c_set_intersection() // // Container-based version of the `std::set_intersection()` function -// to return an iterator containing the intersection of two containers. +// to return an iterator containing the intersection of two sorted containers. template ::value, @@ -1235,6 +1272,11 @@ template ::type> OutputIterator c_set_intersection(const C1& c1, const C2& c2, OutputIterator output) { + // In debug builds, ensure that both containers are sorted with respect to the + // default comparator. std::set_intersection requires the containers be sorted + // using operator<. + assert(absl::c_is_sorted(c1)); + assert(absl::c_is_sorted(c2)); return std::set_intersection(container_algorithm_internal::c_begin(c1), container_algorithm_internal::c_end(c1), container_algorithm_internal::c_begin(c2), @@ -1243,7 +1285,7 @@ OutputIterator c_set_intersection(const C1& c1, const C2& c2, // Overload of c_set_intersection() for performing a merge using a `comp` other // than `operator<`. -template ::value, void>::type, @@ -1251,12 +1293,17 @@ template ::value, void>::type> OutputIterator c_set_intersection(const C1& c1, const C2& c2, - OutputIterator output, Compare&& comp) { + OutputIterator output, LessThan&& comp) { + // In debug builds, ensure that both containers are sorted with respect to the + // default comparator. std::set_intersection requires the containers be sorted + // using the same comparator. + assert(absl::c_is_sorted(c1, comp)); + assert(absl::c_is_sorted(c2, comp)); return std::set_intersection(container_algorithm_internal::c_begin(c1), container_algorithm_internal::c_end(c1), container_algorithm_internal::c_begin(c2), container_algorithm_internal::c_end(c2), output, - std::forward(comp)); + std::forward(comp)); } // c_set_difference() @@ -1281,7 +1328,7 @@ OutputIterator c_set_difference(const C1& c1, const C2& c2, // Overload of c_set_difference() for performing a merge using a `comp` other // than `operator<`. -template ::value, void>::type, @@ -1289,12 +1336,12 @@ template ::value, void>::type> OutputIterator c_set_difference(const C1& c1, const C2& c2, - OutputIterator output, Compare&& comp) { + OutputIterator output, LessThan&& comp) { return std::set_difference(container_algorithm_internal::c_begin(c1), container_algorithm_internal::c_end(c1), container_algorithm_internal::c_begin(c2), container_algorithm_internal::c_end(c2), output, - std::forward(comp)); + std::forward(comp)); } // c_set_symmetric_difference() @@ -1320,7 +1367,7 @@ OutputIterator c_set_symmetric_difference(const C1& c1, const C2& c2, // Overload of c_set_symmetric_difference() for performing a merge using a // `comp` other than `operator<`. -template ::value, void>::type, @@ -1329,13 +1376,13 @@ template ::type> OutputIterator c_set_symmetric_difference(const C1& c1, const C2& c2, OutputIterator output, - Compare&& comp) { + LessThan&& comp) { return std::set_symmetric_difference( container_algorithm_internal::c_begin(c1), container_algorithm_internal::c_end(c1), container_algorithm_internal::c_begin(c2), container_algorithm_internal::c_end(c2), output, - std::forward(comp)); + std::forward(comp)); } //------------------------------------------------------------------------------ @@ -1354,11 +1401,11 @@ void c_push_heap(RandomAccessContainer& sequence) { // Overload of c_push_heap() for performing a push operation on a heap using a // `comp` other than `operator<`. -template -void c_push_heap(RandomAccessContainer& sequence, Compare&& comp) { +template +void c_push_heap(RandomAccessContainer& sequence, LessThan&& comp) { std::push_heap(container_algorithm_internal::c_begin(sequence), container_algorithm_internal::c_end(sequence), - std::forward(comp)); + std::forward(comp)); } // c_pop_heap() @@ -1373,11 +1420,11 @@ void c_pop_heap(RandomAccessContainer& sequence) { // Overload of c_pop_heap() for performing a pop operation on a heap using a // `comp` other than `operator<`. -template -void c_pop_heap(RandomAccessContainer& sequence, Compare&& comp) { +template +void c_pop_heap(RandomAccessContainer& sequence, LessThan&& comp) { std::pop_heap(container_algorithm_internal::c_begin(sequence), container_algorithm_internal::c_end(sequence), - std::forward(comp)); + std::forward(comp)); } // c_make_heap() @@ -1392,11 +1439,11 @@ void c_make_heap(RandomAccessContainer& sequence) { // Overload of c_make_heap() for performing heap comparisons using a // `comp` other than `operator<` -template -void c_make_heap(RandomAccessContainer& sequence, Compare&& comp) { +template +void c_make_heap(RandomAccessContainer& sequence, LessThan&& comp) { std::make_heap(container_algorithm_internal::c_begin(sequence), container_algorithm_internal::c_end(sequence), - std::forward(comp)); + std::forward(comp)); } // c_sort_heap() @@ -1411,11 +1458,11 @@ void c_sort_heap(RandomAccessContainer& sequence) { // Overload of c_sort_heap() for performing heap comparisons using a // `comp` other than `operator<` -template -void c_sort_heap(RandomAccessContainer& sequence, Compare&& comp) { +template +void c_sort_heap(RandomAccessContainer& sequence, LessThan&& comp) { std::sort_heap(container_algorithm_internal::c_begin(sequence), container_algorithm_internal::c_end(sequence), - std::forward(comp)); + std::forward(comp)); } // c_is_heap() @@ -1430,11 +1477,11 @@ bool c_is_heap(const RandomAccessContainer& sequence) { // Overload of c_is_heap() for performing heap comparisons using a // `comp` other than `operator<` -template -bool c_is_heap(const RandomAccessContainer& sequence, Compare&& comp) { +template +bool c_is_heap(const RandomAccessContainer& sequence, LessThan&& comp) { return std::is_heap(container_algorithm_internal::c_begin(sequence), container_algorithm_internal::c_end(sequence), - std::forward(comp)); + std::forward(comp)); } // c_is_heap_until() @@ -1450,12 +1497,12 @@ c_is_heap_until(RandomAccessContainer& sequence) { // Overload of c_is_heap_until() for performing heap comparisons using a // `comp` other than `operator<` -template +template container_algorithm_internal::ContainerIter -c_is_heap_until(RandomAccessContainer& sequence, Compare&& comp) { +c_is_heap_until(RandomAccessContainer& sequence, LessThan&& comp) { return std::is_heap_until(container_algorithm_internal::c_begin(sequence), container_algorithm_internal::c_end(sequence), - std::forward(comp)); + std::forward(comp)); } //------------------------------------------------------------------------------ @@ -1476,12 +1523,12 @@ container_algorithm_internal::ContainerIter c_min_element( // Overload of c_min_element() for performing a `comp` comparison other than // `operator<`. -template +template container_algorithm_internal::ContainerIter c_min_element( - Sequence& sequence, Compare&& comp) { + Sequence& sequence, LessThan&& comp) { return std::min_element(container_algorithm_internal::c_begin(sequence), container_algorithm_internal::c_end(sequence), - std::forward(comp)); + std::forward(comp)); } // c_max_element() @@ -1498,12 +1545,12 @@ container_algorithm_internal::ContainerIter c_max_element( // Overload of c_max_element() for performing a `comp` comparison other than // `operator<`. -template +template container_algorithm_internal::ContainerIter c_max_element( - Sequence& sequence, Compare&& comp) { + Sequence& sequence, LessThan&& comp) { return std::max_element(container_algorithm_internal::c_begin(sequence), container_algorithm_internal::c_end(sequence), - std::forward(comp)); + std::forward(comp)); } // c_minmax_element() @@ -1521,12 +1568,12 @@ c_minmax_element(C& c) { // Overload of c_minmax_element() for performing `comp` comparisons other than // `operator<`. -template +template container_algorithm_internal::ContainerIterPairType -c_minmax_element(C& c, Compare&& comp) { +c_minmax_element(C& c, LessThan&& comp) { return std::minmax_element(container_algorithm_internal::c_begin(c), container_algorithm_internal::c_end(c), - std::forward(comp)); + std::forward(comp)); } //------------------------------------------------------------------------------ @@ -1551,15 +1598,15 @@ bool c_lexicographical_compare(Sequence1&& sequence1, Sequence2&& sequence2) { // Overload of c_lexicographical_compare() for performing a lexicographical // comparison using a `comp` operator instead of `operator<`. -template +template bool c_lexicographical_compare(Sequence1&& sequence1, Sequence2&& sequence2, - Compare&& comp) { + LessThan&& comp) { return std::lexicographical_compare( container_algorithm_internal::c_begin(sequence1), container_algorithm_internal::c_end(sequence1), container_algorithm_internal::c_begin(sequence2), container_algorithm_internal::c_end(sequence2), - std::forward(comp)); + std::forward(comp)); } // c_next_permutation() @@ -1575,11 +1622,11 @@ bool c_next_permutation(C& c) { // Overload of c_next_permutation() for performing a lexicographical // comparison using a `comp` operator instead of `operator<`. -template -bool c_next_permutation(C& c, Compare&& comp) { +template +bool c_next_permutation(C& c, LessThan&& comp) { return std::next_permutation(container_algorithm_internal::c_begin(c), container_algorithm_internal::c_end(c), - std::forward(comp)); + std::forward(comp)); } // c_prev_permutation() @@ -1595,11 +1642,11 @@ bool c_prev_permutation(C& c) { // Overload of c_prev_permutation() for performing a lexicographical // comparison using a `comp` operator instead of `operator<`. -template -bool c_prev_permutation(C& c, Compare&& comp) { +template +bool c_prev_permutation(C& c, LessThan&& comp) { return std::prev_permutation(container_algorithm_internal::c_begin(c), container_algorithm_internal::c_end(c), - std::forward(comp)); + std::forward(comp)); } //------------------------------------------------------------------------------ diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/algorithm/container_test.cc b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/algorithm/container_test.cc index 0a4abe9462..605afc8040 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/algorithm/container_test.cc +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/algorithm/container_test.cc @@ -57,9 +57,7 @@ class NonMutatingTest : public testing::Test { }; struct AccumulateCalls { - void operator()(int value) { - calls.push_back(value); - } + void operator()(int value) { calls.push_back(value); } std::vector calls; }; @@ -68,7 +66,6 @@ bool BinPredicate(int v1, int v2) { return v1 < v2; } bool Equals(int v1, int v2) { return v1 == v2; } bool IsOdd(int x) { return x % 2 != 0; } - TEST_F(NonMutatingTest, Distance) { EXPECT_EQ(container_.size(), absl::c_distance(container_)); EXPECT_EQ(sequence_.size(), absl::c_distance(sequence_)); @@ -151,13 +148,90 @@ TEST_F(NonMutatingTest, CountIf) { } TEST_F(NonMutatingTest, Mismatch) { - absl::c_mismatch(container_, sequence_); - absl::c_mismatch(sequence_, container_); + // Testing necessary as absl::c_mismatch executes logic. + { + auto result = absl::c_mismatch(vector_, sequence_); + EXPECT_EQ(result.first, vector_.end()); + EXPECT_EQ(result.second, sequence_.end()); + } + { + auto result = absl::c_mismatch(sequence_, vector_); + EXPECT_EQ(result.first, sequence_.end()); + EXPECT_EQ(result.second, vector_.end()); + } + + sequence_.back() = 5; + { + auto result = absl::c_mismatch(vector_, sequence_); + EXPECT_EQ(result.first, std::prev(vector_.end())); + EXPECT_EQ(result.second, std::prev(sequence_.end())); + } + { + auto result = absl::c_mismatch(sequence_, vector_); + EXPECT_EQ(result.first, std::prev(sequence_.end())); + EXPECT_EQ(result.second, std::prev(vector_.end())); + } + + sequence_.pop_back(); + { + auto result = absl::c_mismatch(vector_, sequence_); + EXPECT_EQ(result.first, std::prev(vector_.end())); + EXPECT_EQ(result.second, sequence_.end()); + } + { + auto result = absl::c_mismatch(sequence_, vector_); + EXPECT_EQ(result.first, sequence_.end()); + EXPECT_EQ(result.second, std::prev(vector_.end())); + } + { + struct NoNotEquals { + constexpr bool operator==(NoNotEquals) const { return true; } + constexpr bool operator!=(NoNotEquals) const = delete; + }; + std::vector first; + std::list second; + + // Check this still compiles. + absl::c_mismatch(first, second); + } } TEST_F(NonMutatingTest, MismatchWithPredicate) { - absl::c_mismatch(container_, sequence_, BinPredicate); - absl::c_mismatch(sequence_, container_, BinPredicate); + // Testing necessary as absl::c_mismatch executes logic. + { + auto result = absl::c_mismatch(vector_, sequence_, BinPredicate); + EXPECT_EQ(result.first, vector_.begin()); + EXPECT_EQ(result.second, sequence_.begin()); + } + { + auto result = absl::c_mismatch(sequence_, vector_, BinPredicate); + EXPECT_EQ(result.first, sequence_.begin()); + EXPECT_EQ(result.second, vector_.begin()); + } + + sequence_.front() = 0; + { + auto result = absl::c_mismatch(vector_, sequence_, BinPredicate); + EXPECT_EQ(result.first, vector_.begin()); + EXPECT_EQ(result.second, sequence_.begin()); + } + { + auto result = absl::c_mismatch(sequence_, vector_, BinPredicate); + EXPECT_EQ(result.first, std::next(sequence_.begin())); + EXPECT_EQ(result.second, std::next(vector_.begin())); + } + + sequence_.clear(); + { + auto result = absl::c_mismatch(vector_, sequence_, BinPredicate); + EXPECT_EQ(result.first, vector_.begin()); + EXPECT_EQ(result.second, sequence_.end()); + } + { + auto result = absl::c_mismatch(sequence_, vector_, BinPredicate); + EXPECT_EQ(result.first, sequence_.end()); + EXPECT_EQ(result.second, vector_.begin()); + } } TEST_F(NonMutatingTest, Equal) { @@ -519,11 +593,9 @@ TEST_F(SortingTest, IsSortedUntil) { TEST_F(SortingTest, NthElement) { std::vector unsorted = {2, 4, 1, 3}; absl::c_nth_element(unsorted, unsorted.begin() + 2); - EXPECT_THAT(unsorted, - ElementsAre(Lt(3), Lt(3), 3, Gt(3))); + EXPECT_THAT(unsorted, ElementsAre(Lt(3), Lt(3), 3, Gt(3))); absl::c_nth_element(unsorted, unsorted.begin() + 2, std::greater()); - EXPECT_THAT(unsorted, - ElementsAre(Gt(2), Gt(2), 2, Lt(2))); + EXPECT_THAT(unsorted, ElementsAre(Gt(2), Gt(2), 2, Lt(2))); } TEST(MutatingTest, IsPartitioned) { @@ -676,6 +748,15 @@ TEST(MutatingTest, SwapRanges) { absl::c_swap_ranges(odds, evens); EXPECT_THAT(odds, ElementsAre(1, 3, 5)); EXPECT_THAT(evens, ElementsAre(2, 4, 6)); + + odds.pop_back(); + absl::c_swap_ranges(odds, evens); + EXPECT_THAT(odds, ElementsAre(2, 4)); + EXPECT_THAT(evens, ElementsAre(1, 3, 6)); + + absl::c_swap_ranges(evens, odds); + EXPECT_THAT(odds, ElementsAre(1, 3)); + EXPECT_THAT(evens, ElementsAre(2, 4, 6)); } TEST_F(NonMutatingTest, Transform) { @@ -690,6 +771,20 @@ TEST_F(NonMutatingTest, Transform) { EXPECT_EQ(std::vector({1, 5, 4}), z); *end = 7; EXPECT_EQ(std::vector({1, 5, 4, 7}), z); + + z.clear(); + y.pop_back(); + end = absl::c_transform(x, y, std::back_inserter(z), std::plus()); + EXPECT_EQ(std::vector({1, 5}), z); + *end = 7; + EXPECT_EQ(std::vector({1, 5, 7}), z); + + z.clear(); + std::swap(x, y); + end = absl::c_transform(x, y, std::back_inserter(z), std::plus()); + EXPECT_EQ(std::vector({1, 5}), z); + *end = 7; + EXPECT_EQ(std::vector({1, 5, 7}), z); } TEST(MutatingTest, Replace) { @@ -755,10 +850,9 @@ MATCHER_P2(IsElement, key, value, "") { TEST(MutatingTest, StableSort) { std::vector test_vector = {{1, 1}, {2, 1}, {2, 0}, {1, 0}, {2, 2}}; absl::c_stable_sort(test_vector); - EXPECT_THAT( - test_vector, - ElementsAre(IsElement(1, 1), IsElement(1, 0), IsElement(2, 1), - IsElement(2, 0), IsElement(2, 2))); + EXPECT_THAT(test_vector, + ElementsAre(IsElement(1, 1), IsElement(1, 0), IsElement(2, 1), + IsElement(2, 0), IsElement(2, 2))); } TEST(MutatingTest, StableSortWithPredicate) { @@ -766,10 +860,9 @@ TEST(MutatingTest, StableSortWithPredicate) { absl::c_stable_sort(test_vector, [](const Element& e1, const Element& e2) { return e2 < e1; }); - EXPECT_THAT( - test_vector, - ElementsAre(IsElement(2, 1), IsElement(2, 0), IsElement(2, 2), - IsElement(1, 1), IsElement(1, 0))); + EXPECT_THAT(test_vector, + ElementsAre(IsElement(2, 1), IsElement(2, 0), IsElement(2, 2), + IsElement(1, 1), IsElement(1, 0))); } TEST(MutatingTest, ReplaceCopyIf) { diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/BUILD.gn b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/BUILD.gn deleted file mode 100644 index e34065f96b..0000000000 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/BUILD.gn +++ /dev/null @@ -1,304 +0,0 @@ -# Copyright 2018 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -import("//third_party/abseil-cpp/absl.gni") - -absl_source_set("atomic_hook") { - public = [ "internal/atomic_hook.h" ] - deps = [ - ":config", - ":core_headers", - ] - visibility = [] - visibility += [ "../*" ] -} - -absl_source_set("errno_saver") { - public = [ "internal/errno_saver.h" ] - deps = [ ":config" ] - visibility = [] - visibility += [ "../*" ] -} - -absl_source_set("log_severity") { - sources = [ "log_severity.cc" ] - public = [ "log_severity.h" ] - deps = [ - ":config", - ":core_headers", - ] -} - -absl_source_set("raw_logging_internal") { - sources = [ "internal/raw_logging.cc" ] - public = [ "internal/raw_logging.h" ] - deps = [ - ":atomic_hook", - ":config", - ":core_headers", - ":log_severity", - ] - visibility = [] - visibility += [ "../*" ] -} - -absl_source_set("spinlock_wait") { - sources = [ - "internal/spinlock_akaros.inc", - "internal/spinlock_linux.inc", - "internal/spinlock_posix.inc", - "internal/spinlock_wait.cc", - "internal/spinlock_win32.inc", - ] - public = [ "internal/spinlock_wait.h" ] - deps = [ - ":base_internal", - ":core_headers", - ":errno_saver", - ] - visibility = [] - visibility += [ "../base:*" ] -} - -absl_source_set("config") { - public = [ - "config.h", - "options.h", - "policy_checks.h", - ] -} - -config("clang_support_dynamic_annotations") { - cflags_cc = [ "-D__CLANG_SUPPORT_DYN_ANNOTATION__" ] -} - -absl_source_set("dynamic_annotations") { - public_configs = [ ":clang_support_dynamic_annotations" ] - sources = [ "dynamic_annotations.cc" ] - public = [ "dynamic_annotations.h" ] - - # Abseil's dynamic annotations are only visible inside Abseil because - # their usage is deprecated in Chromium (see README.chromium for more info). - visibility = [] - visibility = [ "../*" ] -} - -absl_source_set("core_headers") { - public = [ - "attributes.h", - "const_init.h", - "macros.h", - "optimization.h", - "port.h", - "thread_annotations.h", - ] - deps = [ ":config" ] -} - -absl_source_set("malloc_internal") { - sources = [ "internal/low_level_alloc.cc" ] - public = [ - "internal/direct_mmap.h", - "internal/low_level_alloc.h", - ] - deps = [ - ":base", - ":base_internal", - ":config", - ":core_headers", - ":dynamic_annotations", - ":raw_logging_internal", - ] -} - -absl_source_set("base_internal") { - public = [ - "internal/hide_ptr.h", - "internal/identity.h", - "internal/inline_variable.h", - "internal/invoke.h", - "internal/scheduling_mode.h", - ] - deps = [ - ":config", - "../meta:type_traits", - ] - visibility = [] - visibility += [ "../*" ] -} - -absl_source_set("base") { - sources = [ - "internal/cycleclock.cc", - "internal/spinlock.cc", - "internal/sysinfo.cc", - "internal/thread_identity.cc", - "internal/unscaledcycleclock.cc", - ] - public = [ - "call_once.h", - "casts.h", - "internal/cycleclock.h", - "internal/low_level_scheduling.h", - "internal/per_thread_tls.h", - "internal/spinlock.h", - "internal/sysinfo.h", - "internal/thread_identity.h", - "internal/tsan_mutex_interface.h", - "internal/unscaledcycleclock.h", - ] - - # TODO(mbonadei): The bazel file has: - # "-DEFAULTLIB:advapi32.lib" - # understand if this is needed here as well. - deps = [ - ":atomic_hook", - ":base_internal", - ":config", - ":core_headers", - ":dynamic_annotations", - ":log_severity", - ":raw_logging_internal", - ":spinlock_wait", - "../meta:type_traits", - ] -} - -absl_source_set("throw_delegate") { - sources = [ "internal/throw_delegate.cc" ] - public = [ "internal/throw_delegate.h" ] - deps = [ - ":config", - ":raw_logging_internal", - ] - visibility = [] - visibility += [ "../*" ] -} - -absl_source_set("exception_testing") { - testonly = true - public = [ "internal/exception_testing.h" ] - deps = [ ":config" ] - visibility = [] - visibility += [ "../*" ] -} - -absl_source_set("pretty_function") { - public = [ "internal/pretty_function.h" ] - visibility = [] - visibility += [ "../*" ] -} - -# TODO(mbonadei): This target throws by design. We should probably -# just remove it. -# source_set("exception_safety_testing") { -# testonly = true -# configs -= [ "//build/config/compiler:chromium_code" ] -# configs += [ -# "//build/config/compiler:no_chromium_code", -# "//third_party/abseil-cpp:absl_test_cflags_cc", -# ] -# public_configs = [ "//third_party/abseil-cpp:absl_include_config" ] -# sources = [ -# "internal/exception_safety_testing.cc", -# ] -# public = [ -# "internal/exception_safety_testing.h", -# ] -# deps = [ -# ":config", -# ":pretty_function", -# "../memory", -# "../meta:type_traits", -# "../strings", -# "../utility", -# "//testing/gtest", -# ] -# } - -absl_source_set("spinlock_test_common") { - testonly = true - sources = [ "spinlock_test_common.cc" ] - deps = [ - ":base", - ":base_internal", - ":core_headers", - "../synchronization", - "//testing/gtest", - ] -} - -absl_source_set("endian") { - public = [ - "internal/endian.h", - "internal/unaligned_access.h", - ] - deps = [ - ":config", - ":core_headers", - ] -} - -absl_source_set("bits") { - public = [ "internal/bits.h" ] - deps = [ - ":config", - ":core_headers", - ] - visibility = [] - visibility += [ "../*" ] -} - -absl_source_set("exponential_biased") { - sources = [ "internal/exponential_biased.cc" ] - public = [ "internal/exponential_biased.h" ] - deps = [ - ":config", - ":core_headers", - ] - visibility = [] - visibility += [ "../*" ] -} - -absl_source_set("periodic_sampler") { - sources = [ "internal/periodic_sampler.cc" ] - public = [ "internal/periodic_sampler.h" ] - deps = [ - ":core_headers", - ":exponential_biased", - ] -} - -absl_source_set("scoped_set_env") { - testonly = true - public = [ "internal/scoped_set_env.h" ] - sources = [ "internal/scoped_set_env.cc" ] - deps = [ - ":config", - ":raw_logging_internal", - ] - visibility = [] - visibility += [ "../*" ] -} - -absl_source_set("strerror") { - sources = ["internal/strerror.cc"] - public = ["internal/strerror.h"] - deps = [ - ":config", - ":core_headers", - ":errno_saver", - ] - visibility = [] - visibility += [ "../*" ] -} - -absl_source_set("fast_type_id") { - public = ["internal/fast_type_id.h"] - deps = [ - ":config", - ] - visibility = [] - visibility += [ "../*" ] -} diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/CMakeLists.txt b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/CMakeLists.txt index 5454992002..7d56aa1346 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/CMakeLists.txt +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/CMakeLists.txt @@ -105,11 +105,11 @@ absl_cc_library( HDRS "dynamic_annotations.h" SRCS - "dynamic_annotations.cc" + "internal/dynamic_annotations.h" COPTS ${ABSL_DEFAULT_COPTS} - DEFINES - "__CLANG_SUPPORT_DYN_ANNOTATION__" + DEPS + absl::config PUBLIC ) @@ -191,7 +191,7 @@ absl_cc_library( ${ABSL_DEFAULT_COPTS} LINKOPTS ${ABSL_DEFAULT_LINKOPTS} - $<$:${LIBRT}> + $<$:-lrt> $<$:"advapi32"> DEPS absl::atomic_hook @@ -230,7 +230,7 @@ absl_cc_library( ${ABSL_DEFAULT_COPTS} DEPS absl::config - gtest + GTest::gtest TESTONLY ) @@ -259,7 +259,7 @@ absl_cc_library( absl::meta absl::strings absl::utility - gtest + GTest::gtest TESTONLY ) @@ -273,7 +273,7 @@ absl_cc_test( DEPS absl::exception_safety_testing absl::memory - gtest_main + GTest::gtest_main ) absl_cc_library( @@ -300,8 +300,8 @@ absl_cc_test( absl::atomic_hook_test_helper absl::atomic_hook absl::core_headers - gmock - gtest_main + GTest::gmock + GTest::gtest_main ) absl_cc_test( @@ -314,7 +314,7 @@ absl_cc_test( DEPS absl::base absl::core_headers - gtest_main + GTest::gtest_main ) absl_cc_test( @@ -327,8 +327,8 @@ absl_cc_test( DEPS absl::errno_saver absl::strerror - gmock - gtest_main + GTest::gmock + GTest::gtest_main ) absl_cc_test( @@ -342,7 +342,7 @@ absl_cc_test( absl::base absl::config absl::throw_delegate - gtest_main + GTest::gtest_main ) absl_cc_test( @@ -357,7 +357,7 @@ absl_cc_test( ${ABSL_TEST_COPTS} DEPS absl::base_internal - gtest_main + GTest::gtest_main ) absl_cc_test( @@ -371,8 +371,8 @@ absl_cc_test( absl::base_internal absl::memory absl::strings - gmock - gtest_main + GTest::gmock + GTest::gtest_main ) absl_cc_library( @@ -384,10 +384,11 @@ absl_cc_library( ${ABSL_TEST_COPTS} DEPS absl::base + absl::config absl::base_internal absl::core_headers absl::synchronization - gtest + GTest::gtest TESTONLY ) @@ -402,9 +403,10 @@ absl_cc_test( DEPS absl::base absl::base_internal + absl::config absl::core_headers absl::synchronization - gtest_main + GTest::gtest_main ) absl_cc_library( @@ -416,6 +418,7 @@ absl_cc_library( COPTS ${ABSL_DEFAULT_COPTS} DEPS + absl::base absl::config absl::core_headers PUBLIC @@ -432,7 +435,7 @@ absl_cc_test( absl::base absl::config absl::endian - gtest_main + GTest::gtest_main ) absl_cc_test( @@ -445,7 +448,7 @@ absl_cc_test( DEPS absl::config absl::synchronization - gtest_main + GTest::gtest_main ) absl_cc_test( @@ -459,7 +462,7 @@ absl_cc_test( absl::base absl::core_headers absl::synchronization - gtest_main + GTest::gtest_main ) absl_cc_test( @@ -472,7 +475,7 @@ absl_cc_test( DEPS absl::raw_logging_internal absl::strings - gtest_main + GTest::gtest_main ) absl_cc_test( @@ -485,7 +488,7 @@ absl_cc_test( DEPS absl::base absl::synchronization - gtest_main + GTest::gtest_main ) absl_cc_test( @@ -497,6 +500,7 @@ absl_cc_test( ${ABSL_TEST_COPTS} DEPS absl::malloc_internal + absl::node_hash_map Threads::Threads ) @@ -512,31 +516,7 @@ absl_cc_test( absl::core_headers absl::synchronization Threads::Threads - gtest_main -) - -absl_cc_library( - NAME - bits - HDRS - "internal/bits.h" - COPTS - ${ABSL_DEFAULT_COPTS} - DEPS - absl::config - absl::core_headers -) - -absl_cc_test( - NAME - bits_test - SRCS - "internal/bits_test.cc" - COPTS - ${ABSL_TEST_COPTS} - DEPS - absl::bits - gtest_main + GTest::gtest_main ) absl_cc_library( @@ -563,7 +543,7 @@ absl_cc_test( DEPS absl::exponential_biased absl::strings - gmock_main + GTest::gmock_main ) absl_cc_library( @@ -590,7 +570,7 @@ absl_cc_test( DEPS absl::core_headers absl::periodic_sampler - gmock_main + GTest::gmock_main ) absl_cc_library( @@ -616,7 +596,7 @@ absl_cc_test( ${ABSL_TEST_COPTS} DEPS absl::scoped_set_env - gtest_main + GTest::gtest_main ) absl_cc_test( @@ -640,8 +620,8 @@ absl_cc_test( absl::flags_marshalling absl::log_severity absl::strings - gmock - gtest_main + GTest::gmock + GTest::gtest_main ) absl_cc_library( @@ -671,8 +651,8 @@ absl_cc_test( DEPS absl::strerror absl::strings - gmock - gtest_main + GTest::gmock + GTest::gtest_main ) absl_cc_library( @@ -697,5 +677,18 @@ absl_cc_test( ${ABSL_TEST_COPTS} DEPS absl::fast_type_id - gtest_main + GTest::gtest_main +) + +absl_cc_test( + NAME + optimization_test + SRCS + "optimization_test.cc" + COPTS + ${ABSL_TEST_COPTS} + DEPS + absl::core_headers + absl::optional + GTest::gtest_main ) diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/attributes.h b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/attributes.h index b4bb6cf873..2665d8f387 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/attributes.h +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/attributes.h @@ -18,8 +18,6 @@ // These macros are used within Abseil and allow the compiler to optimize, where // applicable, certain function calls. // -// This file is used for both C and C++! -// // Most macros here are exposing GCC or Clang features, and are stubbed out for // other compilers. // @@ -32,34 +30,12 @@ // of them are not supported in older version of Clang. Thus, we check // `__has_attribute()` first. If the check fails, we check if we are on GCC and // assume the attribute exists on GCC (which is verified on GCC 4.7). -// -// ----------------------------------------------------------------------------- -// Sanitizer Attributes -// ----------------------------------------------------------------------------- -// -// Sanitizer-related attributes are not "defined" in this file (and indeed -// are not defined as such in any file). To utilize the following -// sanitizer-related attributes within your builds, define the following macros -// within your build using a `-D` flag, along with the given value for -// `-fsanitize`: -// -// * `ADDRESS_SANITIZER` + `-fsanitize=address` (Clang, GCC 4.8) -// * `MEMORY_SANITIZER` + `-fsanitize=memory` (Clang-only) -// * `THREAD_SANITIZER + `-fsanitize=thread` (Clang, GCC 4.8+) -// * `UNDEFINED_BEHAVIOR_SANITIZER` + `-fsanitize=undefined` (Clang, GCC 4.9+) -// * `CONTROL_FLOW_INTEGRITY` + -fsanitize=cfi (Clang-only) -// -// Example: -// -// // Enable branches in the Abseil code that are tagged for ASan: -// $ bazel build --copt=-DADDRESS_SANITIZER --copt=-fsanitize=address -// --linkopt=-fsanitize=address *target* -// -// Since these macro names are only supported by GCC and Clang, we only check -// for `__GNUC__` (GCC or Clang) and the above macros. + #ifndef ABSL_BASE_ATTRIBUTES_H_ #define ABSL_BASE_ATTRIBUTES_H_ +#include "absl/base/config.h" + // ABSL_HAVE_ATTRIBUTE // // A function-like feature checking macro that is a wrapper around @@ -143,7 +119,7 @@ #if ABSL_HAVE_ATTRIBUTE(disable_tail_calls) #define ABSL_HAVE_ATTRIBUTE_NO_TAIL_CALL 1 #define ABSL_ATTRIBUTE_NO_TAIL_CALL __attribute__((disable_tail_calls)) -#elif defined(__GNUC__) && !defined(__clang__) +#elif defined(__GNUC__) && !defined(__clang__) && !defined(__e2k__) #define ABSL_HAVE_ATTRIBUTE_NO_TAIL_CALL 1 #define ABSL_ATTRIBUTE_NO_TAIL_CALL \ __attribute__((optimize("no-optimize-sibling-calls"))) @@ -155,14 +131,14 @@ // ABSL_ATTRIBUTE_WEAK // // Tags a function as weak for the purposes of compilation and linking. -// Weak attributes currently do not work properly in LLVM's Windows backend, -// so disable them there. See https://bugs.llvm.org/show_bug.cgi?id=37598 +// Weak attributes did not work properly in LLVM's Windows backend before +// 9.0.0, so disable them there. See https://bugs.llvm.org/show_bug.cgi?id=37598 // for further information. // The MinGW compiler doesn't complain about the weak attribute until the link // step, presumably because Windows doesn't use ELF binaries. #if (ABSL_HAVE_ATTRIBUTE(weak) || \ (defined(__GNUC__) && !defined(__clang__))) && \ - !(defined(__llvm__) && defined(_WIN32)) && !defined(__MINGW32__) + (!defined(_WIN32) || __clang_major__ < 9) && !defined(__MINGW32__) #undef ABSL_ATTRIBUTE_WEAK #define ABSL_ATTRIBUTE_WEAK __attribute__((weak)) #define ABSL_HAVE_ATTRIBUTE_WEAK 1 @@ -234,7 +210,7 @@ // out of bounds or does other scary things with memory. // NOTE: GCC supports AddressSanitizer(asan) since 4.8. // https://gcc.gnu.org/gcc-4.8/changes.html -#if defined(__GNUC__) +#if ABSL_HAVE_ATTRIBUTE(no_sanitize_address) #define ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS __attribute__((no_sanitize_address)) #else #define ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS @@ -242,13 +218,13 @@ // ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY // -// Tells the MemorySanitizer to relax the handling of a given function. All -// "Use of uninitialized value" warnings from such functions will be suppressed, -// and all values loaded from memory will be considered fully initialized. -// This attribute is similar to the ADDRESS_SANITIZER attribute above, but deals -// with initialized-ness rather than addressability issues. +// Tells the MemorySanitizer to relax the handling of a given function. All "Use +// of uninitialized value" warnings from such functions will be suppressed, and +// all values loaded from memory will be considered fully initialized. This +// attribute is similar to the ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS attribute +// above, but deals with initialized-ness rather than addressability issues. // NOTE: MemorySanitizer(msan) is supported by Clang but not GCC. -#if defined(__clang__) +#if ABSL_HAVE_ATTRIBUTE(no_sanitize_memory) #define ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY __attribute__((no_sanitize_memory)) #else #define ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY @@ -259,7 +235,7 @@ // Tells the ThreadSanitizer to not instrument a given function. // NOTE: GCC supports ThreadSanitizer(tsan) since 4.8. // https://gcc.gnu.org/gcc-4.8/changes.html -#if defined(__GNUC__) +#if ABSL_HAVE_ATTRIBUTE(no_sanitize_thread) #define ABSL_ATTRIBUTE_NO_SANITIZE_THREAD __attribute__((no_sanitize_thread)) #else #define ABSL_ATTRIBUTE_NO_SANITIZE_THREAD @@ -271,8 +247,10 @@ // where certain behavior (eg. division by zero) is being used intentionally. // NOTE: GCC supports UndefinedBehaviorSanitizer(ubsan) since 4.9. // https://gcc.gnu.org/gcc-4.9/changes.html -#if defined(__GNUC__) && \ - (defined(UNDEFINED_BEHAVIOR_SANITIZER) || defined(ADDRESS_SANITIZER)) +#if ABSL_HAVE_ATTRIBUTE(no_sanitize_undefined) +#define ABSL_ATTRIBUTE_NO_SANITIZE_UNDEFINED \ + __attribute__((no_sanitize_undefined)) +#elif ABSL_HAVE_ATTRIBUTE(no_sanitize) #define ABSL_ATTRIBUTE_NO_SANITIZE_UNDEFINED \ __attribute__((no_sanitize("undefined"))) #else @@ -283,7 +261,7 @@ // // Tells the ControlFlowIntegrity sanitizer to not instrument a given function. // See https://clang.llvm.org/docs/ControlFlowIntegrity.html for details. -#if defined(__GNUC__) && defined(CONTROL_FLOW_INTEGRITY) +#if ABSL_HAVE_ATTRIBUTE(no_sanitize) #define ABSL_ATTRIBUTE_NO_SANITIZE_CFI __attribute__((no_sanitize("cfi"))) #else #define ABSL_ATTRIBUTE_NO_SANITIZE_CFI @@ -293,7 +271,7 @@ // // Tells the SafeStack to not instrument a given function. // See https://clang.llvm.org/docs/SafeStack.html for details. -#if defined(__GNUC__) && defined(SAFESTACK_SANITIZER) +#if ABSL_HAVE_ATTRIBUTE(no_sanitize) #define ABSL_ATTRIBUTE_NO_SANITIZE_SAFESTACK \ __attribute__((no_sanitize("safe-stack"))) #else @@ -303,10 +281,7 @@ // ABSL_ATTRIBUTE_RETURNS_NONNULL // // Tells the compiler that a particular function never returns a null pointer. -#if ABSL_HAVE_ATTRIBUTE(returns_nonnull) || \ - (defined(__GNUC__) && \ - (__GNUC__ > 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 9)) && \ - !defined(__clang__)) +#if ABSL_HAVE_ATTRIBUTE(returns_nonnull) #define ABSL_ATTRIBUTE_RETURNS_NONNULL __attribute__((returns_nonnull)) #else #define ABSL_ATTRIBUTE_RETURNS_NONNULL @@ -546,6 +521,13 @@ // ABSL_ATTRIBUTE_UNUSED // // Prevents the compiler from complaining about variables that appear unused. +// +// For code or headers that are assured to only build with C++17 and up, prefer +// just using the standard '[[maybe_unused]]' directly over this macro. +// +// Due to differences in positioning requirements between the old, compiler +// specific __attribute__ syntax and the now standard [[maybe_unused]], this +// macro does not attempt to take advantage of '[[maybe_unused]]'. #if ABSL_HAVE_ATTRIBUTE(unused) || (defined(__GNUC__) && !defined(__clang__)) #undef ABSL_ATTRIBUTE_UNUSED #define ABSL_ATTRIBUTE_UNUSED __attribute__((__unused__)) @@ -566,13 +548,19 @@ // ABSL_ATTRIBUTE_PACKED // // Instructs the compiler not to use natural alignment for a tagged data -// structure, but instead to reduce its alignment to 1. This attribute can -// either be applied to members of a structure or to a structure in its -// entirety. Applying this attribute (judiciously) to a structure in its -// entirety to optimize the memory footprint of very commonly-used structs is -// fine. Do not apply this attribute to a structure in its entirety if the -// purpose is to control the offsets of the members in the structure. Instead, -// apply this attribute only to structure members that need it. +// structure, but instead to reduce its alignment to 1. +// +// Therefore, DO NOT APPLY THIS ATTRIBUTE TO STRUCTS CONTAINING ATOMICS. Doing +// so can cause atomic variables to be mis-aligned and silently violate +// atomicity on x86. +// +// This attribute can either be applied to members of a structure or to a +// structure in its entirety. Applying this attribute (judiciously) to a +// structure in its entirety to optimize the memory footprint of very +// commonly-used structs is fine. Do not apply this attribute to a structure in +// its entirety if the purpose is to control the offsets of the members in the +// structure. Instead, apply this attribute only to structure members that need +// it. // // When applying ABSL_ATTRIBUTE_PACKED only to specific structure members the // natural alignment of structure members not annotated is preserved. Aligned @@ -594,6 +582,79 @@ #define ABSL_ATTRIBUTE_FUNC_ALIGN(bytes) #endif +// ABSL_FALLTHROUGH_INTENDED +// +// Annotates implicit fall-through between switch labels, allowing a case to +// indicate intentional fallthrough and turn off warnings about any lack of a +// `break` statement. The ABSL_FALLTHROUGH_INTENDED macro should be followed by +// a semicolon and can be used in most places where `break` can, provided that +// no statements exist between it and the next switch label. +// +// Example: +// +// switch (x) { +// case 40: +// case 41: +// if (truth_is_out_there) { +// ++x; +// ABSL_FALLTHROUGH_INTENDED; // Use instead of/along with annotations +// // in comments +// } else { +// return x; +// } +// case 42: +// ... +// +// Notes: When supported, GCC and Clang can issue a warning on switch labels +// with unannotated fallthrough using the warning `-Wimplicit-fallthrough`. See +// clang documentation on language extensions for details: +// https://clang.llvm.org/docs/AttributeReference.html#fallthrough-clang-fallthrough +// +// When used with unsupported compilers, the ABSL_FALLTHROUGH_INTENDED macro has +// no effect on diagnostics. In any case this macro has no effect on runtime +// behavior and performance of code. + +#ifdef ABSL_FALLTHROUGH_INTENDED +#error "ABSL_FALLTHROUGH_INTENDED should not be defined." +#elif ABSL_HAVE_CPP_ATTRIBUTE(fallthrough) +#define ABSL_FALLTHROUGH_INTENDED [[fallthrough]] +#elif ABSL_HAVE_CPP_ATTRIBUTE(clang::fallthrough) +#define ABSL_FALLTHROUGH_INTENDED [[clang::fallthrough]] +#elif ABSL_HAVE_CPP_ATTRIBUTE(gnu::fallthrough) +#define ABSL_FALLTHROUGH_INTENDED [[gnu::fallthrough]] +#else +#define ABSL_FALLTHROUGH_INTENDED \ + do { \ + } while (0) +#endif + +// ABSL_DEPRECATED() +// +// Marks a deprecated class, struct, enum, function, method and variable +// declarations. The macro argument is used as a custom diagnostic message (e.g. +// suggestion of a better alternative). +// +// Examples: +// +// class ABSL_DEPRECATED("Use Bar instead") Foo {...}; +// +// ABSL_DEPRECATED("Use Baz() instead") void Bar() {...} +// +// template +// ABSL_DEPRECATED("Use DoThat() instead") +// void DoThis(); +// +// Every usage of a deprecated entity will trigger a warning when compiled with +// clang's `-Wdeprecated-declarations` option. This option is turned off by +// default, but the warnings will be reported by clang-tidy. +#if defined(__clang__) && defined(__cplusplus) && __cplusplus >= 201103L +#define ABSL_DEPRECATED(message) __attribute__((deprecated(message))) +#endif + +#ifndef ABSL_DEPRECATED +#define ABSL_DEPRECATED(message) +#endif + // ABSL_CONST_INIT // // A variable declaration annotated with the `ABSL_CONST_INIT` attribute will @@ -620,4 +681,47 @@ #define ABSL_CONST_INIT #endif // ABSL_HAVE_CPP_ATTRIBUTE(clang::require_constant_initialization) +// ABSL_ATTRIBUTE_PURE_FUNCTION +// +// ABSL_ATTRIBUTE_PURE_FUNCTION is used to annotate declarations of "pure" +// functions. A function is pure if its return value is only a function of its +// arguments. The pure attribute prohibits a function from modifying the state +// of the program that is observable by means other than inspecting the +// function's return value. Declaring such functions with the pure attribute +// allows the compiler to avoid emitting some calls in repeated invocations of +// the function with the same argument values. +// +// Example: +// +// ABSL_ATTRIBUTE_PURE_FUNCTION int64_t ToInt64Milliseconds(Duration d); +#if ABSL_HAVE_CPP_ATTRIBUTE(gnu::pure) +#define ABSL_ATTRIBUTE_PURE_FUNCTION [[gnu::pure]] +#elif ABSL_HAVE_ATTRIBUTE(pure) +#define ABSL_ATTRIBUTE_PURE_FUNCTION __attribute__((pure)) +#else +#define ABSL_ATTRIBUTE_PURE_FUNCTION +#endif + +// ABSL_ATTRIBUTE_LIFETIME_BOUND indicates that a resource owned by a function +// parameter or implicit object parameter is retained by the return value of the +// annotated function (or, for a parameter of a constructor, in the value of the +// constructed object). This attribute causes warnings to be produced if a +// temporary object does not live long enough. +// +// When applied to a reference parameter, the referenced object is assumed to be +// retained by the return value of the function. When applied to a non-reference +// parameter (for example, a pointer or a class type), all temporaries +// referenced by the parameter are assumed to be retained by the return value of +// the function. +// +// See also the upstream documentation: +// https://clang.llvm.org/docs/AttributeReference.html#lifetimebound +#if ABSL_HAVE_CPP_ATTRIBUTE(clang::lifetimebound) +#define ABSL_ATTRIBUTE_LIFETIME_BOUND [[clang::lifetimebound]] +#elif ABSL_HAVE_ATTRIBUTE(lifetimebound) +#define ABSL_ATTRIBUTE_LIFETIME_BOUND __attribute__((lifetimebound)) +#else +#define ABSL_ATTRIBUTE_LIFETIME_BOUND +#endif + #endif // ABSL_BASE_ATTRIBUTES_H_ diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/call_once.h b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/call_once.h index bc5ec93704..96109f537c 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/call_once.h +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/call_once.h @@ -175,17 +175,10 @@ void CallOnceImpl(std::atomic* control, std::memory_order_relaxed) || base_internal::SpinLockWait(control, ABSL_ARRAYSIZE(trans), trans, scheduling_mode) == kOnceInit) { - base_internal::Invoke(std::forward(fn), + base_internal::invoke(std::forward(fn), std::forward(args)...); - // The call to SpinLockWake below is an optimization, because the waiter - // in SpinLockWait is waiting with a short timeout. The atomic load/store - // sequence is slightly faster than an atomic exchange: - // old_control = control->exchange(base_internal::kOnceDone, - // std::memory_order_release); - // We opt for a slightly faster case when there are no waiters, in spite - // of longer tail latency when there are waiters. - old_control = control->load(std::memory_order_relaxed); - control->store(base_internal::kOnceDone, std::memory_order_release); + old_control = + control->exchange(base_internal::kOnceDone, std::memory_order_release); if (old_control == base_internal::kOnceWaiter) { base_internal::SpinLockWake(control, true); } diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/casts.h b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/casts.h index 322cc1d243..83c691265f 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/casts.h +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/casts.h @@ -159,16 +159,19 @@ inline Dest bit_cast(const Source& source) { return dest; } -// NOTE: This overload is only picked if the requirements of bit_cast are not -// met. It is therefore UB, but is provided temporarily as previous versions of -// this function template were unchecked. Do not use this in new code. +// NOTE: This overload is only picked if the requirements of bit_cast are +// not met. It is therefore UB, but is provided temporarily as previous +// versions of this function template were unchecked. Do not use this in +// new code. template < typename Dest, typename Source, typename std::enable_if< - !internal_casts::is_bitcastable::value, int>::type = 0> + !internal_casts::is_bitcastable::value, + int>::type = 0> ABSL_DEPRECATED( - "absl::bit_cast type requirements were violated. Update the types being " - "used such that they are the same size and are both TriviallyCopyable.") + "absl::bit_cast type requirements were violated. Update the types " + "being used such that they are the same size and are both " + "TriviallyCopyable.") inline Dest bit_cast(const Source& source) { static_assert(sizeof(Dest) == sizeof(Source), "Source and destination types should have equal sizes."); diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/config.h b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/config.h index f54466deeb..c7b2e64de8 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/config.h +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/config.h @@ -66,6 +66,35 @@ #include "absl/base/options.h" #include "absl/base/policy_checks.h" +// Abseil long-term support (LTS) releases will define +// `ABSL_LTS_RELEASE_VERSION` to the integer representing the date string of the +// LTS release version, and will define `ABSL_LTS_RELEASE_PATCH_LEVEL` to the +// integer representing the patch-level for that release. +// +// For example, for LTS release version "20300401.2", this would give us +// ABSL_LTS_RELEASE_VERSION == 20300401 && ABSL_LTS_RELEASE_PATCH_LEVEL == 2 +// +// These symbols will not be defined in non-LTS code. +// +// Abseil recommends that clients live-at-head. Therefore, if you are using +// these symbols to assert a minimum version requirement, we recommend you do it +// as +// +// #if defined(ABSL_LTS_RELEASE_VERSION) && ABSL_LTS_RELEASE_VERSION < 20300401 +// #error Project foo requires Abseil LTS version >= 20300401 +// #endif +// +// The `defined(ABSL_LTS_RELEASE_VERSION)` part of the check excludes +// live-at-head clients from the minimum version assertion. +// +// See https://abseil.io/about/releases for more information on Abseil release +// management. +// +// LTS releases can be obtained from +// https://github.com/abseil/abseil-cpp/releases. +#undef ABSL_LTS_RELEASE_VERSION +#undef ABSL_LTS_RELEASE_PATCH_LEVEL + // Helper macro to convert a CPP variable to a string literal. #define ABSL_INTERNAL_DO_TOKEN_STR(x) #x #define ABSL_INTERNAL_TOKEN_STR(x) ABSL_INTERNAL_DO_TOKEN_STR(x) @@ -121,10 +150,16 @@ static_assert(ABSL_INTERNAL_INLINE_NAMESPACE_STR[0] != 'h' || #if ABSL_OPTION_USE_INLINE_NAMESPACE == 0 #define ABSL_NAMESPACE_BEGIN #define ABSL_NAMESPACE_END +#define ABSL_INTERNAL_C_SYMBOL(x) x #elif ABSL_OPTION_USE_INLINE_NAMESPACE == 1 #define ABSL_NAMESPACE_BEGIN \ inline namespace ABSL_OPTION_INLINE_NAMESPACE_NAME { #define ABSL_NAMESPACE_END } +#define ABSL_INTERNAL_C_SYMBOL_HELPER_2(x, v) x##_##v +#define ABSL_INTERNAL_C_SYMBOL_HELPER_1(x, v) \ + ABSL_INTERNAL_C_SYMBOL_HELPER_2(x, v) +#define ABSL_INTERNAL_C_SYMBOL(x) \ + ABSL_INTERNAL_C_SYMBOL_HELPER_1(x, ABSL_OPTION_INLINE_NAMESPACE_NAME) #else #error options.h is misconfigured. #endif @@ -154,6 +189,28 @@ static_assert(ABSL_INTERNAL_INLINE_NAMESPACE_STR[0] != 'h' || #define ABSL_INTERNAL_HAS_KEYWORD(x) 0 #endif +#ifdef __has_feature +#define ABSL_HAVE_FEATURE(f) __has_feature(f) +#else +#define ABSL_HAVE_FEATURE(f) 0 +#endif + +// Portable check for GCC minimum version: +// https://gcc.gnu.org/onlinedocs/cpp/Common-Predefined-Macros.html +#if defined(__GNUC__) && defined(__GNUC_MINOR__) +#define ABSL_INTERNAL_HAVE_MIN_GNUC_VERSION(x, y) \ + (__GNUC__ > (x) || __GNUC__ == (x) && __GNUC_MINOR__ >= (y)) +#else +#define ABSL_INTERNAL_HAVE_MIN_GNUC_VERSION(x, y) 0 +#endif + +#if defined(__clang__) && defined(__clang_major__) && defined(__clang_minor__) +#define ABSL_INTERNAL_HAVE_MIN_CLANG_VERSION(x, y) \ + (__clang_major__ > (x) || __clang_major__ == (x) && __clang_minor__ >= (y)) +#else +#define ABSL_INTERNAL_HAVE_MIN_CLANG_VERSION(x, y) 0 +#endif + // ABSL_HAVE_TLS is defined to 1 when __thread should be supported. // We assume __thread is supported on Linux when compiled with Clang or compiled // against libstdc++ with _GLIBCXX_HAVE_TLS defined. @@ -171,10 +228,9 @@ static_assert(ABSL_INTERNAL_INLINE_NAMESPACE_STR[0] != 'h' || // gcc >= 4.8.1 using libstdc++, and Visual Studio. #ifdef ABSL_HAVE_STD_IS_TRIVIALLY_DESTRUCTIBLE #error ABSL_HAVE_STD_IS_TRIVIALLY_DESTRUCTIBLE cannot be directly set -#elif defined(_LIBCPP_VERSION) || \ - (!defined(__clang__) && defined(__GNUC__) && defined(__GLIBCXX__) && \ - (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))) || \ - defined(_MSC_VER) +#elif defined(_LIBCPP_VERSION) || defined(_MSC_VER) || \ + (!defined(__clang__) && defined(__GLIBCXX__) && \ + ABSL_INTERNAL_HAVE_MIN_GNUC_VERSION(4, 8)) #define ABSL_HAVE_STD_IS_TRIVIALLY_DESTRUCTIBLE 1 #endif @@ -193,10 +249,9 @@ static_assert(ABSL_INTERNAL_INLINE_NAMESPACE_STR[0] != 'h' || #error ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE cannot be directly set #elif defined(ABSL_HAVE_STD_IS_TRIVIALLY_ASSIGNABLE) #error ABSL_HAVE_STD_IS_TRIVIALLY_ASSIGNABLE cannot directly set -#elif (defined(__clang__) && defined(_LIBCPP_VERSION)) || \ - (!defined(__clang__) && defined(__GNUC__) && \ - (__GNUC__ > 7 || (__GNUC__ == 7 && __GNUC_MINOR__ >= 4)) && \ - (defined(_LIBCPP_VERSION) || defined(__GLIBCXX__))) || \ +#elif (defined(__clang__) && defined(_LIBCPP_VERSION)) || \ + (!defined(__clang__) && ABSL_INTERNAL_HAVE_MIN_GNUC_VERSION(7, 4) && \ + (defined(_LIBCPP_VERSION) || defined(__GLIBCXX__))) || \ (defined(_MSC_VER) && !defined(__NVCC__)) #define ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE 1 #define ABSL_HAVE_STD_IS_TRIVIALLY_ASSIGNABLE 1 @@ -210,6 +265,8 @@ static_assert(ABSL_INTERNAL_INLINE_NAMESPACE_STR[0] != 'h' || #if ABSL_INTERNAL_HAS_KEYWORD(__builtin_LINE) && \ ABSL_INTERNAL_HAS_KEYWORD(__builtin_FILE) #define ABSL_HAVE_SOURCE_LOCATION_CURRENT 1 +#elif ABSL_INTERNAL_HAVE_MIN_GNUC_VERSION(5, 0) +#define ABSL_HAVE_SOURCE_LOCATION_CURRENT 1 #endif #endif @@ -226,11 +283,9 @@ static_assert(ABSL_INTERNAL_INLINE_NAMESPACE_STR[0] != 'h' || // * Xcode 9.3 started disallowing `thread_local` for 32-bit iOS simulator // targeting iOS 9.x. // * Xcode 10 moves the deployment target check for iOS < 9.0 to link time -// making __has_feature unreliable there. +// making ABSL_HAVE_FEATURE unreliable there. // -// Otherwise, `__has_feature` is only supported by Clang so it has be inside -// `defined(__APPLE__)` check. -#if __has_feature(cxx_thread_local) && \ +#if ABSL_HAVE_FEATURE(cxx_thread_local) && \ !(TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_9_0) #define ABSL_HAVE_THREAD_LOCAL 1 #endif @@ -307,25 +362,21 @@ static_assert(ABSL_INTERNAL_INLINE_NAMESPACE_STR[0] != 'h' || // For further details, consult the compiler's documentation. #ifdef ABSL_HAVE_EXCEPTIONS #error ABSL_HAVE_EXCEPTIONS cannot be directly set. - -#elif defined(__clang__) - -#if __clang_major__ > 3 || (__clang_major__ == 3 && __clang_minor__ >= 6) +#elif ABSL_INTERNAL_HAVE_MIN_CLANG_VERSION(3, 6) // Clang >= 3.6 -#if __has_feature(cxx_exceptions) +#if ABSL_HAVE_FEATURE(cxx_exceptions) #define ABSL_HAVE_EXCEPTIONS 1 -#endif // __has_feature(cxx_exceptions) -#else +#endif // ABSL_HAVE_FEATURE(cxx_exceptions) +#elif defined(__clang__) // Clang < 3.6 // http://releases.llvm.org/3.6.0/tools/clang/docs/ReleaseNotes.html#the-exceptions-macro -#if defined(__EXCEPTIONS) && __has_feature(cxx_exceptions) +#if defined(__EXCEPTIONS) && ABSL_HAVE_FEATURE(cxx_exceptions) #define ABSL_HAVE_EXCEPTIONS 1 -#endif // defined(__EXCEPTIONS) && __has_feature(cxx_exceptions) -#endif // __clang_major__ > 3 || (__clang_major__ == 3 && __clang_minor__ >= 6) - +#endif // defined(__EXCEPTIONS) && ABSL_HAVE_FEATURE(cxx_exceptions) // Handle remaining special cases and default to exceptions being supported. -#elif !(defined(__GNUC__) && (__GNUC__ < 5) && !defined(__EXCEPTIONS)) && \ - !(defined(__GNUC__) && (__GNUC__ >= 5) && !defined(__cpp_exceptions)) && \ +#elif !(defined(__GNUC__) && (__GNUC__ < 5) && !defined(__EXCEPTIONS)) && \ + !(ABSL_INTERNAL_HAVE_MIN_GNUC_VERSION(5, 0) && \ + !defined(__cpp_exceptions)) && \ !(defined(_MSC_VER) && !defined(_CPPUNWIND)) #define ABSL_HAVE_EXCEPTIONS 1 #endif @@ -360,7 +411,7 @@ static_assert(ABSL_INTERNAL_INLINE_NAMESPACE_STR[0] != 'h' || #elif defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) || \ defined(__ros__) || defined(__native_client__) || defined(__asmjs__) || \ defined(__wasm__) || defined(__Fuchsia__) || defined(__sun) || \ - defined(__ASYLO__) + defined(__ASYLO__) || defined(__myriad2__) #define ABSL_HAVE_MMAP 1 #endif @@ -375,6 +426,15 @@ static_assert(ABSL_INTERNAL_INLINE_NAMESPACE_STR[0] != 'h' || #define ABSL_HAVE_PTHREAD_GETSCHEDPARAM 1 #endif +// ABSL_HAVE_SCHED_GETCPU +// +// Checks whether sched_getcpu is available. +#ifdef ABSL_HAVE_SCHED_GETCPU +#error ABSL_HAVE_SCHED_GETCPU cannot be directly set +#elif defined(__linux__) +#define ABSL_HAVE_SCHED_GETCPU 1 +#endif + // ABSL_HAVE_SCHED_YIELD // // Checks whether the platform implements sched_yield(2) as defined in @@ -470,9 +530,9 @@ static_assert(ABSL_INTERNAL_INLINE_NAMESPACE_STR[0] != 'h' || (defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__) && \ __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ < 120000) || \ (defined(__ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__) && \ - __ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__ < 120000) || \ + __ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__ < 50000) || \ (defined(__ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__) && \ - __ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__ < 50000)) + __ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__ < 120000)) #define ABSL_INTERNAL_APPLE_CXX17_TYPES_UNAVAILABLE 1 #else #define ABSL_INTERNAL_APPLE_CXX17_TYPES_UNAVAILABLE 0 @@ -486,7 +546,7 @@ static_assert(ABSL_INTERNAL_INLINE_NAMESPACE_STR[0] != 'h' || #endif #ifdef __has_include -#if __has_include() && __cplusplus >= 201703L && \ +#if __has_include() && defined(__cplusplus) && __cplusplus >= 201703L && \ !ABSL_INTERNAL_APPLE_CXX17_TYPES_UNAVAILABLE #define ABSL_HAVE_STD_ANY 1 #endif @@ -500,8 +560,8 @@ static_assert(ABSL_INTERNAL_INLINE_NAMESPACE_STR[0] != 'h' || #endif #ifdef __has_include -#if __has_include() && __cplusplus >= 201703L && \ - !ABSL_INTERNAL_APPLE_CXX17_TYPES_UNAVAILABLE +#if __has_include() && defined(__cplusplus) && \ + __cplusplus >= 201703L && !ABSL_INTERNAL_APPLE_CXX17_TYPES_UNAVAILABLE #define ABSL_HAVE_STD_OPTIONAL 1 #endif #endif @@ -514,8 +574,8 @@ static_assert(ABSL_INTERNAL_INLINE_NAMESPACE_STR[0] != 'h' || #endif #ifdef __has_include -#if __has_include() && __cplusplus >= 201703L && \ - !ABSL_INTERNAL_APPLE_CXX17_TYPES_UNAVAILABLE +#if __has_include() && defined(__cplusplus) && \ + __cplusplus >= 201703L && !ABSL_INTERNAL_APPLE_CXX17_TYPES_UNAVAILABLE #define ABSL_HAVE_STD_VARIANT 1 #endif #endif @@ -528,7 +588,8 @@ static_assert(ABSL_INTERNAL_INLINE_NAMESPACE_STR[0] != 'h' || #endif #ifdef __has_include -#if __has_include() && __cplusplus >= 201703L +#if __has_include() && defined(__cplusplus) && \ + __cplusplus >= 201703L #define ABSL_HAVE_STD_STRING_VIEW 1 #endif #endif @@ -540,8 +601,9 @@ static_assert(ABSL_INTERNAL_INLINE_NAMESPACE_STR[0] != 'h' || // not correctly set by MSVC, so we use `_MSVC_LANG` to check the language // version. // TODO(zhangxy): fix tests before enabling aliasing for `std::any`. -#if defined(_MSC_VER) && _MSC_VER >= 1910 && \ - ((defined(_MSVC_LANG) && _MSVC_LANG > 201402) || __cplusplus > 201402) +#if defined(_MSC_VER) && _MSC_VER >= 1910 && \ + ((defined(_MSVC_LANG) && _MSVC_LANG > 201402) || \ + (defined(__cplusplus) && __cplusplus > 201402)) // #define ABSL_HAVE_STD_ANY 1 #define ABSL_HAVE_STD_OPTIONAL 1 #define ABSL_HAVE_STD_VARIANT 1 @@ -661,4 +723,47 @@ static_assert(ABSL_INTERNAL_INLINE_NAMESPACE_STR[0] != 'h' || #define ABSL_DLL #endif // defined(_MSC_VER) +// ABSL_HAVE_MEMORY_SANITIZER +// +// MemorySanitizer (MSan) is a detector of uninitialized reads. It consists of +// a compiler instrumentation module and a run-time library. +#ifdef ABSL_HAVE_MEMORY_SANITIZER +#error "ABSL_HAVE_MEMORY_SANITIZER cannot be directly set." +#elif defined(__SANITIZE_MEMORY__) +#define ABSL_HAVE_MEMORY_SANITIZER 1 +#elif !defined(__native_client__) && ABSL_HAVE_FEATURE(memory_sanitizer) +#define ABSL_HAVE_MEMORY_SANITIZER 1 +#endif + +// ABSL_HAVE_THREAD_SANITIZER +// +// ThreadSanitizer (TSan) is a fast data race detector. +#ifdef ABSL_HAVE_THREAD_SANITIZER +#error "ABSL_HAVE_THREAD_SANITIZER cannot be directly set." +#elif defined(__SANITIZE_THREAD__) +#define ABSL_HAVE_THREAD_SANITIZER 1 +#elif ABSL_HAVE_FEATURE(thread_sanitizer) +#define ABSL_HAVE_THREAD_SANITIZER 1 +#endif + +// ABSL_HAVE_ADDRESS_SANITIZER +// +// AddressSanitizer (ASan) is a fast memory error detector. +#ifdef ABSL_HAVE_ADDRESS_SANITIZER +#error "ABSL_HAVE_ADDRESS_SANITIZER cannot be directly set." +#elif defined(__SANITIZE_ADDRESS__) +#define ABSL_HAVE_ADDRESS_SANITIZER 1 +#elif ABSL_HAVE_FEATURE(address_sanitizer) +#define ABSL_HAVE_ADDRESS_SANITIZER 1 +#endif + +// ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION +// +// Class template argument deduction is a language feature added in C++17. +#ifdef ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION +#error "ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION cannot be directly set." +#elif defined(__cpp_deduction_guides) +#define ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION 1 +#endif + #endif // ABSL_BASE_CONFIG_H_ diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/dynamic_annotations.cc b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/dynamic_annotations.cc deleted file mode 100644 index 1411093757..0000000000 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/dynamic_annotations.cc +++ /dev/null @@ -1,129 +0,0 @@ -// Copyright 2017 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include -#include - -#include "absl/base/dynamic_annotations.h" - -#ifndef __has_feature -#define __has_feature(x) 0 -#endif - -/* Compiler-based ThreadSanitizer defines - ABSL_DYNAMIC_ANNOTATIONS_EXTERNAL_IMPL = 1 - and provides its own definitions of the functions. */ - -#ifndef ABSL_DYNAMIC_ANNOTATIONS_EXTERNAL_IMPL -# define ABSL_DYNAMIC_ANNOTATIONS_EXTERNAL_IMPL 0 -#endif - -/* Each function is empty and called (via a macro) only in debug mode. - The arguments are captured by dynamic tools at runtime. */ - -#if ABSL_DYNAMIC_ANNOTATIONS_EXTERNAL_IMPL == 0 && !defined(__native_client__) - -#if __has_feature(memory_sanitizer) -#include -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -void AbslAnnotateRWLockCreate(const char *, int, - const volatile void *){} -void AbslAnnotateRWLockDestroy(const char *, int, - const volatile void *){} -void AbslAnnotateRWLockAcquired(const char *, int, - const volatile void *, long){} -void AbslAnnotateRWLockReleased(const char *, int, - const volatile void *, long){} -void AbslAnnotateBenignRace(const char *, int, - const volatile void *, - const char *){} -void AbslAnnotateBenignRaceSized(const char *, int, - const volatile void *, - size_t, - const char *) {} -void AbslAnnotateThreadName(const char *, int, - const char *){} -void AbslAnnotateIgnoreReadsBegin(const char *, int){} -void AbslAnnotateIgnoreReadsEnd(const char *, int){} -void AbslAnnotateIgnoreWritesBegin(const char *, int){} -void AbslAnnotateIgnoreWritesEnd(const char *, int){} -void AbslAnnotateEnableRaceDetection(const char *, int, int){} -void AbslAnnotateMemoryIsInitialized(const char *, int, - const volatile void *mem, size_t size) { -#if __has_feature(memory_sanitizer) - __msan_unpoison(mem, size); -#else - (void)mem; - (void)size; -#endif -} - -void AbslAnnotateMemoryIsUninitialized(const char *, int, - const volatile void *mem, size_t size) { -#if __has_feature(memory_sanitizer) - __msan_allocated_memory(mem, size); -#else - (void)mem; - (void)size; -#endif -} - -static int AbslGetRunningOnValgrind(void) { -#ifdef RUNNING_ON_VALGRIND - if (RUNNING_ON_VALGRIND) return 1; -#endif - char *running_on_valgrind_str = getenv("RUNNING_ON_VALGRIND"); - if (running_on_valgrind_str) { - return strcmp(running_on_valgrind_str, "0") != 0; - } - return 0; -} - -/* See the comments in dynamic_annotations.h */ -int AbslRunningOnValgrind(void) { - static volatile int running_on_valgrind = -1; - int local_running_on_valgrind = running_on_valgrind; - /* C doesn't have thread-safe initialization of statics, and we - don't want to depend on pthread_once here, so hack it. */ - ABSL_ANNOTATE_BENIGN_RACE(&running_on_valgrind, "safe hack"); - if (local_running_on_valgrind == -1) - running_on_valgrind = local_running_on_valgrind = AbslGetRunningOnValgrind(); - return local_running_on_valgrind; -} - -/* See the comments in dynamic_annotations.h */ -double AbslValgrindSlowdown(void) { - /* Same initialization hack as in AbslRunningOnValgrind(). */ - static volatile double slowdown = 0.0; - double local_slowdown = slowdown; - ABSL_ANNOTATE_BENIGN_RACE(&slowdown, "safe hack"); - if (AbslRunningOnValgrind() == 0) { - return 1.0; - } - if (local_slowdown == 0.0) { - char *env = getenv("VALGRIND_SLOWDOWN"); - slowdown = local_slowdown = env ? atof(env) : 50.0; - } - return local_slowdown; -} - -#ifdef __cplusplus -} // extern "C" -#endif -#endif /* ABSL_DYNAMIC_ANNOTATIONS_EXTERNAL_IMPL == 0 */ diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/dynamic_annotations.h b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/dynamic_annotations.h index c156e06397..3ea7c1568c 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/dynamic_annotations.h +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/dynamic_annotations.h @@ -1,389 +1,471 @@ -/* - * Copyright 2017 The Abseil Authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/* This file defines dynamic annotations for use with dynamic analysis - tool such as valgrind, PIN, etc. +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. - Dynamic annotation is a source code annotation that affects - the generated code (that is, the annotation is not a comment). - Each such annotation is attached to a particular - instruction and/or to a particular object (address) in the program. - - The annotations that should be used by users are macros in all upper-case - (e.g., ABSL_ANNOTATE_THREAD_NAME). - - Actual implementation of these macros may differ depending on the - dynamic analysis tool being used. - - This file supports the following configurations: - - Dynamic Annotations enabled (with static thread-safety warnings disabled). - In this case, macros expand to functions implemented by Thread Sanitizer, - when building with TSan. When not provided an external implementation, - dynamic_annotations.cc provides no-op implementations. - - - Static Clang thread-safety warnings enabled. - When building with a Clang compiler that supports thread-safety warnings, - a subset of annotations can be statically-checked at compile-time. We - expand these macros to static-inline functions that can be analyzed for - thread-safety, but afterwards elided when building the final binary. - - - All annotations are disabled. - If neither Dynamic Annotations nor Clang thread-safety warnings are - enabled, then all annotation-macros expand to empty. */ +// This file defines dynamic annotations for use with dynamic analysis tool +// such as valgrind, PIN, etc. +// +// Dynamic annotation is a source code annotation that affects the generated +// code (that is, the annotation is not a comment). Each such annotation is +// attached to a particular instruction and/or to a particular object (address) +// in the program. +// +// The annotations that should be used by users are macros in all upper-case +// (e.g., ABSL_ANNOTATE_THREAD_NAME). +// +// Actual implementation of these macros may differ depending on the dynamic +// analysis tool being used. +// +// This file supports the following configurations: +// - Dynamic Annotations enabled (with static thread-safety warnings disabled). +// In this case, macros expand to functions implemented by Thread Sanitizer, +// when building with TSan. When not provided an external implementation, +// dynamic_annotations.cc provides no-op implementations. +// +// - Static Clang thread-safety warnings enabled. +// When building with a Clang compiler that supports thread-safety warnings, +// a subset of annotations can be statically-checked at compile-time. We +// expand these macros to static-inline functions that can be analyzed for +// thread-safety, but afterwards elided when building the final binary. +// +// - All annotations are disabled. +// If neither Dynamic Annotations nor Clang thread-safety warnings are +// enabled, then all annotation-macros expand to empty. #ifndef ABSL_BASE_DYNAMIC_ANNOTATIONS_H_ #define ABSL_BASE_DYNAMIC_ANNOTATIONS_H_ -#ifndef ABSL_DYNAMIC_ANNOTATIONS_ENABLED -# define ABSL_DYNAMIC_ANNOTATIONS_ENABLED 0 -#endif - -#if ABSL_DYNAMIC_ANNOTATIONS_ENABLED != 0 - - /* ------------------------------------------------------------- - Annotations that suppress errors. It is usually better to express the - program's synchronization using the other annotations, but these can - be used when all else fails. */ - - /* Report that we may have a benign race at "pointer", with size - "sizeof(*(pointer))". "pointer" must be a non-void* pointer. Insert at the - point where "pointer" has been allocated, preferably close to the point - where the race happens. See also ABSL_ANNOTATE_BENIGN_RACE_STATIC. */ - #define ABSL_ANNOTATE_BENIGN_RACE(pointer, description) \ - AbslAnnotateBenignRaceSized(__FILE__, __LINE__, pointer, \ - sizeof(*(pointer)), description) - - /* Same as ABSL_ANNOTATE_BENIGN_RACE(address, description), but applies to - the memory range [address, address+size). */ - #define ABSL_ANNOTATE_BENIGN_RACE_SIZED(address, size, description) \ - AbslAnnotateBenignRaceSized(__FILE__, __LINE__, address, size, description) - - /* Enable (enable!=0) or disable (enable==0) race detection for all threads. - This annotation could be useful if you want to skip expensive race analysis - during some period of program execution, e.g. during initialization. */ - #define ABSL_ANNOTATE_ENABLE_RACE_DETECTION(enable) \ - AbslAnnotateEnableRaceDetection(__FILE__, __LINE__, enable) - - /* ------------------------------------------------------------- - Annotations useful for debugging. */ - - /* Report the current thread name to a race detector. */ - #define ABSL_ANNOTATE_THREAD_NAME(name) \ - AbslAnnotateThreadName(__FILE__, __LINE__, name) - - /* ------------------------------------------------------------- - Annotations useful when implementing locks. They are not - normally needed by modules that merely use locks. - The "lock" argument is a pointer to the lock object. */ - - /* Report that a lock has been created at address "lock". */ - #define ABSL_ANNOTATE_RWLOCK_CREATE(lock) \ - AbslAnnotateRWLockCreate(__FILE__, __LINE__, lock) - - /* Report that a linker initialized lock has been created at address "lock". - */ -#ifdef THREAD_SANITIZER - #define ABSL_ANNOTATE_RWLOCK_CREATE_STATIC(lock) \ - AbslAnnotateRWLockCreateStatic(__FILE__, __LINE__, lock) -#else - #define ABSL_ANNOTATE_RWLOCK_CREATE_STATIC(lock) ABSL_ANNOTATE_RWLOCK_CREATE(lock) -#endif - - /* Report that the lock at address "lock" is about to be destroyed. */ - #define ABSL_ANNOTATE_RWLOCK_DESTROY(lock) \ - AbslAnnotateRWLockDestroy(__FILE__, __LINE__, lock) - - /* Report that the lock at address "lock" has been acquired. - is_w=1 for writer lock, is_w=0 for reader lock. */ - #define ABSL_ANNOTATE_RWLOCK_ACQUIRED(lock, is_w) \ - AbslAnnotateRWLockAcquired(__FILE__, __LINE__, lock, is_w) - - /* Report that the lock at address "lock" is about to be released. */ - #define ABSL_ANNOTATE_RWLOCK_RELEASED(lock, is_w) \ - AbslAnnotateRWLockReleased(__FILE__, __LINE__, lock, is_w) - -#else /* ABSL_DYNAMIC_ANNOTATIONS_ENABLED == 0 */ - - #define ABSL_ANNOTATE_RWLOCK_CREATE(lock) /* empty */ - #define ABSL_ANNOTATE_RWLOCK_CREATE_STATIC(lock) /* empty */ - #define ABSL_ANNOTATE_RWLOCK_DESTROY(lock) /* empty */ - #define ABSL_ANNOTATE_RWLOCK_ACQUIRED(lock, is_w) /* empty */ - #define ABSL_ANNOTATE_RWLOCK_RELEASED(lock, is_w) /* empty */ - #define ABSL_ANNOTATE_BENIGN_RACE(address, description) /* empty */ - #define ABSL_ANNOTATE_BENIGN_RACE_SIZED(address, size, description) /* empty */ - #define ABSL_ANNOTATE_THREAD_NAME(name) /* empty */ - #define ABSL_ANNOTATE_ENABLE_RACE_DETECTION(enable) /* empty */ - -#endif /* ABSL_DYNAMIC_ANNOTATIONS_ENABLED */ - -/* These annotations are also made available to LLVM's Memory Sanitizer */ -#if ABSL_DYNAMIC_ANNOTATIONS_ENABLED == 1 || defined(MEMORY_SANITIZER) - #define ABSL_ANNOTATE_MEMORY_IS_INITIALIZED(address, size) \ - AbslAnnotateMemoryIsInitialized(__FILE__, __LINE__, address, size) - - #define ABSL_ANNOTATE_MEMORY_IS_UNINITIALIZED(address, size) \ - AbslAnnotateMemoryIsUninitialized(__FILE__, __LINE__, address, size) -#else - #define ABSL_ANNOTATE_MEMORY_IS_INITIALIZED(address, size) /* empty */ - #define ABSL_ANNOTATE_MEMORY_IS_UNINITIALIZED(address, size) /* empty */ -#endif /* ABSL_DYNAMIC_ANNOTATIONS_ENABLED || MEMORY_SANITIZER */ - -/* TODO(delesley) -- Replace __CLANG_SUPPORT_DYN_ANNOTATION__ with the - appropriate feature ID. */ -#if defined(__clang__) && (!defined(SWIG)) \ - && defined(__CLANG_SUPPORT_DYN_ANNOTATION__) - - #if ABSL_DYNAMIC_ANNOTATIONS_ENABLED == 0 - #define ABSL_ANNOTALYSIS_ENABLED - #endif - - /* When running in opt-mode, GCC will issue a warning, if these attributes are - compiled. Only include them when compiling using Clang. */ - #define ABSL_ATTRIBUTE_IGNORE_READS_BEGIN \ - __attribute((exclusive_lock_function("*"))) - #define ABSL_ATTRIBUTE_IGNORE_READS_END \ - __attribute((unlock_function("*"))) -#else - #define ABSL_ATTRIBUTE_IGNORE_READS_BEGIN /* empty */ - #define ABSL_ATTRIBUTE_IGNORE_READS_END /* empty */ -#endif /* defined(__clang__) && ... */ - -#if (ABSL_DYNAMIC_ANNOTATIONS_ENABLED != 0) || defined(ABSL_ANNOTALYSIS_ENABLED) - #define ABSL_ANNOTATIONS_ENABLED -#endif - -#if (ABSL_DYNAMIC_ANNOTATIONS_ENABLED != 0) - - /* Request the analysis tool to ignore all reads in the current thread - until ABSL_ANNOTATE_IGNORE_READS_END is called. - Useful to ignore intentional racey reads, while still checking - other reads and all writes. - See also ABSL_ANNOTATE_UNPROTECTED_READ. */ - #define ABSL_ANNOTATE_IGNORE_READS_BEGIN() \ - AbslAnnotateIgnoreReadsBegin(__FILE__, __LINE__) - - /* Stop ignoring reads. */ - #define ABSL_ANNOTATE_IGNORE_READS_END() \ - AbslAnnotateIgnoreReadsEnd(__FILE__, __LINE__) - - /* Similar to ABSL_ANNOTATE_IGNORE_READS_BEGIN, but ignore writes instead. */ - #define ABSL_ANNOTATE_IGNORE_WRITES_BEGIN() \ - AbslAnnotateIgnoreWritesBegin(__FILE__, __LINE__) - - /* Stop ignoring writes. */ - #define ABSL_ANNOTATE_IGNORE_WRITES_END() \ - AbslAnnotateIgnoreWritesEnd(__FILE__, __LINE__) - -/* Clang provides limited support for static thread-safety analysis - through a feature called Annotalysis. We configure macro-definitions - according to whether Annotalysis support is available. */ -#elif defined(ABSL_ANNOTALYSIS_ENABLED) - - #define ABSL_ANNOTATE_IGNORE_READS_BEGIN() \ - AbslStaticAnnotateIgnoreReadsBegin(__FILE__, __LINE__) - - #define ABSL_ANNOTATE_IGNORE_READS_END() \ - AbslStaticAnnotateIgnoreReadsEnd(__FILE__, __LINE__) - - #define ABSL_ANNOTATE_IGNORE_WRITES_BEGIN() \ - AbslStaticAnnotateIgnoreWritesBegin(__FILE__, __LINE__) - - #define ABSL_ANNOTATE_IGNORE_WRITES_END() \ - AbslStaticAnnotateIgnoreWritesEnd(__FILE__, __LINE__) - -#else - #define ABSL_ANNOTATE_IGNORE_READS_BEGIN() /* empty */ - #define ABSL_ANNOTATE_IGNORE_READS_END() /* empty */ - #define ABSL_ANNOTATE_IGNORE_WRITES_BEGIN() /* empty */ - #define ABSL_ANNOTATE_IGNORE_WRITES_END() /* empty */ -#endif - -/* Implement the ANNOTATE_IGNORE_READS_AND_WRITES_* annotations using the more - primitive annotations defined above. */ -#if defined(ABSL_ANNOTATIONS_ENABLED) - - /* Start ignoring all memory accesses (both reads and writes). */ - #define ABSL_ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN() \ - do { \ - ABSL_ANNOTATE_IGNORE_READS_BEGIN(); \ - ABSL_ANNOTATE_IGNORE_WRITES_BEGIN(); \ - }while (0) - - /* Stop ignoring both reads and writes. */ - #define ABSL_ANNOTATE_IGNORE_READS_AND_WRITES_END() \ - do { \ - ABSL_ANNOTATE_IGNORE_WRITES_END(); \ - ABSL_ANNOTATE_IGNORE_READS_END(); \ - }while (0) - -#else - #define ABSL_ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN() /* empty */ - #define ABSL_ANNOTATE_IGNORE_READS_AND_WRITES_END() /* empty */ -#endif - -/* Use the macros above rather than using these functions directly. */ #include + +#include "absl/base/attributes.h" +#include "absl/base/config.h" #ifdef __cplusplus -extern "C" { -#endif -void AbslAnnotateRWLockCreate(const char *file, int line, - const volatile void *lock); -void AbslAnnotateRWLockCreateStatic(const char *file, int line, - const volatile void *lock); -void AbslAnnotateRWLockDestroy(const char *file, int line, - const volatile void *lock); -void AbslAnnotateRWLockAcquired(const char *file, int line, - const volatile void *lock, long is_w); /* NOLINT */ -void AbslAnnotateRWLockReleased(const char *file, int line, - const volatile void *lock, long is_w); /* NOLINT */ -void AbslAnnotateBenignRace(const char *file, int line, - const volatile void *address, - const char *description); -void AbslAnnotateBenignRaceSized(const char *file, int line, - const volatile void *address, - size_t size, - const char *description); -void AbslAnnotateThreadName(const char *file, int line, - const char *name); -void AbslAnnotateEnableRaceDetection(const char *file, int line, int enable); -void AbslAnnotateMemoryIsInitialized(const char *file, int line, - const volatile void *mem, size_t size); -void AbslAnnotateMemoryIsUninitialized(const char *file, int line, - const volatile void *mem, size_t size); - -/* Annotations expand to these functions, when Dynamic Annotations are enabled. - These functions are either implemented as no-op calls, if no Sanitizer is - attached, or provided with externally-linked implementations by a library - like ThreadSanitizer. */ -void AbslAnnotateIgnoreReadsBegin(const char *file, int line) - ABSL_ATTRIBUTE_IGNORE_READS_BEGIN; -void AbslAnnotateIgnoreReadsEnd(const char *file, int line) - ABSL_ATTRIBUTE_IGNORE_READS_END; -void AbslAnnotateIgnoreWritesBegin(const char *file, int line); -void AbslAnnotateIgnoreWritesEnd(const char *file, int line); - -#if defined(ABSL_ANNOTALYSIS_ENABLED) -/* When Annotalysis is enabled without Dynamic Annotations, the use of - static-inline functions allows the annotations to be read at compile-time, - while still letting the compiler elide the functions from the final build. - - TODO(delesley) -- The exclusive lock here ignores writes as well, but - allows IGNORE_READS_AND_WRITES to work properly. */ -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wunused-function" -static inline void AbslStaticAnnotateIgnoreReadsBegin(const char *file, int line) - ABSL_ATTRIBUTE_IGNORE_READS_BEGIN { (void)file; (void)line; } -static inline void AbslStaticAnnotateIgnoreReadsEnd(const char *file, int line) - ABSL_ATTRIBUTE_IGNORE_READS_END { (void)file; (void)line; } -static inline void AbslStaticAnnotateIgnoreWritesBegin( - const char *file, int line) { (void)file; (void)line; } -static inline void AbslStaticAnnotateIgnoreWritesEnd( - const char *file, int line) { (void)file; (void)line; } -#pragma GCC diagnostic pop +#include "absl/base/macros.h" #endif -/* Return non-zero value if running under valgrind. +// TODO(rogeeff): Remove after the backward compatibility period. +#include "absl/base/internal/dynamic_annotations.h" // IWYU pragma: export - If "valgrind.h" is included into dynamic_annotations.cc, - the regular valgrind mechanism will be used. - See http://valgrind.org/docs/manual/manual-core-adv.html about - RUNNING_ON_VALGRIND and other valgrind "client requests". - The file "valgrind.h" may be obtained by doing - svn co svn://svn.valgrind.org/valgrind/trunk/include +// ------------------------------------------------------------------------- +// Decide which features are enabled. - If for some reason you can't use "valgrind.h" or want to fake valgrind, - there are two ways to make this function return non-zero: - - Use environment variable: export RUNNING_ON_VALGRIND=1 - - Make your tool intercept the function AbslRunningOnValgrind() and - change its return value. - */ -int AbslRunningOnValgrind(void); +#ifdef ABSL_HAVE_THREAD_SANITIZER -/* AbslValgrindSlowdown returns: - * 1.0, if (AbslRunningOnValgrind() == 0) - * 50.0, if (AbslRunningOnValgrind() != 0 && getenv("VALGRIND_SLOWDOWN") == NULL) - * atof(getenv("VALGRIND_SLOWDOWN")) otherwise - This function can be used to scale timeout values: - EXAMPLE: - for (;;) { - DoExpensiveBackgroundTask(); - SleepForSeconds(5 * AbslValgrindSlowdown()); - } - */ -double AbslValgrindSlowdown(void); +#define ABSL_INTERNAL_RACE_ANNOTATIONS_ENABLED 1 +#define ABSL_INTERNAL_READS_ANNOTATIONS_ENABLED 1 +#define ABSL_INTERNAL_WRITES_ANNOTATIONS_ENABLED 1 +#define ABSL_INTERNAL_ANNOTALYSIS_ENABLED 0 +#define ABSL_INTERNAL_READS_WRITES_ANNOTATIONS_ENABLED 1 + +#else + +#define ABSL_INTERNAL_RACE_ANNOTATIONS_ENABLED 0 +#define ABSL_INTERNAL_READS_ANNOTATIONS_ENABLED 0 +#define ABSL_INTERNAL_WRITES_ANNOTATIONS_ENABLED 0 + +// Clang provides limited support for static thread-safety analysis through a +// feature called Annotalysis. We configure macro-definitions according to +// whether Annotalysis support is available. When running in opt-mode, GCC +// will issue a warning, if these attributes are compiled. Only include them +// when compiling using Clang. + +#if defined(__clang__) +#define ABSL_INTERNAL_ANNOTALYSIS_ENABLED 1 +#if !defined(SWIG) +#define ABSL_INTERNAL_IGNORE_READS_ATTRIBUTE_ENABLED 1 +#endif +#else +#define ABSL_INTERNAL_ANNOTALYSIS_ENABLED 0 +#endif + +// Read/write annotations are enabled in Annotalysis mode; disabled otherwise. +#define ABSL_INTERNAL_READS_WRITES_ANNOTATIONS_ENABLED \ + ABSL_INTERNAL_ANNOTALYSIS_ENABLED + +#endif // ABSL_HAVE_THREAD_SANITIZER #ifdef __cplusplus -} +#define ABSL_INTERNAL_BEGIN_EXTERN_C extern "C" { +#define ABSL_INTERNAL_END_EXTERN_C } // extern "C" +#define ABSL_INTERNAL_GLOBAL_SCOPED(F) ::F +#define ABSL_INTERNAL_STATIC_INLINE inline +#else +#define ABSL_INTERNAL_BEGIN_EXTERN_C // empty +#define ABSL_INTERNAL_END_EXTERN_C // empty +#define ABSL_INTERNAL_GLOBAL_SCOPED(F) F +#define ABSL_INTERNAL_STATIC_INLINE static inline #endif -/* ABSL_ANNOTATE_UNPROTECTED_READ is the preferred way to annotate racey reads. +// ------------------------------------------------------------------------- +// Define race annotations. + +#if ABSL_INTERNAL_RACE_ANNOTATIONS_ENABLED == 1 +// Some of the symbols used in this section (e.g. AnnotateBenignRaceSized) are +// defined by the compiler-based santizer implementation, not by the Abseil +// library. Therefore they do not use ABSL_INTERNAL_C_SYMBOL. + +// ------------------------------------------------------------- +// Annotations that suppress errors. It is usually better to express the +// program's synchronization using the other annotations, but these can be used +// when all else fails. + +// Report that we may have a benign race at `pointer`, with size +// "sizeof(*(pointer))". `pointer` must be a non-void* pointer. Insert at the +// point where `pointer` has been allocated, preferably close to the point +// where the race happens. See also ABSL_ANNOTATE_BENIGN_RACE_STATIC. +#define ABSL_ANNOTATE_BENIGN_RACE(pointer, description) \ + ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateBenignRaceSized) \ + (__FILE__, __LINE__, pointer, sizeof(*(pointer)), description) + +// Same as ABSL_ANNOTATE_BENIGN_RACE(`address`, `description`), but applies to +// the memory range [`address`, `address`+`size`). +#define ABSL_ANNOTATE_BENIGN_RACE_SIZED(address, size, description) \ + ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateBenignRaceSized) \ + (__FILE__, __LINE__, address, size, description) + +// Enable (`enable`!=0) or disable (`enable`==0) race detection for all threads. +// This annotation could be useful if you want to skip expensive race analysis +// during some period of program execution, e.g. during initialization. +#define ABSL_ANNOTATE_ENABLE_RACE_DETECTION(enable) \ + ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateEnableRaceDetection) \ + (__FILE__, __LINE__, enable) + +// ------------------------------------------------------------- +// Annotations useful for debugging. + +// Report the current thread `name` to a race detector. +#define ABSL_ANNOTATE_THREAD_NAME(name) \ + ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateThreadName)(__FILE__, __LINE__, name) + +// ------------------------------------------------------------- +// Annotations useful when implementing locks. They are not normally needed by +// modules that merely use locks. The `lock` argument is a pointer to the lock +// object. + +// Report that a lock has been created at address `lock`. +#define ABSL_ANNOTATE_RWLOCK_CREATE(lock) \ + ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateRWLockCreate)(__FILE__, __LINE__, lock) + +// Report that a linker initialized lock has been created at address `lock`. +#ifdef ABSL_HAVE_THREAD_SANITIZER +#define ABSL_ANNOTATE_RWLOCK_CREATE_STATIC(lock) \ + ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateRWLockCreateStatic) \ + (__FILE__, __LINE__, lock) +#else +#define ABSL_ANNOTATE_RWLOCK_CREATE_STATIC(lock) \ + ABSL_ANNOTATE_RWLOCK_CREATE(lock) +#endif + +// Report that the lock at address `lock` is about to be destroyed. +#define ABSL_ANNOTATE_RWLOCK_DESTROY(lock) \ + ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateRWLockDestroy)(__FILE__, __LINE__, lock) + +// Report that the lock at address `lock` has been acquired. +// `is_w`=1 for writer lock, `is_w`=0 for reader lock. +#define ABSL_ANNOTATE_RWLOCK_ACQUIRED(lock, is_w) \ + ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateRWLockAcquired) \ + (__FILE__, __LINE__, lock, is_w) + +// Report that the lock at address `lock` is about to be released. +// `is_w`=1 for writer lock, `is_w`=0 for reader lock. +#define ABSL_ANNOTATE_RWLOCK_RELEASED(lock, is_w) \ + ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateRWLockReleased) \ + (__FILE__, __LINE__, lock, is_w) + +// Apply ABSL_ANNOTATE_BENIGN_RACE_SIZED to a static variable `static_var`. +#define ABSL_ANNOTATE_BENIGN_RACE_STATIC(static_var, description) \ + namespace { \ + class static_var##_annotator { \ + public: \ + static_var##_annotator() { \ + ABSL_ANNOTATE_BENIGN_RACE_SIZED(&static_var, sizeof(static_var), \ + #static_var ": " description); \ + } \ + }; \ + static static_var##_annotator the##static_var##_annotator; \ + } // namespace + +// Function prototypes of annotations provided by the compiler-based sanitizer +// implementation. +ABSL_INTERNAL_BEGIN_EXTERN_C +void AnnotateRWLockCreate(const char* file, int line, + const volatile void* lock); +void AnnotateRWLockCreateStatic(const char* file, int line, + const volatile void* lock); +void AnnotateRWLockDestroy(const char* file, int line, + const volatile void* lock); +void AnnotateRWLockAcquired(const char* file, int line, + const volatile void* lock, long is_w); // NOLINT +void AnnotateRWLockReleased(const char* file, int line, + const volatile void* lock, long is_w); // NOLINT +void AnnotateBenignRace(const char* file, int line, + const volatile void* address, const char* description); +void AnnotateBenignRaceSized(const char* file, int line, + const volatile void* address, size_t size, + const char* description); +void AnnotateThreadName(const char* file, int line, const char* name); +void AnnotateEnableRaceDetection(const char* file, int line, int enable); +ABSL_INTERNAL_END_EXTERN_C + +#else // ABSL_INTERNAL_RACE_ANNOTATIONS_ENABLED == 0 + +#define ABSL_ANNOTATE_RWLOCK_CREATE(lock) // empty +#define ABSL_ANNOTATE_RWLOCK_CREATE_STATIC(lock) // empty +#define ABSL_ANNOTATE_RWLOCK_DESTROY(lock) // empty +#define ABSL_ANNOTATE_RWLOCK_ACQUIRED(lock, is_w) // empty +#define ABSL_ANNOTATE_RWLOCK_RELEASED(lock, is_w) // empty +#define ABSL_ANNOTATE_BENIGN_RACE(address, description) // empty +#define ABSL_ANNOTATE_BENIGN_RACE_SIZED(address, size, description) // empty +#define ABSL_ANNOTATE_THREAD_NAME(name) // empty +#define ABSL_ANNOTATE_ENABLE_RACE_DETECTION(enable) // empty +#define ABSL_ANNOTATE_BENIGN_RACE_STATIC(static_var, description) // empty + +#endif // ABSL_INTERNAL_RACE_ANNOTATIONS_ENABLED + +// ------------------------------------------------------------------------- +// Define memory annotations. + +#ifdef ABSL_HAVE_MEMORY_SANITIZER + +#include + +#define ABSL_ANNOTATE_MEMORY_IS_INITIALIZED(address, size) \ + __msan_unpoison(address, size) + +#define ABSL_ANNOTATE_MEMORY_IS_UNINITIALIZED(address, size) \ + __msan_allocated_memory(address, size) + +#else // !defined(ABSL_HAVE_MEMORY_SANITIZER) + +// TODO(rogeeff): remove this branch +#ifdef ABSL_HAVE_THREAD_SANITIZER +#define ABSL_ANNOTATE_MEMORY_IS_INITIALIZED(address, size) \ + do { \ + (void)(address); \ + (void)(size); \ + } while (0) +#define ABSL_ANNOTATE_MEMORY_IS_UNINITIALIZED(address, size) \ + do { \ + (void)(address); \ + (void)(size); \ + } while (0) +#else + +#define ABSL_ANNOTATE_MEMORY_IS_INITIALIZED(address, size) // empty +#define ABSL_ANNOTATE_MEMORY_IS_UNINITIALIZED(address, size) // empty + +#endif + +#endif // ABSL_HAVE_MEMORY_SANITIZER + +// ------------------------------------------------------------------------- +// Define IGNORE_READS_BEGIN/_END attributes. + +#if defined(ABSL_INTERNAL_IGNORE_READS_ATTRIBUTE_ENABLED) + +#define ABSL_INTERNAL_IGNORE_READS_BEGIN_ATTRIBUTE \ + __attribute((exclusive_lock_function("*"))) +#define ABSL_INTERNAL_IGNORE_READS_END_ATTRIBUTE \ + __attribute((unlock_function("*"))) + +#else // !defined(ABSL_INTERNAL_IGNORE_READS_ATTRIBUTE_ENABLED) + +#define ABSL_INTERNAL_IGNORE_READS_BEGIN_ATTRIBUTE // empty +#define ABSL_INTERNAL_IGNORE_READS_END_ATTRIBUTE // empty + +#endif // defined(ABSL_INTERNAL_IGNORE_READS_ATTRIBUTE_ENABLED) + +// ------------------------------------------------------------------------- +// Define IGNORE_READS_BEGIN/_END annotations. + +#if ABSL_INTERNAL_READS_ANNOTATIONS_ENABLED == 1 +// Some of the symbols used in this section (e.g. AnnotateIgnoreReadsBegin) are +// defined by the compiler-based implementation, not by the Abseil +// library. Therefore they do not use ABSL_INTERNAL_C_SYMBOL. + +// Request the analysis tool to ignore all reads in the current thread until +// ABSL_ANNOTATE_IGNORE_READS_END is called. Useful to ignore intentional racey +// reads, while still checking other reads and all writes. +// See also ABSL_ANNOTATE_UNPROTECTED_READ. +#define ABSL_ANNOTATE_IGNORE_READS_BEGIN() \ + ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateIgnoreReadsBegin) \ + (__FILE__, __LINE__) + +// Stop ignoring reads. +#define ABSL_ANNOTATE_IGNORE_READS_END() \ + ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateIgnoreReadsEnd) \ + (__FILE__, __LINE__) + +// Function prototypes of annotations provided by the compiler-based sanitizer +// implementation. +ABSL_INTERNAL_BEGIN_EXTERN_C +void AnnotateIgnoreReadsBegin(const char* file, int line) + ABSL_INTERNAL_IGNORE_READS_BEGIN_ATTRIBUTE; +void AnnotateIgnoreReadsEnd(const char* file, + int line) ABSL_INTERNAL_IGNORE_READS_END_ATTRIBUTE; +ABSL_INTERNAL_END_EXTERN_C + +#elif defined(ABSL_INTERNAL_ANNOTALYSIS_ENABLED) + +// When Annotalysis is enabled without Dynamic Annotations, the use of +// static-inline functions allows the annotations to be read at compile-time, +// while still letting the compiler elide the functions from the final build. +// +// TODO(delesley) -- The exclusive lock here ignores writes as well, but +// allows IGNORE_READS_AND_WRITES to work properly. + +#define ABSL_ANNOTATE_IGNORE_READS_BEGIN() \ + ABSL_INTERNAL_GLOBAL_SCOPED( \ + ABSL_INTERNAL_C_SYMBOL(AbslInternalAnnotateIgnoreReadsBegin)) \ + () + +#define ABSL_ANNOTATE_IGNORE_READS_END() \ + ABSL_INTERNAL_GLOBAL_SCOPED( \ + ABSL_INTERNAL_C_SYMBOL(AbslInternalAnnotateIgnoreReadsEnd)) \ + () + +ABSL_INTERNAL_STATIC_INLINE void ABSL_INTERNAL_C_SYMBOL( + AbslInternalAnnotateIgnoreReadsBegin)() + ABSL_INTERNAL_IGNORE_READS_BEGIN_ATTRIBUTE {} + +ABSL_INTERNAL_STATIC_INLINE void ABSL_INTERNAL_C_SYMBOL( + AbslInternalAnnotateIgnoreReadsEnd)() + ABSL_INTERNAL_IGNORE_READS_END_ATTRIBUTE {} + +#else + +#define ABSL_ANNOTATE_IGNORE_READS_BEGIN() // empty +#define ABSL_ANNOTATE_IGNORE_READS_END() // empty + +#endif + +// ------------------------------------------------------------------------- +// Define IGNORE_WRITES_BEGIN/_END annotations. + +#if ABSL_INTERNAL_WRITES_ANNOTATIONS_ENABLED == 1 + +// Similar to ABSL_ANNOTATE_IGNORE_READS_BEGIN, but ignore writes instead. +#define ABSL_ANNOTATE_IGNORE_WRITES_BEGIN() \ + ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateIgnoreWritesBegin)(__FILE__, __LINE__) + +// Stop ignoring writes. +#define ABSL_ANNOTATE_IGNORE_WRITES_END() \ + ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateIgnoreWritesEnd)(__FILE__, __LINE__) + +// Function prototypes of annotations provided by the compiler-based sanitizer +// implementation. +ABSL_INTERNAL_BEGIN_EXTERN_C +void AnnotateIgnoreWritesBegin(const char* file, int line); +void AnnotateIgnoreWritesEnd(const char* file, int line); +ABSL_INTERNAL_END_EXTERN_C + +#else + +#define ABSL_ANNOTATE_IGNORE_WRITES_BEGIN() // empty +#define ABSL_ANNOTATE_IGNORE_WRITES_END() // empty + +#endif + +// ------------------------------------------------------------------------- +// Define the ABSL_ANNOTATE_IGNORE_READS_AND_WRITES_* annotations using the more +// primitive annotations defined above. +// +// Instead of doing +// ABSL_ANNOTATE_IGNORE_READS_BEGIN(); +// ... = x; +// ABSL_ANNOTATE_IGNORE_READS_END(); +// one can use +// ... = ABSL_ANNOTATE_UNPROTECTED_READ(x); + +#if defined(ABSL_INTERNAL_READS_WRITES_ANNOTATIONS_ENABLED) + +// Start ignoring all memory accesses (both reads and writes). +#define ABSL_ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN() \ + do { \ + ABSL_ANNOTATE_IGNORE_READS_BEGIN(); \ + ABSL_ANNOTATE_IGNORE_WRITES_BEGIN(); \ + } while (0) + +// Stop ignoring both reads and writes. +#define ABSL_ANNOTATE_IGNORE_READS_AND_WRITES_END() \ + do { \ + ABSL_ANNOTATE_IGNORE_WRITES_END(); \ + ABSL_ANNOTATE_IGNORE_READS_END(); \ + } while (0) + +#ifdef __cplusplus +// ABSL_ANNOTATE_UNPROTECTED_READ is the preferred way to annotate racey reads. +#define ABSL_ANNOTATE_UNPROTECTED_READ(x) \ + absl::base_internal::AnnotateUnprotectedRead(x) + +namespace absl { +ABSL_NAMESPACE_BEGIN +namespace base_internal { - Instead of doing - ABSL_ANNOTATE_IGNORE_READS_BEGIN(); - ... = x; - ABSL_ANNOTATE_IGNORE_READS_END(); - one can use - ... = ABSL_ANNOTATE_UNPROTECTED_READ(x); */ -#if defined(__cplusplus) && defined(ABSL_ANNOTATIONS_ENABLED) template -inline T ABSL_ANNOTATE_UNPROTECTED_READ(const volatile T &x) { /* NOLINT */ +inline T AnnotateUnprotectedRead(const volatile T& x) { // NOLINT ABSL_ANNOTATE_IGNORE_READS_BEGIN(); T res = x; ABSL_ANNOTATE_IGNORE_READS_END(); return res; - } -#else - #define ABSL_ANNOTATE_UNPROTECTED_READ(x) (x) +} + +} // namespace base_internal +ABSL_NAMESPACE_END +} // namespace absl #endif -#if ABSL_DYNAMIC_ANNOTATIONS_ENABLED != 0 && defined(__cplusplus) - /* Apply ABSL_ANNOTATE_BENIGN_RACE_SIZED to a static variable. */ - #define ABSL_ANNOTATE_BENIGN_RACE_STATIC(static_var, description) \ - namespace { \ - class static_var ## _annotator { \ - public: \ - static_var ## _annotator() { \ - ABSL_ANNOTATE_BENIGN_RACE_SIZED(&static_var, \ - sizeof(static_var), \ - # static_var ": " description); \ - } \ - }; \ - static static_var ## _annotator the ## static_var ## _annotator;\ - } // namespace -#else /* ABSL_DYNAMIC_ANNOTATIONS_ENABLED == 0 */ - #define ABSL_ANNOTATE_BENIGN_RACE_STATIC(static_var, description) /* empty */ -#endif /* ABSL_DYNAMIC_ANNOTATIONS_ENABLED */ +#else -#ifdef ADDRESS_SANITIZER -/* Describe the current state of a contiguous container such as e.g. - * std::vector or std::string. For more details see - * sanitizer/common_interface_defs.h, which is provided by the compiler. */ +#define ABSL_ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN() // empty +#define ABSL_ANNOTATE_IGNORE_READS_AND_WRITES_END() // empty +#define ABSL_ANNOTATE_UNPROTECTED_READ(x) (x) + +#endif + +// ------------------------------------------------------------------------- +// Address sanitizer annotations + +#ifdef ABSL_HAVE_ADDRESS_SANITIZER +// Describe the current state of a contiguous container such as e.g. +// std::vector or std::string. For more details see +// sanitizer/common_interface_defs.h, which is provided by the compiler. #include + #define ABSL_ANNOTATE_CONTIGUOUS_CONTAINER(beg, end, old_mid, new_mid) \ __sanitizer_annotate_contiguous_container(beg, end, old_mid, new_mid) -#define ABSL_ADDRESS_SANITIZER_REDZONE(name) \ - struct { char x[8] __attribute__ ((aligned (8))); } name +#define ABSL_ADDRESS_SANITIZER_REDZONE(name) \ + struct { \ + alignas(8) char x[8]; \ + } name + #else -#define ABSL_ANNOTATE_CONTIGUOUS_CONTAINER(beg, end, old_mid, new_mid) + +#define ABSL_ANNOTATE_CONTIGUOUS_CONTAINER(beg, end, old_mid, new_mid) // empty #define ABSL_ADDRESS_SANITIZER_REDZONE(name) static_assert(true, "") -#endif // ADDRESS_SANITIZER -/* Undefine the macros intended only in this file. */ -#undef ABSL_ANNOTALYSIS_ENABLED -#undef ABSL_ANNOTATIONS_ENABLED -#undef ABSL_ATTRIBUTE_IGNORE_READS_BEGIN -#undef ABSL_ATTRIBUTE_IGNORE_READS_END +#endif // ABSL_HAVE_ADDRESS_SANITIZER -#endif /* ABSL_BASE_DYNAMIC_ANNOTATIONS_H_ */ +// ------------------------------------------------------------------------- +// Undefine the macros intended only for this file. + +#undef ABSL_INTERNAL_RACE_ANNOTATIONS_ENABLED +#undef ABSL_INTERNAL_READS_ANNOTATIONS_ENABLED +#undef ABSL_INTERNAL_WRITES_ANNOTATIONS_ENABLED +#undef ABSL_INTERNAL_ANNOTALYSIS_ENABLED +#undef ABSL_INTERNAL_READS_WRITES_ANNOTATIONS_ENABLED +#undef ABSL_INTERNAL_BEGIN_EXTERN_C +#undef ABSL_INTERNAL_END_EXTERN_C +#undef ABSL_INTERNAL_STATIC_INLINE + +#endif // ABSL_BASE_DYNAMIC_ANNOTATIONS_H_ diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/bits.h b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/bits.h deleted file mode 100644 index 14c51d8b30..0000000000 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/bits.h +++ /dev/null @@ -1,218 +0,0 @@ -// Copyright 2018 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef ABSL_BASE_INTERNAL_BITS_H_ -#define ABSL_BASE_INTERNAL_BITS_H_ - -// This file contains bitwise ops which are implementation details of various -// absl libraries. - -#include - -#include "absl/base/config.h" - -// Clang on Windows has __builtin_clzll; otherwise we need to use the -// windows intrinsic functions. -#if defined(_MSC_VER) && !defined(__clang__) -#include -#if defined(_M_X64) -#pragma intrinsic(_BitScanReverse64) -#pragma intrinsic(_BitScanForward64) -#endif -#pragma intrinsic(_BitScanReverse) -#pragma intrinsic(_BitScanForward) -#endif - -#include "absl/base/attributes.h" - -#if defined(_MSC_VER) && !defined(__clang__) -// We can achieve something similar to attribute((always_inline)) with MSVC by -// using the __forceinline keyword, however this is not perfect. MSVC is -// much less aggressive about inlining, and even with the __forceinline keyword. -#define ABSL_BASE_INTERNAL_FORCEINLINE __forceinline -#else -// Use default attribute inline. -#define ABSL_BASE_INTERNAL_FORCEINLINE inline ABSL_ATTRIBUTE_ALWAYS_INLINE -#endif - - -namespace absl { -ABSL_NAMESPACE_BEGIN -namespace base_internal { - -ABSL_BASE_INTERNAL_FORCEINLINE int CountLeadingZeros64Slow(uint64_t n) { - int zeroes = 60; - if (n >> 32) { - zeroes -= 32; - n >>= 32; - } - if (n >> 16) { - zeroes -= 16; - n >>= 16; - } - if (n >> 8) { - zeroes -= 8; - n >>= 8; - } - if (n >> 4) { - zeroes -= 4; - n >>= 4; - } - return "\4\3\2\2\1\1\1\1\0\0\0\0\0\0\0"[n] + zeroes; -} - -ABSL_BASE_INTERNAL_FORCEINLINE int CountLeadingZeros64(uint64_t n) { -#if defined(_MSC_VER) && !defined(__clang__) && defined(_M_X64) - // MSVC does not have __buitin_clzll. Use _BitScanReverse64. - unsigned long result = 0; // NOLINT(runtime/int) - if (_BitScanReverse64(&result, n)) { - return 63 - result; - } - return 64; -#elif defined(_MSC_VER) && !defined(__clang__) - // MSVC does not have __buitin_clzll. Compose two calls to _BitScanReverse - unsigned long result = 0; // NOLINT(runtime/int) - if ((n >> 32) && _BitScanReverse(&result, n >> 32)) { - return 31 - result; - } - if (_BitScanReverse(&result, n)) { - return 63 - result; - } - return 64; -#elif defined(__GNUC__) || defined(__clang__) - // Use __builtin_clzll, which uses the following instructions: - // x86: bsr - // ARM64: clz - // PPC: cntlzd - static_assert(sizeof(unsigned long long) == sizeof(n), // NOLINT(runtime/int) - "__builtin_clzll does not take 64-bit arg"); - - // Handle 0 as a special case because __builtin_clzll(0) is undefined. - if (n == 0) { - return 64; - } - return __builtin_clzll(n); -#else - return CountLeadingZeros64Slow(n); -#endif -} - -ABSL_BASE_INTERNAL_FORCEINLINE int CountLeadingZeros32Slow(uint64_t n) { - int zeroes = 28; - if (n >> 16) { - zeroes -= 16; - n >>= 16; - } - if (n >> 8) { - zeroes -= 8; - n >>= 8; - } - if (n >> 4) { - zeroes -= 4; - n >>= 4; - } - return "\4\3\2\2\1\1\1\1\0\0\0\0\0\0\0"[n] + zeroes; -} - -ABSL_BASE_INTERNAL_FORCEINLINE int CountLeadingZeros32(uint32_t n) { -#if defined(_MSC_VER) && !defined(__clang__) - unsigned long result = 0; // NOLINT(runtime/int) - if (_BitScanReverse(&result, n)) { - return 31 - result; - } - return 32; -#elif defined(__GNUC__) || defined(__clang__) - // Use __builtin_clz, which uses the following instructions: - // x86: bsr - // ARM64: clz - // PPC: cntlzd - static_assert(sizeof(int) == sizeof(n), - "__builtin_clz does not take 32-bit arg"); - - // Handle 0 as a special case because __builtin_clz(0) is undefined. - if (n == 0) { - return 32; - } - return __builtin_clz(n); -#else - return CountLeadingZeros32Slow(n); -#endif -} - -ABSL_BASE_INTERNAL_FORCEINLINE int CountTrailingZerosNonZero64Slow(uint64_t n) { - int c = 63; - n &= ~n + 1; - if (n & 0x00000000FFFFFFFF) c -= 32; - if (n & 0x0000FFFF0000FFFF) c -= 16; - if (n & 0x00FF00FF00FF00FF) c -= 8; - if (n & 0x0F0F0F0F0F0F0F0F) c -= 4; - if (n & 0x3333333333333333) c -= 2; - if (n & 0x5555555555555555) c -= 1; - return c; -} - -ABSL_BASE_INTERNAL_FORCEINLINE int CountTrailingZerosNonZero64(uint64_t n) { -#if defined(_MSC_VER) && !defined(__clang__) && defined(_M_X64) - unsigned long result = 0; // NOLINT(runtime/int) - _BitScanForward64(&result, n); - return result; -#elif defined(_MSC_VER) && !defined(__clang__) - unsigned long result = 0; // NOLINT(runtime/int) - if (static_cast(n) == 0) { - _BitScanForward(&result, n >> 32); - return result + 32; - } - _BitScanForward(&result, n); - return result; -#elif defined(__GNUC__) || defined(__clang__) - static_assert(sizeof(unsigned long long) == sizeof(n), // NOLINT(runtime/int) - "__builtin_ctzll does not take 64-bit arg"); - return __builtin_ctzll(n); -#else - return CountTrailingZerosNonZero64Slow(n); -#endif -} - -ABSL_BASE_INTERNAL_FORCEINLINE int CountTrailingZerosNonZero32Slow(uint32_t n) { - int c = 31; - n &= ~n + 1; - if (n & 0x0000FFFF) c -= 16; - if (n & 0x00FF00FF) c -= 8; - if (n & 0x0F0F0F0F) c -= 4; - if (n & 0x33333333) c -= 2; - if (n & 0x55555555) c -= 1; - return c; -} - -ABSL_BASE_INTERNAL_FORCEINLINE int CountTrailingZerosNonZero32(uint32_t n) { -#if defined(_MSC_VER) && !defined(__clang__) - unsigned long result = 0; // NOLINT(runtime/int) - _BitScanForward(&result, n); - return result; -#elif defined(__GNUC__) || defined(__clang__) - static_assert(sizeof(int) == sizeof(n), - "__builtin_ctz does not take 32-bit arg"); - return __builtin_ctz(n); -#else - return CountTrailingZerosNonZero32Slow(n); -#endif -} - -#undef ABSL_BASE_INTERNAL_FORCEINLINE - -} // namespace base_internal -ABSL_NAMESPACE_END -} // namespace absl - -#endif // ABSL_BASE_INTERNAL_BITS_H_ diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/bits_test.cc b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/bits_test.cc deleted file mode 100644 index 7855fa6297..0000000000 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/bits_test.cc +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright 2018 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "absl/base/internal/bits.h" - -#include "gtest/gtest.h" - -namespace { - -int CLZ64(uint64_t n) { - int fast = absl::base_internal::CountLeadingZeros64(n); - int slow = absl::base_internal::CountLeadingZeros64Slow(n); - EXPECT_EQ(fast, slow) << n; - return fast; -} - -TEST(BitsTest, CountLeadingZeros64) { - EXPECT_EQ(64, CLZ64(uint64_t{})); - EXPECT_EQ(0, CLZ64(~uint64_t{})); - - for (int index = 0; index < 64; index++) { - uint64_t x = static_cast(1) << index; - const auto cnt = 63 - index; - ASSERT_EQ(cnt, CLZ64(x)) << index; - ASSERT_EQ(cnt, CLZ64(x + x - 1)) << index; - } -} - -int CLZ32(uint32_t n) { - int fast = absl::base_internal::CountLeadingZeros32(n); - int slow = absl::base_internal::CountLeadingZeros32Slow(n); - EXPECT_EQ(fast, slow) << n; - return fast; -} - -TEST(BitsTest, CountLeadingZeros32) { - EXPECT_EQ(32, CLZ32(uint32_t{})); - EXPECT_EQ(0, CLZ32(~uint32_t{})); - - for (int index = 0; index < 32; index++) { - uint32_t x = static_cast(1) << index; - const auto cnt = 31 - index; - ASSERT_EQ(cnt, CLZ32(x)) << index; - ASSERT_EQ(cnt, CLZ32(x + x - 1)) << index; - ASSERT_EQ(CLZ64(x), CLZ32(x) + 32); - } -} - -int CTZ64(uint64_t n) { - int fast = absl::base_internal::CountTrailingZerosNonZero64(n); - int slow = absl::base_internal::CountTrailingZerosNonZero64Slow(n); - EXPECT_EQ(fast, slow) << n; - return fast; -} - -TEST(BitsTest, CountTrailingZerosNonZero64) { - EXPECT_EQ(0, CTZ64(~uint64_t{})); - - for (int index = 0; index < 64; index++) { - uint64_t x = static_cast(1) << index; - const auto cnt = index; - ASSERT_EQ(cnt, CTZ64(x)) << index; - ASSERT_EQ(cnt, CTZ64(~(x - 1))) << index; - } -} - -int CTZ32(uint32_t n) { - int fast = absl::base_internal::CountTrailingZerosNonZero32(n); - int slow = absl::base_internal::CountTrailingZerosNonZero32Slow(n); - EXPECT_EQ(fast, slow) << n; - return fast; -} - -TEST(BitsTest, CountTrailingZerosNonZero32) { - EXPECT_EQ(0, CTZ32(~uint32_t{})); - - for (int index = 0; index < 32; index++) { - uint32_t x = static_cast(1) << index; - const auto cnt = index; - ASSERT_EQ(cnt, CTZ32(x)) << index; - ASSERT_EQ(cnt, CTZ32(~(x - 1))) << index; - } -} - - -} // namespace diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/direct_mmap.h b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/direct_mmap.h index 5618867ba0..274054cd5a 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/direct_mmap.h +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/direct_mmap.h @@ -61,6 +61,10 @@ extern "C" void* __mmap2(void*, size_t, int, int, int, size_t); #endif #endif // __BIONIC__ +#if defined(__NR_mmap2) && !defined(SYS_mmap2) +#define SYS_mmap2 __NR_mmap2 +#endif + namespace absl { ABSL_NAMESPACE_BEGIN namespace base_internal { @@ -70,9 +74,13 @@ namespace base_internal { inline void* DirectMmap(void* start, size_t length, int prot, int flags, int fd, off64_t offset) noexcept { #if defined(__i386__) || defined(__ARM_ARCH_3__) || defined(__ARM_EABI__) || \ + defined(__m68k__) || defined(__sh__) || \ + (defined(__hppa__) && !defined(__LP64__)) || \ (defined(__mips__) && _MIPS_SIM == _MIPS_SIM_ABI32) || \ (defined(__PPC__) && !defined(__PPC64__)) || \ - (defined(__s390__) && !defined(__s390x__)) + (defined(__riscv) && __riscv_xlen == 32) || \ + (defined(__s390__) && !defined(__s390x__)) || \ + (defined(__sparc__) && !defined(__arch64__)) // On these architectures, implement mmap with mmap2. static int pagesize = 0; if (pagesize == 0) { diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/dynamic_annotations.h b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/dynamic_annotations.h new file mode 100644 index 0000000000..b23c5ec1c4 --- /dev/null +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/dynamic_annotations.h @@ -0,0 +1,398 @@ +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// This file defines dynamic annotations for use with dynamic analysis tool +// such as valgrind, PIN, etc. +// +// Dynamic annotation is a source code annotation that affects the generated +// code (that is, the annotation is not a comment). Each such annotation is +// attached to a particular instruction and/or to a particular object (address) +// in the program. +// +// The annotations that should be used by users are macros in all upper-case +// (e.g., ANNOTATE_THREAD_NAME). +// +// Actual implementation of these macros may differ depending on the dynamic +// analysis tool being used. +// +// This file supports the following configurations: +// - Dynamic Annotations enabled (with static thread-safety warnings disabled). +// In this case, macros expand to functions implemented by Thread Sanitizer, +// when building with TSan. When not provided an external implementation, +// dynamic_annotations.cc provides no-op implementations. +// +// - Static Clang thread-safety warnings enabled. +// When building with a Clang compiler that supports thread-safety warnings, +// a subset of annotations can be statically-checked at compile-time. We +// expand these macros to static-inline functions that can be analyzed for +// thread-safety, but afterwards elided when building the final binary. +// +// - All annotations are disabled. +// If neither Dynamic Annotations nor Clang thread-safety warnings are +// enabled, then all annotation-macros expand to empty. + +#ifndef ABSL_BASE_INTERNAL_DYNAMIC_ANNOTATIONS_H_ +#define ABSL_BASE_INTERNAL_DYNAMIC_ANNOTATIONS_H_ + +#include + +#include "absl/base/config.h" + +// ------------------------------------------------------------------------- +// Decide which features are enabled + +#ifndef DYNAMIC_ANNOTATIONS_ENABLED +#define DYNAMIC_ANNOTATIONS_ENABLED 0 +#endif + +#if defined(__clang__) && !defined(SWIG) +#define ABSL_INTERNAL_IGNORE_READS_ATTRIBUTE_ENABLED 1 +#endif + +#if DYNAMIC_ANNOTATIONS_ENABLED != 0 + +#define ABSL_INTERNAL_RACE_ANNOTATIONS_ENABLED 1 +#define ABSL_INTERNAL_READS_ANNOTATIONS_ENABLED 1 +#define ABSL_INTERNAL_WRITES_ANNOTATIONS_ENABLED 1 +#define ABSL_INTERNAL_ANNOTALYSIS_ENABLED 0 +#define ABSL_INTERNAL_READS_WRITES_ANNOTATIONS_ENABLED 1 + +#else + +#define ABSL_INTERNAL_RACE_ANNOTATIONS_ENABLED 0 +#define ABSL_INTERNAL_READS_ANNOTATIONS_ENABLED 0 +#define ABSL_INTERNAL_WRITES_ANNOTATIONS_ENABLED 0 + +// Clang provides limited support for static thread-safety analysis through a +// feature called Annotalysis. We configure macro-definitions according to +// whether Annotalysis support is available. When running in opt-mode, GCC +// will issue a warning, if these attributes are compiled. Only include them +// when compiling using Clang. + +// ANNOTALYSIS_ENABLED == 1 when IGNORE_READ_ATTRIBUTE_ENABLED == 1 +#define ABSL_INTERNAL_ANNOTALYSIS_ENABLED \ + defined(ABSL_INTERNAL_IGNORE_READS_ATTRIBUTE_ENABLED) +// Read/write annotations are enabled in Annotalysis mode; disabled otherwise. +#define ABSL_INTERNAL_READS_WRITES_ANNOTATIONS_ENABLED \ + ABSL_INTERNAL_ANNOTALYSIS_ENABLED +#endif + +// Memory annotations are also made available to LLVM's Memory Sanitizer +#if defined(ABSL_HAVE_MEMORY_SANITIZER) && !defined(__native_client__) +#define ABSL_INTERNAL_MEMORY_ANNOTATIONS_ENABLED 1 +#endif + +#ifndef ABSL_INTERNAL_MEMORY_ANNOTATIONS_ENABLED +#define ABSL_INTERNAL_MEMORY_ANNOTATIONS_ENABLED 0 +#endif + +#ifdef __cplusplus +#define ABSL_INTERNAL_BEGIN_EXTERN_C extern "C" { +#define ABSL_INTERNAL_END_EXTERN_C } // extern "C" +#define ABSL_INTERNAL_GLOBAL_SCOPED(F) ::F +#define ABSL_INTERNAL_STATIC_INLINE inline +#else +#define ABSL_INTERNAL_BEGIN_EXTERN_C // empty +#define ABSL_INTERNAL_END_EXTERN_C // empty +#define ABSL_INTERNAL_GLOBAL_SCOPED(F) F +#define ABSL_INTERNAL_STATIC_INLINE static inline +#endif + +// ------------------------------------------------------------------------- +// Define race annotations. + +#if ABSL_INTERNAL_RACE_ANNOTATIONS_ENABLED == 1 + +// ------------------------------------------------------------- +// Annotations that suppress errors. It is usually better to express the +// program's synchronization using the other annotations, but these can be used +// when all else fails. + +// Report that we may have a benign race at `pointer`, with size +// "sizeof(*(pointer))". `pointer` must be a non-void* pointer. Insert at the +// point where `pointer` has been allocated, preferably close to the point +// where the race happens. See also ANNOTATE_BENIGN_RACE_STATIC. +#define ANNOTATE_BENIGN_RACE(pointer, description) \ + ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateBenignRaceSized) \ + (__FILE__, __LINE__, pointer, sizeof(*(pointer)), description) + +// Same as ANNOTATE_BENIGN_RACE(`address`, `description`), but applies to +// the memory range [`address`, `address`+`size`). +#define ANNOTATE_BENIGN_RACE_SIZED(address, size, description) \ + ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateBenignRaceSized) \ + (__FILE__, __LINE__, address, size, description) + +// Enable (`enable`!=0) or disable (`enable`==0) race detection for all threads. +// This annotation could be useful if you want to skip expensive race analysis +// during some period of program execution, e.g. during initialization. +#define ANNOTATE_ENABLE_RACE_DETECTION(enable) \ + ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateEnableRaceDetection) \ + (__FILE__, __LINE__, enable) + +// ------------------------------------------------------------- +// Annotations useful for debugging. + +// Report the current thread `name` to a race detector. +#define ANNOTATE_THREAD_NAME(name) \ + ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateThreadName)(__FILE__, __LINE__, name) + +// ------------------------------------------------------------- +// Annotations useful when implementing locks. They are not normally needed by +// modules that merely use locks. The `lock` argument is a pointer to the lock +// object. + +// Report that a lock has been created at address `lock`. +#define ANNOTATE_RWLOCK_CREATE(lock) \ + ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateRWLockCreate)(__FILE__, __LINE__, lock) + +// Report that a linker initialized lock has been created at address `lock`. +#ifdef ABSL_HAVE_THREAD_SANITIZER +#define ANNOTATE_RWLOCK_CREATE_STATIC(lock) \ + ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateRWLockCreateStatic) \ + (__FILE__, __LINE__, lock) +#else +#define ANNOTATE_RWLOCK_CREATE_STATIC(lock) ANNOTATE_RWLOCK_CREATE(lock) +#endif + +// Report that the lock at address `lock` is about to be destroyed. +#define ANNOTATE_RWLOCK_DESTROY(lock) \ + ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateRWLockDestroy)(__FILE__, __LINE__, lock) + +// Report that the lock at address `lock` has been acquired. +// `is_w`=1 for writer lock, `is_w`=0 for reader lock. +#define ANNOTATE_RWLOCK_ACQUIRED(lock, is_w) \ + ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateRWLockAcquired) \ + (__FILE__, __LINE__, lock, is_w) + +// Report that the lock at address `lock` is about to be released. +// `is_w`=1 for writer lock, `is_w`=0 for reader lock. +#define ANNOTATE_RWLOCK_RELEASED(lock, is_w) \ + ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateRWLockReleased) \ + (__FILE__, __LINE__, lock, is_w) + +// Apply ANNOTATE_BENIGN_RACE_SIZED to a static variable `static_var`. +#define ANNOTATE_BENIGN_RACE_STATIC(static_var, description) \ + namespace { \ + class static_var##_annotator { \ + public: \ + static_var##_annotator() { \ + ANNOTATE_BENIGN_RACE_SIZED(&static_var, sizeof(static_var), \ + #static_var ": " description); \ + } \ + }; \ + static static_var##_annotator the##static_var##_annotator; \ + } // namespace + +#else // ABSL_INTERNAL_RACE_ANNOTATIONS_ENABLED == 0 + +#define ANNOTATE_RWLOCK_CREATE(lock) // empty +#define ANNOTATE_RWLOCK_CREATE_STATIC(lock) // empty +#define ANNOTATE_RWLOCK_DESTROY(lock) // empty +#define ANNOTATE_RWLOCK_ACQUIRED(lock, is_w) // empty +#define ANNOTATE_RWLOCK_RELEASED(lock, is_w) // empty +#define ANNOTATE_BENIGN_RACE(address, description) // empty +#define ANNOTATE_BENIGN_RACE_SIZED(address, size, description) // empty +#define ANNOTATE_THREAD_NAME(name) // empty +#define ANNOTATE_ENABLE_RACE_DETECTION(enable) // empty +#define ANNOTATE_BENIGN_RACE_STATIC(static_var, description) // empty + +#endif // ABSL_INTERNAL_RACE_ANNOTATIONS_ENABLED + +// ------------------------------------------------------------------------- +// Define memory annotations. + +#if ABSL_INTERNAL_MEMORY_ANNOTATIONS_ENABLED == 1 + +#include + +#define ANNOTATE_MEMORY_IS_INITIALIZED(address, size) \ + __msan_unpoison(address, size) + +#define ANNOTATE_MEMORY_IS_UNINITIALIZED(address, size) \ + __msan_allocated_memory(address, size) + +#else // ABSL_INTERNAL_MEMORY_ANNOTATIONS_ENABLED == 0 + +#if DYNAMIC_ANNOTATIONS_ENABLED == 1 +#define ANNOTATE_MEMORY_IS_INITIALIZED(address, size) \ + do { \ + (void)(address); \ + (void)(size); \ + } while (0) +#define ANNOTATE_MEMORY_IS_UNINITIALIZED(address, size) \ + do { \ + (void)(address); \ + (void)(size); \ + } while (0) +#else +#define ANNOTATE_MEMORY_IS_INITIALIZED(address, size) // empty +#define ANNOTATE_MEMORY_IS_UNINITIALIZED(address, size) // empty +#endif + +#endif // ABSL_INTERNAL_MEMORY_ANNOTATIONS_ENABLED + +// ------------------------------------------------------------------------- +// Define IGNORE_READS_BEGIN/_END attributes. + +#if defined(ABSL_INTERNAL_IGNORE_READS_ATTRIBUTE_ENABLED) + +#define ABSL_INTERNAL_IGNORE_READS_BEGIN_ATTRIBUTE \ + __attribute((exclusive_lock_function("*"))) +#define ABSL_INTERNAL_IGNORE_READS_END_ATTRIBUTE \ + __attribute((unlock_function("*"))) + +#else // !defined(ABSL_INTERNAL_IGNORE_READS_ATTRIBUTE_ENABLED) + +#define ABSL_INTERNAL_IGNORE_READS_BEGIN_ATTRIBUTE // empty +#define ABSL_INTERNAL_IGNORE_READS_END_ATTRIBUTE // empty + +#endif // defined(ABSL_INTERNAL_IGNORE_READS_ATTRIBUTE_ENABLED) + +// ------------------------------------------------------------------------- +// Define IGNORE_READS_BEGIN/_END annotations. + +#if ABSL_INTERNAL_READS_ANNOTATIONS_ENABLED == 1 + +// Request the analysis tool to ignore all reads in the current thread until +// ANNOTATE_IGNORE_READS_END is called. Useful to ignore intentional racey +// reads, while still checking other reads and all writes. +// See also ANNOTATE_UNPROTECTED_READ. +#define ANNOTATE_IGNORE_READS_BEGIN() \ + ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateIgnoreReadsBegin)(__FILE__, __LINE__) + +// Stop ignoring reads. +#define ANNOTATE_IGNORE_READS_END() \ + ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateIgnoreReadsEnd)(__FILE__, __LINE__) + +#elif defined(ABSL_INTERNAL_ANNOTALYSIS_ENABLED) + +// When Annotalysis is enabled without Dynamic Annotations, the use of +// static-inline functions allows the annotations to be read at compile-time, +// while still letting the compiler elide the functions from the final build. +// +// TODO(delesley) -- The exclusive lock here ignores writes as well, but +// allows IGNORE_READS_AND_WRITES to work properly. + +#define ANNOTATE_IGNORE_READS_BEGIN() \ + ABSL_INTERNAL_GLOBAL_SCOPED(AbslInternalAnnotateIgnoreReadsBegin)() + +#define ANNOTATE_IGNORE_READS_END() \ + ABSL_INTERNAL_GLOBAL_SCOPED(AbslInternalAnnotateIgnoreReadsEnd)() + +#else + +#define ANNOTATE_IGNORE_READS_BEGIN() // empty +#define ANNOTATE_IGNORE_READS_END() // empty + +#endif + +// ------------------------------------------------------------------------- +// Define IGNORE_WRITES_BEGIN/_END annotations. + +#if ABSL_INTERNAL_WRITES_ANNOTATIONS_ENABLED == 1 + +// Similar to ANNOTATE_IGNORE_READS_BEGIN, but ignore writes instead. +#define ANNOTATE_IGNORE_WRITES_BEGIN() \ + ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateIgnoreWritesBegin)(__FILE__, __LINE__) + +// Stop ignoring writes. +#define ANNOTATE_IGNORE_WRITES_END() \ + ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateIgnoreWritesEnd)(__FILE__, __LINE__) + +#else + +#define ANNOTATE_IGNORE_WRITES_BEGIN() // empty +#define ANNOTATE_IGNORE_WRITES_END() // empty + +#endif + +// ------------------------------------------------------------------------- +// Define the ANNOTATE_IGNORE_READS_AND_WRITES_* annotations using the more +// primitive annotations defined above. +// +// Instead of doing +// ANNOTATE_IGNORE_READS_BEGIN(); +// ... = x; +// ANNOTATE_IGNORE_READS_END(); +// one can use +// ... = ANNOTATE_UNPROTECTED_READ(x); + +#if defined(ABSL_INTERNAL_READS_WRITES_ANNOTATIONS_ENABLED) + +// Start ignoring all memory accesses (both reads and writes). +#define ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN() \ + do { \ + ANNOTATE_IGNORE_READS_BEGIN(); \ + ANNOTATE_IGNORE_WRITES_BEGIN(); \ + } while (0) + +// Stop ignoring both reads and writes. +#define ANNOTATE_IGNORE_READS_AND_WRITES_END() \ + do { \ + ANNOTATE_IGNORE_WRITES_END(); \ + ANNOTATE_IGNORE_READS_END(); \ + } while (0) + +#ifdef __cplusplus +// ANNOTATE_UNPROTECTED_READ is the preferred way to annotate racey reads. +#define ANNOTATE_UNPROTECTED_READ(x) \ + absl::base_internal::AnnotateUnprotectedRead(x) + +#endif + +#else + +#define ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN() // empty +#define ANNOTATE_IGNORE_READS_AND_WRITES_END() // empty +#define ANNOTATE_UNPROTECTED_READ(x) (x) + +#endif + +// ------------------------------------------------------------------------- +// Address sanitizer annotations + +#ifdef ABSL_HAVE_ADDRESS_SANITIZER +// Describe the current state of a contiguous container such as e.g. +// std::vector or std::string. For more details see +// sanitizer/common_interface_defs.h, which is provided by the compiler. +#include + +#define ANNOTATE_CONTIGUOUS_CONTAINER(beg, end, old_mid, new_mid) \ + __sanitizer_annotate_contiguous_container(beg, end, old_mid, new_mid) +#define ADDRESS_SANITIZER_REDZONE(name) \ + struct { \ + char x[8] __attribute__((aligned(8))); \ + } name + +#else + +#define ANNOTATE_CONTIGUOUS_CONTAINER(beg, end, old_mid, new_mid) +#define ADDRESS_SANITIZER_REDZONE(name) static_assert(true, "") + +#endif // ABSL_HAVE_ADDRESS_SANITIZER + +// ------------------------------------------------------------------------- +// Undefine the macros intended only for this file. + +#undef ABSL_INTERNAL_RACE_ANNOTATIONS_ENABLED +#undef ABSL_INTERNAL_MEMORY_ANNOTATIONS_ENABLED +#undef ABSL_INTERNAL_READS_ANNOTATIONS_ENABLED +#undef ABSL_INTERNAL_WRITES_ANNOTATIONS_ENABLED +#undef ABSL_INTERNAL_ANNOTALYSIS_ENABLED +#undef ABSL_INTERNAL_READS_WRITES_ANNOTATIONS_ENABLED +#undef ABSL_INTERNAL_BEGIN_EXTERN_C +#undef ABSL_INTERNAL_END_EXTERN_C +#undef ABSL_INTERNAL_STATIC_INLINE + +#endif // ABSL_BASE_INTERNAL_DYNAMIC_ANNOTATIONS_H_ diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/endian.h b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/endian.h index 9677530e8d..dad0e9aeb0 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/endian.h +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/endian.h @@ -26,6 +26,7 @@ #endif #include +#include "absl/base/casts.h" #include "absl/base/config.h" #include "absl/base/internal/unaligned_access.h" #include "absl/base/port.h" @@ -173,6 +174,36 @@ inline constexpr bool IsLittleEndian() { return false; } #endif /* ENDIAN */ +inline uint8_t FromHost(uint8_t x) { return x; } +inline uint16_t FromHost(uint16_t x) { return FromHost16(x); } +inline uint32_t FromHost(uint32_t x) { return FromHost32(x); } +inline uint64_t FromHost(uint64_t x) { return FromHost64(x); } +inline uint8_t ToHost(uint8_t x) { return x; } +inline uint16_t ToHost(uint16_t x) { return ToHost16(x); } +inline uint32_t ToHost(uint32_t x) { return ToHost32(x); } +inline uint64_t ToHost(uint64_t x) { return ToHost64(x); } + +inline int8_t FromHost(int8_t x) { return x; } +inline int16_t FromHost(int16_t x) { + return bit_cast(FromHost16(bit_cast(x))); +} +inline int32_t FromHost(int32_t x) { + return bit_cast(FromHost32(bit_cast(x))); +} +inline int64_t FromHost(int64_t x) { + return bit_cast(FromHost64(bit_cast(x))); +} +inline int8_t ToHost(int8_t x) { return x; } +inline int16_t ToHost(int16_t x) { + return bit_cast(ToHost16(bit_cast(x))); +} +inline int32_t ToHost(int32_t x) { + return bit_cast(ToHost32(bit_cast(x))); +} +inline int64_t ToHost(int64_t x) { + return bit_cast(ToHost64(bit_cast(x))); +} + // Functions to do unaligned loads and stores in little-endian order. inline uint16_t Load16(const void *p) { return ToHost16(ABSL_INTERNAL_UNALIGNED_LOAD16(p)); @@ -233,6 +264,36 @@ inline constexpr bool IsLittleEndian() { return false; } #endif /* ENDIAN */ +inline uint8_t FromHost(uint8_t x) { return x; } +inline uint16_t FromHost(uint16_t x) { return FromHost16(x); } +inline uint32_t FromHost(uint32_t x) { return FromHost32(x); } +inline uint64_t FromHost(uint64_t x) { return FromHost64(x); } +inline uint8_t ToHost(uint8_t x) { return x; } +inline uint16_t ToHost(uint16_t x) { return ToHost16(x); } +inline uint32_t ToHost(uint32_t x) { return ToHost32(x); } +inline uint64_t ToHost(uint64_t x) { return ToHost64(x); } + +inline int8_t FromHost(int8_t x) { return x; } +inline int16_t FromHost(int16_t x) { + return bit_cast(FromHost16(bit_cast(x))); +} +inline int32_t FromHost(int32_t x) { + return bit_cast(FromHost32(bit_cast(x))); +} +inline int64_t FromHost(int64_t x) { + return bit_cast(FromHost64(bit_cast(x))); +} +inline int8_t ToHost(int8_t x) { return x; } +inline int16_t ToHost(int16_t x) { + return bit_cast(ToHost16(bit_cast(x))); +} +inline int32_t ToHost(int32_t x) { + return bit_cast(ToHost32(bit_cast(x))); +} +inline int64_t ToHost(int64_t x) { + return bit_cast(ToHost64(bit_cast(x))); +} + // Functions to do unaligned loads and stores in big-endian order. inline uint16_t Load16(const void *p) { return ToHost16(ABSL_INTERNAL_UNALIGNED_LOAD16(p)); diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/endian_test.cc b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/endian_test.cc index aa6b849690..a1691b1f82 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/endian_test.cc +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/endian_test.cc @@ -54,24 +54,22 @@ const uint32_t k32ValueBE{0x67452301}; const uint16_t k16ValueBE{0x2301}; #endif -template -std::vector GenerateAllValuesForType() { - std::vector result; - T next = std::numeric_limits::min(); - while (true) { - result.push_back(next); - if (next == std::numeric_limits::max()) { - return result; - } - ++next; +std::vector GenerateAllUint16Values() { + std::vector result; + result.reserve(size_t{1} << (sizeof(uint16_t) * 8)); + for (uint32_t i = std::numeric_limits::min(); + i <= std::numeric_limits::max(); ++i) { + result.push_back(static_cast(i)); } + return result; } template -std::vector GenerateRandomIntegers(size_t numValuesToTest) { +std::vector GenerateRandomIntegers(size_t num_values_to_test) { std::vector result; + result.reserve(num_values_to_test); std::mt19937_64 rng(kRandomSeed); - for (size_t i = 0; i < numValuesToTest; ++i) { + for (size_t i = 0; i < num_values_to_test; ++i) { result.push_back(rng()); } return result; @@ -148,7 +146,7 @@ void Swap64(char* bytes) { } TEST(EndianessTest, Uint16) { - GBSwapHelper(GenerateAllValuesForType(), &Swap16); + GBSwapHelper(GenerateAllUint16Values(), &Swap16); } TEST(EndianessTest, Uint32) { diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/exception_safety_testing.h b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/exception_safety_testing.h index 6ba89d05df..77a5aec642 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/exception_safety_testing.h +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/exception_safety_testing.h @@ -536,7 +536,22 @@ class ThrowingValue : private exceptions_internal::TrackedObject { } // Memory management operators - // Args.. allows us to overload regular and placement new in one shot + static void* operator new(size_t s) noexcept( + IsSpecified(TypeSpec::kNoThrowNew)) { + if (!IsSpecified(TypeSpec::kNoThrowNew)) { + exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION, true); + } + return ::operator new(s); + } + + static void* operator new[](size_t s) noexcept( + IsSpecified(TypeSpec::kNoThrowNew)) { + if (!IsSpecified(TypeSpec::kNoThrowNew)) { + exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION, true); + } + return ::operator new[](s); + } + template static void* operator new(size_t s, Args&&... args) noexcept( IsSpecified(TypeSpec::kNoThrowNew)) { @@ -557,12 +572,6 @@ class ThrowingValue : private exceptions_internal::TrackedObject { // Abseil doesn't support throwing overloaded operator delete. These are // provided so a throwing operator-new can clean up after itself. - // - // We provide both regular and templated operator delete because if only the - // templated version is provided as we did with operator new, the compiler has - // no way of knowing which overload of operator delete to call. See - // https://en.cppreference.com/w/cpp/memory/new/operator_delete and - // https://en.cppreference.com/w/cpp/language/delete for the gory details. void operator delete(void* p) noexcept { ::operator delete(p); } template @@ -726,9 +735,8 @@ class ThrowingAllocator : private exceptions_internal::TrackedObject { ThrowingAllocator select_on_container_copy_construction() noexcept( IsSpecified(AllocSpec::kNoThrowAllocate)) { - auto& out = *this; ReadStateAndMaybeThrow(ABSL_PRETTY_FUNCTION); - return out; + return *this; } template diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/exponential_biased.cc b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/exponential_biased.cc index 1b30c061e3..05aeea566c 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/exponential_biased.cc +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/exponential_biased.cc @@ -64,7 +64,7 @@ int64_t ExponentialBiased::GetSkipCount(int64_t mean) { // Assume huge values are bias neutral, retain bias for next call. return std::numeric_limits::max() / 2; } - double value = std::round(interval); + double value = std::rint(interval); bias_ = interval - value; return value; } diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/exponential_biased.h b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/exponential_biased.h index 94f79a3378..a81f10e230 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/exponential_biased.h +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/exponential_biased.h @@ -66,7 +66,7 @@ namespace base_internal { // Adjusting with rounding bias is relatively trivial: // // double value = bias_ + exponential_distribution(mean)(); -// double rounded_value = std::round(value); +// double rounded_value = std::rint(value); // bias_ = value - rounded_value; // return rounded_value; // diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/exponential_biased_test.cc b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/exponential_biased_test.cc index 90a482d2a9..075583ca6f 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/exponential_biased_test.cc +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/exponential_biased_test.cc @@ -185,7 +185,7 @@ TEST(ExponentialBiasedTest, InitializationModes) { ABSL_CONST_INIT static ExponentialBiased eb_static; EXPECT_THAT(eb_static.GetSkipCount(2), Ge(0)); -#if ABSL_HAVE_THREAD_LOCAL +#ifdef ABSL_HAVE_THREAD_LOCAL thread_local ExponentialBiased eb_thread; EXPECT_THAT(eb_thread.GetSkipCount(2), Ge(0)); #endif diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/invoke.h b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/invoke.h index c4eceebd7c..5c71f32823 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/invoke.h +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/invoke.h @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. // -// absl::base_internal::Invoke(f, args...) is an implementation of +// absl::base_internal::invoke(f, args...) is an implementation of // INVOKE(f, args...) from section [func.require] of the C++ standard. // // [func.require] @@ -29,7 +29,7 @@ // is not one of the types described in the previous item; // 5. f(t1, t2, ..., tN) in all other cases. // -// The implementation is SFINAE-friendly: substitution failure within Invoke() +// The implementation is SFINAE-friendly: substitution failure within invoke() // isn't an error. #ifndef ABSL_BASE_INTERNAL_INVOKE_H_ @@ -170,13 +170,13 @@ struct Invoker { // The result type of Invoke. template -using InvokeT = decltype(Invoker::type::Invoke( +using invoke_result_t = decltype(Invoker::type::Invoke( std::declval(), std::declval()...)); // Invoke(f, args...) is an implementation of INVOKE(f, args...) from section // [func.require] of the C++ standard. template -InvokeT Invoke(F&& f, Args&&... args) { +invoke_result_t invoke(F&& f, Args&&... args) { return Invoker::type::Invoke(std::forward(f), std::forward(args)...); } diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/low_level_alloc_test.cc b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/low_level_alloc_test.cc index 7abbbf9c59..31abb888a6 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/low_level_alloc_test.cc +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/low_level_alloc_test.cc @@ -21,6 +21,12 @@ #include #include +#ifdef __EMSCRIPTEN__ +#include +#endif + +#include "absl/container/node_hash_map.h" + namespace absl { ABSL_NAMESPACE_BEGIN namespace base_internal { @@ -75,7 +81,7 @@ static bool using_low_level_alloc = false; // allocations and deallocations are reported via the MallocHook // interface. static void Test(bool use_new_arena, bool call_malloc_hook, int n) { - typedef std::unordered_map AllocMap; + typedef absl::node_hash_map AllocMap; AllocMap allocated; AllocMap::iterator it; BlockDesc block_desc; @@ -156,5 +162,20 @@ ABSL_NAMESPACE_END int main(int argc, char *argv[]) { // The actual test runs in the global constructor of `before_main`. printf("PASS\n"); +#ifdef __EMSCRIPTEN__ + // clang-format off +// This is JS here. Don't try to format it. + MAIN_THREAD_EM_ASM({ + if (ENVIRONMENT_IS_WEB) { + if (typeof TEST_FINISH === 'function') { + TEST_FINISH($0); + } else { + console.error('Attempted to exit with status ' + $0); + console.error('But TEST_FINSIHED is not a function.'); + } + } + }, 0); +// clang-format on +#endif return 0; } diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/low_level_scheduling.h b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/low_level_scheduling.h index 961cc981b8..9baccc0659 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/low_level_scheduling.h +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/low_level_scheduling.h @@ -18,6 +18,7 @@ #ifndef ABSL_BASE_INTERNAL_LOW_LEVEL_SCHEDULING_H_ #define ABSL_BASE_INTERNAL_LOW_LEVEL_SCHEDULING_H_ +#include "absl/base/internal/raw_logging.h" #include "absl/base/internal/scheduling_mode.h" #include "absl/base/macros.h" @@ -29,6 +30,13 @@ extern "C" void __google_enable_rescheduling(bool disable_result); namespace absl { ABSL_NAMESPACE_BEGIN +class CondVar; +class Mutex; + +namespace synchronization_internal { +int MutexDelay(int32_t c, int mode); +} // namespace synchronization_internal + namespace base_internal { class SchedulingHelper; // To allow use of SchedulingGuard. @@ -53,6 +61,8 @@ class SchedulingGuard { public: // Returns true iff the calling thread may be cooperatively rescheduled. static bool ReschedulingIsAllowed(); + SchedulingGuard(const SchedulingGuard&) = delete; + SchedulingGuard& operator=(const SchedulingGuard&) = delete; private: // Disable cooperative rescheduling of the calling thread. It may still @@ -76,12 +86,23 @@ class SchedulingGuard { bool disabled; }; - // Access to SchedulingGuard is explicitly white-listed. + // A scoped helper to enable rescheduling temporarily. + // REQUIRES: destructor must run in same thread as constructor. + class ScopedEnable { + public: + ScopedEnable(); + ~ScopedEnable(); + + private: + int scheduling_disabled_depth_; + }; + + // Access to SchedulingGuard is explicitly permitted. + friend class absl::CondVar; + friend class absl::Mutex; friend class SchedulingHelper; friend class SpinLock; - - SchedulingGuard(const SchedulingGuard&) = delete; - SchedulingGuard& operator=(const SchedulingGuard&) = delete; + friend int absl::synchronization_internal::MutexDelay(int32_t c, int mode); }; //------------------------------------------------------------------------------ @@ -100,6 +121,12 @@ inline void SchedulingGuard::EnableRescheduling(bool /* disable_result */) { return; } +inline SchedulingGuard::ScopedEnable::ScopedEnable() + : scheduling_disabled_depth_(0) {} +inline SchedulingGuard::ScopedEnable::~ScopedEnable() { + ABSL_RAW_CHECK(scheduling_disabled_depth_ == 0, "disable unused warning"); +} + } // namespace base_internal ABSL_NAMESPACE_END } // namespace absl diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/raw_logging.cc b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/raw_logging.cc index 40cea55061..074e026adb 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/raw_logging.cc +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/raw_logging.cc @@ -67,28 +67,32 @@ #undef ABSL_HAVE_RAW_IO #endif -// TODO(gfalcon): We want raw-logging to work on as many platforms as possible. -// Explicitly #error out when not ABSL_LOW_LEVEL_WRITE_SUPPORTED, except for a -// whitelisted set of platforms for which we expect not to be able to raw log. +namespace absl { +ABSL_NAMESPACE_BEGIN +namespace raw_logging_internal { +namespace { -ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES static absl::base_internal::AtomicHook< - absl::raw_logging_internal::LogPrefixHook> - log_prefix_hook; -ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES static absl::base_internal::AtomicHook< - absl::raw_logging_internal::AbortHook> - abort_hook; +// TODO(gfalcon): We want raw-logging to work on as many platforms as possible. +// Explicitly `#error` out when not `ABSL_LOW_LEVEL_WRITE_SUPPORTED`, except for +// a selected set of platforms for which we expect not to be able to raw log. + +ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES + absl::base_internal::AtomicHook + log_prefix_hook; +ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES + absl::base_internal::AtomicHook + abort_hook; #ifdef ABSL_LOW_LEVEL_WRITE_SUPPORTED -static const char kTruncated[] = " ... (message truncated)\n"; +constexpr char kTruncated[] = " ... (message truncated)\n"; // sprintf the format to the buffer, adjusting *buf and *size to reflect the // consumed bytes, and return whether the message fit without truncation. If // truncation occurred, if possible leave room in the buffer for the message // kTruncated[]. -inline static bool VADoRawLog(char** buf, int* size, const char* format, - va_list ap) ABSL_PRINTF_ATTRIBUTE(3, 0); -inline static bool VADoRawLog(char** buf, int* size, - const char* format, va_list ap) { +bool VADoRawLog(char** buf, int* size, const char* format, va_list ap) + ABSL_PRINTF_ATTRIBUTE(3, 0); +bool VADoRawLog(char** buf, int* size, const char* format, va_list ap) { int n = vsnprintf(*buf, *size, format, ap); bool result = true; if (n < 0 || n > *size) { @@ -96,7 +100,7 @@ inline static bool VADoRawLog(char** buf, int* size, if (static_cast(*size) > sizeof(kTruncated)) { n = *size - sizeof(kTruncated); // room for truncation message } else { - n = 0; // no room for truncation message + n = 0; // no room for truncation message } } *size -= n; @@ -105,9 +109,7 @@ inline static bool VADoRawLog(char** buf, int* size, } #endif // ABSL_LOW_LEVEL_WRITE_SUPPORTED -static constexpr int kLogBufSize = 3000; - -namespace { +constexpr int kLogBufSize = 3000; // CAVEAT: vsnprintf called from *DoRawLog below has some (exotic) code paths // that invoke malloc() and getenv() that might acquire some locks. @@ -166,7 +168,7 @@ void RawLogVA(absl::LogSeverity severity, const char* file, int line, } else { DoRawLog(&buf, &size, "%s", kTruncated); } - absl::raw_logging_internal::SafeWriteToStderr(buffer, strlen(buffer)); + SafeWriteToStderr(buffer, strlen(buffer)); } #else static_cast(format); @@ -181,11 +183,18 @@ void RawLogVA(absl::LogSeverity severity, const char* file, int line, } } +// Non-formatting version of RawLog(). +// +// TODO(gfalcon): When string_view no longer depends on base, change this +// interface to take its message as a string_view instead. +void DefaultInternalLog(absl::LogSeverity severity, const char* file, int line, + const std::string& message) { + RawLog(severity, file, line, "%.*s", static_cast(message.size()), + message.data()); +} + } // namespace -namespace absl { -ABSL_NAMESPACE_BEGIN -namespace raw_logging_internal { void SafeWriteToStderr(const char *s, size_t len) { #if defined(ABSL_HAVE_SYSCALL_WRITE) syscall(SYS_write, STDERR_FILENO, s, len); @@ -200,8 +209,6 @@ void SafeWriteToStderr(const char *s, size_t len) { #endif } -void RawLog(absl::LogSeverity severity, const char* file, int line, - const char* format, ...) ABSL_PRINTF_ATTRIBUTE(4, 5); void RawLog(absl::LogSeverity severity, const char* file, int line, const char* format, ...) { va_list ap; @@ -210,15 +217,6 @@ void RawLog(absl::LogSeverity severity, const char* file, int line, va_end(ap); } -// Non-formatting version of RawLog(). -// -// TODO(gfalcon): When string_view no longer depends on base, change this -// interface to take its message as a string_view instead. -static void DefaultInternalLog(absl::LogSeverity severity, const char* file, - int line, const std::string& message) { - RawLog(severity, file, line, "%s", message.c_str()); -} - bool RawLoggingFullySupported() { #ifdef ABSL_LOW_LEVEL_WRITE_SUPPORTED return true; @@ -227,10 +225,14 @@ bool RawLoggingFullySupported() { #endif // !ABSL_LOW_LEVEL_WRITE_SUPPORTED } -ABSL_DLL ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES +ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES ABSL_DLL absl::base_internal::AtomicHook internal_log_function(DefaultInternalLog); +void RegisterLogPrefixHook(LogPrefixHook func) { log_prefix_hook.Store(func); } + +void RegisterAbortHook(AbortHook func) { abort_hook.Store(func); } + void RegisterInternalLogFunction(InternalLogFunction func) { internal_log_function.Store(func); } diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/raw_logging.h b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/raw_logging.h index 418d6c856f..2bf7aabac1 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/raw_logging.h +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/raw_logging.h @@ -72,10 +72,14 @@ // // The API is a subset of the above: each macro only takes two arguments. Use // StrCat if you need to build a richer message. -#define ABSL_INTERNAL_LOG(severity, message) \ - do { \ - ::absl::raw_logging_internal::internal_log_function( \ - ABSL_RAW_LOGGING_INTERNAL_##severity, __FILE__, __LINE__, message); \ +#define ABSL_INTERNAL_LOG(severity, message) \ + do { \ + constexpr const char* absl_raw_logging_internal_filename = __FILE__; \ + ::absl::raw_logging_internal::internal_log_function( \ + ABSL_RAW_LOGGING_INTERNAL_##severity, \ + absl_raw_logging_internal_filename, __LINE__, message); \ + if (ABSL_RAW_LOGGING_INTERNAL_##severity == ::absl::LogSeverity::kFatal) \ + ABSL_INTERNAL_UNREACHABLE; \ } while (0) #define ABSL_INTERNAL_CHECK(condition, message) \ @@ -170,10 +174,18 @@ using InternalLogFunction = void (*)(absl::LogSeverity severity, const char* file, int line, const std::string& message); -ABSL_DLL ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES extern base_internal::AtomicHook< +ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES ABSL_DLL extern base_internal::AtomicHook< InternalLogFunction> internal_log_function; +// Registers hooks of the above types. Only a single hook of each type may be +// registered. It is an error to call these functions multiple times with +// different input arguments. +// +// These functions are safe to call at any point during initialization; they do +// not block or malloc, and are async-signal safe. +void RegisterLogPrefixHook(LogPrefixHook func); +void RegisterAbortHook(AbortHook func); void RegisterInternalLogFunction(InternalLogFunction func); } // namespace raw_logging_internal diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/spinlock.cc b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/spinlock.cc index fd0c733e23..35c0696a34 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/spinlock.cc +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/spinlock.cc @@ -66,35 +66,19 @@ void RegisterSpinLockProfiler(void (*fn)(const void *contendedlock, submit_profile_data.Store(fn); } +// Static member variable definitions. +constexpr uint32_t SpinLock::kSpinLockHeld; +constexpr uint32_t SpinLock::kSpinLockCooperative; +constexpr uint32_t SpinLock::kSpinLockDisabledScheduling; +constexpr uint32_t SpinLock::kSpinLockSleeper; +constexpr uint32_t SpinLock::kWaitTimeMask; + // Uncommon constructors. SpinLock::SpinLock(base_internal::SchedulingMode mode) : lockword_(IsCooperative(mode) ? kSpinLockCooperative : 0) { ABSL_TSAN_MUTEX_CREATE(this, __tsan_mutex_not_static); } -SpinLock::SpinLock(base_internal::LinkerInitialized, - base_internal::SchedulingMode mode) { - ABSL_TSAN_MUTEX_CREATE(this, 0); - if (IsCooperative(mode)) { - InitLinkerInitializedAndCooperative(); - } - // Otherwise, lockword_ is already initialized. -} - -// Static (linker initialized) spinlocks always start life as functional -// non-cooperative locks. When their static constructor does run, it will call -// this initializer to augment the lockword with the cooperative bit. By -// actually taking the lock when we do this we avoid the need for an atomic -// operation in the regular unlock path. -// -// SlowLock() must be careful to re-test for this bit so that any outstanding -// waiters may be upgraded to cooperative status. -void SpinLock::InitLinkerInitializedAndCooperative() { - Lock(); - lockword_.fetch_or(kSpinLockCooperative, std::memory_order_relaxed); - Unlock(); -} - // Monitor the lock to see if its value changes within some time period // (adaptive_spin_count loop iterations). The last value read from the lock // is returned from the method. @@ -121,6 +105,14 @@ void SpinLock::SlowLock() { if ((lock_value & kSpinLockHeld) == 0) { return; } + + base_internal::SchedulingMode scheduling_mode; + if ((lock_value & kSpinLockCooperative) != 0) { + scheduling_mode = base_internal::SCHEDULE_COOPERATIVE_AND_KERNEL; + } else { + scheduling_mode = base_internal::SCHEDULE_KERNEL_ONLY; + } + // The lock was not obtained initially, so this thread needs to wait for // it. Record the current timestamp in the local variable wait_start_time // so the total wait time can be stored in the lockword once this thread @@ -133,8 +125,9 @@ void SpinLock::SlowLock() { // it as having a sleeper. if ((lock_value & kWaitTimeMask) == 0) { // Here, just "mark" that the thread is going to sleep. Don't store the - // lock wait time in the lock as that will cause the current lock - // owner to think it experienced contention. + // lock wait time in the lock -- the lock word stores the amount of time + // that the current holder waited before acquiring the lock, not the wait + // time of any thread currently waiting to acquire it. if (lockword_.compare_exchange_strong( lock_value, lock_value | kSpinLockSleeper, std::memory_order_relaxed, std::memory_order_relaxed)) { @@ -148,15 +141,17 @@ void SpinLock::SlowLock() { // this thread obtains the lock. lock_value = TryLockInternal(lock_value, wait_cycles); continue; // Skip the delay at the end of the loop. + } else if ((lock_value & kWaitTimeMask) == 0) { + // The lock is still held, without a waiter being marked, but something + // else about the lock word changed, causing our CAS to fail. For + // example, a new lock holder may have acquired the lock with + // kSpinLockDisabledScheduling set, whereas the previous holder had not + // set that flag. In this case, attempt again to mark ourselves as a + // waiter. + continue; } } - base_internal::SchedulingMode scheduling_mode; - if ((lock_value & kSpinLockCooperative) != 0) { - scheduling_mode = base_internal::SCHEDULE_COOPERATIVE_AND_KERNEL; - } else { - scheduling_mode = base_internal::SCHEDULE_KERNEL_ONLY; - } // SpinLockDelay() calls into fiber scheduler, we need to see // synchronization there to avoid false positives. ABSL_TSAN_MUTEX_PRE_DIVERT(this, 0); diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/spinlock.h b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/spinlock.h index 89e93aad0b..c73b5e0967 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/spinlock.h +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/spinlock.h @@ -15,11 +15,8 @@ // // Most users requiring mutual exclusion should use Mutex. -// SpinLock is provided for use in three situations: +// SpinLock is provided for use in two situations: // - for use in code that Mutex itself depends on -// - to get a faster fast-path release under low contention (without an -// atomic read-modify-write) In return, SpinLock has worse behaviour under -// contention, which is why Mutex is preferred in most situations. // - for async signal safety (see below) // SpinLock is async signal safe. If a spinlock is used within a signal @@ -36,6 +33,7 @@ #include #include "absl/base/attributes.h" +#include "absl/base/const_init.h" #include "absl/base/dynamic_annotations.h" #include "absl/base/internal/low_level_scheduling.h" #include "absl/base/internal/raw_logging.h" @@ -55,29 +53,22 @@ class ABSL_LOCKABLE SpinLock { ABSL_TSAN_MUTEX_CREATE(this, __tsan_mutex_not_static); } - // Special constructor for use with static SpinLock objects. E.g., - // - // static SpinLock lock(base_internal::kLinkerInitialized); - // - // When initialized using this constructor, we depend on the fact - // that the linker has already initialized the memory appropriately. The lock - // is initialized in non-cooperative mode. - // - // A SpinLock constructed like this can be freely used from global - // initializers without worrying about the order in which global - // initializers run. - explicit SpinLock(base_internal::LinkerInitialized) { - // Does nothing; lockword_ is already initialized - ABSL_TSAN_MUTEX_CREATE(this, 0); - } - // Constructors that allow non-cooperative spinlocks to be created for use // inside thread schedulers. Normal clients should not use these. explicit SpinLock(base_internal::SchedulingMode mode); - SpinLock(base_internal::LinkerInitialized, - base_internal::SchedulingMode mode); + // Constructor for global SpinLock instances. See absl/base/const_init.h. + constexpr SpinLock(absl::ConstInitType, base_internal::SchedulingMode mode) + : lockword_(IsCooperative(mode) ? kSpinLockCooperative : 0) {} + + // For global SpinLock instances prefer trivial destructor when possible. + // Default but non-trivial destructor in some build configurations causes an + // extra static initializer. +#ifdef ABSL_INTERNAL_HAVE_TSAN_INTERFACE ~SpinLock() { ABSL_TSAN_MUTEX_DESTROY(this, __tsan_mutex_not_static); } +#else + ~SpinLock() = default; +#endif // Acquire this SpinLock. inline void Lock() ABSL_EXCLUSIVE_LOCK_FUNCTION() { @@ -146,8 +137,20 @@ class ABSL_LOCKABLE SpinLock { // // bit[0] encodes whether a lock is being held. // bit[1] encodes whether a lock uses cooperative scheduling. - // bit[2] encodes whether a lock disables scheduling. + // bit[2] encodes whether the current lock holder disabled scheduling when + // acquiring the lock. Only set when kSpinLockHeld is also set. // bit[3:31] encodes time a lock spent on waiting as a 29-bit unsigned int. + // This is set by the lock holder to indicate how long it waited on + // the lock before eventually acquiring it. The number of cycles is + // encoded as a 29-bit unsigned int, or in the case that the current + // holder did not wait but another waiter is queued, the LSB + // (kSpinLockSleeper) is set. The implementation does not explicitly + // track the number of queued waiters beyond this. It must always be + // assumed that waiters may exist if the current holder was required to + // queue. + // + // Invariant: if the lock is not held, the value is either 0 or + // kSpinLockCooperative. static constexpr uint32_t kSpinLockHeld = 1; static constexpr uint32_t kSpinLockCooperative = 2; static constexpr uint32_t kSpinLockDisabledScheduling = 4; @@ -163,7 +166,6 @@ class ABSL_LOCKABLE SpinLock { } uint32_t TryLockInternal(uint32_t lock_value, uint32_t wait_cycles); - void InitLinkerInitializedAndCooperative(); void SlowLock() ABSL_ATTRIBUTE_COLD; void SlowUnlock(uint32_t lock_value) ABSL_ATTRIBUTE_COLD; uint32_t SpinLoop(); diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/spinlock_akaros.inc b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/spinlock_akaros.inc index bc468940fc..7b0cada4f1 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/spinlock_akaros.inc +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/spinlock_akaros.inc @@ -20,7 +20,7 @@ extern "C" { -ABSL_ATTRIBUTE_WEAK void AbslInternalSpinLockDelay( +ABSL_ATTRIBUTE_WEAK void ABSL_INTERNAL_C_SYMBOL(AbslInternalSpinLockDelay)( std::atomic* /* lock_word */, uint32_t /* value */, int /* loop */, absl::base_internal::SchedulingMode /* mode */) { // In Akaros, one must take care not to call anything that could cause a @@ -29,7 +29,7 @@ ABSL_ATTRIBUTE_WEAK void AbslInternalSpinLockDelay( // arbitrary code. } -ABSL_ATTRIBUTE_WEAK void AbslInternalSpinLockWake( +ABSL_ATTRIBUTE_WEAK void ABSL_INTERNAL_C_SYMBOL(AbslInternalSpinLockWake)( std::atomic* /* lock_word */, bool /* all */) {} } // extern "C" diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/spinlock_linux.inc b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/spinlock_linux.inc index 323edd62f4..202f7cdfc8 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/spinlock_linux.inc +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/spinlock_linux.inc @@ -46,9 +46,17 @@ static_assert(sizeof(std::atomic) == sizeof(int), #endif #endif +#if defined(__NR_futex_time64) && !defined(SYS_futex_time64) +#define SYS_futex_time64 __NR_futex_time64 +#endif + +#if defined(SYS_futex_time64) && !defined(SYS_futex) +#define SYS_futex SYS_futex_time64 +#endif + extern "C" { -ABSL_ATTRIBUTE_WEAK void AbslInternalSpinLockDelay( +ABSL_ATTRIBUTE_WEAK void ABSL_INTERNAL_C_SYMBOL(AbslInternalSpinLockDelay)( std::atomic *w, uint32_t value, int loop, absl::base_internal::SchedulingMode) { absl::base_internal::ErrnoSaver errno_saver; @@ -58,8 +66,8 @@ ABSL_ATTRIBUTE_WEAK void AbslInternalSpinLockDelay( syscall(SYS_futex, w, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, value, &tm); } -ABSL_ATTRIBUTE_WEAK void AbslInternalSpinLockWake(std::atomic *w, - bool all) { +ABSL_ATTRIBUTE_WEAK void ABSL_INTERNAL_C_SYMBOL(AbslInternalSpinLockWake)( + std::atomic *w, bool all) { syscall(SYS_futex, w, FUTEX_WAKE | FUTEX_PRIVATE_FLAG, all ? INT_MAX : 1, 0); } diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/spinlock_posix.inc b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/spinlock_posix.inc index fcd21b151b..4f6f887d99 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/spinlock_posix.inc +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/spinlock_posix.inc @@ -25,7 +25,7 @@ extern "C" { -ABSL_ATTRIBUTE_WEAK void AbslInternalSpinLockDelay( +ABSL_ATTRIBUTE_WEAK void ABSL_INTERNAL_C_SYMBOL(AbslInternalSpinLockDelay)( std::atomic* /* lock_word */, uint32_t /* value */, int loop, absl::base_internal::SchedulingMode /* mode */) { absl::base_internal::ErrnoSaver errno_saver; @@ -40,7 +40,7 @@ ABSL_ATTRIBUTE_WEAK void AbslInternalSpinLockDelay( } } -ABSL_ATTRIBUTE_WEAK void AbslInternalSpinLockWake( +ABSL_ATTRIBUTE_WEAK void ABSL_INTERNAL_C_SYMBOL(AbslInternalSpinLockWake)( std::atomic* /* lock_word */, bool /* all */) {} } // extern "C" diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/spinlock_wait.h b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/spinlock_wait.h index 169bc749fb..579bd09fa0 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/spinlock_wait.h +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/spinlock_wait.h @@ -43,18 +43,16 @@ uint32_t SpinLockWait(std::atomic *w, int n, const SpinLockWaitTransition trans[], SchedulingMode scheduling_mode); -// If possible, wake some thread that has called SpinLockDelay(w, ...). If -// "all" is true, wake all such threads. This call is a hint, and on some -// systems it may be a no-op; threads calling SpinLockDelay() will always wake -// eventually even if SpinLockWake() is never called. +// If possible, wake some thread that has called SpinLockDelay(w, ...). If `all` +// is true, wake all such threads. On some systems, this may be a no-op; on +// those systems, threads calling SpinLockDelay() will always wake eventually +// even if SpinLockWake() is never called. void SpinLockWake(std::atomic *w, bool all); // Wait for an appropriate spin delay on iteration "loop" of a // spin loop on location *w, whose previously observed value was "value". // SpinLockDelay() may do nothing, may yield the CPU, may sleep a clock tick, -// or may wait for a delay that can be truncated by a call to SpinLockWake(w). -// In all cases, it must return in bounded time even if SpinLockWake() is not -// called. +// or may wait for a call to SpinLockWake(w). void SpinLockDelay(std::atomic *w, uint32_t value, int loop, base_internal::SchedulingMode scheduling_mode); @@ -73,21 +71,23 @@ ABSL_NAMESPACE_END // By changing our extension points to be extern "C", we dodge this // check. extern "C" { -void AbslInternalSpinLockWake(std::atomic *w, bool all); -void AbslInternalSpinLockDelay( +void ABSL_INTERNAL_C_SYMBOL(AbslInternalSpinLockWake)(std::atomic *w, + bool all); +void ABSL_INTERNAL_C_SYMBOL(AbslInternalSpinLockDelay)( std::atomic *w, uint32_t value, int loop, absl::base_internal::SchedulingMode scheduling_mode); } inline void absl::base_internal::SpinLockWake(std::atomic *w, bool all) { - AbslInternalSpinLockWake(w, all); + ABSL_INTERNAL_C_SYMBOL(AbslInternalSpinLockWake)(w, all); } inline void absl::base_internal::SpinLockDelay( std::atomic *w, uint32_t value, int loop, absl::base_internal::SchedulingMode scheduling_mode) { - AbslInternalSpinLockDelay(w, value, loop, scheduling_mode); + ABSL_INTERNAL_C_SYMBOL(AbslInternalSpinLockDelay) + (w, value, loop, scheduling_mode); } #endif // ABSL_BASE_INTERNAL_SPINLOCK_WAIT_H_ diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/spinlock_win32.inc b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/spinlock_win32.inc index 78654b5b59..9d224813a5 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/spinlock_win32.inc +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/spinlock_win32.inc @@ -20,9 +20,9 @@ extern "C" { -void AbslInternalSpinLockDelay(std::atomic* /* lock_word */, - uint32_t /* value */, int loop, - absl::base_internal::SchedulingMode /* mode */) { +void ABSL_INTERNAL_C_SYMBOL(AbslInternalSpinLockDelay)( + std::atomic* /* lock_word */, uint32_t /* value */, int loop, + absl::base_internal::SchedulingMode /* mode */) { if (loop == 0) { } else if (loop == 1) { Sleep(0); @@ -31,7 +31,7 @@ void AbslInternalSpinLockDelay(std::atomic* /* lock_word */, } } -void AbslInternalSpinLockWake(std::atomic* /* lock_word */, - bool /* all */) {} +void ABSL_INTERNAL_C_SYMBOL(AbslInternalSpinLockWake)( + std::atomic* /* lock_word */, bool /* all */) {} } // extern "C" diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/strerror.cc b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/strerror.cc index af181513cd..0d6226fd0a 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/strerror.cc +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/strerror.cc @@ -14,6 +14,7 @@ #include "absl/base/internal/strerror.h" +#include #include #include #include @@ -21,13 +22,13 @@ #include #include -#include "absl/base/attributes.h" #include "absl/base/internal/errno_saver.h" namespace absl { ABSL_NAMESPACE_BEGIN namespace base_internal { namespace { + const char* StrErrorAdaptor(int errnum, char* buf, size_t buflen) { #if defined(_WIN32) int rc = strerror_s(buf, buflen, errnum); @@ -35,15 +36,6 @@ const char* StrErrorAdaptor(int errnum, char* buf, size_t buflen) { if (rc == 0 && strncmp(buf, "Unknown error", buflen) == 0) *buf = '\0'; return buf; #else -#if defined(__GLIBC__) || defined(__APPLE__) - // Use the BSD sys_errlist API provided by GNU glibc and others to - // avoid any need to copy the message into the local buffer first. - if (0 <= errnum && errnum < sys_nerr) { - if (const char* p = sys_errlist[errnum]) { - return p; - } - } -#endif // The type of `ret` is platform-specific; both of these branches must compile // either way but only one will execute on any given platform: auto ret = strerror_r(errnum, buf, buflen); @@ -57,10 +49,8 @@ const char* StrErrorAdaptor(int errnum, char* buf, size_t buflen) { } #endif } -} // namespace -std::string StrError(int errnum) { - absl::base_internal::ErrnoSaver errno_saver; +std::string StrErrorInternal(int errnum) { char buf[100]; const char* str = StrErrorAdaptor(errnum, buf, sizeof buf); if (*str == '\0') { @@ -70,6 +60,29 @@ std::string StrError(int errnum) { return str; } +// kSysNerr is the number of errors from a recent glibc. `StrError()` falls back +// to `StrErrorAdaptor()` if the value is larger than this. +constexpr int kSysNerr = 135; + +std::array* NewStrErrorTable() { + auto* table = new std::array; + for (int i = 0; i < static_cast(table->size()); ++i) { + (*table)[i] = StrErrorInternal(i); + } + return table; +} + +} // namespace + +std::string StrError(int errnum) { + absl::base_internal::ErrnoSaver errno_saver; + static const auto* table = NewStrErrorTable(); + if (errnum >= 0 && errnum < static_cast(table->size())) { + return (*table)[errnum]; + } + return StrErrorInternal(errnum); +} + } // namespace base_internal ABSL_NAMESPACE_END } // namespace absl diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/strerror_benchmark.cc b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/strerror_benchmark.cc index d8ca86b95b..c9ab14a89d 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/strerror_benchmark.cc +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/strerror_benchmark.cc @@ -20,15 +20,6 @@ #include "benchmark/benchmark.h" namespace { -#if defined(__GLIBC__) || defined(__APPLE__) -void BM_SysErrList(benchmark::State& state) { - for (auto _ : state) { - benchmark::DoNotOptimize(std::string(sys_errlist[ERANGE])); - } -} -BENCHMARK(BM_SysErrList); -#endif - void BM_AbslStrError(benchmark::State& state) { for (auto _ : state) { benchmark::DoNotOptimize(absl::base_internal::StrError(ERANGE)); diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/strerror_test.cc b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/strerror_test.cc index a53da97f92..e32d5b5c9b 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/strerror_test.cc +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/strerror_test.cc @@ -62,12 +62,14 @@ TEST(StrErrorTest, MultipleThreads) { ++counter; errno = ERANGE; const std::string value = absl::base_internal::StrError(i); + // EXPECT_* could change errno. Stash it first. + int check_err = errno; + EXPECT_THAT(check_err, Eq(ERANGE)); // Only the GNU implementation is guaranteed to provide the // string "Unknown error nnn". POSIX doesn't say anything. if (!absl::StartsWith(value, "Unknown error ")) { - EXPECT_THAT(absl::base_internal::StrError(i), Eq(expected_strings[i])); + EXPECT_THAT(value, Eq(expected_strings[i])); } - EXPECT_THAT(errno, Eq(ERANGE)); } }; diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/sysinfo.cc b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/sysinfo.cc index 0bed0d8ccb..08a1e28894 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/sysinfo.cc +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/sysinfo.cc @@ -39,6 +39,7 @@ #endif #include + #include #include #include @@ -50,17 +51,86 @@ #include #include "absl/base/call_once.h" +#include "absl/base/config.h" #include "absl/base/internal/raw_logging.h" #include "absl/base/internal/spinlock.h" #include "absl/base/internal/unscaledcycleclock.h" +#include "absl/base/thread_annotations.h" namespace absl { ABSL_NAMESPACE_BEGIN namespace base_internal { +namespace { + +#if defined(_WIN32) + +// Returns number of bits set in `bitMask` +DWORD Win32CountSetBits(ULONG_PTR bitMask) { + for (DWORD bitSetCount = 0; ; ++bitSetCount) { + if (bitMask == 0) return bitSetCount; + bitMask &= bitMask - 1; + } +} + +// Returns the number of logical CPUs using GetLogicalProcessorInformation(), or +// 0 if the number of processors is not available or can not be computed. +// https://docs.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getlogicalprocessorinformation +int Win32NumCPUs() { +#pragma comment(lib, "kernel32.lib") + using Info = SYSTEM_LOGICAL_PROCESSOR_INFORMATION; + + DWORD info_size = sizeof(Info); + Info* info(static_cast(malloc(info_size))); + if (info == nullptr) return 0; + + bool success = GetLogicalProcessorInformation(info, &info_size); + if (!success && GetLastError() == ERROR_INSUFFICIENT_BUFFER) { + free(info); + info = static_cast(malloc(info_size)); + if (info == nullptr) return 0; + success = GetLogicalProcessorInformation(info, &info_size); + } + + DWORD logicalProcessorCount = 0; + if (success) { + Info* ptr = info; + DWORD byteOffset = 0; + while (byteOffset + sizeof(Info) <= info_size) { + switch (ptr->Relationship) { + case RelationProcessorCore: + logicalProcessorCount += Win32CountSetBits(ptr->ProcessorMask); + break; + + case RelationNumaNode: + case RelationCache: + case RelationProcessorPackage: + // Ignore other entries + break; + + default: + // Ignore unknown entries + break; + } + byteOffset += sizeof(Info); + ptr++; + } + } + free(info); + return logicalProcessorCount; +} + +#endif + +} // namespace + + static int GetNumCPUs() { #if defined(__myriad2__) return 1; +#elif defined(_WIN32) + const unsigned hardware_concurrency = Win32NumCPUs(); + return hardware_concurrency ? hardware_concurrency : 1; #else // Other possibilities: // - Read /sys/devices/system/cpu/online and use cpumask_parse() @@ -343,15 +413,16 @@ pid_t GetTID() { #else // Fallback implementation of GetTID using pthread_getspecific. -static once_flag tid_once; -static pthread_key_t tid_key; -static absl::base_internal::SpinLock tid_lock( - absl::base_internal::kLinkerInitialized); +ABSL_CONST_INIT static once_flag tid_once; +ABSL_CONST_INIT static pthread_key_t tid_key; +ABSL_CONST_INIT static absl::base_internal::SpinLock tid_lock( + absl::kConstInit, base_internal::SCHEDULE_KERNEL_ONLY); // We set a bit per thread in this array to indicate that an ID is in // use. ID 0 is unused because it is the default value returned by // pthread_getspecific(). -static std::vector* tid_array ABSL_GUARDED_BY(tid_lock) = nullptr; +ABSL_CONST_INIT static std::vector *tid_array + ABSL_GUARDED_BY(tid_lock) = nullptr; static constexpr int kBitsPerWord = 32; // tid_array is uint32_t. // Returns the TID to tid_array. @@ -418,6 +489,18 @@ pid_t GetTID() { #endif +// GetCachedTID() caches the thread ID in thread-local storage (which is a +// userspace construct) to avoid unnecessary system calls. Without this caching, +// it can take roughly 98ns, while it takes roughly 1ns with this caching. +pid_t GetCachedTID() { +#ifdef ABSL_HAVE_THREAD_LOCAL + static thread_local pid_t thread_id = GetTID(); + return thread_id; +#else + return GetTID(); +#endif // ABSL_HAVE_THREAD_LOCAL +} + } // namespace base_internal ABSL_NAMESPACE_END } // namespace absl diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/sysinfo.h b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/sysinfo.h index 7246d5dd95..119cf1f0e8 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/sysinfo.h +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/sysinfo.h @@ -30,6 +30,7 @@ #include +#include "absl/base/config.h" #include "absl/base/port.h" namespace absl { @@ -59,6 +60,13 @@ using pid_t = uint32_t; #endif pid_t GetTID(); +// Like GetTID(), but caches the result in thread-local storage in order +// to avoid unnecessary system calls. Note that there are some cases where +// one must call through to GetTID directly, which is why this exists as a +// separate function. For example, GetCachedTID() is not safe to call in +// an asynchronous signal-handling context nor right after a call to fork(). +pid_t GetCachedTID(); + } // namespace base_internal ABSL_NAMESPACE_END } // namespace absl diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/sysinfo_test.cc b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/sysinfo_test.cc index fa8b88b1dc..5f9e45f6aa 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/sysinfo_test.cc +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/sysinfo_test.cc @@ -37,17 +37,28 @@ TEST(SysinfoTest, NumCPUs) { << "NumCPUs() should not have the default value of 0"; } +// Ensure that NominalCPUFrequency returns a reasonable value, or 1.00 on +// platforms where the CPU frequency is not available through sysfs. +// +// POWER is particularly problematic here; some Linux kernels expose the CPU +// frequency, while others do not. Since we can't predict a priori what a given +// machine is going to do, just disable this test on POWER on Linux. +#if !(defined(__linux) && (defined(__ppc64__) || defined(__PPC64__))) TEST(SysinfoTest, NominalCPUFrequency) { -#if !(defined(__aarch64__) && defined(__linux__)) && !defined(__EMSCRIPTEN__) - EXPECT_GE(NominalCPUFrequency(), 1000.0) - << "NominalCPUFrequency() did not return a reasonable value"; -#else - // Aarch64 cannot read the CPU frequency from sysfs, so we get back 1.0. - // Emscripten does not have a sysfs to read from at all. + // Linux only exposes the CPU frequency on certain architectures, and + // Emscripten doesn't expose it at all. +#if defined(__linux__) && \ + (defined(__aarch64__) || defined(__hppa__) || defined(__mips__) || \ + defined(__riscv) || defined(__s390x__)) || \ + defined(__EMSCRIPTEN__) EXPECT_EQ(NominalCPUFrequency(), 1.0) << "CPU frequency detection was fixed! Please update unittest."; +#else + EXPECT_GE(NominalCPUFrequency(), 1000.0) + << "NominalCPUFrequency() did not return a reasonable value"; #endif } +#endif TEST(SysinfoTest, GetTID) { EXPECT_EQ(GetTID(), GetTID()); // Basic compile and equality test. diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/thread_annotations.h b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/thread_annotations.h new file mode 100644 index 0000000000..4dab6a9c15 --- /dev/null +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/thread_annotations.h @@ -0,0 +1,271 @@ +// Copyright 2019 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// ----------------------------------------------------------------------------- +// File: thread_annotations.h +// ----------------------------------------------------------------------------- +// +// WARNING: This is a backwards compatible header and it will be removed after +// the migration to prefixed thread annotations is finished; please include +// "absl/base/thread_annotations.h". +// +// This header file contains macro definitions for thread safety annotations +// that allow developers to document the locking policies of multi-threaded +// code. The annotations can also help program analysis tools to identify +// potential thread safety issues. +// +// These annotations are implemented using compiler attributes. Using the macros +// defined here instead of raw attributes allow for portability and future +// compatibility. +// +// When referring to mutexes in the arguments of the attributes, you should +// use variable names or more complex expressions (e.g. my_object->mutex_) +// that evaluate to a concrete mutex object whenever possible. If the mutex +// you want to refer to is not in scope, you may use a member pointer +// (e.g. &MyClass::mutex_) to refer to a mutex in some (unknown) object. + +#ifndef ABSL_BASE_INTERNAL_THREAD_ANNOTATIONS_H_ +#define ABSL_BASE_INTERNAL_THREAD_ANNOTATIONS_H_ + +#if defined(__clang__) +#define THREAD_ANNOTATION_ATTRIBUTE__(x) __attribute__((x)) +#else +#define THREAD_ANNOTATION_ATTRIBUTE__(x) // no-op +#endif + +// GUARDED_BY() +// +// Documents if a shared field or global variable needs to be protected by a +// mutex. GUARDED_BY() allows the user to specify a particular mutex that +// should be held when accessing the annotated variable. +// +// Although this annotation (and PT_GUARDED_BY, below) cannot be applied to +// local variables, a local variable and its associated mutex can often be +// combined into a small class or struct, thereby allowing the annotation. +// +// Example: +// +// class Foo { +// Mutex mu_; +// int p1_ GUARDED_BY(mu_); +// ... +// }; +#define GUARDED_BY(x) THREAD_ANNOTATION_ATTRIBUTE__(guarded_by(x)) + +// PT_GUARDED_BY() +// +// Documents if the memory location pointed to by a pointer should be guarded +// by a mutex when dereferencing the pointer. +// +// Example: +// class Foo { +// Mutex mu_; +// int *p1_ PT_GUARDED_BY(mu_); +// ... +// }; +// +// Note that a pointer variable to a shared memory location could itself be a +// shared variable. +// +// Example: +// +// // `q_`, guarded by `mu1_`, points to a shared memory location that is +// // guarded by `mu2_`: +// int *q_ GUARDED_BY(mu1_) PT_GUARDED_BY(mu2_); +#define PT_GUARDED_BY(x) THREAD_ANNOTATION_ATTRIBUTE__(pt_guarded_by(x)) + +// ACQUIRED_AFTER() / ACQUIRED_BEFORE() +// +// Documents the acquisition order between locks that can be held +// simultaneously by a thread. For any two locks that need to be annotated +// to establish an acquisition order, only one of them needs the annotation. +// (i.e. You don't have to annotate both locks with both ACQUIRED_AFTER +// and ACQUIRED_BEFORE.) +// +// As with GUARDED_BY, this is only applicable to mutexes that are shared +// fields or global variables. +// +// Example: +// +// Mutex m1_; +// Mutex m2_ ACQUIRED_AFTER(m1_); +#define ACQUIRED_AFTER(...) \ + THREAD_ANNOTATION_ATTRIBUTE__(acquired_after(__VA_ARGS__)) + +#define ACQUIRED_BEFORE(...) \ + THREAD_ANNOTATION_ATTRIBUTE__(acquired_before(__VA_ARGS__)) + +// EXCLUSIVE_LOCKS_REQUIRED() / SHARED_LOCKS_REQUIRED() +// +// Documents a function that expects a mutex to be held prior to entry. +// The mutex is expected to be held both on entry to, and exit from, the +// function. +// +// An exclusive lock allows read-write access to the guarded data member(s), and +// only one thread can acquire a lock exclusively at any one time. A shared lock +// allows read-only access, and any number of threads can acquire a shared lock +// concurrently. +// +// Generally, non-const methods should be annotated with +// EXCLUSIVE_LOCKS_REQUIRED, while const methods should be annotated with +// SHARED_LOCKS_REQUIRED. +// +// Example: +// +// Mutex mu1, mu2; +// int a GUARDED_BY(mu1); +// int b GUARDED_BY(mu2); +// +// void foo() EXCLUSIVE_LOCKS_REQUIRED(mu1, mu2) { ... } +// void bar() const SHARED_LOCKS_REQUIRED(mu1, mu2) { ... } +#define EXCLUSIVE_LOCKS_REQUIRED(...) \ + THREAD_ANNOTATION_ATTRIBUTE__(exclusive_locks_required(__VA_ARGS__)) + +#define SHARED_LOCKS_REQUIRED(...) \ + THREAD_ANNOTATION_ATTRIBUTE__(shared_locks_required(__VA_ARGS__)) + +// LOCKS_EXCLUDED() +// +// Documents the locks acquired in the body of the function. These locks +// cannot be held when calling this function (as Abseil's `Mutex` locks are +// non-reentrant). +#define LOCKS_EXCLUDED(...) \ + THREAD_ANNOTATION_ATTRIBUTE__(locks_excluded(__VA_ARGS__)) + +// LOCK_RETURNED() +// +// Documents a function that returns a mutex without acquiring it. For example, +// a public getter method that returns a pointer to a private mutex should +// be annotated with LOCK_RETURNED. +#define LOCK_RETURNED(x) \ + THREAD_ANNOTATION_ATTRIBUTE__(lock_returned(x)) + +// LOCKABLE +// +// Documents if a class/type is a lockable type (such as the `Mutex` class). +#define LOCKABLE \ + THREAD_ANNOTATION_ATTRIBUTE__(lockable) + +// SCOPED_LOCKABLE +// +// Documents if a class does RAII locking (such as the `MutexLock` class). +// The constructor should use `LOCK_FUNCTION()` to specify the mutex that is +// acquired, and the destructor should use `UNLOCK_FUNCTION()` with no +// arguments; the analysis will assume that the destructor unlocks whatever the +// constructor locked. +#define SCOPED_LOCKABLE \ + THREAD_ANNOTATION_ATTRIBUTE__(scoped_lockable) + +// EXCLUSIVE_LOCK_FUNCTION() +// +// Documents functions that acquire a lock in the body of a function, and do +// not release it. +#define EXCLUSIVE_LOCK_FUNCTION(...) \ + THREAD_ANNOTATION_ATTRIBUTE__(exclusive_lock_function(__VA_ARGS__)) + +// SHARED_LOCK_FUNCTION() +// +// Documents functions that acquire a shared (reader) lock in the body of a +// function, and do not release it. +#define SHARED_LOCK_FUNCTION(...) \ + THREAD_ANNOTATION_ATTRIBUTE__(shared_lock_function(__VA_ARGS__)) + +// UNLOCK_FUNCTION() +// +// Documents functions that expect a lock to be held on entry to the function, +// and release it in the body of the function. +#define UNLOCK_FUNCTION(...) \ + THREAD_ANNOTATION_ATTRIBUTE__(unlock_function(__VA_ARGS__)) + +// EXCLUSIVE_TRYLOCK_FUNCTION() / SHARED_TRYLOCK_FUNCTION() +// +// Documents functions that try to acquire a lock, and return success or failure +// (or a non-boolean value that can be interpreted as a boolean). +// The first argument should be `true` for functions that return `true` on +// success, or `false` for functions that return `false` on success. The second +// argument specifies the mutex that is locked on success. If unspecified, this +// mutex is assumed to be `this`. +#define EXCLUSIVE_TRYLOCK_FUNCTION(...) \ + THREAD_ANNOTATION_ATTRIBUTE__(exclusive_trylock_function(__VA_ARGS__)) + +#define SHARED_TRYLOCK_FUNCTION(...) \ + THREAD_ANNOTATION_ATTRIBUTE__(shared_trylock_function(__VA_ARGS__)) + +// ASSERT_EXCLUSIVE_LOCK() / ASSERT_SHARED_LOCK() +// +// Documents functions that dynamically check to see if a lock is held, and fail +// if it is not held. +#define ASSERT_EXCLUSIVE_LOCK(...) \ + THREAD_ANNOTATION_ATTRIBUTE__(assert_exclusive_lock(__VA_ARGS__)) + +#define ASSERT_SHARED_LOCK(...) \ + THREAD_ANNOTATION_ATTRIBUTE__(assert_shared_lock(__VA_ARGS__)) + +// NO_THREAD_SAFETY_ANALYSIS +// +// Turns off thread safety checking within the body of a particular function. +// This annotation is used to mark functions that are known to be correct, but +// the locking behavior is more complicated than the analyzer can handle. +#define NO_THREAD_SAFETY_ANALYSIS \ + THREAD_ANNOTATION_ATTRIBUTE__(no_thread_safety_analysis) + +//------------------------------------------------------------------------------ +// Tool-Supplied Annotations +//------------------------------------------------------------------------------ + +// TS_UNCHECKED should be placed around lock expressions that are not valid +// C++ syntax, but which are present for documentation purposes. These +// annotations will be ignored by the analysis. +#define TS_UNCHECKED(x) "" + +// TS_FIXME is used to mark lock expressions that are not valid C++ syntax. +// It is used by automated tools to mark and disable invalid expressions. +// The annotation should either be fixed, or changed to TS_UNCHECKED. +#define TS_FIXME(x) "" + +// Like NO_THREAD_SAFETY_ANALYSIS, this turns off checking within the body of +// a particular function. However, this attribute is used to mark functions +// that are incorrect and need to be fixed. It is used by automated tools to +// avoid breaking the build when the analysis is updated. +// Code owners are expected to eventually fix the routine. +#define NO_THREAD_SAFETY_ANALYSIS_FIXME NO_THREAD_SAFETY_ANALYSIS + +// Similar to NO_THREAD_SAFETY_ANALYSIS_FIXME, this macro marks a GUARDED_BY +// annotation that needs to be fixed, because it is producing thread safety +// warning. It disables the GUARDED_BY. +#define GUARDED_BY_FIXME(x) + +// Disables warnings for a single read operation. This can be used to avoid +// warnings when it is known that the read is not actually involved in a race, +// but the compiler cannot confirm that. +#define TS_UNCHECKED_READ(x) thread_safety_analysis::ts_unchecked_read(x) + + +namespace thread_safety_analysis { + +// Takes a reference to a guarded data member, and returns an unguarded +// reference. +template +inline const T& ts_unchecked_read(const T& v) NO_THREAD_SAFETY_ANALYSIS { + return v; +} + +template +inline T& ts_unchecked_read(T& v) NO_THREAD_SAFETY_ANALYSIS { + return v; +} + +} // namespace thread_safety_analysis + +#endif // ABSL_BASE_INTERNAL_THREAD_ANNOTATIONS_H_ diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/thread_identity.cc b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/thread_identity.cc index d63a04ae91..9950e63a79 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/thread_identity.cc +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/thread_identity.cc @@ -23,6 +23,7 @@ #include #include +#include "absl/base/attributes.h" #include "absl/base/call_once.h" #include "absl/base/internal/raw_logging.h" #include "absl/base/internal/spinlock.h" @@ -53,9 +54,11 @@ void AllocateThreadIdentityKey(ThreadIdentityReclaimerFunction reclaimer) { // exist within a process (via dlopen() or similar), references to // thread_identity_ptr from each instance of the code will refer to // *different* instances of this ptr. -#ifdef __GNUC__ +// Apple platforms have the visibility attribute, but issue a compile warning +// that protected visibility is unsupported. +#if ABSL_HAVE_ATTRIBUTE(visibility) && !defined(__APPLE__) __attribute__((visibility("protected"))) -#endif // __GNUC__ +#endif // ABSL_HAVE_ATTRIBUTE(visibility) && !defined(__APPLE__) #if ABSL_PER_THREAD_TLS // Prefer __thread to thread_local as benchmarks indicate it is a bit faster. ABSL_PER_THREAD_TLS_KEYWORD ThreadIdentity* thread_identity_ptr = nullptr; @@ -117,10 +120,10 @@ void SetCurrentThreadIdentity( ABSL_THREAD_IDENTITY_MODE == ABSL_THREAD_IDENTITY_MODE_USE_CPP11 // Please see the comment on `CurrentThreadIdentityIfPresent` in -// thread_identity.h. Because DLLs cannot expose thread_local variables in -// headers, we opt for the correct-but-slower option of placing the definition -// of this function only in a translation unit inside DLL. -#if defined(ABSL_BUILD_DLL) || defined(ABSL_CONSUME_DLL) +// thread_identity.h. When we cannot expose thread_local variables in +// headers, we opt for the correct-but-slower option of not inlining this +// function. +#ifndef ABSL_INTERNAL_INLINE_CURRENT_THREAD_IDENTITY_IF_PRESENT ThreadIdentity* CurrentThreadIdentityIfPresent() { return thread_identity_ptr; } #endif #endif diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/thread_identity.h b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/thread_identity.h index ceb109b41c..659694b326 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/thread_identity.h +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/thread_identity.h @@ -32,6 +32,7 @@ #include "absl/base/config.h" #include "absl/base/internal/per_thread_tls.h" +#include "absl/base/optimization.h" namespace absl { ABSL_NAMESPACE_BEGIN @@ -69,30 +70,28 @@ struct PerThreadSynch { // is using this PerThreadSynch as a terminator. Its // skip field must not be filled in because the loop // might then skip over the terminator. - - // The wait parameters of the current wait. waitp is null if the - // thread is not waiting. Transitions from null to non-null must - // occur before the enqueue commit point (state = kQueued in - // Enqueue() and CondVarEnqueue()). Transitions from non-null to - // null must occur after the wait is finished (state = kAvailable in - // Mutex::Block() and CondVar::WaitCommon()). This field may be - // changed only by the thread that describes this PerThreadSynch. A - // special case is Fer(), which calls Enqueue() on another thread, - // but with an identical SynchWaitParams pointer, thus leaving the - // pointer unchanged. - SynchWaitParams *waitp; - - bool suppress_fatal_errors; // If true, try to proceed even in the face of - // broken invariants. This is used within fatal - // signal handlers to improve the chances of - // debug logging information being output - // successfully. - - intptr_t readers; // Number of readers in mutex. - int priority; // Priority of thread (updated every so often). - - // When priority will next be read (cycles). - int64_t next_priority_read_cycles; + bool wake; // This thread is to be woken from a Mutex. + // If "x" is on a waiter list for a mutex, "x->cond_waiter" is true iff the + // waiter is waiting on the mutex as part of a CV Wait or Mutex Await. + // + // The value of "x->cond_waiter" is meaningless if "x" is not on a + // Mutex waiter list. + bool cond_waiter; + bool maybe_unlocking; // Valid at head of Mutex waiter queue; + // true if UnlockSlow could be searching + // for a waiter to wake. Used for an optimization + // in Enqueue(). true is always a valid value. + // Can be reset to false when the unlocker or any + // writer releases the lock, or a reader fully + // releases the lock. It may not be set to false + // by a reader that decrements the count to + // non-zero. protected by mutex spinlock + bool suppress_fatal_errors; // If true, try to proceed even in the face + // of broken invariants. This is used within + // fatal signal handlers to improve the + // chances of debug logging information being + // output successfully. + int priority; // Priority of thread (updated every so often). // State values: // kAvailable: This PerThreadSynch is available. @@ -111,30 +110,30 @@ struct PerThreadSynch { }; std::atomic state; - bool maybe_unlocking; // Valid at head of Mutex waiter queue; - // true if UnlockSlow could be searching - // for a waiter to wake. Used for an optimization - // in Enqueue(). true is always a valid value. - // Can be reset to false when the unlocker or any - // writer releases the lock, or a reader fully releases - // the lock. It may not be set to false by a reader - // that decrements the count to non-zero. - // protected by mutex spinlock + // The wait parameters of the current wait. waitp is null if the + // thread is not waiting. Transitions from null to non-null must + // occur before the enqueue commit point (state = kQueued in + // Enqueue() and CondVarEnqueue()). Transitions from non-null to + // null must occur after the wait is finished (state = kAvailable in + // Mutex::Block() and CondVar::WaitCommon()). This field may be + // changed only by the thread that describes this PerThreadSynch. A + // special case is Fer(), which calls Enqueue() on another thread, + // but with an identical SynchWaitParams pointer, thus leaving the + // pointer unchanged. + SynchWaitParams* waitp; - bool wake; // This thread is to be woken from a Mutex. + intptr_t readers; // Number of readers in mutex. - // If "x" is on a waiter list for a mutex, "x->cond_waiter" is true iff the - // waiter is waiting on the mutex as part of a CV Wait or Mutex Await. - // - // The value of "x->cond_waiter" is meaningless if "x" is not on a - // Mutex waiter list. - bool cond_waiter; + // When priority will next be read (cycles). + int64_t next_priority_read_cycles; // Locks held; used during deadlock detection. // Allocated in Synch_GetAllLocks() and freed in ReclaimThreadIdentity(). SynchLocksHeld *all_locks; }; +// The instances of this class are allocated in NewThreadIdentity() with an +// alignment of PerThreadSynch::kAlignment. struct ThreadIdentity { // Must be the first member. The Mutex implementation requires that // the PerThreadSynch object associated with each thread is @@ -144,7 +143,7 @@ struct ThreadIdentity { // Private: Reserved for absl::synchronization_internal::Waiter. struct WaiterState { - char data[128]; + alignas(void*) char data[128]; } waiter_state; // Used by PerThreadSem::{Get,Set}ThreadBlockedCounter(). @@ -189,30 +188,32 @@ void ClearCurrentThreadIdentity(); // May be chosen at compile time via: -DABSL_FORCE_THREAD_IDENTITY_MODE= #ifdef ABSL_THREAD_IDENTITY_MODE_USE_POSIX_SETSPECIFIC -#error ABSL_THREAD_IDENTITY_MODE_USE_POSIX_SETSPECIFIC cannot be direcly set +#error ABSL_THREAD_IDENTITY_MODE_USE_POSIX_SETSPECIFIC cannot be directly set #else #define ABSL_THREAD_IDENTITY_MODE_USE_POSIX_SETSPECIFIC 0 #endif #ifdef ABSL_THREAD_IDENTITY_MODE_USE_TLS -#error ABSL_THREAD_IDENTITY_MODE_USE_TLS cannot be direcly set +#error ABSL_THREAD_IDENTITY_MODE_USE_TLS cannot be directly set #else #define ABSL_THREAD_IDENTITY_MODE_USE_TLS 1 #endif #ifdef ABSL_THREAD_IDENTITY_MODE_USE_CPP11 -#error ABSL_THREAD_IDENTITY_MODE_USE_CPP11 cannot be direcly set +#error ABSL_THREAD_IDENTITY_MODE_USE_CPP11 cannot be directly set #else #define ABSL_THREAD_IDENTITY_MODE_USE_CPP11 2 #endif #ifdef ABSL_THREAD_IDENTITY_MODE -#error ABSL_THREAD_IDENTITY_MODE cannot be direcly set +#error ABSL_THREAD_IDENTITY_MODE cannot be directly set #elif defined(ABSL_FORCE_THREAD_IDENTITY_MODE) #define ABSL_THREAD_IDENTITY_MODE ABSL_FORCE_THREAD_IDENTITY_MODE #elif defined(_WIN32) && !defined(__MINGW32__) #define ABSL_THREAD_IDENTITY_MODE ABSL_THREAD_IDENTITY_MODE_USE_CPP11 -#elif ABSL_PER_THREAD_TLS && defined(__GOOGLE_GRTE_VERSION__) && \ +#elif defined(__APPLE__) && defined(ABSL_HAVE_THREAD_LOCAL) +#define ABSL_THREAD_IDENTITY_MODE ABSL_THREAD_IDENTITY_MODE_USE_CPP11 +#elif ABSL_PER_THREAD_TLS && defined(__GOOGLE_GRTE_VERSION__) && \ (__GOOGLE_GRTE_VERSION__ >= 20140228L) // Support for async-safe TLS was specifically added in GRTEv4. It's not // present in the upstream eglibc. @@ -235,13 +236,18 @@ ABSL_CONST_INIT extern thread_local ThreadIdentity* thread_identity_ptr; #error Thread-local storage not detected on this platform #endif -// thread_local variables cannot be in headers exposed by DLLs. However, it is -// important for performance reasons in general that -// `CurrentThreadIdentityIfPresent` be inlined. This is not possible across a -// DLL boundary so, with DLLs, we opt to have the function not be inlined. Note +// thread_local variables cannot be in headers exposed by DLLs or in certain +// build configurations on Apple platforms. However, it is important for +// performance reasons in general that `CurrentThreadIdentityIfPresent` be +// inlined. In the other cases we opt to have the function not be inlined. Note // that `CurrentThreadIdentityIfPresent` is declared above so we can exclude -// this entire inline definition when compiling as a DLL. -#if !defined(ABSL_BUILD_DLL) && !defined(ABSL_CONSUME_DLL) +// this entire inline definition. +#if !defined(__APPLE__) && !defined(ABSL_BUILD_DLL) && \ + !defined(ABSL_CONSUME_DLL) +#define ABSL_INTERNAL_INLINE_CURRENT_THREAD_IDENTITY_IF_PRESENT 1 +#endif + +#ifdef ABSL_INTERNAL_INLINE_CURRENT_THREAD_IDENTITY_IF_PRESENT inline ThreadIdentity* CurrentThreadIdentityIfPresent() { return thread_identity_ptr; } diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/thread_identity_test.cc b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/thread_identity_test.cc index 3685779ce8..46a6f74346 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/thread_identity_test.cc +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/thread_identity_test.cc @@ -21,6 +21,7 @@ #include "absl/base/attributes.h" #include "absl/base/internal/spinlock.h" #include "absl/base/macros.h" +#include "absl/base/thread_annotations.h" #include "absl/synchronization/internal/per_thread_sem.h" #include "absl/synchronization/mutex.h" @@ -29,10 +30,9 @@ ABSL_NAMESPACE_BEGIN namespace base_internal { namespace { -// protects num_identities_reused -static absl::base_internal::SpinLock map_lock( - absl::base_internal::kLinkerInitialized); -static int num_identities_reused; +ABSL_CONST_INIT static absl::base_internal::SpinLock map_lock( + absl::kConstInit, base_internal::SCHEDULE_KERNEL_ONLY); +ABSL_CONST_INIT static int num_identities_reused ABSL_GUARDED_BY(map_lock); static const void* const kCheckNoIdentity = reinterpret_cast(1); @@ -75,7 +75,7 @@ TEST(ThreadIdentityTest, BasicIdentityWorksThreaded) { // - If a thread implementation chooses to recycle threads, that // correct re-initialization occurs. static const int kNumLoops = 3; - static const int kNumThreads = 400; + static const int kNumThreads = 32; for (int iter = 0; iter < kNumLoops; iter++) { std::vector threads; for (int i = 0; i < kNumThreads; ++i) { @@ -90,6 +90,7 @@ TEST(ThreadIdentityTest, BasicIdentityWorksThreaded) { // We should have recycled ThreadIdentity objects above; while (external) // library threads allocating their own identities may preclude some // reuse, we should have sufficient repetitions to exclude this. + absl::base_internal::SpinLockHolder l(&map_lock); EXPECT_LT(kNumThreads, num_identities_reused); } diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/throw_delegate.cc b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/throw_delegate.cc index c055f75d9d..c260ff1eed 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/throw_delegate.cc +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/throw_delegate.cc @@ -18,6 +18,7 @@ #include #include #include + #include "absl/base/config.h" #include "absl/base/internal/raw_logging.h" @@ -25,83 +26,186 @@ namespace absl { ABSL_NAMESPACE_BEGIN namespace base_internal { +// NOTE: The various STL exception throwing functions are placed within the +// #ifdef blocks so the symbols aren't exposed on platforms that don't support +// them, such as the Android NDK. For example, ANGLE fails to link when building +// within AOSP without them, since the STL functions don't exist. namespace { +#ifdef ABSL_HAVE_EXCEPTIONS template [[noreturn]] void Throw(const T& error) { -#ifdef ABSL_HAVE_EXCEPTIONS throw error; -#else - ABSL_RAW_LOG(FATAL, "%s", error.what()); - std::abort(); -#endif } +#endif } // namespace void ThrowStdLogicError(const std::string& what_arg) { +#ifdef ABSL_HAVE_EXCEPTIONS Throw(std::logic_error(what_arg)); +#else + ABSL_RAW_LOG(FATAL, "%s", what_arg.c_str()); + std::abort(); +#endif } void ThrowStdLogicError(const char* what_arg) { +#ifdef ABSL_HAVE_EXCEPTIONS Throw(std::logic_error(what_arg)); +#else + ABSL_RAW_LOG(FATAL, "%s", what_arg); + std::abort(); +#endif } void ThrowStdInvalidArgument(const std::string& what_arg) { +#ifdef ABSL_HAVE_EXCEPTIONS Throw(std::invalid_argument(what_arg)); +#else + ABSL_RAW_LOG(FATAL, "%s", what_arg.c_str()); + std::abort(); +#endif } void ThrowStdInvalidArgument(const char* what_arg) { +#ifdef ABSL_HAVE_EXCEPTIONS Throw(std::invalid_argument(what_arg)); +#else + ABSL_RAW_LOG(FATAL, "%s", what_arg); + std::abort(); +#endif } void ThrowStdDomainError(const std::string& what_arg) { +#ifdef ABSL_HAVE_EXCEPTIONS Throw(std::domain_error(what_arg)); +#else + ABSL_RAW_LOG(FATAL, "%s", what_arg.c_str()); + std::abort(); +#endif } void ThrowStdDomainError(const char* what_arg) { +#ifdef ABSL_HAVE_EXCEPTIONS Throw(std::domain_error(what_arg)); +#else + ABSL_RAW_LOG(FATAL, "%s", what_arg); + std::abort(); +#endif } void ThrowStdLengthError(const std::string& what_arg) { +#ifdef ABSL_HAVE_EXCEPTIONS Throw(std::length_error(what_arg)); +#else + ABSL_RAW_LOG(FATAL, "%s", what_arg.c_str()); + std::abort(); +#endif } void ThrowStdLengthError(const char* what_arg) { +#ifdef ABSL_HAVE_EXCEPTIONS Throw(std::length_error(what_arg)); +#else + ABSL_RAW_LOG(FATAL, "%s", what_arg); + std::abort(); +#endif } void ThrowStdOutOfRange(const std::string& what_arg) { +#ifdef ABSL_HAVE_EXCEPTIONS Throw(std::out_of_range(what_arg)); +#else + ABSL_RAW_LOG(FATAL, "%s", what_arg.c_str()); + std::abort(); +#endif } void ThrowStdOutOfRange(const char* what_arg) { +#ifdef ABSL_HAVE_EXCEPTIONS Throw(std::out_of_range(what_arg)); +#else + ABSL_RAW_LOG(FATAL, "%s", what_arg); + std::abort(); +#endif } void ThrowStdRuntimeError(const std::string& what_arg) { +#ifdef ABSL_HAVE_EXCEPTIONS Throw(std::runtime_error(what_arg)); +#else + ABSL_RAW_LOG(FATAL, "%s", what_arg.c_str()); + std::abort(); +#endif } void ThrowStdRuntimeError(const char* what_arg) { +#ifdef ABSL_HAVE_EXCEPTIONS Throw(std::runtime_error(what_arg)); +#else + ABSL_RAW_LOG(FATAL, "%s", what_arg); + std::abort(); +#endif } void ThrowStdRangeError(const std::string& what_arg) { +#ifdef ABSL_HAVE_EXCEPTIONS Throw(std::range_error(what_arg)); +#else + ABSL_RAW_LOG(FATAL, "%s", what_arg.c_str()); + std::abort(); +#endif } void ThrowStdRangeError(const char* what_arg) { +#ifdef ABSL_HAVE_EXCEPTIONS Throw(std::range_error(what_arg)); +#else + ABSL_RAW_LOG(FATAL, "%s", what_arg); + std::abort(); +#endif } void ThrowStdOverflowError(const std::string& what_arg) { +#ifdef ABSL_HAVE_EXCEPTIONS Throw(std::overflow_error(what_arg)); +#else + ABSL_RAW_LOG(FATAL, "%s", what_arg.c_str()); + std::abort(); +#endif } void ThrowStdOverflowError(const char* what_arg) { +#ifdef ABSL_HAVE_EXCEPTIONS Throw(std::overflow_error(what_arg)); +#else + ABSL_RAW_LOG(FATAL, "%s", what_arg); + std::abort(); +#endif } void ThrowStdUnderflowError(const std::string& what_arg) { +#ifdef ABSL_HAVE_EXCEPTIONS Throw(std::underflow_error(what_arg)); +#else + ABSL_RAW_LOG(FATAL, "%s", what_arg.c_str()); + std::abort(); +#endif } void ThrowStdUnderflowError(const char* what_arg) { +#ifdef ABSL_HAVE_EXCEPTIONS Throw(std::underflow_error(what_arg)); +#else + ABSL_RAW_LOG(FATAL, "%s", what_arg); + std::abort(); +#endif } -void ThrowStdBadFunctionCall() { Throw(std::bad_function_call()); } +void ThrowStdBadFunctionCall() { +#ifdef ABSL_HAVE_EXCEPTIONS + Throw(std::bad_function_call()); +#else + std::abort(); +#endif +} -void ThrowStdBadAlloc() { Throw(std::bad_alloc()); } +void ThrowStdBadAlloc() { +#ifdef ABSL_HAVE_EXCEPTIONS + Throw(std::bad_alloc()); +#else + std::abort(); +#endif +} } // namespace base_internal ABSL_NAMESPACE_END diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/tsan_mutex_interface.h b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/tsan_mutex_interface.h index 2a510603bc..39207d8a5c 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/tsan_mutex_interface.h +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/tsan_mutex_interface.h @@ -19,6 +19,8 @@ #ifndef ABSL_BASE_INTERNAL_TSAN_MUTEX_INTERFACE_H_ #define ABSL_BASE_INTERNAL_TSAN_MUTEX_INTERFACE_H_ +#include "absl/base/config.h" + // ABSL_INTERNAL_HAVE_TSAN_INTERFACE // Macro intended only for internal use. // @@ -28,7 +30,7 @@ #error "ABSL_INTERNAL_HAVE_TSAN_INTERFACE cannot be directly set." #endif -#if defined(THREAD_SANITIZER) && defined(__has_include) +#if defined(ABSL_HAVE_THREAD_SANITIZER) && defined(__has_include) #if __has_include() #define ABSL_INTERNAL_HAVE_TSAN_INTERFACE 1 #endif diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/unaligned_access.h b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/unaligned_access.h index 6be56c865b..093dd9b499 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/unaligned_access.h +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/unaligned_access.h @@ -31,80 +31,6 @@ // The unaligned API is C++ only. The declarations use C++ features // (namespaces, inline) which are absent or incompatible in C. #if defined(__cplusplus) - -#if defined(ADDRESS_SANITIZER) || defined(THREAD_SANITIZER) ||\ - defined(MEMORY_SANITIZER) -// Consider we have an unaligned load/store of 4 bytes from address 0x...05. -// AddressSanitizer will treat it as a 3-byte access to the range 05:07 and -// will miss a bug if 08 is the first unaddressable byte. -// ThreadSanitizer will also treat this as a 3-byte access to 05:07 and will -// miss a race between this access and some other accesses to 08. -// MemorySanitizer will correctly propagate the shadow on unaligned stores -// and correctly report bugs on unaligned loads, but it may not properly -// update and report the origin of the uninitialized memory. -// For all three tools, replacing an unaligned access with a tool-specific -// callback solves the problem. - -// Make sure uint16_t/uint32_t/uint64_t are defined. -#include - -extern "C" { -uint16_t __sanitizer_unaligned_load16(const void *p); -uint32_t __sanitizer_unaligned_load32(const void *p); -uint64_t __sanitizer_unaligned_load64(const void *p); -void __sanitizer_unaligned_store16(void *p, uint16_t v); -void __sanitizer_unaligned_store32(void *p, uint32_t v); -void __sanitizer_unaligned_store64(void *p, uint64_t v); -} // extern "C" - -namespace absl { -ABSL_NAMESPACE_BEGIN -namespace base_internal { - -inline uint16_t UnalignedLoad16(const void *p) { - return __sanitizer_unaligned_load16(p); -} - -inline uint32_t UnalignedLoad32(const void *p) { - return __sanitizer_unaligned_load32(p); -} - -inline uint64_t UnalignedLoad64(const void *p) { - return __sanitizer_unaligned_load64(p); -} - -inline void UnalignedStore16(void *p, uint16_t v) { - __sanitizer_unaligned_store16(p, v); -} - -inline void UnalignedStore32(void *p, uint32_t v) { - __sanitizer_unaligned_store32(p, v); -} - -inline void UnalignedStore64(void *p, uint64_t v) { - __sanitizer_unaligned_store64(p, v); -} - -} // namespace base_internal -ABSL_NAMESPACE_END -} // namespace absl - -#define ABSL_INTERNAL_UNALIGNED_LOAD16(_p) \ - (absl::base_internal::UnalignedLoad16(_p)) -#define ABSL_INTERNAL_UNALIGNED_LOAD32(_p) \ - (absl::base_internal::UnalignedLoad32(_p)) -#define ABSL_INTERNAL_UNALIGNED_LOAD64(_p) \ - (absl::base_internal::UnalignedLoad64(_p)) - -#define ABSL_INTERNAL_UNALIGNED_STORE16(_p, _val) \ - (absl::base_internal::UnalignedStore16(_p, _val)) -#define ABSL_INTERNAL_UNALIGNED_STORE32(_p, _val) \ - (absl::base_internal::UnalignedStore32(_p, _val)) -#define ABSL_INTERNAL_UNALIGNED_STORE64(_p, _val) \ - (absl::base_internal::UnalignedStore64(_p, _val)) - -#else - namespace absl { ABSL_NAMESPACE_BEGIN namespace base_internal { @@ -151,8 +77,6 @@ ABSL_NAMESPACE_END #define ABSL_INTERNAL_UNALIGNED_STORE64(_p, _val) \ (absl::base_internal::UnalignedStore64(_p, _val)) -#endif - #endif // defined(__cplusplus), end of unaligned API #endif // ABSL_BASE_INTERNAL_UNALIGNED_ACCESS_H_ diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/unique_small_name_test.cc b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/unique_small_name_test.cc new file mode 100644 index 0000000000..ff8c2b3fb4 --- /dev/null +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/unique_small_name_test.cc @@ -0,0 +1,77 @@ +// Copyright 2020 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "gtest/gtest.h" +#include "absl/base/optimization.h" +#include "absl/strings/string_view.h" + +// This test by itself does not do anything fancy, but it serves as binary I can +// query in shell test. + +namespace { + +template +void DoNotOptimize(const T& var) { +#ifdef __GNUC__ + asm volatile("" : "+m"(const_cast(var))); +#else + std::cout << (void*)&var; +#endif +} + +int very_long_int_variable_name ABSL_INTERNAL_UNIQUE_SMALL_NAME() = 0; +char very_long_str_variable_name[] ABSL_INTERNAL_UNIQUE_SMALL_NAME() = "abc"; + +TEST(UniqueSmallName, NonAutomaticVar) { + EXPECT_EQ(very_long_int_variable_name, 0); + EXPECT_EQ(absl::string_view(very_long_str_variable_name), "abc"); +} + +int VeryLongFreeFunctionName() ABSL_INTERNAL_UNIQUE_SMALL_NAME(); + +TEST(UniqueSmallName, FreeFunction) { + DoNotOptimize(&VeryLongFreeFunctionName); + + EXPECT_EQ(VeryLongFreeFunctionName(), 456); +} + +int VeryLongFreeFunctionName() { return 456; } + +struct VeryLongStructName { + explicit VeryLongStructName(int i); + + int VeryLongMethodName() ABSL_INTERNAL_UNIQUE_SMALL_NAME(); + + static int VeryLongStaticMethodName() ABSL_INTERNAL_UNIQUE_SMALL_NAME(); + + private: + int fld; +}; + +TEST(UniqueSmallName, Struct) { + VeryLongStructName var(10); + + DoNotOptimize(var); + DoNotOptimize(&VeryLongStructName::VeryLongMethodName); + DoNotOptimize(&VeryLongStructName::VeryLongStaticMethodName); + + EXPECT_EQ(var.VeryLongMethodName(), 10); + EXPECT_EQ(VeryLongStructName::VeryLongStaticMethodName(), 123); +} + +VeryLongStructName::VeryLongStructName(int i) : fld(i) {} +int VeryLongStructName::VeryLongMethodName() { return fld; } +int VeryLongStructName::VeryLongStaticMethodName() { return 123; } + +} // namespace diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/unscaledcycleclock.cc b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/unscaledcycleclock.cc index f1e7bbef84..fc07e30057 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/unscaledcycleclock.cc +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/unscaledcycleclock.cc @@ -119,13 +119,23 @@ double UnscaledCycleClock::Frequency() { return aarch64_timer_frequency; } +#elif defined(__riscv) + +int64_t UnscaledCycleClock::Now() { + int64_t virtual_timer_value; + asm volatile("rdcycle %0" : "=r"(virtual_timer_value)); + return virtual_timer_value; +} + +double UnscaledCycleClock::Frequency() { + return base_internal::NominalCPUFrequency(); +} + #elif defined(_M_IX86) || defined(_M_X64) #pragma intrinsic(__rdtsc) -int64_t UnscaledCycleClock::Now() { - return __rdtsc(); -} +int64_t UnscaledCycleClock::Now() { return __rdtsc(); } double UnscaledCycleClock::Frequency() { return base_internal::NominalCPUFrequency(); diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/unscaledcycleclock.h b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/unscaledcycleclock.h index cdce9bf8a8..681ff8f996 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/unscaledcycleclock.h +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/internal/unscaledcycleclock.h @@ -15,8 +15,8 @@ // UnscaledCycleClock // An UnscaledCycleClock yields the value and frequency of a cycle counter // that increments at a rate that is approximately constant. -// This class is for internal / whitelisted use only, you should consider -// using CycleClock instead. +// This class is for internal use only, you should consider using CycleClock +// instead. // // Notes: // The cycle counter frequency is not necessarily the core clock frequency. @@ -46,8 +46,8 @@ // The following platforms have an implementation of a hardware counter. #if defined(__i386__) || defined(__x86_64__) || defined(__aarch64__) || \ - defined(__powerpc__) || defined(__ppc__) || \ - defined(_M_IX86) || defined(_M_X64) + defined(__powerpc__) || defined(__ppc__) || defined(__riscv) || \ + defined(_M_IX86) || defined(_M_X64) #define ABSL_HAVE_UNSCALED_CYCLECLOCK_IMPLEMENTATION 1 #else #define ABSL_HAVE_UNSCALED_CYCLECLOCK_IMPLEMENTATION 0 @@ -80,8 +80,8 @@ // This macro can be used to test if UnscaledCycleClock::Frequency() // is NominalCPUFrequency() on a particular platform. -#if (defined(__i386__) || defined(__x86_64__) || \ - defined(_M_IX86) || defined(_M_X64)) +#if (defined(__i386__) || defined(__x86_64__) || defined(__riscv) || \ + defined(_M_IX86) || defined(_M_X64)) #define ABSL_INTERNAL_UNSCALED_CYCLECLOCK_FREQUENCY_IS_CPU_FREQUENCY #endif @@ -109,7 +109,7 @@ class UnscaledCycleClock { // value. static double Frequency(); - // Whitelisted friends. + // Allowed users friend class base_internal::CycleClock; friend class time_internal::UnscaledCycleClockWrapperForGetCurrentTime; friend class base_internal::UnscaledCycleClockWrapperForInitializeFrequency; diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/invoke_test.cc b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/invoke_test.cc index 6aa613c913..bcdef36c3b 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/invoke_test.cc +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/invoke_test.cc @@ -86,71 +86,73 @@ struct FlipFlop { int member; }; -// CallMaybeWithArg(f) resolves either to Invoke(f) or Invoke(f, 42), depending +// CallMaybeWithArg(f) resolves either to invoke(f) or invoke(f, 42), depending // on which one is valid. template -decltype(Invoke(std::declval())) CallMaybeWithArg(const F& f) { - return Invoke(f); +decltype(base_internal::invoke(std::declval())) CallMaybeWithArg( + const F& f) { + return base_internal::invoke(f); } template -decltype(Invoke(std::declval(), 42)) CallMaybeWithArg(const F& f) { - return Invoke(f, 42); +decltype(base_internal::invoke(std::declval(), 42)) CallMaybeWithArg( + const F& f) { + return base_internal::invoke(f, 42); } TEST(InvokeTest, Function) { - EXPECT_EQ(1, Invoke(Function, 3, 2)); - EXPECT_EQ(1, Invoke(&Function, 3, 2)); + EXPECT_EQ(1, base_internal::invoke(Function, 3, 2)); + EXPECT_EQ(1, base_internal::invoke(&Function, 3, 2)); } TEST(InvokeTest, NonCopyableArgument) { - EXPECT_EQ(42, Invoke(Sink, make_unique(42))); + EXPECT_EQ(42, base_internal::invoke(Sink, make_unique(42))); } TEST(InvokeTest, NonCopyableResult) { - EXPECT_THAT(Invoke(Factory, 42), ::testing::Pointee(42)); + EXPECT_THAT(base_internal::invoke(Factory, 42), ::testing::Pointee(42)); } -TEST(InvokeTest, VoidResult) { - Invoke(NoOp); -} +TEST(InvokeTest, VoidResult) { base_internal::invoke(NoOp); } TEST(InvokeTest, ConstFunctor) { - EXPECT_EQ(1, Invoke(ConstFunctor(), 3, 2)); + EXPECT_EQ(1, base_internal::invoke(ConstFunctor(), 3, 2)); } TEST(InvokeTest, MutableFunctor) { MutableFunctor f; - EXPECT_EQ(1, Invoke(f, 3, 2)); - EXPECT_EQ(1, Invoke(MutableFunctor(), 3, 2)); + EXPECT_EQ(1, base_internal::invoke(f, 3, 2)); + EXPECT_EQ(1, base_internal::invoke(MutableFunctor(), 3, 2)); } TEST(InvokeTest, EphemeralFunctor) { EphemeralFunctor f; - EXPECT_EQ(1, Invoke(std::move(f), 3, 2)); - EXPECT_EQ(1, Invoke(EphemeralFunctor(), 3, 2)); + EXPECT_EQ(1, base_internal::invoke(std::move(f), 3, 2)); + EXPECT_EQ(1, base_internal::invoke(EphemeralFunctor(), 3, 2)); } TEST(InvokeTest, OverloadedFunctor) { OverloadedFunctor f; const OverloadedFunctor& cf = f; - EXPECT_EQ("&", Invoke(f)); - EXPECT_EQ("& 42", Invoke(f, " 42")); + EXPECT_EQ("&", base_internal::invoke(f)); + EXPECT_EQ("& 42", base_internal::invoke(f, " 42")); - EXPECT_EQ("const&", Invoke(cf)); - EXPECT_EQ("const& 42", Invoke(cf, " 42")); + EXPECT_EQ("const&", base_internal::invoke(cf)); + EXPECT_EQ("const& 42", base_internal::invoke(cf, " 42")); - EXPECT_EQ("&&", Invoke(std::move(f))); - EXPECT_EQ("&& 42", Invoke(std::move(f), " 42")); + EXPECT_EQ("&&", base_internal::invoke(std::move(f))); + + OverloadedFunctor f2; + EXPECT_EQ("&& 42", base_internal::invoke(std::move(f2), " 42")); } TEST(InvokeTest, ReferenceWrapper) { ConstFunctor cf; MutableFunctor mf; - EXPECT_EQ(1, Invoke(std::cref(cf), 3, 2)); - EXPECT_EQ(1, Invoke(std::ref(cf), 3, 2)); - EXPECT_EQ(1, Invoke(std::ref(mf), 3, 2)); + EXPECT_EQ(1, base_internal::invoke(std::cref(cf), 3, 2)); + EXPECT_EQ(1, base_internal::invoke(std::ref(cf), 3, 2)); + EXPECT_EQ(1, base_internal::invoke(std::ref(mf), 3, 2)); } TEST(InvokeTest, MemberFunction) { @@ -158,58 +160,62 @@ TEST(InvokeTest, MemberFunction) { std::unique_ptr cp(new Class); std::unique_ptr vp(new Class); - EXPECT_EQ(1, Invoke(&Class::Method, p, 3, 2)); - EXPECT_EQ(1, Invoke(&Class::Method, p.get(), 3, 2)); - EXPECT_EQ(1, Invoke(&Class::Method, *p, 3, 2)); - EXPECT_EQ(1, Invoke(&Class::RefMethod, p, 3, 2)); - EXPECT_EQ(1, Invoke(&Class::RefMethod, p.get(), 3, 2)); - EXPECT_EQ(1, Invoke(&Class::RefMethod, *p, 3, 2)); - EXPECT_EQ(1, Invoke(&Class::RefRefMethod, std::move(*p), 3, 2)); // NOLINT - EXPECT_EQ(1, Invoke(&Class::NoExceptMethod, p, 3, 2)); - EXPECT_EQ(1, Invoke(&Class::NoExceptMethod, p.get(), 3, 2)); - EXPECT_EQ(1, Invoke(&Class::NoExceptMethod, *p, 3, 2)); + EXPECT_EQ(1, base_internal::invoke(&Class::Method, p, 3, 2)); + EXPECT_EQ(1, base_internal::invoke(&Class::Method, p.get(), 3, 2)); + EXPECT_EQ(1, base_internal::invoke(&Class::Method, *p, 3, 2)); + EXPECT_EQ(1, base_internal::invoke(&Class::RefMethod, p, 3, 2)); + EXPECT_EQ(1, base_internal::invoke(&Class::RefMethod, p.get(), 3, 2)); + EXPECT_EQ(1, base_internal::invoke(&Class::RefMethod, *p, 3, 2)); + EXPECT_EQ(1, base_internal::invoke(&Class::RefRefMethod, std::move(*p), 3, + 2)); // NOLINT + EXPECT_EQ(1, base_internal::invoke(&Class::NoExceptMethod, p, 3, 2)); + EXPECT_EQ(1, base_internal::invoke(&Class::NoExceptMethod, p.get(), 3, 2)); + EXPECT_EQ(1, base_internal::invoke(&Class::NoExceptMethod, *p, 3, 2)); - EXPECT_EQ(1, Invoke(&Class::ConstMethod, p, 3, 2)); - EXPECT_EQ(1, Invoke(&Class::ConstMethod, p.get(), 3, 2)); - EXPECT_EQ(1, Invoke(&Class::ConstMethod, *p, 3, 2)); + EXPECT_EQ(1, base_internal::invoke(&Class::ConstMethod, p, 3, 2)); + EXPECT_EQ(1, base_internal::invoke(&Class::ConstMethod, p.get(), 3, 2)); + EXPECT_EQ(1, base_internal::invoke(&Class::ConstMethod, *p, 3, 2)); - EXPECT_EQ(1, Invoke(&Class::ConstMethod, cp, 3, 2)); - EXPECT_EQ(1, Invoke(&Class::ConstMethod, cp.get(), 3, 2)); - EXPECT_EQ(1, Invoke(&Class::ConstMethod, *cp, 3, 2)); + EXPECT_EQ(1, base_internal::invoke(&Class::ConstMethod, cp, 3, 2)); + EXPECT_EQ(1, base_internal::invoke(&Class::ConstMethod, cp.get(), 3, 2)); + EXPECT_EQ(1, base_internal::invoke(&Class::ConstMethod, *cp, 3, 2)); - EXPECT_EQ(1, Invoke(&Class::VolatileMethod, p, 3, 2)); - EXPECT_EQ(1, Invoke(&Class::VolatileMethod, p.get(), 3, 2)); - EXPECT_EQ(1, Invoke(&Class::VolatileMethod, *p, 3, 2)); - EXPECT_EQ(1, Invoke(&Class::VolatileMethod, vp, 3, 2)); - EXPECT_EQ(1, Invoke(&Class::VolatileMethod, vp.get(), 3, 2)); - EXPECT_EQ(1, Invoke(&Class::VolatileMethod, *vp, 3, 2)); + EXPECT_EQ(1, base_internal::invoke(&Class::VolatileMethod, p, 3, 2)); + EXPECT_EQ(1, base_internal::invoke(&Class::VolatileMethod, p.get(), 3, 2)); + EXPECT_EQ(1, base_internal::invoke(&Class::VolatileMethod, *p, 3, 2)); + EXPECT_EQ(1, base_internal::invoke(&Class::VolatileMethod, vp, 3, 2)); + EXPECT_EQ(1, base_internal::invoke(&Class::VolatileMethod, vp.get(), 3, 2)); + EXPECT_EQ(1, base_internal::invoke(&Class::VolatileMethod, *vp, 3, 2)); - EXPECT_EQ(1, Invoke(&Class::Method, make_unique(), 3, 2)); - EXPECT_EQ(1, Invoke(&Class::ConstMethod, make_unique(), 3, 2)); - EXPECT_EQ(1, Invoke(&Class::ConstMethod, make_unique(), 3, 2)); + EXPECT_EQ(1, + base_internal::invoke(&Class::Method, make_unique(), 3, 2)); + EXPECT_EQ(1, base_internal::invoke(&Class::ConstMethod, make_unique(), + 3, 2)); + EXPECT_EQ(1, base_internal::invoke(&Class::ConstMethod, + make_unique(), 3, 2)); } TEST(InvokeTest, DataMember) { std::unique_ptr p(new Class{42}); std::unique_ptr cp(new Class{42}); - EXPECT_EQ(42, Invoke(&Class::member, p)); - EXPECT_EQ(42, Invoke(&Class::member, *p)); - EXPECT_EQ(42, Invoke(&Class::member, p.get())); + EXPECT_EQ(42, base_internal::invoke(&Class::member, p)); + EXPECT_EQ(42, base_internal::invoke(&Class::member, *p)); + EXPECT_EQ(42, base_internal::invoke(&Class::member, p.get())); - Invoke(&Class::member, p) = 42; - Invoke(&Class::member, p.get()) = 42; + base_internal::invoke(&Class::member, p) = 42; + base_internal::invoke(&Class::member, p.get()) = 42; - EXPECT_EQ(42, Invoke(&Class::member, cp)); - EXPECT_EQ(42, Invoke(&Class::member, *cp)); - EXPECT_EQ(42, Invoke(&Class::member, cp.get())); + EXPECT_EQ(42, base_internal::invoke(&Class::member, cp)); + EXPECT_EQ(42, base_internal::invoke(&Class::member, *cp)); + EXPECT_EQ(42, base_internal::invoke(&Class::member, cp.get())); } TEST(InvokeTest, FlipFlop) { FlipFlop obj = {42}; // This call could resolve to (obj.*&FlipFlop::ConstMethod)() or // ((*obj).*&FlipFlop::ConstMethod)(). We verify that it's the former. - EXPECT_EQ(42, Invoke(&FlipFlop::ConstMethod, obj)); - EXPECT_EQ(42, Invoke(&FlipFlop::member, obj)); + EXPECT_EQ(42, base_internal::invoke(&FlipFlop::ConstMethod, obj)); + EXPECT_EQ(42, base_internal::invoke(&FlipFlop::member, obj)); } TEST(InvokeTest, SfinaeFriendly) { diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/log_severity.h b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/log_severity.h index 65a3b16672..2236422462 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/log_severity.h +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/log_severity.h @@ -12,8 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -#ifndef ABSL_BASE_INTERNAL_LOG_SEVERITY_H_ -#define ABSL_BASE_INTERNAL_LOG_SEVERITY_H_ +#ifndef ABSL_BASE_LOG_SEVERITY_H_ +#define ABSL_BASE_LOG_SEVERITY_H_ #include #include @@ -36,7 +36,7 @@ ABSL_NAMESPACE_BEGIN // such values to a defined severity level, however in some cases values other // than the defined levels are useful for comparison. // -// Exmaple: +// Example: // // // Effectively disables all logging: // SetMinLogLevel(static_cast(100)); @@ -118,4 +118,4 @@ std::ostream& operator<<(std::ostream& os, absl::LogSeverity s); ABSL_NAMESPACE_END } // namespace absl -#endif // ABSL_BASE_INTERNAL_LOG_SEVERITY_H_ +#endif // ABSL_BASE_LOG_SEVERITY_H_ diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/log_severity_test.cc b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/log_severity_test.cc index 2c6872b00a..55b26d1774 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/log_severity_test.cc +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/log_severity_test.cc @@ -52,9 +52,9 @@ TEST(StreamTest, Works) { Eq("absl::LogSeverity(4)")); } -static_assert( - absl::flags_internal::FlagUseOneWordStorage::value, - "Flags of type absl::LogSeverity ought to be lock-free."); +static_assert(absl::flags_internal::FlagUseValueAndInitBitStorage< + absl::LogSeverity>::value, + "Flags of type absl::LogSeverity ought to be lock-free."); using ParseFlagFromOutOfRangeIntegerTest = TestWithParam; INSTANTIATE_TEST_SUITE_P( diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/macros.h b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/macros.h index 2c4e3570cd..3e085a916b 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/macros.h +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/macros.h @@ -55,115 +55,6 @@ auto ArraySizeHelper(const T (&array)[N]) -> char (&)[N]; ABSL_NAMESPACE_END } // namespace absl -// kLinkerInitialized -// -// An enum used only as a constructor argument to indicate that a variable has -// static storage duration, and that the constructor should do nothing to its -// state. Use of this macro indicates to the reader that it is legal to -// declare a static instance of the class, provided the constructor is given -// the absl::base_internal::kLinkerInitialized argument. -// -// Normally, it is unsafe to declare a static variable that has a constructor or -// a destructor because invocation order is undefined. However, if the type can -// be zero-initialized (which the loader does for static variables) into a valid -// state and the type's destructor does not affect storage, then a constructor -// for static initialization can be declared. -// -// Example: -// // Declaration -// explicit MyClass(absl::base_internal:LinkerInitialized x) {} -// -// // Invocation -// static MyClass my_global(absl::base_internal::kLinkerInitialized); -namespace absl { -ABSL_NAMESPACE_BEGIN -namespace base_internal { -enum LinkerInitialized { - kLinkerInitialized = 0, -}; -} // namespace base_internal -ABSL_NAMESPACE_END -} // namespace absl - -// ABSL_FALLTHROUGH_INTENDED -// -// Annotates implicit fall-through between switch labels, allowing a case to -// indicate intentional fallthrough and turn off warnings about any lack of a -// `break` statement. The ABSL_FALLTHROUGH_INTENDED macro should be followed by -// a semicolon and can be used in most places where `break` can, provided that -// no statements exist between it and the next switch label. -// -// Example: -// -// switch (x) { -// case 40: -// case 41: -// if (truth_is_out_there) { -// ++x; -// ABSL_FALLTHROUGH_INTENDED; // Use instead of/along with annotations -// // in comments -// } else { -// return x; -// } -// case 42: -// ... -// -// Notes: when compiled with clang in C++11 mode, the ABSL_FALLTHROUGH_INTENDED -// macro is expanded to the [[clang::fallthrough]] attribute, which is analysed -// when performing switch labels fall-through diagnostic -// (`-Wimplicit-fallthrough`). See clang documentation on language extensions -// for details: -// https://clang.llvm.org/docs/AttributeReference.html#fallthrough-clang-fallthrough -// -// When used with unsupported compilers, the ABSL_FALLTHROUGH_INTENDED macro -// has no effect on diagnostics. In any case this macro has no effect on runtime -// behavior and performance of code. -#ifdef ABSL_FALLTHROUGH_INTENDED -#error "ABSL_FALLTHROUGH_INTENDED should not be defined." -#endif - -// TODO(zhangxy): Use c++17 standard [[fallthrough]] macro, when supported. -#if defined(__clang__) && defined(__has_warning) -#if __has_feature(cxx_attributes) && __has_warning("-Wimplicit-fallthrough") -#define ABSL_FALLTHROUGH_INTENDED [[clang::fallthrough]] -#endif -#elif defined(__GNUC__) && __GNUC__ >= 7 -#define ABSL_FALLTHROUGH_INTENDED [[gnu::fallthrough]] -#endif - -#ifndef ABSL_FALLTHROUGH_INTENDED -#define ABSL_FALLTHROUGH_INTENDED \ - do { \ - } while (0) -#endif - -// ABSL_DEPRECATED() -// -// Marks a deprecated class, struct, enum, function, method and variable -// declarations. The macro argument is used as a custom diagnostic message (e.g. -// suggestion of a better alternative). -// -// Examples: -// -// class ABSL_DEPRECATED("Use Bar instead") Foo {...}; -// -// ABSL_DEPRECATED("Use Baz() instead") void Bar() {...} -// -// template -// ABSL_DEPRECATED("Use DoThat() instead") -// void DoThis(); -// -// Every usage of a deprecated entity will trigger a warning when compiled with -// clang's `-Wdeprecated-declarations` option. This option is turned off by -// default, but the warnings will be reported by clang-tidy. -#if defined(__clang__) && __cplusplus >= 201103L -#define ABSL_DEPRECATED(message) __attribute__((deprecated(message))) -#endif - -#ifndef ABSL_DEPRECATED -#define ABSL_DEPRECATED(message) -#endif - // ABSL_BAD_CALL_IF() // // Used on a function overload to trap bad calls: any call that matches the @@ -253,4 +144,15 @@ ABSL_NAMESPACE_END #define ABSL_INTERNAL_RETHROW do {} while (false) #endif // ABSL_HAVE_EXCEPTIONS +// `ABSL_INTERNAL_UNREACHABLE` is an unreachable statement. A program which +// reaches one has undefined behavior, and the compiler may optimize +// accordingly. +#if defined(__GNUC__) || ABSL_HAVE_BUILTIN(__builtin_unreachable) +#define ABSL_INTERNAL_UNREACHABLE __builtin_unreachable() +#elif defined(_MSC_VER) +#define ABSL_INTERNAL_UNREACHABLE __assume(0) +#else +#define ABSL_INTERNAL_UNREACHABLE +#endif + #endif // ABSL_BASE_MACROS_H_ diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/optimization.h b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/optimization.h index 646523b346..d090be1286 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/optimization.h +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/optimization.h @@ -22,13 +22,15 @@ #ifndef ABSL_BASE_OPTIMIZATION_H_ #define ABSL_BASE_OPTIMIZATION_H_ +#include + #include "absl/base/config.h" // ABSL_BLOCK_TAIL_CALL_OPTIMIZATION // -// Instructs the compiler to avoid optimizing tail-call recursion. Use of this -// macro is useful when you wish to preserve the existing function order within -// a stack trace for logging, debugging, or profiling purposes. +// Instructs the compiler to avoid optimizing tail-call recursion. This macro is +// useful when you wish to preserve the existing function order within a stack +// trace for logging, debugging, or profiling purposes. // // Example: // @@ -104,9 +106,10 @@ // Cacheline aligning objects properly allows constructive memory sharing and // prevents destructive (or "false") memory sharing. // -// NOTE: this macro should be replaced with usage of `alignas()` using +// NOTE: callers should replace uses of this macro with `alignas()` using // `std::hardware_constructive_interference_size` and/or -// `std::hardware_destructive_interference_size` when available within C++17. +// `std::hardware_destructive_interference_size` when C++17 becomes available to +// them. // // See http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0154r1.html // for more information. @@ -171,11 +174,71 @@ // to yield performance improvements. #if ABSL_HAVE_BUILTIN(__builtin_expect) || \ (defined(__GNUC__) && !defined(__clang__)) -#define ABSL_PREDICT_FALSE(x) (__builtin_expect(x, 0)) +#define ABSL_PREDICT_FALSE(x) (__builtin_expect(false || (x), false)) #define ABSL_PREDICT_TRUE(x) (__builtin_expect(false || (x), true)) #else #define ABSL_PREDICT_FALSE(x) (x) #define ABSL_PREDICT_TRUE(x) (x) #endif +// ABSL_INTERNAL_ASSUME(cond) +// Informs the compiler that a condition is always true and that it can assume +// it to be true for optimization purposes. The call has undefined behavior if +// the condition is false. +// In !NDEBUG mode, the condition is checked with an assert(). +// NOTE: The expression must not have side effects, as it will only be evaluated +// in some compilation modes and not others. +// +// Example: +// +// int x = ...; +// ABSL_INTERNAL_ASSUME(x >= 0); +// // The compiler can optimize the division to a simple right shift using the +// // assumption specified above. +// int y = x / 16; +// +#if !defined(NDEBUG) +#define ABSL_INTERNAL_ASSUME(cond) assert(cond) +#elif ABSL_HAVE_BUILTIN(__builtin_assume) +#define ABSL_INTERNAL_ASSUME(cond) __builtin_assume(cond) +#elif defined(__GNUC__) || ABSL_HAVE_BUILTIN(__builtin_unreachable) +#define ABSL_INTERNAL_ASSUME(cond) \ + do { \ + if (!(cond)) __builtin_unreachable(); \ + } while (0) +#elif defined(_MSC_VER) +#define ABSL_INTERNAL_ASSUME(cond) __assume(cond) +#else +#define ABSL_INTERNAL_ASSUME(cond) \ + do { \ + static_cast(false && (cond)); \ + } while (0) +#endif + +// ABSL_INTERNAL_UNIQUE_SMALL_NAME(cond) +// This macro forces small unique name on a static file level symbols like +// static local variables or static functions. This is intended to be used in +// macro definitions to optimize the cost of generated code. Do NOT use it on +// symbols exported from translation unit since it may cause a link time +// conflict. +// +// Example: +// +// #define MY_MACRO(txt) +// namespace { +// char VeryVeryLongVarName[] ABSL_INTERNAL_UNIQUE_SMALL_NAME() = txt; +// const char* VeryVeryLongFuncName() ABSL_INTERNAL_UNIQUE_SMALL_NAME(); +// const char* VeryVeryLongFuncName() { return txt; } +// } +// + +#if defined(__GNUC__) +#define ABSL_INTERNAL_UNIQUE_SMALL_NAME2(x) #x +#define ABSL_INTERNAL_UNIQUE_SMALL_NAME1(x) ABSL_INTERNAL_UNIQUE_SMALL_NAME2(x) +#define ABSL_INTERNAL_UNIQUE_SMALL_NAME() \ + asm(ABSL_INTERNAL_UNIQUE_SMALL_NAME1(.absl.__COUNTER__)) +#else +#define ABSL_INTERNAL_UNIQUE_SMALL_NAME() +#endif + #endif // ABSL_BASE_OPTIMIZATION_H_ diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/optimization_test.cc b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/optimization_test.cc new file mode 100644 index 0000000000..e83369f322 --- /dev/null +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/optimization_test.cc @@ -0,0 +1,129 @@ +// Copyright 2020 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "absl/base/optimization.h" + +#include "gtest/gtest.h" +#include "absl/types/optional.h" + +namespace { + +// Tests for the ABSL_PREDICT_TRUE and ABSL_PREDICT_FALSE macros. +// The tests only verify that the macros are functionally correct - i.e. code +// behaves as if they weren't used. They don't try to check their impact on +// optimization. + +TEST(PredictTest, PredictTrue) { + EXPECT_TRUE(ABSL_PREDICT_TRUE(true)); + EXPECT_FALSE(ABSL_PREDICT_TRUE(false)); + EXPECT_TRUE(ABSL_PREDICT_TRUE(1 == 1)); + EXPECT_FALSE(ABSL_PREDICT_TRUE(1 == 2)); + + if (ABSL_PREDICT_TRUE(false)) ADD_FAILURE(); + if (!ABSL_PREDICT_TRUE(true)) ADD_FAILURE(); + + EXPECT_TRUE(ABSL_PREDICT_TRUE(true) && true); + EXPECT_TRUE(ABSL_PREDICT_TRUE(true) || false); +} + +TEST(PredictTest, PredictFalse) { + EXPECT_TRUE(ABSL_PREDICT_FALSE(true)); + EXPECT_FALSE(ABSL_PREDICT_FALSE(false)); + EXPECT_TRUE(ABSL_PREDICT_FALSE(1 == 1)); + EXPECT_FALSE(ABSL_PREDICT_FALSE(1 == 2)); + + if (ABSL_PREDICT_FALSE(false)) ADD_FAILURE(); + if (!ABSL_PREDICT_FALSE(true)) ADD_FAILURE(); + + EXPECT_TRUE(ABSL_PREDICT_FALSE(true) && true); + EXPECT_TRUE(ABSL_PREDICT_FALSE(true) || false); +} + +TEST(PredictTest, OneEvaluation) { + // Verify that the expression is only evaluated once. + int x = 0; + if (ABSL_PREDICT_TRUE((++x) == 0)) ADD_FAILURE(); + EXPECT_EQ(x, 1); + if (ABSL_PREDICT_FALSE((++x) == 0)) ADD_FAILURE(); + EXPECT_EQ(x, 2); +} + +TEST(PredictTest, OperatorOrder) { + // Verify that operator order inside and outside the macro behaves well. + // These would fail for a naive '#define ABSL_PREDICT_TRUE(x) x' + EXPECT_TRUE(ABSL_PREDICT_TRUE(1 && 2) == true); + EXPECT_TRUE(ABSL_PREDICT_FALSE(1 && 2) == true); + EXPECT_TRUE(!ABSL_PREDICT_TRUE(1 == 2)); + EXPECT_TRUE(!ABSL_PREDICT_FALSE(1 == 2)); +} + +TEST(PredictTest, Pointer) { + const int x = 3; + const int *good_intptr = &x; + const int *null_intptr = nullptr; + EXPECT_TRUE(ABSL_PREDICT_TRUE(good_intptr)); + EXPECT_FALSE(ABSL_PREDICT_TRUE(null_intptr)); + EXPECT_TRUE(ABSL_PREDICT_FALSE(good_intptr)); + EXPECT_FALSE(ABSL_PREDICT_FALSE(null_intptr)); +} + +TEST(PredictTest, Optional) { + // Note: An optional's truth value is the value's existence, not its truth. + absl::optional has_value(false); + absl::optional no_value; + EXPECT_TRUE(ABSL_PREDICT_TRUE(has_value)); + EXPECT_FALSE(ABSL_PREDICT_TRUE(no_value)); + EXPECT_TRUE(ABSL_PREDICT_FALSE(has_value)); + EXPECT_FALSE(ABSL_PREDICT_FALSE(no_value)); +} + +class ImplictlyConvertibleToBool { + public: + explicit ImplictlyConvertibleToBool(bool value) : value_(value) {} + operator bool() const { // NOLINT(google-explicit-constructor) + return value_; + } + + private: + bool value_; +}; + +TEST(PredictTest, ImplicitBoolConversion) { + const ImplictlyConvertibleToBool is_true(true); + const ImplictlyConvertibleToBool is_false(false); + if (!ABSL_PREDICT_TRUE(is_true)) ADD_FAILURE(); + if (ABSL_PREDICT_TRUE(is_false)) ADD_FAILURE(); + if (!ABSL_PREDICT_FALSE(is_true)) ADD_FAILURE(); + if (ABSL_PREDICT_FALSE(is_false)) ADD_FAILURE(); +} + +class ExplictlyConvertibleToBool { + public: + explicit ExplictlyConvertibleToBool(bool value) : value_(value) {} + explicit operator bool() const { return value_; } + + private: + bool value_; +}; + +TEST(PredictTest, ExplicitBoolConversion) { + const ExplictlyConvertibleToBool is_true(true); + const ExplictlyConvertibleToBool is_false(false); + if (!ABSL_PREDICT_TRUE(is_true)) ADD_FAILURE(); + if (ABSL_PREDICT_TRUE(is_false)) ADD_FAILURE(); + if (!ABSL_PREDICT_FALSE(is_true)) ADD_FAILURE(); + if (ABSL_PREDICT_FALSE(is_false)) ADD_FAILURE(); +} + +} // namespace diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/policy_checks.h b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/policy_checks.h index 4dfa49e54a..06b3243916 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/policy_checks.h +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/policy_checks.h @@ -41,7 +41,7 @@ #endif // ----------------------------------------------------------------------------- -// Compiler Check +// Toolchain Check // ----------------------------------------------------------------------------- // We support MSVC++ 14.0 update 2 and later. diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/port.h b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/port.h index 6c28068d4f..5bc4d6cd95 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/port.h +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/port.h @@ -14,7 +14,6 @@ // // This files is a forwarding header for other headers containing various // portability macros and functions. -// This file is used for both C and C++! #ifndef ABSL_BASE_PORT_H_ #define ABSL_BASE_PORT_H_ diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/spinlock_test_common.cc b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/spinlock_test_common.cc index 08f61ba86a..2b572c5b3f 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/spinlock_test_common.cc +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/spinlock_test_common.cc @@ -20,10 +20,12 @@ #include #include #include // NOLINT(build/c++11) +#include #include #include "gtest/gtest.h" #include "absl/base/attributes.h" +#include "absl/base/config.h" #include "absl/base/internal/low_level_scheduling.h" #include "absl/base/internal/scheduling_mode.h" #include "absl/base/internal/spinlock.h" @@ -56,12 +58,10 @@ namespace { static constexpr int kArrayLength = 10; static uint32_t values[kArrayLength]; -static SpinLock static_spinlock(base_internal::kLinkerInitialized); -static SpinLock static_cooperative_spinlock( - base_internal::kLinkerInitialized, - base_internal::SCHEDULE_COOPERATIVE_AND_KERNEL); -static SpinLock static_noncooperative_spinlock( - base_internal::kLinkerInitialized, base_internal::SCHEDULE_KERNEL_ONLY); +ABSL_CONST_INIT static SpinLock static_cooperative_spinlock( + absl::kConstInit, base_internal::SCHEDULE_COOPERATIVE_AND_KERNEL); +ABSL_CONST_INIT static SpinLock static_noncooperative_spinlock( + absl::kConstInit, base_internal::SCHEDULE_KERNEL_ONLY); // Simple integer hash function based on the public domain lookup2 hash. // http://burtleburtle.net/bob/c/lookup2.c @@ -92,6 +92,7 @@ static void TestFunction(int thread_salt, SpinLock* spinlock) { static void ThreadedTest(SpinLock* spinlock) { std::vector threads; + threads.reserve(kNumThreads); for (int i = 0; i < kNumThreads; ++i) { threads.push_back(std::thread(TestFunction, i, spinlock)); } @@ -105,6 +106,10 @@ static void ThreadedTest(SpinLock* spinlock) { } } +#ifndef ABSL_HAVE_THREAD_SANITIZER +static_assert(std::is_trivially_destructible(), ""); +#endif + TEST(SpinLock, StackNonCooperativeDisablesScheduling) { SpinLock spinlock(base_internal::SCHEDULE_KERNEL_ONLY); spinlock.Lock(); @@ -191,10 +196,6 @@ TEST(SpinLock, WaitCyclesEncoding) { EXPECT_GT(expected_max_value_decoded, before_max_value_decoded); } -TEST(SpinLockWithThreads, StaticSpinLock) { - ThreadedTest(&static_spinlock); -} - TEST(SpinLockWithThreads, StackSpinLock) { SpinLock spinlock; ThreadedTest(&spinlock); diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/thread_annotations.h b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/thread_annotations.h index bcd05e51d4..9695f6de67 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/thread_annotations.h +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/base/thread_annotations.h @@ -34,13 +34,10 @@ #ifndef ABSL_BASE_THREAD_ANNOTATIONS_H_ #define ABSL_BASE_THREAD_ANNOTATIONS_H_ +#include "absl/base/attributes.h" #include "absl/base/config.h" - -#if defined(__clang__) -#define ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(x) __attribute__((x)) -#else -#define ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(x) // no-op -#endif +// TODO(mbonadei): Remove after the backward compatibility period. +#include "absl/base/internal/thread_annotations.h" // IWYU pragma: export // ABSL_GUARDED_BY() // @@ -59,8 +56,11 @@ // int p1_ ABSL_GUARDED_BY(mu_); // ... // }; -#define ABSL_GUARDED_BY(x) \ - ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(guarded_by(x)) +#if ABSL_HAVE_ATTRIBUTE(guarded_by) +#define ABSL_GUARDED_BY(x) __attribute__((guarded_by(x))) +#else +#define ABSL_GUARDED_BY(x) +#endif // ABSL_PT_GUARDED_BY() // @@ -82,8 +82,11 @@ // // `q_`, guarded by `mu1_`, points to a shared memory location that is // // guarded by `mu2_`: // int *q_ ABSL_GUARDED_BY(mu1_) ABSL_PT_GUARDED_BY(mu2_); -#define ABSL_PT_GUARDED_BY(x) \ - ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(pt_guarded_by(x)) +#if ABSL_HAVE_ATTRIBUTE(pt_guarded_by) +#define ABSL_PT_GUARDED_BY(x) __attribute__((pt_guarded_by(x))) +#else +#define ABSL_PT_GUARDED_BY(x) +#endif // ABSL_ACQUIRED_AFTER() / ABSL_ACQUIRED_BEFORE() // @@ -100,11 +103,17 @@ // // Mutex m1_; // Mutex m2_ ABSL_ACQUIRED_AFTER(m1_); -#define ABSL_ACQUIRED_AFTER(...) \ - ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(acquired_after(__VA_ARGS__)) +#if ABSL_HAVE_ATTRIBUTE(acquired_after) +#define ABSL_ACQUIRED_AFTER(...) __attribute__((acquired_after(__VA_ARGS__))) +#else +#define ABSL_ACQUIRED_AFTER(...) +#endif -#define ABSL_ACQUIRED_BEFORE(...) \ - ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(acquired_before(__VA_ARGS__)) +#if ABSL_HAVE_ATTRIBUTE(acquired_before) +#define ABSL_ACQUIRED_BEFORE(...) __attribute__((acquired_before(__VA_ARGS__))) +#else +#define ABSL_ACQUIRED_BEFORE(...) +#endif // ABSL_EXCLUSIVE_LOCKS_REQUIRED() / ABSL_SHARED_LOCKS_REQUIRED() // @@ -129,65 +138,95 @@ // // void foo() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mu1, mu2) { ... } // void bar() const ABSL_SHARED_LOCKS_REQUIRED(mu1, mu2) { ... } -#define ABSL_EXCLUSIVE_LOCKS_REQUIRED(...) \ - ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE( \ - exclusive_locks_required(__VA_ARGS__)) +#if ABSL_HAVE_ATTRIBUTE(exclusive_locks_required) +#define ABSL_EXCLUSIVE_LOCKS_REQUIRED(...) \ + __attribute__((exclusive_locks_required(__VA_ARGS__))) +#else +#define ABSL_EXCLUSIVE_LOCKS_REQUIRED(...) +#endif +#if ABSL_HAVE_ATTRIBUTE(shared_locks_required) #define ABSL_SHARED_LOCKS_REQUIRED(...) \ - ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(shared_locks_required(__VA_ARGS__)) + __attribute__((shared_locks_required(__VA_ARGS__))) +#else +#define ABSL_SHARED_LOCKS_REQUIRED(...) +#endif // ABSL_LOCKS_EXCLUDED() // // Documents the locks acquired in the body of the function. These locks // cannot be held when calling this function (as Abseil's `Mutex` locks are // non-reentrant). -#define ABSL_LOCKS_EXCLUDED(...) \ - ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(locks_excluded(__VA_ARGS__)) +#if ABSL_HAVE_ATTRIBUTE(locks_excluded) +#define ABSL_LOCKS_EXCLUDED(...) __attribute__((locks_excluded(__VA_ARGS__))) +#else +#define ABSL_LOCKS_EXCLUDED(...) +#endif // ABSL_LOCK_RETURNED() // // Documents a function that returns a mutex without acquiring it. For example, // a public getter method that returns a pointer to a private mutex should // be annotated with ABSL_LOCK_RETURNED. -#define ABSL_LOCK_RETURNED(x) \ - ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(lock_returned(x)) +#if ABSL_HAVE_ATTRIBUTE(lock_returned) +#define ABSL_LOCK_RETURNED(x) __attribute__((lock_returned(x))) +#else +#define ABSL_LOCK_RETURNED(x) +#endif // ABSL_LOCKABLE // // Documents if a class/type is a lockable type (such as the `Mutex` class). -#define ABSL_LOCKABLE ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(lockable) +#if ABSL_HAVE_ATTRIBUTE(lockable) +#define ABSL_LOCKABLE __attribute__((lockable)) +#else +#define ABSL_LOCKABLE +#endif // ABSL_SCOPED_LOCKABLE // // Documents if a class does RAII locking (such as the `MutexLock` class). // The constructor should use `LOCK_FUNCTION()` to specify the mutex that is -// acquired, and the destructor should use `ABSL_UNLOCK_FUNCTION()` with no +// acquired, and the destructor should use `UNLOCK_FUNCTION()` with no // arguments; the analysis will assume that the destructor unlocks whatever the // constructor locked. -#define ABSL_SCOPED_LOCKABLE \ - ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(scoped_lockable) +#if ABSL_HAVE_ATTRIBUTE(scoped_lockable) +#define ABSL_SCOPED_LOCKABLE __attribute__((scoped_lockable)) +#else +#define ABSL_SCOPED_LOCKABLE +#endif // ABSL_EXCLUSIVE_LOCK_FUNCTION() // // Documents functions that acquire a lock in the body of a function, and do // not release it. -#define ABSL_EXCLUSIVE_LOCK_FUNCTION(...) \ - ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE( \ - exclusive_lock_function(__VA_ARGS__)) +#if ABSL_HAVE_ATTRIBUTE(exclusive_lock_function) +#define ABSL_EXCLUSIVE_LOCK_FUNCTION(...) \ + __attribute__((exclusive_lock_function(__VA_ARGS__))) +#else +#define ABSL_EXCLUSIVE_LOCK_FUNCTION(...) +#endif // ABSL_SHARED_LOCK_FUNCTION() // // Documents functions that acquire a shared (reader) lock in the body of a // function, and do not release it. +#if ABSL_HAVE_ATTRIBUTE(shared_lock_function) #define ABSL_SHARED_LOCK_FUNCTION(...) \ - ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(shared_lock_function(__VA_ARGS__)) + __attribute__((shared_lock_function(__VA_ARGS__))) +#else +#define ABSL_SHARED_LOCK_FUNCTION(...) +#endif // ABSL_UNLOCK_FUNCTION() // // Documents functions that expect a lock to be held on entry to the function, // and release it in the body of the function. -#define ABSL_UNLOCK_FUNCTION(...) \ - ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(unlock_function(__VA_ARGS__)) +#if ABSL_HAVE_ATTRIBUTE(unlock_function) +#define ABSL_UNLOCK_FUNCTION(...) __attribute__((unlock_function(__VA_ARGS__))) +#else +#define ABSL_UNLOCK_FUNCTION(...) +#endif // ABSL_EXCLUSIVE_TRYLOCK_FUNCTION() / ABSL_SHARED_TRYLOCK_FUNCTION() // @@ -197,31 +236,49 @@ // success, or `false` for functions that return `false` on success. The second // argument specifies the mutex that is locked on success. If unspecified, this // mutex is assumed to be `this`. +#if ABSL_HAVE_ATTRIBUTE(exclusive_trylock_function) #define ABSL_EXCLUSIVE_TRYLOCK_FUNCTION(...) \ - ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE( \ - exclusive_trylock_function(__VA_ARGS__)) + __attribute__((exclusive_trylock_function(__VA_ARGS__))) +#else +#define ABSL_EXCLUSIVE_TRYLOCK_FUNCTION(...) +#endif -#define ABSL_SHARED_TRYLOCK_FUNCTION(...) \ - ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE( \ - shared_trylock_function(__VA_ARGS__)) +#if ABSL_HAVE_ATTRIBUTE(shared_trylock_function) +#define ABSL_SHARED_TRYLOCK_FUNCTION(...) \ + __attribute__((shared_trylock_function(__VA_ARGS__))) +#else +#define ABSL_SHARED_TRYLOCK_FUNCTION(...) +#endif // ABSL_ASSERT_EXCLUSIVE_LOCK() / ABSL_ASSERT_SHARED_LOCK() // // Documents functions that dynamically check to see if a lock is held, and fail // if it is not held. +#if ABSL_HAVE_ATTRIBUTE(assert_exclusive_lock) #define ABSL_ASSERT_EXCLUSIVE_LOCK(...) \ - ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(assert_exclusive_lock(__VA_ARGS__)) + __attribute__((assert_exclusive_lock(__VA_ARGS__))) +#else +#define ABSL_ASSERT_EXCLUSIVE_LOCK(...) +#endif +#if ABSL_HAVE_ATTRIBUTE(assert_shared_lock) #define ABSL_ASSERT_SHARED_LOCK(...) \ - ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(assert_shared_lock(__VA_ARGS__)) + __attribute__((assert_shared_lock(__VA_ARGS__))) +#else +#define ABSL_ASSERT_SHARED_LOCK(...) +#endif // ABSL_NO_THREAD_SAFETY_ANALYSIS // // Turns off thread safety checking within the body of a particular function. // This annotation is used to mark functions that are known to be correct, but // the locking behavior is more complicated than the analyzer can handle. +#if ABSL_HAVE_ATTRIBUTE(no_thread_safety_analysis) #define ABSL_NO_THREAD_SAFETY_ANALYSIS \ - ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(no_thread_safety_analysis) + __attribute__((no_thread_safety_analysis)) +#else +#define ABSL_NO_THREAD_SAFETY_ANALYSIS +#endif //------------------------------------------------------------------------------ // Tool-Supplied Annotations @@ -252,7 +309,7 @@ // Disables warnings for a single read operation. This can be used to avoid // warnings when it is known that the read is not actually involved in a race, // but the compiler cannot confirm that. -#define ABSL_TS_UNCHECKED_READ(x) absl::base_internal::absl_ts_unchecked_read(x) +#define ABSL_TS_UNCHECKED_READ(x) absl::base_internal::ts_unchecked_read(x) namespace absl { ABSL_NAMESPACE_BEGIN @@ -260,14 +317,14 @@ namespace base_internal { // Takes a reference to a guarded data member, and returns an unguarded // reference. -// Do not used this function directly, use ABSL_TS_UNCHECKED_READ instead. +// Do not use this function directly, use ABSL_TS_UNCHECKED_READ instead. template -inline const T& absl_ts_unchecked_read(const T& v) ABSL_NO_THREAD_SAFETY_ANALYSIS { +inline const T& ts_unchecked_read(const T& v) ABSL_NO_THREAD_SAFETY_ANALYSIS { return v; } template -inline T& absl_ts_unchecked_read(T& v) ABSL_NO_THREAD_SAFETY_ANALYSIS { +inline T& ts_unchecked_read(T& v) ABSL_NO_THREAD_SAFETY_ANALYSIS { return v; } diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/cleanup/CMakeLists.txt b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/cleanup/CMakeLists.txt new file mode 100644 index 0000000000..26a6d0dce3 --- /dev/null +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/cleanup/CMakeLists.txt @@ -0,0 +1,55 @@ +# Copyright 2021 The Abseil Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +absl_cc_library( + NAME + cleanup_internal + HDRS + "internal/cleanup.h" + COPTS + ${ABSL_DEFAULT_COPTS} + DEPS + absl::base_internal + absl::core_headers + absl::utility + PUBLIC +) + +absl_cc_library( + NAME + cleanup + HDRS + "cleanup.h" + COPTS + ${ABSL_DEFAULT_COPTS} + DEPS + absl::cleanup_internal + absl::config + absl::core_headers + PUBLIC +) + +absl_cc_test( + NAME + cleanup_test + SRCS + "cleanup_test.cc" + COPTS + ${ABSL_TEST_COPTS} + DEPS + absl::cleanup + absl::config + absl::utility + GTest::gmock_main +) diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/cleanup/cleanup.h b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/cleanup/cleanup.h new file mode 100644 index 0000000000..960ccd080e --- /dev/null +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/cleanup/cleanup.h @@ -0,0 +1,140 @@ +// Copyright 2021 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// ----------------------------------------------------------------------------- +// File: cleanup.h +// ----------------------------------------------------------------------------- +// +// `absl::Cleanup` implements the scope guard idiom, invoking the contained +// callback's `operator()() &&` on scope exit. +// +// Example: +// +// ``` +// absl::Status CopyGoodData(const char* source_path, const char* sink_path) { +// FILE* source_file = fopen(source_path, "r"); +// if (source_file == nullptr) { +// return absl::NotFoundError("No source file"); // No cleanups execute +// } +// +// // C++17 style cleanup using class template argument deduction +// absl::Cleanup source_closer = [source_file] { fclose(source_file); }; +// +// FILE* sink_file = fopen(sink_path, "w"); +// if (sink_file == nullptr) { +// return absl::NotFoundError("No sink file"); // First cleanup executes +// } +// +// // C++11 style cleanup using the factory function +// auto sink_closer = absl::MakeCleanup([sink_file] { fclose(sink_file); }); +// +// Data data; +// while (ReadData(source_file, &data)) { +// if (!data.IsGood()) { +// absl::Status result = absl::FailedPreconditionError("Read bad data"); +// return result; // Both cleanups execute +// } +// SaveData(sink_file, &data); +// } +// +// return absl::OkStatus(); // Both cleanups execute +// } +// ``` +// +// Methods: +// +// `std::move(cleanup).Cancel()` will prevent the callback from executing. +// +// `std::move(cleanup).Invoke()` will execute the callback early, before +// destruction, and prevent the callback from executing in the destructor. +// +// Usage: +// +// `absl::Cleanup` is not an interface type. It is only intended to be used +// within the body of a function. It is not a value type and instead models a +// control flow construct. Check out `defer` in Golang for something similar. + +#ifndef ABSL_CLEANUP_CLEANUP_H_ +#define ABSL_CLEANUP_CLEANUP_H_ + +#include + +#include "absl/base/config.h" +#include "absl/base/macros.h" +#include "absl/cleanup/internal/cleanup.h" + +namespace absl { +ABSL_NAMESPACE_BEGIN + +template +class ABSL_MUST_USE_RESULT Cleanup final { + static_assert(cleanup_internal::WasDeduced(), + "Explicit template parameters are not supported."); + + static_assert(cleanup_internal::ReturnsVoid(), + "Callbacks that return values are not supported."); + + public: + Cleanup(Callback callback) : storage_(std::move(callback)) {} // NOLINT + + Cleanup(Cleanup&& other) = default; + + void Cancel() && { + ABSL_HARDENING_ASSERT(storage_.IsCallbackEngaged()); + storage_.DestroyCallback(); + } + + void Invoke() && { + ABSL_HARDENING_ASSERT(storage_.IsCallbackEngaged()); + storage_.InvokeCallback(); + storage_.DestroyCallback(); + } + + ~Cleanup() { + if (storage_.IsCallbackEngaged()) { + storage_.InvokeCallback(); + storage_.DestroyCallback(); + } + } + + private: + cleanup_internal::Storage storage_; +}; + +// `absl::Cleanup c = /* callback */;` +// +// C++17 type deduction API for creating an instance of `absl::Cleanup` +#if defined(ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION) +template +Cleanup(Callback callback) -> Cleanup; +#endif // defined(ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION) + +// `auto c = absl::MakeCleanup(/* callback */);` +// +// C++11 type deduction API for creating an instance of `absl::Cleanup` +template +absl::Cleanup MakeCleanup(Callback callback) { + static_assert(cleanup_internal::WasDeduced(), + "Explicit template parameters are not supported."); + + static_assert(cleanup_internal::ReturnsVoid(), + "Callbacks that return values are not supported."); + + return {std::move(callback)}; +} + +ABSL_NAMESPACE_END +} // namespace absl + +#endif // ABSL_CLEANUP_CLEANUP_H_ diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/cleanup/cleanup_test.cc b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/cleanup/cleanup_test.cc new file mode 100644 index 0000000000..46b885899c --- /dev/null +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/cleanup/cleanup_test.cc @@ -0,0 +1,311 @@ +// Copyright 2021 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "absl/cleanup/cleanup.h" + +#include +#include +#include + +#include "gtest/gtest.h" +#include "absl/base/config.h" +#include "absl/utility/utility.h" + +namespace { + +using Tag = absl::cleanup_internal::Tag; + +template +constexpr bool IsSame() { + return (std::is_same::value); +} + +struct IdentityFactory { + template + static Callback AsCallback(Callback callback) { + return Callback(std::move(callback)); + } +}; + +// `FunctorClass` is a type used for testing `absl::Cleanup`. It is intended to +// represent users that make their own move-only callback types outside of +// `std::function` and lambda literals. +class FunctorClass { + using Callback = std::function; + + public: + explicit FunctorClass(Callback callback) : callback_(std::move(callback)) {} + + FunctorClass(FunctorClass&& other) + : callback_(absl::exchange(other.callback_, Callback())) {} + + FunctorClass(const FunctorClass&) = delete; + + FunctorClass& operator=(const FunctorClass&) = delete; + + FunctorClass& operator=(FunctorClass&&) = delete; + + void operator()() const& = delete; + + void operator()() && { + ASSERT_TRUE(callback_); + callback_(); + callback_ = nullptr; + } + + private: + Callback callback_; +}; + +struct FunctorClassFactory { + template + static FunctorClass AsCallback(Callback callback) { + return FunctorClass(std::move(callback)); + } +}; + +struct StdFunctionFactory { + template + static std::function AsCallback(Callback callback) { + return std::function(std::move(callback)); + } +}; + +using CleanupTestParams = + ::testing::Types; +template +struct CleanupTest : public ::testing::Test {}; +TYPED_TEST_SUITE(CleanupTest, CleanupTestParams); + +bool fn_ptr_called = false; +void FnPtrFunction() { fn_ptr_called = true; } + +TYPED_TEST(CleanupTest, FactoryProducesCorrectType) { + { + auto callback = TypeParam::AsCallback([] {}); + auto cleanup = absl::MakeCleanup(std::move(callback)); + + static_assert( + IsSame, decltype(cleanup)>(), + ""); + } + + { + auto cleanup = absl::MakeCleanup(&FnPtrFunction); + + static_assert(IsSame, decltype(cleanup)>(), + ""); + } + + { + auto cleanup = absl::MakeCleanup(FnPtrFunction); + + static_assert(IsSame, decltype(cleanup)>(), + ""); + } +} + +#if defined(ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION) +TYPED_TEST(CleanupTest, CTADProducesCorrectType) { + { + auto callback = TypeParam::AsCallback([] {}); + absl::Cleanup cleanup = std::move(callback); + + static_assert( + IsSame, decltype(cleanup)>(), + ""); + } + + { + absl::Cleanup cleanup = &FnPtrFunction; + + static_assert(IsSame, decltype(cleanup)>(), + ""); + } + + { + absl::Cleanup cleanup = FnPtrFunction; + + static_assert(IsSame, decltype(cleanup)>(), + ""); + } +} + +TYPED_TEST(CleanupTest, FactoryAndCTADProduceSameType) { + { + auto callback = IdentityFactory::AsCallback([] {}); + auto factory_cleanup = absl::MakeCleanup(callback); + absl::Cleanup deduction_cleanup = callback; + + static_assert( + IsSame(), ""); + } + + { + auto factory_cleanup = + absl::MakeCleanup(FunctorClassFactory::AsCallback([] {})); + absl::Cleanup deduction_cleanup = FunctorClassFactory::AsCallback([] {}); + + static_assert( + IsSame(), ""); + } + + { + auto factory_cleanup = + absl::MakeCleanup(StdFunctionFactory::AsCallback([] {})); + absl::Cleanup deduction_cleanup = StdFunctionFactory::AsCallback([] {}); + + static_assert( + IsSame(), ""); + } + + { + auto factory_cleanup = absl::MakeCleanup(&FnPtrFunction); + absl::Cleanup deduction_cleanup = &FnPtrFunction; + + static_assert( + IsSame(), ""); + } + + { + auto factory_cleanup = absl::MakeCleanup(FnPtrFunction); + absl::Cleanup deduction_cleanup = FnPtrFunction; + + static_assert( + IsSame(), ""); + } +} +#endif // defined(ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION) + +TYPED_TEST(CleanupTest, BasicUsage) { + bool called = false; + + { + auto cleanup = + absl::MakeCleanup(TypeParam::AsCallback([&called] { called = true; })); + EXPECT_FALSE(called); // Constructor shouldn't invoke the callback + } + + EXPECT_TRUE(called); // Destructor should invoke the callback +} + +TYPED_TEST(CleanupTest, BasicUsageWithFunctionPointer) { + fn_ptr_called = false; + + { + auto cleanup = absl::MakeCleanup(TypeParam::AsCallback(&FnPtrFunction)); + EXPECT_FALSE(fn_ptr_called); // Constructor shouldn't invoke the callback + } + + EXPECT_TRUE(fn_ptr_called); // Destructor should invoke the callback +} + +TYPED_TEST(CleanupTest, Cancel) { + bool called = false; + + { + auto cleanup = + absl::MakeCleanup(TypeParam::AsCallback([&called] { called = true; })); + EXPECT_FALSE(called); // Constructor shouldn't invoke the callback + + std::move(cleanup).Cancel(); + EXPECT_FALSE(called); // Cancel shouldn't invoke the callback + } + + EXPECT_FALSE(called); // Destructor shouldn't invoke the callback +} + +TYPED_TEST(CleanupTest, Invoke) { + bool called = false; + + { + auto cleanup = + absl::MakeCleanup(TypeParam::AsCallback([&called] { called = true; })); + EXPECT_FALSE(called); // Constructor shouldn't invoke the callback + + std::move(cleanup).Invoke(); + EXPECT_TRUE(called); // Invoke should invoke the callback + + called = false; // Reset tracker before destructor runs + } + + EXPECT_FALSE(called); // Destructor shouldn't invoke the callback +} + +TYPED_TEST(CleanupTest, Move) { + bool called = false; + + { + auto moved_from_cleanup = + absl::MakeCleanup(TypeParam::AsCallback([&called] { called = true; })); + EXPECT_FALSE(called); // Constructor shouldn't invoke the callback + + { + auto moved_to_cleanup = std::move(moved_from_cleanup); + EXPECT_FALSE(called); // Move shouldn't invoke the callback + } + + EXPECT_TRUE(called); // Destructor should invoke the callback + + called = false; // Reset tracker before destructor runs + } + + EXPECT_FALSE(called); // Destructor shouldn't invoke the callback +} + +int DestructionCount = 0; + +struct DestructionCounter { + void operator()() {} + + ~DestructionCounter() { ++DestructionCount; } +}; + +TYPED_TEST(CleanupTest, DestructorDestroys) { + { + auto cleanup = + absl::MakeCleanup(TypeParam::AsCallback(DestructionCounter())); + DestructionCount = 0; + } + + EXPECT_EQ(DestructionCount, 1); // Engaged cleanup destroys +} + +TYPED_TEST(CleanupTest, CancelDestroys) { + { + auto cleanup = + absl::MakeCleanup(TypeParam::AsCallback(DestructionCounter())); + DestructionCount = 0; + + std::move(cleanup).Cancel(); + EXPECT_EQ(DestructionCount, 1); // Cancel destroys + } + + EXPECT_EQ(DestructionCount, 1); // Canceled cleanup does not double destroy +} + +TYPED_TEST(CleanupTest, InvokeDestroys) { + { + auto cleanup = + absl::MakeCleanup(TypeParam::AsCallback(DestructionCounter())); + DestructionCount = 0; + + std::move(cleanup).Invoke(); + EXPECT_EQ(DestructionCount, 1); // Invoke destroys + } + + EXPECT_EQ(DestructionCount, 1); // Invoked cleanup does not double destroy +} + +} // namespace diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/cleanup/internal/cleanup.h b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/cleanup/internal/cleanup.h new file mode 100644 index 0000000000..2783fcb7c1 --- /dev/null +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/cleanup/internal/cleanup.h @@ -0,0 +1,100 @@ +// Copyright 2021 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef ABSL_CLEANUP_INTERNAL_CLEANUP_H_ +#define ABSL_CLEANUP_INTERNAL_CLEANUP_H_ + +#include +#include +#include + +#include "absl/base/internal/invoke.h" +#include "absl/base/macros.h" +#include "absl/base/thread_annotations.h" +#include "absl/utility/utility.h" + +namespace absl { +ABSL_NAMESPACE_BEGIN + +namespace cleanup_internal { + +struct Tag {}; + +template +constexpr bool WasDeduced() { + return (std::is_same::value) && + (sizeof...(Args) == 0); +} + +template +constexpr bool ReturnsVoid() { + return (std::is_same, void>::value); +} + +template +class Storage { + public: + Storage() = delete; + + explicit Storage(Callback callback) { + // Placement-new into a character buffer is used for eager destruction when + // the cleanup is invoked or cancelled. To ensure this optimizes well, the + // behavior is implemented locally instead of using an absl::optional. + ::new (GetCallbackBuffer()) Callback(std::move(callback)); + is_callback_engaged_ = true; + } + + Storage(Storage&& other) { + ABSL_HARDENING_ASSERT(other.IsCallbackEngaged()); + + ::new (GetCallbackBuffer()) Callback(std::move(other.GetCallback())); + is_callback_engaged_ = true; + + other.DestroyCallback(); + } + + Storage(const Storage& other) = delete; + + Storage& operator=(Storage&& other) = delete; + + Storage& operator=(const Storage& other) = delete; + + void* GetCallbackBuffer() { return static_cast(+callback_buffer_); } + + Callback& GetCallback() { + return *reinterpret_cast(GetCallbackBuffer()); + } + + bool IsCallbackEngaged() const { return is_callback_engaged_; } + + void DestroyCallback() { + is_callback_engaged_ = false; + GetCallback().~Callback(); + } + + void InvokeCallback() ABSL_NO_THREAD_SAFETY_ANALYSIS { + std::move(GetCallback())(); + } + + private: + bool is_callback_engaged_; + alignas(Callback) char callback_buffer_[sizeof(Callback)]; +}; + +} // namespace cleanup_internal + +ABSL_NAMESPACE_END +} // namespace absl + +#endif // ABSL_CLEANUP_INTERNAL_CLEANUP_H_ diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/compiler_config_setting.bzl b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/compiler_config_setting.bzl deleted file mode 100644 index 66962294d0..0000000000 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/compiler_config_setting.bzl +++ /dev/null @@ -1,38 +0,0 @@ -# -# Copyright 2018 The Abseil Authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Creates config_setting that allows selecting based on 'compiler' value.""" - -def create_llvm_config(name, visibility): - # The "do_not_use_tools_cpp_compiler_present" attribute exists to - # distinguish between older versions of Bazel that do not support - # "@bazel_tools//tools/cpp:compiler" flag_value, and newer ones that do. - # In the future, the only way to select on the compiler will be through - # flag_values{"@bazel_tools//tools/cpp:compiler"} and the else branch can - # be removed. - if hasattr(cc_common, "do_not_use_tools_cpp_compiler_present"): - native.config_setting( - name = name, - flag_values = { - "@bazel_tools//tools/cpp:compiler": "llvm", - }, - visibility = visibility, - ) - else: - native.config_setting( - name = name, - values = {"compiler": "llvm"}, - visibility = visibility, - ) diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/BUILD.gn b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/BUILD.gn deleted file mode 100644 index 5c34ce5a49..0000000000 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/BUILD.gn +++ /dev/null @@ -1,352 +0,0 @@ -# Copyright 2018 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -import("//third_party/abseil-cpp/absl.gni") - -absl_source_set("compressed_tuple") { - public = [ "internal/compressed_tuple.h" ] - deps = [ "../utility" ] -} - -absl_source_set("fixed_array") { - public = [ "fixed_array.h" ] - deps = [ - ":compressed_tuple", - "../algorithm", - "../base:core_headers", - "../base:dynamic_annotations", - "../base:throw_delegate", - "../memory", - ] -} - -absl_source_set("inlined_vector_internal") { - public = [ "internal/inlined_vector.h" ] - deps = [ - ":compressed_tuple", - "../base:core_headers", - "../memory", - "../meta:type_traits", - "../types:span", - ] -} - -absl_source_set("inlined_vector") { - public = [ "inlined_vector.h" ] - deps = [ - ":inlined_vector_internal", - "../algorithm", - "../base:core_headers", - "../base:throw_delegate", - "../memory", - ] -} - -absl_source_set("counting_allocator") { - testonly = true - public = [ "internal/counting_allocator.h" ] - deps = [ "../base:config" ] - visibility = [] - visibility += [ ":*" ] -} - -absl_source_set("test_instance_tracker") { - testonly = true - sources = [ "internal/test_instance_tracker.cc" ] - public = [ "internal/test_instance_tracker.h" ] - deps = [ "../types:compare" ] - visibility = [] - visibility += [ "../*" ] -} - -absl_source_set("flat_hash_map") { - public = [ "flat_hash_map.h" ] - deps = [ - ":container_memory", - ":hash_function_defaults", - ":raw_hash_map", - "../algorithm:container", - "../memory", - ] -} - -absl_source_set("flat_hash_set") { - public = [ "flat_hash_set.h" ] - deps = [ - ":container_memory", - ":hash_function_defaults", - ":raw_hash_set", - "../algorithm:container", - "../base:core_headers", - "../memory", - ] -} - -absl_source_set("node_hash_map") { - public = [ "node_hash_map.h" ] - deps = [ - ":container_memory", - ":hash_function_defaults", - ":node_hash_policy", - ":raw_hash_map", - "../algorithm:container", - "../memory", - ] -} - -absl_source_set("node_hash_set") { - public = [ "node_hash_set.h" ] - deps = [ - ":container_memory", - ":hash_function_defaults", - ":node_hash_policy", - ":raw_hash_set", - "../algorithm:container", - "../memory", - ] -} - -absl_source_set("container_memory") { - public = [ "internal/container_memory.h" ] - deps = [ - "../memory", - "../meta:type_traits", - "../utility", - ] -} - -absl_source_set("hash_function_defaults") { - public = [ "internal/hash_function_defaults.h" ] - deps = [ - "../base:config", - "../hash", - "../strings", - "../strings:cord", - ] -} - -absl_source_set("hash_generator_testing") { - testonly = true - sources = [ "internal/hash_generator_testing.cc" ] - public = [ "internal/hash_generator_testing.h" ] - deps = [ - ":hash_policy_testing", - "../memory", - "../meta:type_traits", - "../strings", - ] -} - -absl_source_set("hash_policy_testing") { - testonly = true - public = [ "internal/hash_policy_testing.h" ] - deps = [ - "../hash", - "../strings", - ] -} - -absl_source_set("hash_policy_traits") { - public = [ "internal/hash_policy_traits.h" ] - deps = [ "../meta:type_traits" ] -} - -absl_source_set("hashtable_debug") { - public = [ "internal/hashtable_debug.h" ] - deps = [ ":hashtable_debug_hooks" ] -} - -absl_source_set("hashtable_debug_hooks") { - public = [ "internal/hashtable_debug_hooks.h" ] - deps = [ "../base:config" ] -} - -absl_source_set("hashtablez_sampler") { - public = [ "internal/hashtablez_sampler.h" ] - sources = [ - "internal/hashtablez_sampler.cc", - "internal/hashtablez_sampler_force_weak_definition.cc", - ] - deps = [ - ":have_sse", - "../base", - "../base:core_headers", - "../base:exponential_biased", - "../debugging:stacktrace", - "../memory", - "../synchronization", - "../utility", - ] -} - -absl_source_set("node_hash_policy") { - public = [ "internal/node_hash_policy.h" ] - deps = [ "../base:config" ] -} - -absl_source_set("raw_hash_map") { - public = [ "internal/raw_hash_map.h" ] - deps = [ - ":container_memory", - ":raw_hash_set", - "../base:throw_delegate", - ] -} - -absl_source_set("have_sse") { - public = [ "internal/have_sse.h" ] - visibility = [] - visibility += [ ":*" ] -} - -absl_source_set("common") { - public = [ "internal/common.h" ] - deps = [ - "../meta:type_traits", - "../types:optional", - ] -} - -absl_source_set("raw_hash_set") { - sources = [ "internal/raw_hash_set.cc" ] - public = [ "internal/raw_hash_set.h" ] - deps = [ - ":common", - ":compressed_tuple", - ":container_memory", - ":hash_policy_traits", - ":hashtable_debug_hooks", - ":hashtablez_sampler", - ":have_sse", - ":layout", - "../base:bits", - "../base:config", - "../base:core_headers", - "../base:endian", - "../memory", - "../meta:type_traits", - "../utility", - ] -} - -absl_source_set("layout") { - public = [ "internal/layout.h" ] - deps = [ - "../base:core_headers", - "../meta:type_traits", - "../strings", - "../types:span", - "../utility", - ] -} - -absl_source_set("tracked") { - testonly = true - public = [ "internal/tracked.h" ] - deps = [ "../base:config" ] -} - -absl_source_set("unordered_map_constructor_test") { - testonly = true - public = [ "internal/unordered_map_constructor_test.h" ] - deps = [ - ":hash_generator_testing", - ":hash_policy_testing", - "//testing/gtest", - ] -} - -absl_source_set("unordered_map_lookup_test") { - testonly = true - public = [ "internal/unordered_map_lookup_test.h" ] - deps = [ - ":hash_generator_testing", - ":hash_policy_testing", - "//testing/gtest", - ] -} - -absl_source_set("unordered_map_modifiers_test") { - testonly = true - public = [ "internal/unordered_map_modifiers_test.h" ] - deps = [ - ":hash_generator_testing", - ":hash_policy_testing", - "//testing/gtest", - ] -} - -absl_source_set("unordered_set_constructor_test") { - testonly = true - public = [ "internal/unordered_set_constructor_test.h" ] - deps = [ - ":hash_generator_testing", - ":hash_policy_testing", - "../meta:type_traits", - "//testing/gtest", - ] -} - -absl_source_set("unordered_set_members_test") { - testonly = true - public = [ "internal/unordered_set_members_test.h" ] - deps = [ - "../meta:type_traits", - "//testing/gtest", - ] -} - -absl_source_set("unordered_map_members_test") { - testonly = true - public = [ "internal/unordered_map_members_test.h" ] - deps = [ - "../meta:type_traits", - "//testing/gtest", - ] -} - -absl_source_set("unordered_set_lookup_test") { - testonly = true - public = [ "internal/unordered_set_lookup_test.h" ] - deps = [ - ":hash_generator_testing", - ":hash_policy_testing", - "//testing/gtest", - ] -} - -absl_source_set("unordered_set_modifiers_test") { - testonly = true - public = [ "internal/unordered_set_modifiers_test.h" ] - deps = [ - ":hash_generator_testing", - ":hash_policy_testing", - "//testing/gtest", - ] -} - -absl_source_set("btree") { - sources = [ - "internal/btree.h", - "internal/btree_container.h", - ] - public = [ - "btree_map.h", - "btree_set.h", - ] - deps = [ - ":common", - ":compressed_tuple", - ":container_memory", - ":layout", - "../base:core_headers", - "../base:throw_delegate", - "../memory", - "../meta:type_traits", - "../strings", - "../strings:cord", - "../types:compare", - "../utility", - ] -} diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/CMakeLists.txt b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/CMakeLists.txt index d79fa12e46..9b8a7509ad 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/CMakeLists.txt +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/CMakeLists.txt @@ -14,15 +14,6 @@ # limitations under the License. # -# This is deprecated and will be removed in the future. It also doesn't do -# anything anyways. Prefer to use the library associated with the API you are -# using. -absl_cc_library( - NAME - container - PUBLIC -) - absl_cc_library( NAME btree @@ -89,7 +80,7 @@ absl_cc_test( absl::strings absl::test_instance_tracker absl::type_traits - gmock_main + GTest::gmock_main ) absl_cc_library( @@ -118,7 +109,7 @@ absl_cc_test( absl::optional absl::test_instance_tracker absl::utility - gmock_main + GTest::gmock_main ) absl_cc_library( @@ -131,6 +122,7 @@ absl_cc_library( DEPS absl::compressed_tuple absl::algorithm + absl::config absl::core_headers absl::dynamic_annotations absl::throw_delegate @@ -147,11 +139,12 @@ absl_cc_test( ${ABSL_TEST_COPTS} DEPS absl::fixed_array + absl::counting_allocator absl::config absl::exception_testing absl::hash_testing absl::memory - gmock_main + GTest::gmock_main ) absl_cc_test( @@ -165,7 +158,7 @@ absl_cc_test( absl::fixed_array absl::config absl::exception_safety_testing - gmock_main + GTest::gmock_main ) absl_cc_library( @@ -229,7 +222,7 @@ absl_cc_test( absl::memory absl::raw_logging_internal absl::strings - gmock_main + GTest::gmock_main ) absl_cc_test( @@ -243,7 +236,7 @@ absl_cc_test( absl::inlined_vector absl::config absl::exception_safety_testing - gmock_main + GTest::gmock_main ) absl_cc_library( @@ -269,7 +262,7 @@ absl_cc_test( ${ABSL_TEST_COPTS} DEPS absl::test_instance_tracker - gmock_main + GTest::gmock_main ) absl_cc_library( @@ -303,7 +296,8 @@ absl_cc_test( absl::unordered_map_members_test absl::unordered_map_modifiers_test absl::any - gmock_main + absl::raw_logging_internal + GTest::gmock_main ) absl_cc_library( @@ -339,8 +333,9 @@ absl_cc_test( absl::unordered_set_members_test absl::unordered_set_modifiers_test absl::memory + absl::raw_logging_internal absl::strings - gmock_main + GTest::gmock_main ) absl_cc_library( @@ -375,7 +370,7 @@ absl_cc_test( absl::unordered_map_lookup_test absl::unordered_map_members_test absl::unordered_map_modifiers_test - gmock_main + GTest::gmock_main ) absl_cc_library( @@ -409,7 +404,7 @@ absl_cc_test( absl::unordered_set_lookup_test absl::unordered_set_members_test absl::unordered_set_modifiers_test - gmock_main + GTest::gmock_main ) absl_cc_library( @@ -420,6 +415,7 @@ absl_cc_library( COPTS ${ABSL_DEFAULT_COPTS} DEPS + absl::config absl::memory absl::type_traits absl::utility @@ -437,7 +433,7 @@ absl_cc_test( absl::container_memory absl::strings absl::test_instance_tracker - gmock_main + GTest::gmock_main ) absl_cc_library( @@ -469,7 +465,7 @@ absl_cc_test( absl::hash absl::random_random absl::strings - gmock_main + GTest::gmock_main ) absl_cc_library( @@ -511,7 +507,7 @@ absl_cc_test( ${ABSL_TEST_COPTS} DEPS absl::hash_policy_testing - gmock_main + GTest::gmock_main ) absl_cc_library( @@ -535,7 +531,7 @@ absl_cc_test( ${ABSL_TEST_COPTS} DEPS absl::hash_policy_traits - gmock_main + GTest::gmock_main ) absl_cc_library( @@ -552,6 +548,7 @@ absl_cc_library( absl::base absl::exponential_biased absl::have_sse + absl::sample_recorder absl::synchronization ) @@ -565,7 +562,7 @@ absl_cc_test( DEPS absl::hashtablez_sampler absl::have_sse - gmock_main + GTest::gmock_main ) absl_cc_library( @@ -622,7 +619,7 @@ absl_cc_test( DEPS absl::hash_policy_traits absl::node_hash_policy - gmock_main + GTest::gmock_main ) absl_cc_library( @@ -670,7 +667,6 @@ absl_cc_library( absl::hash_policy_traits absl::hashtable_debug_hooks absl::have_sse - absl::layout absl::memory absl::meta absl::optional @@ -693,10 +689,11 @@ absl_cc_test( absl::hashtable_debug absl::raw_hash_set absl::base + absl::config absl::core_headers absl::raw_logging_internal absl::strings - gmock_main + GTest::gmock_main ) absl_cc_test( @@ -710,7 +707,7 @@ absl_cc_test( absl::raw_hash_set absl::tracked absl::core_headers - gmock_main + GTest::gmock_main ) absl_cc_library( @@ -721,6 +718,7 @@ absl_cc_library( COPTS ${ABSL_DEFAULT_COPTS} DEPS + absl::config absl::core_headers absl::meta absl::strings @@ -738,10 +736,11 @@ absl_cc_test( ${ABSL_TEST_COPTS} DEPS absl::layout + absl::config absl::core_headers absl::raw_logging_internal absl::span - gmock_main + GTest::gmock_main ) absl_cc_library( @@ -766,7 +765,7 @@ absl_cc_library( DEPS absl::hash_generator_testing absl::hash_policy_testing - gmock + GTest::gmock TESTONLY ) @@ -780,7 +779,7 @@ absl_cc_library( DEPS absl::hash_generator_testing absl::hash_policy_testing - gmock + GTest::gmock TESTONLY ) @@ -793,7 +792,7 @@ absl_cc_library( ${ABSL_TEST_COPTS} DEPS absl::type_traits - gmock + GTest::gmock TESTONLY ) @@ -807,7 +806,7 @@ absl_cc_library( DEPS absl::hash_generator_testing absl::hash_policy_testing - gmock + GTest::gmock TESTONLY ) @@ -821,7 +820,7 @@ absl_cc_library( DEPS absl::hash_generator_testing absl::hash_policy_testing - gmock + GTest::gmock TESTONLY ) @@ -835,7 +834,7 @@ absl_cc_library( DEPS absl::hash_generator_testing absl::hash_policy_testing - gmock + GTest::gmock TESTONLY ) @@ -848,7 +847,7 @@ absl_cc_library( ${ABSL_TEST_COPTS} DEPS absl::type_traits - gmock + GTest::gmock TESTONLY ) @@ -862,7 +861,7 @@ absl_cc_library( DEPS absl::hash_generator_testing absl::hash_policy_testing - gmock + GTest::gmock TESTONLY ) @@ -878,7 +877,7 @@ absl_cc_test( absl::unordered_set_lookup_test absl::unordered_set_members_test absl::unordered_set_modifiers_test - gmock_main + GTest::gmock_main ) absl_cc_test( @@ -893,5 +892,5 @@ absl_cc_test( absl::unordered_map_lookup_test absl::unordered_map_members_test absl::unordered_map_modifiers_test - gmock_main + GTest::gmock_main ) diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/btree_benchmark.cc b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/btree_benchmark.cc index 467986768a..65b6790b71 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/btree_benchmark.cc +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/btree_benchmark.cc @@ -26,6 +26,7 @@ #include #include +#include "benchmark/benchmark.h" #include "absl/base/internal/raw_logging.h" #include "absl/container/btree_map.h" #include "absl/container/btree_set.h" @@ -39,7 +40,6 @@ #include "absl/strings/cord.h" #include "absl/strings/str_format.h" #include "absl/time/time.h" -#include "benchmark/benchmark.h" namespace absl { ABSL_NAMESPACE_BEGIN @@ -101,39 +101,6 @@ void BM_InsertSorted(benchmark::State& state) { BM_InsertImpl(state, true); } -// container::insert sometimes returns a pair and sometimes -// returns an iterator (for multi- containers). -template -Iter GetIterFromInsert(const std::pair& pair) { - return pair.first; -} -template -Iter GetIterFromInsert(const Iter iter) { - return iter; -} - -// Benchmark insertion of values into a container at the end. -template -void BM_InsertEnd(benchmark::State& state) { - using V = typename remove_pair_const::type; - typename KeyOfValue::type key_of_value; - - T container; - const int kSize = 10000; - for (int i = 0; i < kSize; ++i) { - container.insert(Generator(kSize)(i)); - } - V v = Generator(kSize)(kSize - 1); - typename T::key_type k = key_of_value(v); - - auto it = container.find(k); - while (state.KeepRunning()) { - // Repeatedly removing then adding v. - container.erase(it); - it = GetIterFromInsert(container.insert(v)); - } -} - // Benchmark inserting the first few elements in a container. In b-tree, this is // when the root node grows. template @@ -513,7 +480,6 @@ BTREE_TYPES(Time); #define MY_BENCHMARK3(type) \ MY_BENCHMARK4(type, Insert); \ MY_BENCHMARK4(type, InsertSorted); \ - MY_BENCHMARK4(type, InsertEnd); \ MY_BENCHMARK4(type, InsertSmall); \ MY_BENCHMARK4(type, Lookup); \ MY_BENCHMARK4(type, FullLookup); \ diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/btree_map.h b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/btree_map.h index bb450eadde..6bbf414e8b 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/btree_map.h +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/btree_map.h @@ -185,7 +185,7 @@ class btree_map // template size_type erase(const K& key): // // Erases the element with the matching key, if it exists, returning the - // number of elements erased. + // number of elements erased (0 or 1). using Base::erase; // btree_map::insert() @@ -325,6 +325,11 @@ class btree_map // does not contain an element with a matching key, this function returns an // empty node handle. // + // NOTE: when compiled in an earlier version of C++ than C++17, + // `node_type::key()` returns a const reference to the key instead of a + // mutable reference. We cannot safely return a mutable reference without + // std::launder (which is not available before C++17). + // // NOTE: In this context, `node_type` refers to the C++17 concept of a // move-only type that owns and provides access to the elements in associative // containers (https://en.cppreference.com/w/cpp/container/node_handle). @@ -361,8 +366,8 @@ class btree_map // Determines whether an element comparing equal to the given `key` exists // within the `btree_map`, returning `true` if so or `false` otherwise. // - // Supports heterogeneous lookup, provided that the map is provided a - // compatible heterogeneous comparator. + // Supports heterogeneous lookup, provided that the map has a compatible + // heterogeneous comparator. using Base::contains; // btree_map::count() @@ -373,15 +378,14 @@ class btree_map // the `btree_map`. Note that this function will return either `1` or `0` // since duplicate elements are not allowed within a `btree_map`. // - // Supports heterogeneous lookup, provided that the map is provided a - // compatible heterogeneous comparator. + // Supports heterogeneous lookup, provided that the map has a compatible + // heterogeneous comparator. using Base::count; // btree_map::equal_range() // - // Returns a closed range [first, last], defined by a `std::pair` of two - // iterators, containing all elements with the passed key in the - // `btree_map`. + // Returns a half-open range [first, last), defined by a `std::pair` of two + // iterators, containing all elements with the passed key in the `btree_map`. using Base::equal_range; // btree_map::find() @@ -391,10 +395,34 @@ class btree_map // // Finds an element with the passed `key` within the `btree_map`. // - // Supports heterogeneous lookup, provided that the map is provided a - // compatible heterogeneous comparator. + // Supports heterogeneous lookup, provided that the map has a compatible + // heterogeneous comparator. using Base::find; + // btree_map::lower_bound() + // + // template iterator lower_bound(const K& key): + // template const_iterator lower_bound(const K& key) const: + // + // Finds the first element with a key that is not less than `key` within the + // `btree_map`. + // + // Supports heterogeneous lookup, provided that the map has a compatible + // heterogeneous comparator. + using Base::lower_bound; + + // btree_map::upper_bound() + // + // template iterator upper_bound(const K& key): + // template const_iterator upper_bound(const K& key) const: + // + // Finds the first element with a key that is greater than `key` within the + // `btree_map`. + // + // Supports heterogeneous lookup, provided that the map has a compatible + // heterogeneous comparator. + using Base::upper_bound; + // btree_map::operator[]() // // Returns a reference to the value mapped to the passed key within the @@ -652,6 +680,11 @@ class btree_multimap // does not contain an element with a matching key, this function returns an // empty node handle. // + // NOTE: when compiled in an earlier version of C++ than C++17, + // `node_type::key()` returns a const reference to the key instead of a + // mutable reference. We cannot safely return a mutable reference without + // std::launder (which is not available before C++17). + // // NOTE: In this context, `node_type` refers to the C++17 concept of a // move-only type that owns and provides access to the elements in associative // containers (https://en.cppreference.com/w/cpp/container/node_handle). @@ -682,8 +715,8 @@ class btree_multimap // Determines whether an element comparing equal to the given `key` exists // within the `btree_multimap`, returning `true` if so or `false` otherwise. // - // Supports heterogeneous lookup, provided that the map is provided a - // compatible heterogeneous comparator. + // Supports heterogeneous lookup, provided that the map has a compatible + // heterogeneous comparator. using Base::contains; // btree_multimap::count() @@ -693,13 +726,13 @@ class btree_multimap // Returns the number of elements comparing equal to the given `key` within // the `btree_multimap`. // - // Supports heterogeneous lookup, provided that the map is provided a - // compatible heterogeneous comparator. + // Supports heterogeneous lookup, provided that the map has a compatible + // heterogeneous comparator. using Base::count; // btree_multimap::equal_range() // - // Returns a closed range [first, last], defined by a `std::pair` of two + // Returns a half-open range [first, last), defined by a `std::pair` of two // iterators, containing all elements with the passed key in the // `btree_multimap`. using Base::equal_range; @@ -711,10 +744,34 @@ class btree_multimap // // Finds an element with the passed `key` within the `btree_multimap`. // - // Supports heterogeneous lookup, provided that the map is provided a - // compatible heterogeneous comparator. + // Supports heterogeneous lookup, provided that the map has a compatible + // heterogeneous comparator. using Base::find; + // btree_multimap::lower_bound() + // + // template iterator lower_bound(const K& key): + // template const_iterator lower_bound(const K& key) const: + // + // Finds the first element with a key that is not less than `key` within the + // `btree_multimap`. + // + // Supports heterogeneous lookup, provided that the map has a compatible + // heterogeneous comparator. + using Base::lower_bound; + + // btree_multimap::upper_bound() + // + // template iterator upper_bound(const K& key): + // template const_iterator upper_bound(const K& key) const: + // + // Finds the first element with a key that is greater than `key` within the + // `btree_multimap`. + // + // Supports heterogeneous lookup, provided that the map has a compatible + // heterogeneous comparator. + using Base::upper_bound; + // btree_multimap::get_allocator() // // Returns the allocator function associated with this `btree_multimap`. diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/btree_set.h b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/btree_set.h index d3e78866a7..c07ccd911b 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/btree_set.h +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/btree_set.h @@ -183,7 +183,7 @@ class btree_set // template size_type erase(const K& key): // // Erases the element with the matching key, if it exists, returning the - // number of elements erased. + // number of elements erased (0 or 1). using Base::erase; // btree_set::insert() @@ -300,8 +300,8 @@ class btree_set // Determines whether an element comparing equal to the given `key` exists // within the `btree_set`, returning `true` if so or `false` otherwise. // - // Supports heterogeneous lookup, provided that the set is provided a - // compatible heterogeneous comparator. + // Supports heterogeneous lookup, provided that the set has a compatible + // heterogeneous comparator. using Base::contains; // btree_set::count() @@ -312,8 +312,8 @@ class btree_set // the `btree_set`. Note that this function will return either `1` or `0` // since duplicate elements are not allowed within a `btree_set`. // - // Supports heterogeneous lookup, provided that the set is provided a - // compatible heterogeneous comparator. + // Supports heterogeneous lookup, provided that the set has a compatible + // heterogeneous comparator. using Base::count; // btree_set::equal_range() @@ -330,10 +330,32 @@ class btree_set // // Finds an element with the passed `key` within the `btree_set`. // - // Supports heterogeneous lookup, provided that the set is provided a - // compatible heterogeneous comparator. + // Supports heterogeneous lookup, provided that the set has a compatible + // heterogeneous comparator. using Base::find; + // btree_set::lower_bound() + // + // template iterator lower_bound(const K& key): + // template const_iterator lower_bound(const K& key) const: + // + // Finds the first element that is not less than `key` within the `btree_set`. + // + // Supports heterogeneous lookup, provided that the set has a compatible + // heterogeneous comparator. + using Base::lower_bound; + + // btree_set::upper_bound() + // + // template iterator upper_bound(const K& key): + // template const_iterator upper_bound(const K& key) const: + // + // Finds the first element that is greater than `key` within the `btree_set`. + // + // Supports heterogeneous lookup, provided that the set has a compatible + // heterogeneous comparator. + using Base::upper_bound; + // btree_set::get_allocator() // // Returns the allocator function associated with this `btree_set`. @@ -604,8 +626,8 @@ class btree_multiset // Determines whether an element comparing equal to the given `key` exists // within the `btree_multiset`, returning `true` if so or `false` otherwise. // - // Supports heterogeneous lookup, provided that the set is provided a - // compatible heterogeneous comparator. + // Supports heterogeneous lookup, provided that the set has a compatible + // heterogeneous comparator. using Base::contains; // btree_multiset::count() @@ -615,8 +637,8 @@ class btree_multiset // Returns the number of elements comparing equal to the given `key` within // the `btree_multiset`. // - // Supports heterogeneous lookup, provided that the set is provided a - // compatible heterogeneous comparator. + // Supports heterogeneous lookup, provided that the set has a compatible + // heterogeneous comparator. using Base::count; // btree_multiset::equal_range() @@ -633,10 +655,34 @@ class btree_multiset // // Finds an element with the passed `key` within the `btree_multiset`. // - // Supports heterogeneous lookup, provided that the set is provided a - // compatible heterogeneous comparator. + // Supports heterogeneous lookup, provided that the set has a compatible + // heterogeneous comparator. using Base::find; + // btree_multiset::lower_bound() + // + // template iterator lower_bound(const K& key): + // template const_iterator lower_bound(const K& key) const: + // + // Finds the first element that is not less than `key` within the + // `btree_multiset`. + // + // Supports heterogeneous lookup, provided that the set has a compatible + // heterogeneous comparator. + using Base::lower_bound; + + // btree_multiset::upper_bound() + // + // template iterator upper_bound(const K& key): + // template const_iterator upper_bound(const K& key) const: + // + // Finds the first element that is greater than `key` within the + // `btree_multiset`. + // + // Supports heterogeneous lookup, provided that the set has a compatible + // heterogeneous comparator. + using Base::upper_bound; + // btree_multiset::get_allocator() // // Returns the allocator function associated with this `btree_multiset`. diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/btree_test.cc b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/btree_test.cc index 7ccdf6a179..d27cf27105 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/btree_test.cc +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/btree_test.cc @@ -15,6 +15,7 @@ #include "absl/container/btree_test.h" #include +#include #include #include #include @@ -52,7 +53,9 @@ using ::absl::test_internal::MovableOnlyInstance; using ::testing::ElementsAre; using ::testing::ElementsAreArray; using ::testing::IsEmpty; +using ::testing::IsNull; using ::testing::Pair; +using ::testing::SizeIs; template void CheckPairEquals(const T &x, const U &y) { @@ -592,7 +595,7 @@ void BtreeTest() { using V = typename remove_pair_const::type; const std::vector random_values = GenerateValuesWithSeed( absl::GetFlag(FLAGS_test_values), 4 * absl::GetFlag(FLAGS_test_values), - testing::GTEST_FLAG(random_seed)); + GTEST_FLAG_GET(random_seed)); unique_checker container; @@ -616,7 +619,7 @@ void BtreeMultiTest() { using V = typename remove_pair_const::type; const std::vector random_values = GenerateValuesWithSeed( absl::GetFlag(FLAGS_test_values), 4 * absl::GetFlag(FLAGS_test_values), - testing::GTEST_FLAG(random_seed)); + GTEST_FLAG_GET(random_seed)); multi_checker container; @@ -1180,6 +1183,103 @@ TEST(Btree, RangeCtorSanity) { EXPECT_EQ(1, tmap.size()); } +} // namespace + +class BtreeNodePeer { + public: + // Yields the size of a leaf node with a specific number of values. + template + constexpr static size_t GetTargetNodeSize(size_t target_values_per_node) { + return btree_node< + set_params, std::allocator, + /*TargetNodeSize=*/256, // This parameter isn't used here. + /*Multi=*/false>>::SizeWithNSlots(target_values_per_node); + } + + // Yields the number of slots in a (non-root) leaf node for this btree. + template + constexpr static size_t GetNumSlotsPerNode() { + return btree_node::kNodeSlots; + } + + template + constexpr static size_t GetMaxFieldType() { + return std::numeric_limits< + typename btree_node::field_type>::max(); + } + + template + constexpr static bool UsesLinearNodeSearch() { + return btree_node::use_linear_search::value; + } +}; + +namespace { + +class BtreeMapTest : public ::testing::Test { + public: + struct Key {}; + struct Cmp { + template + bool operator()(T, T) const { + return false; + } + }; + + struct KeyLin { + using absl_btree_prefer_linear_node_search = std::true_type; + }; + struct CmpLin : Cmp { + using absl_btree_prefer_linear_node_search = std::true_type; + }; + + struct KeyBin { + using absl_btree_prefer_linear_node_search = std::false_type; + }; + struct CmpBin : Cmp { + using absl_btree_prefer_linear_node_search = std::false_type; + }; + + template + static bool IsLinear() { + return BtreeNodePeer::UsesLinearNodeSearch>(); + } +}; + +TEST_F(BtreeMapTest, TestLinearSearchPreferredForKeyLinearViaAlias) { + // Test requesting linear search by directly exporting an alias. + EXPECT_FALSE((IsLinear())); + EXPECT_TRUE((IsLinear())); + EXPECT_TRUE((IsLinear())); + EXPECT_TRUE((IsLinear())); +} + +TEST_F(BtreeMapTest, LinearChoiceTree) { + // Cmp has precedence, and is forcing binary + EXPECT_FALSE((IsLinear())); + EXPECT_FALSE((IsLinear())); + EXPECT_FALSE((IsLinear())); + EXPECT_FALSE((IsLinear())); + EXPECT_FALSE((IsLinear())); + // Cmp has precedence, and is forcing linear + EXPECT_TRUE((IsLinear())); + EXPECT_TRUE((IsLinear())); + EXPECT_TRUE((IsLinear())); + EXPECT_TRUE((IsLinear())); + EXPECT_TRUE((IsLinear())); + // Cmp has no preference, Key determines linear vs binary. + EXPECT_FALSE((IsLinear())); + EXPECT_TRUE((IsLinear())); + EXPECT_FALSE((IsLinear())); + // arithmetic key w/ std::less or std::greater: linear + EXPECT_TRUE((IsLinear>())); + EXPECT_TRUE((IsLinear>())); + // arithmetic key w/ custom compare: binary + EXPECT_FALSE((IsLinear())); + // non-arithmetic key: binary + EXPECT_FALSE((IsLinear>())); +} + TEST(Btree, BtreeMapCanHoldMoveOnlyTypes) { absl::btree_map> m; @@ -1325,28 +1425,6 @@ TEST(Btree, RValueInsert) { EXPECT_EQ(tracker.swaps(), 0); } -} // namespace - -class BtreeNodePeer { - public: - // Yields the size of a leaf node with a specific number of values. - template - constexpr static size_t GetTargetNodeSize(size_t target_values_per_node) { - return btree_node< - set_params, std::allocator, - /*TargetNodeSize=*/256, // This parameter isn't used here. - /*Multi=*/false>>::SizeWithNValues(target_values_per_node); - } - - // Yields the number of values in a (non-root) leaf node for this set. - template - constexpr static size_t GetNumValuesPerNode() { - return btree_node::kNodeValues; - } -}; - -namespace { - // A btree set with a specific number of values per node. template > class SizedBtreeSet @@ -1380,7 +1458,7 @@ void ExpectOperationCounts(const int expected_moves, TEST(Btree, MovesComparisonsCopiesSwapsTracking) { InstanceTracker tracker; // Note: this is minimum number of values per node. - SizedBtreeSet set3; + SizedBtreeSet set4; // Note: this is the default number of values per node for a set of int32s // (with 64-bit pointers). SizedBtreeSet set61; @@ -1391,28 +1469,28 @@ TEST(Btree, MovesComparisonsCopiesSwapsTracking) { std::vector values = GenerateValuesWithSeed(10000, 1 << 22, /*seed=*/23); - EXPECT_EQ(BtreeNodePeer::GetNumValuesPerNode(), 3); - EXPECT_EQ(BtreeNodePeer::GetNumValuesPerNode(), 61); - EXPECT_EQ(BtreeNodePeer::GetNumValuesPerNode(), 100); + EXPECT_EQ(BtreeNodePeer::GetNumSlotsPerNode(), 4); + EXPECT_EQ(BtreeNodePeer::GetNumSlotsPerNode(), 61); + EXPECT_EQ(BtreeNodePeer::GetNumSlotsPerNode(), 100); if (sizeof(void *) == 8) { - EXPECT_EQ(BtreeNodePeer::GetNumValuesPerNode>(), - BtreeNodePeer::GetNumValuesPerNode()); + EXPECT_EQ(BtreeNodePeer::GetNumSlotsPerNode>(), + BtreeNodePeer::GetNumSlotsPerNode()); } // Test key insertion/deletion in random order. - ExpectOperationCounts(45281, 132551, values, &tracker, &set3); + ExpectOperationCounts(56540, 134212, values, &tracker, &set4); ExpectOperationCounts(386718, 129807, values, &tracker, &set61); ExpectOperationCounts(586761, 130310, values, &tracker, &set100); // Test key insertion/deletion in sorted order. std::sort(values.begin(), values.end()); - ExpectOperationCounts(26638, 92134, values, &tracker, &set3); + ExpectOperationCounts(24972, 85563, values, &tracker, &set4); ExpectOperationCounts(20208, 87757, values, &tracker, &set61); ExpectOperationCounts(20124, 96583, values, &tracker, &set100); // Test key insertion/deletion in reverse sorted order. std::reverse(values.begin(), values.end()); - ExpectOperationCounts(49951, 119325, values, &tracker, &set3); + ExpectOperationCounts(54949, 127531, values, &tracker, &set4); ExpectOperationCounts(338813, 118266, values, &tracker, &set61); ExpectOperationCounts(534529, 125279, values, &tracker, &set100); } @@ -1429,9 +1507,9 @@ struct MovableOnlyInstanceThreeWayCompare { TEST(Btree, MovesComparisonsCopiesSwapsTrackingThreeWayCompare) { InstanceTracker tracker; // Note: this is minimum number of values per node. - SizedBtreeSet - set3; + set4; // Note: this is the default number of values per node for a set of int32s // (with 64-bit pointers). SizedBtreeSet values = GenerateValuesWithSeed(10000, 1 << 22, /*seed=*/23); - EXPECT_EQ(BtreeNodePeer::GetNumValuesPerNode(), 3); - EXPECT_EQ(BtreeNodePeer::GetNumValuesPerNode(), 61); - EXPECT_EQ(BtreeNodePeer::GetNumValuesPerNode(), 100); + EXPECT_EQ(BtreeNodePeer::GetNumSlotsPerNode(), 4); + EXPECT_EQ(BtreeNodePeer::GetNumSlotsPerNode(), 61); + EXPECT_EQ(BtreeNodePeer::GetNumSlotsPerNode(), 100); if (sizeof(void *) == 8) { - EXPECT_EQ(BtreeNodePeer::GetNumValuesPerNode>(), - BtreeNodePeer::GetNumValuesPerNode()); + EXPECT_EQ(BtreeNodePeer::GetNumSlotsPerNode>(), + BtreeNodePeer::GetNumSlotsPerNode()); } // Test key insertion/deletion in random order. - ExpectOperationCounts(45281, 122560, values, &tracker, &set3); + ExpectOperationCounts(56540, 124221, values, &tracker, &set4); ExpectOperationCounts(386718, 119816, values, &tracker, &set61); ExpectOperationCounts(586761, 120319, values, &tracker, &set100); // Test key insertion/deletion in sorted order. std::sort(values.begin(), values.end()); - ExpectOperationCounts(26638, 92134, values, &tracker, &set3); + ExpectOperationCounts(24972, 85563, values, &tracker, &set4); ExpectOperationCounts(20208, 87757, values, &tracker, &set61); ExpectOperationCounts(20124, 96583, values, &tracker, &set100); // Test key insertion/deletion in reverse sorted order. std::reverse(values.begin(), values.end()); - ExpectOperationCounts(49951, 109326, values, &tracker, &set3); + ExpectOperationCounts(54949, 117532, values, &tracker, &set4); ExpectOperationCounts(338813, 108267, values, &tracker, &set61); ExpectOperationCounts(534529, 115280, values, &tracker, &set100); } @@ -1543,7 +1621,7 @@ TEST(Btree, MapAt) { #ifdef ABSL_HAVE_EXCEPTIONS EXPECT_THROW(map.at(3), std::out_of_range); #else - EXPECT_DEATH(map.at(3), "absl::btree_map::at"); + EXPECT_DEATH_IF_SUPPORTED(map.at(3), "absl::btree_map::at"); #endif } @@ -1630,10 +1708,25 @@ TEST(Btree, StrSplitCompatible) { EXPECT_EQ(split_set, expected_set); } -// We can't use EXPECT_EQ/etc. to compare absl::weak_ordering because they -// convert literal 0 to int and absl::weak_ordering can only be compared with -// literal 0. Defining this function allows for avoiding ClangTidy warnings. -bool Identity(const bool b) { return b; } +TEST(Btree, KeyComp) { + absl::btree_set s; + EXPECT_TRUE(s.key_comp()(1, 2)); + EXPECT_FALSE(s.key_comp()(2, 2)); + EXPECT_FALSE(s.key_comp()(2, 1)); + + absl::btree_map m1; + EXPECT_TRUE(m1.key_comp()(1, 2)); + EXPECT_FALSE(m1.key_comp()(2, 2)); + EXPECT_FALSE(m1.key_comp()(2, 1)); + + // Even though we internally adapt the comparator of `m2` to be three-way and + // heterogeneous, the comparator we expose through key_comp() is the original + // unadapted comparator. + absl::btree_map m2; + EXPECT_TRUE(m2.key_comp()("a", "b")); + EXPECT_FALSE(m2.key_comp()("b", "b")); + EXPECT_FALSE(m2.key_comp()("b", "a")); +} TEST(Btree, ValueComp) { absl::btree_set s; @@ -1646,13 +1739,13 @@ TEST(Btree, ValueComp) { EXPECT_FALSE(m1.value_comp()(std::make_pair(2, 0), std::make_pair(2, 0))); EXPECT_FALSE(m1.value_comp()(std::make_pair(2, 0), std::make_pair(1, 0))); + // Even though we internally adapt the comparator of `m2` to be three-way and + // heterogeneous, the comparator we expose through value_comp() is based on + // the original unadapted comparator. absl::btree_map m2; - EXPECT_TRUE(Identity( - m2.value_comp()(std::make_pair("a", 0), std::make_pair("b", 0)) < 0)); - EXPECT_TRUE(Identity( - m2.value_comp()(std::make_pair("b", 0), std::make_pair("b", 0)) == 0)); - EXPECT_TRUE(Identity( - m2.value_comp()(std::make_pair("b", 0), std::make_pair("a", 0)) > 0)); + EXPECT_TRUE(m2.value_comp()(std::make_pair("a", 0), std::make_pair("b", 0))); + EXPECT_FALSE(m2.value_comp()(std::make_pair("b", 0), std::make_pair("b", 0))); + EXPECT_FALSE(m2.value_comp()(std::make_pair("b", 0), std::make_pair("a", 0))); } TEST(Btree, DefaultConstruction) { @@ -1960,6 +2053,30 @@ TEST(Btree, ExtractAndInsertNodeHandleMultiMap) { EXPECT_EQ(res, ++other.begin()); } +TEST(Btree, ExtractMultiMapEquivalentKeys) { + // Note: using string keys means a three-way comparator. + absl::btree_multimap map; + for (int i = 0; i < 100; ++i) { + for (int j = 0; j < 100; ++j) { + map.insert({absl::StrCat(i), j}); + } + } + + for (int i = 0; i < 100; ++i) { + const std::string key = absl::StrCat(i); + auto node_handle = map.extract(key); + EXPECT_EQ(node_handle.key(), key); + EXPECT_EQ(node_handle.mapped(), 0) << i; + } + + for (int i = 0; i < 100; ++i) { + const std::string key = absl::StrCat(i); + auto node_handle = map.extract(key); + EXPECT_EQ(node_handle.key(), key); + EXPECT_EQ(node_handle.mapped(), 1) << i; + } +} + // For multisets, insert with hint also affects correctness because we need to // insert immediately before the hint if possible. struct InsertMultiHintData { @@ -2101,6 +2218,31 @@ TEST(Btree, MergeIntoMultiMapsWithDifferentComparators) { Pair(4, 1), Pair(4, 4), Pair(5, 5))); } +TEST(Btree, MergeIntoSetMovableOnly) { + absl::btree_set src; + src.insert(MovableOnlyInstance(1)); + absl::btree_multiset dst1; + dst1.insert(MovableOnlyInstance(2)); + absl::btree_set dst2; + + // Test merge into multiset. + dst1.merge(src); + + EXPECT_TRUE(src.empty()); + // ElementsAre/ElementsAreArray don't work with move-only types. + ASSERT_THAT(dst1, SizeIs(2)); + EXPECT_EQ(*dst1.begin(), MovableOnlyInstance(1)); + EXPECT_EQ(*std::next(dst1.begin()), MovableOnlyInstance(2)); + + // Test merge into set. + dst2.merge(dst1); + + EXPECT_TRUE(dst1.empty()); + ASSERT_THAT(dst2, SizeIs(2)); + EXPECT_EQ(*dst2.begin(), MovableOnlyInstance(1)); + EXPECT_EQ(*std::next(dst2.begin()), MovableOnlyInstance(2)); +} + struct KeyCompareToWeakOrdering { template absl::weak_ordering operator()(const T &a, const T &b) const { @@ -2404,6 +2546,408 @@ TEST(Btree, BitfieldArgument) { m[n]; } +TEST(Btree, SetRangeConstructorAndInsertSupportExplicitConversionComparable) { + const absl::string_view names[] = {"n1", "n2"}; + + absl::btree_set name_set1{std::begin(names), std::end(names)}; + EXPECT_THAT(name_set1, ElementsAreArray(names)); + + absl::btree_set name_set2; + name_set2.insert(std::begin(names), std::end(names)); + EXPECT_THAT(name_set2, ElementsAreArray(names)); +} + +// A type that is explicitly convertible from int and counts constructor calls. +struct ConstructorCounted { + explicit ConstructorCounted(int i) : i(i) { ++constructor_calls; } + bool operator==(int other) const { return i == other; } + + int i; + static int constructor_calls; +}; +int ConstructorCounted::constructor_calls = 0; + +struct ConstructorCountedCompare { + bool operator()(int a, const ConstructorCounted &b) const { return a < b.i; } + bool operator()(const ConstructorCounted &a, int b) const { return a.i < b; } + bool operator()(const ConstructorCounted &a, + const ConstructorCounted &b) const { + return a.i < b.i; + } + using is_transparent = void; +}; + +TEST(Btree, + SetRangeConstructorAndInsertExplicitConvComparableLimitConstruction) { + const int i[] = {0, 1, 1}; + ConstructorCounted::constructor_calls = 0; + + absl::btree_set set{ + std::begin(i), std::end(i)}; + EXPECT_THAT(set, ElementsAre(0, 1)); + EXPECT_EQ(ConstructorCounted::constructor_calls, 2); + + set.insert(std::begin(i), std::end(i)); + EXPECT_THAT(set, ElementsAre(0, 1)); + EXPECT_EQ(ConstructorCounted::constructor_calls, 2); +} + +TEST(Btree, + SetRangeConstructorAndInsertSupportExplicitConversionNonComparable) { + const int i[] = {0, 1}; + + absl::btree_set> s1{std::begin(i), std::end(i)}; + EXPECT_THAT(s1, ElementsAre(IsEmpty(), ElementsAre(IsNull()))); + + absl::btree_set> s2; + s2.insert(std::begin(i), std::end(i)); + EXPECT_THAT(s2, ElementsAre(IsEmpty(), ElementsAre(IsNull()))); +} + +// libstdc++ included with GCC 4.9 has a bug in the std::pair constructors that +// prevents explicit conversions between pair types. +// We only run this test for the libstdc++ from GCC 7 or newer because we can't +// reliably check the libstdc++ version prior to that release. +#if !defined(__GLIBCXX__) || \ + (defined(_GLIBCXX_RELEASE) && _GLIBCXX_RELEASE >= 7) +TEST(Btree, MapRangeConstructorAndInsertSupportExplicitConversionComparable) { + const std::pair names[] = {{"n1", 1}, {"n2", 2}}; + + absl::btree_map name_map1{std::begin(names), + std::end(names)}; + EXPECT_THAT(name_map1, ElementsAre(Pair("n1", 1), Pair("n2", 2))); + + absl::btree_map name_map2; + name_map2.insert(std::begin(names), std::end(names)); + EXPECT_THAT(name_map2, ElementsAre(Pair("n1", 1), Pair("n2", 2))); +} + +TEST(Btree, + MapRangeConstructorAndInsertExplicitConvComparableLimitConstruction) { + const std::pair i[] = {{0, 1}, {1, 2}, {1, 3}}; + ConstructorCounted::constructor_calls = 0; + + absl::btree_map map{ + std::begin(i), std::end(i)}; + EXPECT_THAT(map, ElementsAre(Pair(0, 1), Pair(1, 2))); + EXPECT_EQ(ConstructorCounted::constructor_calls, 2); + + map.insert(std::begin(i), std::end(i)); + EXPECT_THAT(map, ElementsAre(Pair(0, 1), Pair(1, 2))); + EXPECT_EQ(ConstructorCounted::constructor_calls, 2); +} + +TEST(Btree, + MapRangeConstructorAndInsertSupportExplicitConversionNonComparable) { + const std::pair i[] = {{0, 1}, {1, 2}}; + + absl::btree_map, int> m1{std::begin(i), std::end(i)}; + EXPECT_THAT(m1, + ElementsAre(Pair(IsEmpty(), 1), Pair(ElementsAre(IsNull()), 2))); + + absl::btree_map, int> m2; + m2.insert(std::begin(i), std::end(i)); + EXPECT_THAT(m2, + ElementsAre(Pair(IsEmpty(), 1), Pair(ElementsAre(IsNull()), 2))); +} + +TEST(Btree, HeterogeneousTryEmplace) { + absl::btree_map m; + std::string s = "key"; + absl::string_view sv = s; + m.try_emplace(sv, 1); + EXPECT_EQ(m[s], 1); + + m.try_emplace(m.end(), sv, 2); + EXPECT_EQ(m[s], 1); +} + +TEST(Btree, HeterogeneousOperatorMapped) { + absl::btree_map m; + std::string s = "key"; + absl::string_view sv = s; + m[sv] = 1; + EXPECT_EQ(m[s], 1); + + m[sv] = 2; + EXPECT_EQ(m[s], 2); +} + +TEST(Btree, HeterogeneousInsertOrAssign) { + absl::btree_map m; + std::string s = "key"; + absl::string_view sv = s; + m.insert_or_assign(sv, 1); + EXPECT_EQ(m[s], 1); + + m.insert_or_assign(m.end(), sv, 2); + EXPECT_EQ(m[s], 2); +} +#endif + +// This test requires std::launder for mutable key access in node handles. +#if defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606 +TEST(Btree, NodeHandleMutableKeyAccess) { + { + absl::btree_map map; + + map["key1"] = "mapped"; + + auto nh = map.extract(map.begin()); + nh.key().resize(3); + map.insert(std::move(nh)); + + EXPECT_THAT(map, ElementsAre(Pair("key", "mapped"))); + } + // Also for multimap. + { + absl::btree_multimap map; + + map.emplace("key1", "mapped"); + + auto nh = map.extract(map.begin()); + nh.key().resize(3); + map.insert(std::move(nh)); + + EXPECT_THAT(map, ElementsAre(Pair("key", "mapped"))); + } +} +#endif + +struct MultiKey { + int i1; + int i2; +}; + +bool operator==(const MultiKey a, const MultiKey b) { + return a.i1 == b.i1 && a.i2 == b.i2; +} + +// A heterogeneous comparator that has different equivalence classes for +// different lookup types. +struct MultiKeyComp { + using is_transparent = void; + bool operator()(const MultiKey a, const MultiKey b) const { + if (a.i1 != b.i1) return a.i1 < b.i1; + return a.i2 < b.i2; + } + bool operator()(const int a, const MultiKey b) const { return a < b.i1; } + bool operator()(const MultiKey a, const int b) const { return a.i1 < b; } +}; + +// A heterogeneous, three-way comparator that has different equivalence classes +// for different lookup types. +struct MultiKeyThreeWayComp { + using is_transparent = void; + absl::weak_ordering operator()(const MultiKey a, const MultiKey b) const { + if (a.i1 < b.i1) return absl::weak_ordering::less; + if (a.i1 > b.i1) return absl::weak_ordering::greater; + if (a.i2 < b.i2) return absl::weak_ordering::less; + if (a.i2 > b.i2) return absl::weak_ordering::greater; + return absl::weak_ordering::equivalent; + } + absl::weak_ordering operator()(const int a, const MultiKey b) const { + if (a < b.i1) return absl::weak_ordering::less; + if (a > b.i1) return absl::weak_ordering::greater; + return absl::weak_ordering::equivalent; + } + absl::weak_ordering operator()(const MultiKey a, const int b) const { + if (a.i1 < b) return absl::weak_ordering::less; + if (a.i1 > b) return absl::weak_ordering::greater; + return absl::weak_ordering::equivalent; + } +}; + +template +class BtreeMultiKeyTest : public ::testing::Test {}; +using MultiKeyComps = ::testing::Types; +TYPED_TEST_SUITE(BtreeMultiKeyTest, MultiKeyComps); + +TYPED_TEST(BtreeMultiKeyTest, EqualRange) { + absl::btree_set set; + for (int i = 0; i < 100; ++i) { + for (int j = 0; j < 100; ++j) { + set.insert({i, j}); + } + } + + for (int i = 0; i < 100; ++i) { + auto equal_range = set.equal_range(i); + EXPECT_EQ(equal_range.first->i1, i); + EXPECT_EQ(equal_range.first->i2, 0) << i; + EXPECT_EQ(std::distance(equal_range.first, equal_range.second), 100) << i; + } +} + +TYPED_TEST(BtreeMultiKeyTest, Extract) { + absl::btree_set set; + for (int i = 0; i < 100; ++i) { + for (int j = 0; j < 100; ++j) { + set.insert({i, j}); + } + } + + for (int i = 0; i < 100; ++i) { + auto node_handle = set.extract(i); + EXPECT_EQ(node_handle.value().i1, i); + EXPECT_EQ(node_handle.value().i2, 0) << i; + } + + for (int i = 0; i < 100; ++i) { + auto node_handle = set.extract(i); + EXPECT_EQ(node_handle.value().i1, i); + EXPECT_EQ(node_handle.value().i2, 1) << i; + } +} + +TYPED_TEST(BtreeMultiKeyTest, Erase) { + absl::btree_set set = { + {1, 1}, {2, 1}, {2, 2}, {3, 1}}; + EXPECT_EQ(set.erase(2), 2); + EXPECT_THAT(set, ElementsAre(MultiKey{1, 1}, MultiKey{3, 1})); +} + +TYPED_TEST(BtreeMultiKeyTest, Count) { + const absl::btree_set set = { + {1, 1}, {2, 1}, {2, 2}, {3, 1}}; + EXPECT_EQ(set.count(2), 2); +} + +TEST(Btree, AllocConstructor) { + using Alloc = CountingAllocator; + using Set = absl::btree_set, Alloc>; + int64_t bytes_used = 0; + Alloc alloc(&bytes_used); + Set set(alloc); + + set.insert({1, 2, 3}); + + EXPECT_THAT(set, ElementsAre(1, 2, 3)); + EXPECT_GT(bytes_used, set.size() * sizeof(int)); +} + +TEST(Btree, AllocInitializerListConstructor) { + using Alloc = CountingAllocator; + using Set = absl::btree_set, Alloc>; + int64_t bytes_used = 0; + Alloc alloc(&bytes_used); + Set set({1, 2, 3}, alloc); + + EXPECT_THAT(set, ElementsAre(1, 2, 3)); + EXPECT_GT(bytes_used, set.size() * sizeof(int)); +} + +TEST(Btree, AllocRangeConstructor) { + using Alloc = CountingAllocator; + using Set = absl::btree_set, Alloc>; + int64_t bytes_used = 0; + Alloc alloc(&bytes_used); + std::vector v = {1, 2, 3}; + Set set(v.begin(), v.end(), alloc); + + EXPECT_THAT(set, ElementsAre(1, 2, 3)); + EXPECT_GT(bytes_used, set.size() * sizeof(int)); +} + +TEST(Btree, AllocCopyConstructor) { + using Alloc = CountingAllocator; + using Set = absl::btree_set, Alloc>; + int64_t bytes_used1 = 0; + Alloc alloc1(&bytes_used1); + Set set1(alloc1); + + set1.insert({1, 2, 3}); + + int64_t bytes_used2 = 0; + Alloc alloc2(&bytes_used2); + Set set2(set1, alloc2); + + EXPECT_THAT(set1, ElementsAre(1, 2, 3)); + EXPECT_THAT(set2, ElementsAre(1, 2, 3)); + EXPECT_GT(bytes_used1, set1.size() * sizeof(int)); + EXPECT_EQ(bytes_used1, bytes_used2); +} + +TEST(Btree, AllocMoveConstructor_SameAlloc) { + using Alloc = CountingAllocator; + using Set = absl::btree_set, Alloc>; + int64_t bytes_used = 0; + Alloc alloc(&bytes_used); + Set set1(alloc); + + set1.insert({1, 2, 3}); + + const int64_t original_bytes_used = bytes_used; + EXPECT_GT(original_bytes_used, set1.size() * sizeof(int)); + + Set set2(std::move(set1), alloc); + + EXPECT_THAT(set2, ElementsAre(1, 2, 3)); + EXPECT_EQ(bytes_used, original_bytes_used); +} + +TEST(Btree, AllocMoveConstructor_DifferentAlloc) { + using Alloc = CountingAllocator; + using Set = absl::btree_set, Alloc>; + int64_t bytes_used1 = 0; + Alloc alloc1(&bytes_used1); + Set set1(alloc1); + + set1.insert({1, 2, 3}); + + const int64_t original_bytes_used = bytes_used1; + EXPECT_GT(original_bytes_used, set1.size() * sizeof(int)); + + int64_t bytes_used2 = 0; + Alloc alloc2(&bytes_used2); + Set set2(std::move(set1), alloc2); + + EXPECT_THAT(set2, ElementsAre(1, 2, 3)); + // We didn't free these bytes allocated by `set1` yet. + EXPECT_EQ(bytes_used1, original_bytes_used); + EXPECT_EQ(bytes_used2, original_bytes_used); +} + +bool IntCmp(const int a, const int b) { return a < b; } + +TEST(Btree, SupportsFunctionPtrComparator) { + absl::btree_set set(IntCmp); + set.insert({1, 2, 3}); + EXPECT_THAT(set, ElementsAre(1, 2, 3)); + EXPECT_TRUE(set.key_comp()(1, 2)); + EXPECT_TRUE(set.value_comp()(1, 2)); + + absl::btree_map map(&IntCmp); + map[1] = 1; + EXPECT_THAT(map, ElementsAre(Pair(1, 1))); + EXPECT_TRUE(map.key_comp()(1, 2)); + EXPECT_TRUE(map.value_comp()(std::make_pair(1, 1), std::make_pair(2, 2))); +} + +template +struct TransparentPassThroughComp { + using is_transparent = void; + + // This will fail compilation if we attempt a comparison that Compare does not + // support, and the failure will happen inside the function implementation so + // it can't be avoided by using SFINAE on this comparator. + template + bool operator()(const T &lhs, const U &rhs) const { + return Compare()(lhs, rhs); + } +}; + +TEST(Btree, + SupportsTransparentComparatorThatDoesNotImplementAllVisibleOperators) { + absl::btree_set> set; + set.insert(MultiKey{1, 2}); + EXPECT_TRUE(set.contains(1)); +} + +TEST(Btree, ConstructImplicitlyWithUnadaptedComparator) { + absl::btree_set set = {{}, MultiKeyComp{}}; +} + } // namespace } // namespace container_internal ABSL_NAMESPACE_END diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/fixed_array.h b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/fixed_array.h index 94385ea7af..839ba0bc16 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/fixed_array.h +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/fixed_array.h @@ -41,6 +41,7 @@ #include #include "absl/algorithm/algorithm.h" +#include "absl/base/config.h" #include "absl/base/dynamic_annotations.h" #include "absl/base/internal/throw_delegate.h" #include "absl/base/macros.h" @@ -72,11 +73,6 @@ constexpr static auto kFixedArrayUseDefault = static_cast(-1); // uninitialized (e.g. int, int[4], double), and others default-constructed. // This matches the behavior of c-style arrays and `std::array`, but not // `std::vector`. -// -// Note that `FixedArray` does not provide a public allocator; if it requires a -// heap allocation, it will do so with global `::operator new[]()` and -// `::operator delete[]()`, even if T provides class-scope overrides for these -// operators. template > class FixedArray { @@ -106,13 +102,13 @@ class FixedArray { public: using allocator_type = typename AllocatorTraits::allocator_type; - using value_type = typename allocator_type::value_type; - using pointer = typename allocator_type::pointer; - using const_pointer = typename allocator_type::const_pointer; - using reference = typename allocator_type::reference; - using const_reference = typename allocator_type::const_reference; - using size_type = typename allocator_type::size_type; - using difference_type = typename allocator_type::difference_type; + using value_type = typename AllocatorTraits::value_type; + using pointer = typename AllocatorTraits::pointer; + using const_pointer = typename AllocatorTraits::const_pointer; + using reference = value_type&; + using const_reference = const value_type&; + using size_type = typename AllocatorTraits::size_type; + using difference_type = typename AllocatorTraits::difference_type; using iterator = pointer; using const_iterator = const_pointer; using reverse_iterator = std::reverse_iterator; @@ -231,8 +227,8 @@ class FixedArray { // FixedArray::at // - // Bounds-checked access. Returns a reference to the ith element of the - // fiexed array, or throws std::out_of_range + // Bounds-checked access. Returns a reference to the ith element of the fixed + // array, or throws std::out_of_range reference at(size_type i) { if (ABSL_PREDICT_FALSE(i >= size())) { base_internal::ThrowStdOutOfRange("FixedArray::at failed bounds check"); @@ -422,10 +418,10 @@ class FixedArray { void AnnotateConstruct(size_type n); void AnnotateDestruct(size_type n); -#ifdef ADDRESS_SANITIZER +#ifdef ABSL_HAVE_ADDRESS_SANITIZER void* RedzoneBegin() { return &redzone_begin_; } void* RedzoneEnd() { return &redzone_end_ + 1; } -#endif // ADDRESS_SANITIZER +#endif // ABSL_HAVE_ADDRESS_SANITIZER private: ABSL_ADDRESS_SANITIZER_REDZONE(redzone_begin_); @@ -503,22 +499,26 @@ constexpr typename FixedArray::size_type template void FixedArray::NonEmptyInlinedStorage::AnnotateConstruct( typename FixedArray::size_type n) { -#ifdef ADDRESS_SANITIZER +#ifdef ABSL_HAVE_ADDRESS_SANITIZER if (!n) return; - ABSL_ANNOTATE_CONTIGUOUS_CONTAINER(data(), RedzoneEnd(), RedzoneEnd(), data() + n); - ABSL_ANNOTATE_CONTIGUOUS_CONTAINER(RedzoneBegin(), data(), data(), RedzoneBegin()); -#endif // ADDRESS_SANITIZER + ABSL_ANNOTATE_CONTIGUOUS_CONTAINER(data(), RedzoneEnd(), RedzoneEnd(), + data() + n); + ABSL_ANNOTATE_CONTIGUOUS_CONTAINER(RedzoneBegin(), data(), data(), + RedzoneBegin()); +#endif // ABSL_HAVE_ADDRESS_SANITIZER static_cast(n); // Mark used when not in asan mode } template void FixedArray::NonEmptyInlinedStorage::AnnotateDestruct( typename FixedArray::size_type n) { -#ifdef ADDRESS_SANITIZER +#ifdef ABSL_HAVE_ADDRESS_SANITIZER if (!n) return; - ABSL_ANNOTATE_CONTIGUOUS_CONTAINER(data(), RedzoneEnd(), data() + n, RedzoneEnd()); - ABSL_ANNOTATE_CONTIGUOUS_CONTAINER(RedzoneBegin(), data(), RedzoneBegin(), data()); -#endif // ADDRESS_SANITIZER + ABSL_ANNOTATE_CONTIGUOUS_CONTAINER(data(), RedzoneEnd(), data() + n, + RedzoneEnd()); + ABSL_ANNOTATE_CONTIGUOUS_CONTAINER(RedzoneBegin(), data(), RedzoneBegin(), + data()); +#endif // ABSL_HAVE_ADDRESS_SANITIZER static_cast(n); // Mark used when not in asan mode } ABSL_NAMESPACE_END diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/fixed_array_exception_safety_test.cc b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/fixed_array_exception_safety_test.cc index a5bb009d98..e5f59299b3 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/fixed_array_exception_safety_test.cc +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/fixed_array_exception_safety_test.cc @@ -150,8 +150,7 @@ TEST(FixedArrayExceptionSafety, InitListConstructorWithAlloc) { template testing::AssertionResult ReadMemory(FixedArrT* fixed_arr) { - // Marked volatile to prevent optimization. Used for running asan tests. - volatile int sum = 0; + int sum = 0; for (const auto& thrower : *fixed_arr) { sum += thrower.Get(); } diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/fixed_array_test.cc b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/fixed_array_test.cc index 9b1c224f86..49598e7a05 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/fixed_array_test.cc +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/fixed_array_test.cc @@ -27,8 +27,10 @@ #include "gmock/gmock.h" #include "gtest/gtest.h" +#include "absl/base/config.h" #include "absl/base/internal/exception_testing.h" #include "absl/base/options.h" +#include "absl/container/internal/counting_allocator.h" #include "absl/hash/hash_testing.h" #include "absl/memory/memory.h" @@ -638,70 +640,9 @@ TEST(FixedArrayTest, DefaultCtorDoesNotValueInit) { } #endif // __GNUC__ -// This is a stateful allocator, but the state lives outside of the -// allocator (in whatever test is using the allocator). This is odd -// but helps in tests where the allocator is propagated into nested -// containers - that chain of allocators uses the same state and is -// thus easier to query for aggregate allocation information. -template -class CountingAllocator : public std::allocator { - public: - using Alloc = std::allocator; - using pointer = typename Alloc::pointer; - using size_type = typename Alloc::size_type; - - CountingAllocator() : bytes_used_(nullptr), instance_count_(nullptr) {} - explicit CountingAllocator(int64_t* b) - : bytes_used_(b), instance_count_(nullptr) {} - CountingAllocator(int64_t* b, int64_t* a) - : bytes_used_(b), instance_count_(a) {} - - template - explicit CountingAllocator(const CountingAllocator& x) - : Alloc(x), - bytes_used_(x.bytes_used_), - instance_count_(x.instance_count_) {} - - pointer allocate(size_type n, const void* const hint = nullptr) { - assert(bytes_used_ != nullptr); - *bytes_used_ += n * sizeof(T); - return Alloc::allocate(n, hint); - } - - void deallocate(pointer p, size_type n) { - Alloc::deallocate(p, n); - assert(bytes_used_ != nullptr); - *bytes_used_ -= n * sizeof(T); - } - - template - void construct(pointer p, Args&&... args) { - Alloc::construct(p, absl::forward(args)...); - if (instance_count_) { - *instance_count_ += 1; - } - } - - void destroy(pointer p) { - Alloc::destroy(p); - if (instance_count_) { - *instance_count_ -= 1; - } - } - - template - class rebind { - public: - using other = CountingAllocator; - }; - - int64_t* bytes_used_; - int64_t* instance_count_; -}; - TEST(AllocatorSupportTest, CountInlineAllocations) { constexpr size_t inlined_size = 4; - using Alloc = CountingAllocator; + using Alloc = absl::container_internal::CountingAllocator; using AllocFxdArr = absl::FixedArray; int64_t allocated = 0; @@ -722,7 +663,7 @@ TEST(AllocatorSupportTest, CountInlineAllocations) { TEST(AllocatorSupportTest, CountOutoflineAllocations) { constexpr size_t inlined_size = 4; - using Alloc = CountingAllocator; + using Alloc = absl::container_internal::CountingAllocator; using AllocFxdArr = absl::FixedArray; int64_t allocated = 0; @@ -743,7 +684,7 @@ TEST(AllocatorSupportTest, CountOutoflineAllocations) { TEST(AllocatorSupportTest, CountCopyInlineAllocations) { constexpr size_t inlined_size = 4; - using Alloc = CountingAllocator; + using Alloc = absl::container_internal::CountingAllocator; using AllocFxdArr = absl::FixedArray; int64_t allocated1 = 0; @@ -771,7 +712,7 @@ TEST(AllocatorSupportTest, CountCopyInlineAllocations) { TEST(AllocatorSupportTest, CountCopyOutoflineAllocations) { constexpr size_t inlined_size = 4; - using Alloc = CountingAllocator; + using Alloc = absl::container_internal::CountingAllocator; using AllocFxdArr = absl::FixedArray; int64_t allocated1 = 0; @@ -803,7 +744,7 @@ TEST(AllocatorSupportTest, SizeValAllocConstructor) { using testing::SizeIs; constexpr size_t inlined_size = 4; - using Alloc = CountingAllocator; + using Alloc = absl::container_internal::CountingAllocator; using AllocFxdArr = absl::FixedArray; { @@ -827,16 +768,16 @@ TEST(AllocatorSupportTest, SizeValAllocConstructor) { } } -#ifdef ADDRESS_SANITIZER +#ifdef ABSL_HAVE_ADDRESS_SANITIZER TEST(FixedArrayTest, AddressSanitizerAnnotations1) { absl::FixedArray a(10); int* raw = a.data(); raw[0] = 0; raw[9] = 0; - EXPECT_DEATH(raw[-2] = 0, "container-overflow"); - EXPECT_DEATH(raw[-1] = 0, "container-overflow"); - EXPECT_DEATH(raw[10] = 0, "container-overflow"); - EXPECT_DEATH(raw[31] = 0, "container-overflow"); + EXPECT_DEATH_IF_SUPPORTED(raw[-2] = 0, "container-overflow"); + EXPECT_DEATH_IF_SUPPORTED(raw[-1] = 0, "container-overflow"); + EXPECT_DEATH_IF_SUPPORTED(raw[10] = 0, "container-overflow"); + EXPECT_DEATH_IF_SUPPORTED(raw[31] = 0, "container-overflow"); } TEST(FixedArrayTest, AddressSanitizerAnnotations2) { @@ -844,10 +785,10 @@ TEST(FixedArrayTest, AddressSanitizerAnnotations2) { char* raw = a.data(); raw[0] = 0; raw[11] = 0; - EXPECT_DEATH(raw[-7] = 0, "container-overflow"); - EXPECT_DEATH(raw[-1] = 0, "container-overflow"); - EXPECT_DEATH(raw[12] = 0, "container-overflow"); - EXPECT_DEATH(raw[17] = 0, "container-overflow"); + EXPECT_DEATH_IF_SUPPORTED(raw[-7] = 0, "container-overflow"); + EXPECT_DEATH_IF_SUPPORTED(raw[-1] = 0, "container-overflow"); + EXPECT_DEATH_IF_SUPPORTED(raw[12] = 0, "container-overflow"); + EXPECT_DEATH_IF_SUPPORTED(raw[17] = 0, "container-overflow"); } TEST(FixedArrayTest, AddressSanitizerAnnotations3) { @@ -855,8 +796,8 @@ TEST(FixedArrayTest, AddressSanitizerAnnotations3) { uint64_t* raw = a.data(); raw[0] = 0; raw[19] = 0; - EXPECT_DEATH(raw[-1] = 0, "container-overflow"); - EXPECT_DEATH(raw[20] = 0, "container-overflow"); + EXPECT_DEATH_IF_SUPPORTED(raw[-1] = 0, "container-overflow"); + EXPECT_DEATH_IF_SUPPORTED(raw[20] = 0, "container-overflow"); } TEST(FixedArrayTest, AddressSanitizerAnnotations4) { @@ -868,13 +809,13 @@ TEST(FixedArrayTest, AddressSanitizerAnnotations4) { // there is only a 8-byte red zone before the container range, so we only // access the last 4 bytes of the struct to make sure it stays within the red // zone. - EXPECT_DEATH(raw[-1].z_ = 0, "container-overflow"); - EXPECT_DEATH(raw[10] = ThreeInts(), "container-overflow"); + EXPECT_DEATH_IF_SUPPORTED(raw[-1].z_ = 0, "container-overflow"); + EXPECT_DEATH_IF_SUPPORTED(raw[10] = ThreeInts(), "container-overflow"); // The actual size of storage is kDefaultBytes=256, 21*12 = 252, // so reading raw[21] should still trigger the correct warning. - EXPECT_DEATH(raw[21] = ThreeInts(), "container-overflow"); + EXPECT_DEATH_IF_SUPPORTED(raw[21] = ThreeInts(), "container-overflow"); } -#endif // ADDRESS_SANITIZER +#endif // ABSL_HAVE_ADDRESS_SANITIZER TEST(FixedArrayTest, AbslHashValueWorks) { using V = absl::FixedArray; diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/flat_hash_map.h b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/flat_hash_map.h index fcb70d861f..74def0df0e 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/flat_hash_map.h +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/flat_hash_map.h @@ -234,7 +234,8 @@ class flat_hash_map : public absl::container_internal::raw_hash_map< // // size_type erase(const key_type& key): // - // Erases the element with the matching key, if it exists. + // Erases the element with the matching key, if it exists, returning the + // number of elements erased (0 or 1). using Base::erase; // flat_hash_map::insert() @@ -383,6 +384,11 @@ class flat_hash_map : public absl::container_internal::raw_hash_map< // key value and returns a node handle owning that extracted data. If the // `flat_hash_map` does not contain an element with a matching key, this // function returns an empty node handle. + // + // NOTE: when compiled in an earlier version of C++ than C++17, + // `node_type::key()` returns a const reference to the key instead of a + // mutable reference. We cannot safely return a mutable reference without + // std::launder (which is not available before C++17). using Base::extract; // flat_hash_map::merge() diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/flat_hash_map_test.cc b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/flat_hash_map_test.cc index 728b693a07..8dda1d3539 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/flat_hash_map_test.cc +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/flat_hash_map_test.cc @@ -16,6 +16,7 @@ #include +#include "absl/base/internal/raw_logging.h" #include "absl/container/internal/hash_generator_testing.h" #include "absl/container/internal/unordered_map_constructor_test.h" #include "absl/container/internal/unordered_map_lookup_test.h" @@ -34,6 +35,19 @@ using ::testing::IsEmpty; using ::testing::Pair; using ::testing::UnorderedElementsAre; +// Check that absl::flat_hash_map works in a global constructor. +struct BeforeMain { + BeforeMain() { + absl::flat_hash_map x; + x.insert({1, 1}); + ABSL_RAW_CHECK(x.find(0) == x.end(), "x should not contain 0"); + auto it = x.find(1); + ABSL_RAW_CHECK(it != x.end(), "x should contain 1"); + ABSL_RAW_CHECK(it->second, "1 should map to 1"); + } +}; +const BeforeMain before_main; + template using Map = flat_hash_map>>; @@ -253,6 +267,47 @@ TEST(FlatHashMap, EraseIf) { } } +// This test requires std::launder for mutable key access in node handles. +#if defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606 +TEST(FlatHashMap, NodeHandleMutableKeyAccess) { + flat_hash_map map; + + map["key1"] = "mapped"; + + auto nh = map.extract(map.begin()); + nh.key().resize(3); + map.insert(std::move(nh)); + + EXPECT_THAT(map, testing::ElementsAre(Pair("key", "mapped"))); +} +#endif + +TEST(FlatHashMap, Reserve) { + // Verify that if we reserve(size() + n) then we can perform n insertions + // without a rehash, i.e., without invalidating any references. + for (size_t trial = 0; trial < 20; ++trial) { + for (size_t initial = 3; initial < 100; ++initial) { + // Fill in `initial` entries, then erase 2 of them, then reserve space for + // two inserts and check for reference stability while doing the inserts. + flat_hash_map map; + for (size_t i = 0; i < initial; ++i) { + map[i] = i; + } + map.erase(0); + map.erase(1); + map.reserve(map.size() + 2); + size_t& a2 = map[2]; + // In the event of a failure, asan will complain in one of these two + // assignments. + map[initial] = a2; + map[initial + 1] = a2; + // Fail even when not under asan: + size_t& a2new = map[2]; + EXPECT_EQ(&a2, &a2new); + } + } +} + } // namespace } // namespace container_internal ABSL_NAMESPACE_END diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/flat_hash_set.h b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/flat_hash_set.h index 94be6e3d13..6b89da6571 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/flat_hash_set.h +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/flat_hash_set.h @@ -227,7 +227,8 @@ class flat_hash_set // // size_type erase(const key_type& key): // - // Erases the element with the matching key, if it exists. + // Erases the element with the matching key, if it exists, returning the + // number of elements erased (0 or 1). using Base::erase; // flat_hash_set::insert() @@ -323,7 +324,7 @@ class flat_hash_set // flat_hash_set::merge() // - // Extracts elements from a given `source` flat hash map into this + // Extracts elements from a given `source` flat hash set into this // `flat_hash_set`. If the destination `flat_hash_set` already contains an // element with an equivalent key, that element is not extracted. using Base::merge; diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/flat_hash_set_test.cc b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/flat_hash_set_test.cc index 40d7f85c5d..8f6f9944ca 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/flat_hash_set_test.cc +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/flat_hash_set_test.cc @@ -16,6 +16,7 @@ #include +#include "absl/base/internal/raw_logging.h" #include "absl/container/internal/hash_generator_testing.h" #include "absl/container/internal/unordered_set_constructor_test.h" #include "absl/container/internal/unordered_set_lookup_test.h" @@ -36,6 +37,17 @@ using ::testing::Pointee; using ::testing::UnorderedElementsAre; using ::testing::UnorderedElementsAreArray; +// Check that absl::flat_hash_set works in a global constructor. +struct BeforeMain { + BeforeMain() { + absl::flat_hash_set x; + x.insert(1); + ABSL_RAW_CHECK(!x.contains(0), "x should not contain 0"); + ABSL_RAW_CHECK(x.contains(1), "x should contain 1"); + } +}; +const BeforeMain before_main; + template using Set = absl::flat_hash_set>; diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/inlined_vector.h b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/inlined_vector.h index 5f6f6154bf..37e5fef8fd 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/inlined_vector.h +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/inlined_vector.h @@ -64,7 +64,7 @@ ABSL_NAMESPACE_BEGIN // `std::vector` for use cases where the vector's size is sufficiently small // that it can be inlined. If the inlined vector does grow beyond its estimated // capacity, it will trigger an initial allocation on the heap, and will behave -// as a `std:vector`. The API of the `absl::InlinedVector` within this file is +// as a `std::vector`. The API of the `absl::InlinedVector` within this file is // designed to cover the same API footprint as covered by `std::vector`. template > class InlinedVector { @@ -72,37 +72,43 @@ class InlinedVector { using Storage = inlined_vector_internal::Storage; - using AllocatorTraits = typename Storage::AllocatorTraits; - using RValueReference = typename Storage::RValueReference; - using MoveIterator = typename Storage::MoveIterator; - using IsMemcpyOk = typename Storage::IsMemcpyOk; + template + using AllocatorTraits = inlined_vector_internal::AllocatorTraits; + template + using MoveIterator = inlined_vector_internal::MoveIterator; + template + using IsMemcpyOk = inlined_vector_internal::IsMemcpyOk; - template + template using IteratorValueAdapter = - typename Storage::template IteratorValueAdapter; - using CopyValueAdapter = typename Storage::CopyValueAdapter; - using DefaultValueAdapter = typename Storage::DefaultValueAdapter; + inlined_vector_internal::IteratorValueAdapter; + template + using CopyValueAdapter = inlined_vector_internal::CopyValueAdapter; + template + using DefaultValueAdapter = + inlined_vector_internal::DefaultValueAdapter; template using EnableIfAtLeastForwardIterator = absl::enable_if_t< - inlined_vector_internal::IsAtLeastForwardIterator::value>; + inlined_vector_internal::IsAtLeastForwardIterator::value, int>; template using DisableIfAtLeastForwardIterator = absl::enable_if_t< - !inlined_vector_internal::IsAtLeastForwardIterator::value>; + !inlined_vector_internal::IsAtLeastForwardIterator::value, int>; public: - using allocator_type = typename Storage::allocator_type; - using value_type = typename Storage::value_type; - using pointer = typename Storage::pointer; - using const_pointer = typename Storage::const_pointer; - using size_type = typename Storage::size_type; - using difference_type = typename Storage::difference_type; - using reference = typename Storage::reference; - using const_reference = typename Storage::const_reference; - using iterator = typename Storage::iterator; - using const_iterator = typename Storage::const_iterator; - using reverse_iterator = typename Storage::reverse_iterator; - using const_reverse_iterator = typename Storage::const_reverse_iterator; + using allocator_type = A; + using value_type = inlined_vector_internal::ValueType; + using pointer = inlined_vector_internal::Pointer; + using const_pointer = inlined_vector_internal::ConstPointer; + using size_type = inlined_vector_internal::SizeType; + using difference_type = inlined_vector_internal::DifferenceType; + using reference = inlined_vector_internal::Reference; + using const_reference = inlined_vector_internal::ConstReference; + using iterator = inlined_vector_internal::Iterator; + using const_iterator = inlined_vector_internal::ConstIterator; + using reverse_iterator = inlined_vector_internal::ReverseIterator; + using const_reverse_iterator = + inlined_vector_internal::ConstReverseIterator; // --------------------------------------------------------------------------- // InlinedVector Constructors and Destructor @@ -111,28 +117,28 @@ class InlinedVector { // Creates an empty inlined vector with a value-initialized allocator. InlinedVector() noexcept(noexcept(allocator_type())) : storage_() {} - // Creates an empty inlined vector with a copy of `alloc`. - explicit InlinedVector(const allocator_type& alloc) noexcept - : storage_(alloc) {} + // Creates an empty inlined vector with a copy of `allocator`. + explicit InlinedVector(const allocator_type& allocator) noexcept + : storage_(allocator) {} // Creates an inlined vector with `n` copies of `value_type()`. explicit InlinedVector(size_type n, - const allocator_type& alloc = allocator_type()) - : storage_(alloc) { - storage_.Initialize(DefaultValueAdapter(), n); + const allocator_type& allocator = allocator_type()) + : storage_(allocator) { + storage_.Initialize(DefaultValueAdapter(), n); } // Creates an inlined vector with `n` copies of `v`. InlinedVector(size_type n, const_reference v, - const allocator_type& alloc = allocator_type()) - : storage_(alloc) { - storage_.Initialize(CopyValueAdapter(v), n); + const allocator_type& allocator = allocator_type()) + : storage_(allocator) { + storage_.Initialize(CopyValueAdapter(std::addressof(v)), n); } // Creates an inlined vector with copies of the elements of `list`. InlinedVector(std::initializer_list list, - const allocator_type& alloc = allocator_type()) - : InlinedVector(list.begin(), list.end(), alloc) {} + const allocator_type& allocator = allocator_type()) + : InlinedVector(list.begin(), list.end(), allocator) {} // Creates an inlined vector with elements constructed from the provided // forward iterator range [`first`, `last`). @@ -141,37 +147,40 @@ class InlinedVector { // this constructor with two integral arguments and a call to the above // `InlinedVector(size_type, const_reference)` constructor. template * = nullptr> + EnableIfAtLeastForwardIterator = 0> InlinedVector(ForwardIterator first, ForwardIterator last, - const allocator_type& alloc = allocator_type()) - : storage_(alloc) { - storage_.Initialize(IteratorValueAdapter(first), + const allocator_type& allocator = allocator_type()) + : storage_(allocator) { + storage_.Initialize(IteratorValueAdapter(first), std::distance(first, last)); } // Creates an inlined vector with elements constructed from the provided input // iterator range [`first`, `last`). template * = nullptr> + DisableIfAtLeastForwardIterator = 0> InlinedVector(InputIterator first, InputIterator last, - const allocator_type& alloc = allocator_type()) - : storage_(alloc) { + const allocator_type& allocator = allocator_type()) + : storage_(allocator) { std::copy(first, last, std::back_inserter(*this)); } // Creates an inlined vector by copying the contents of `other` using // `other`'s allocator. InlinedVector(const InlinedVector& other) - : InlinedVector(other, *other.storage_.GetAllocPtr()) {} + : InlinedVector(other, other.storage_.GetAllocator()) {} - // Creates an inlined vector by copying the contents of `other` using `alloc`. - InlinedVector(const InlinedVector& other, const allocator_type& alloc) - : storage_(alloc) { - if (IsMemcpyOk::value && !other.storage_.GetIsAllocated()) { + // Creates an inlined vector by copying the contents of `other` using the + // provided `allocator`. + InlinedVector(const InlinedVector& other, const allocator_type& allocator) + : storage_(allocator) { + if (other.empty()) { + // Empty; nothing to do. + } else if (IsMemcpyOk::value && !other.storage_.GetIsAllocated()) { + // Memcpy-able and do not need allocation. storage_.MemcpyFrom(other.storage_); } else { - storage_.Initialize(IteratorValueAdapter(other.data()), - other.size()); + storage_.InitFrom(other.storage_); } } @@ -192,8 +201,8 @@ class InlinedVector { InlinedVector(InlinedVector&& other) noexcept( absl::allocator_is_nothrow::value || std::is_nothrow_move_constructible::value) - : storage_(*other.storage_.GetAllocPtr()) { - if (IsMemcpyOk::value) { + : storage_(other.storage_.GetAllocator()) { + if (IsMemcpyOk::value) { storage_.MemcpyFrom(other.storage_); other.storage_.SetInlinedSize(0); @@ -204,11 +213,11 @@ class InlinedVector { other.storage_.SetInlinedSize(0); } else { - IteratorValueAdapter other_values( - MoveIterator(other.storage_.GetInlinedData())); + IteratorValueAdapter> other_values( + MoveIterator(other.storage_.GetInlinedData())); - inlined_vector_internal::ConstructElements( - storage_.GetAllocPtr(), storage_.GetInlinedData(), &other_values, + inlined_vector_internal::ConstructElements( + storage_.GetAllocator(), storage_.GetInlinedData(), other_values, other.storage_.GetSize()); storage_.SetInlinedSize(other.storage_.GetSize()); @@ -216,20 +225,22 @@ class InlinedVector { } // Creates an inlined vector by moving in the contents of `other` with a copy - // of `alloc`. + // of `allocator`. // - // NOTE: if `other`'s allocator is not equal to `alloc`, even if `other` + // NOTE: if `other`'s allocator is not equal to `allocator`, even if `other` // contains allocated memory, this move constructor will still allocate. Since // allocation is performed, this constructor can only be `noexcept` if the // specified allocator is also `noexcept`. - InlinedVector(InlinedVector&& other, const allocator_type& alloc) noexcept( - absl::allocator_is_nothrow::value) - : storage_(alloc) { - if (IsMemcpyOk::value) { + InlinedVector( + InlinedVector&& other, + const allocator_type& allocator) + noexcept(absl::allocator_is_nothrow::value) + : storage_(allocator) { + if (IsMemcpyOk::value) { storage_.MemcpyFrom(other.storage_); other.storage_.SetInlinedSize(0); - } else if ((*storage_.GetAllocPtr() == *other.storage_.GetAllocPtr()) && + } else if ((storage_.GetAllocator() == other.storage_.GetAllocator()) && other.storage_.GetIsAllocated()) { storage_.SetAllocatedData(other.storage_.GetAllocatedData(), other.storage_.GetAllocatedCapacity()); @@ -237,9 +248,9 @@ class InlinedVector { other.storage_.SetInlinedSize(0); } else { - storage_.Initialize( - IteratorValueAdapter(MoveIterator(other.data())), - other.size()); + storage_.Initialize(IteratorValueAdapter>( + MoveIterator(other.data())), + other.size()); } } @@ -351,14 +362,14 @@ class InlinedVector { // Returns a `reference` to the first element of the inlined vector. reference front() { ABSL_HARDENING_ASSERT(!empty()); - return at(0); + return data()[0]; } // Overload of `InlinedVector::front()` that returns a `const_reference` to // the first element of the inlined vector. const_reference front() const { ABSL_HARDENING_ASSERT(!empty()); - return at(0); + return data()[0]; } // `InlinedVector::back()` @@ -366,14 +377,14 @@ class InlinedVector { // Returns a `reference` to the last element of the inlined vector. reference back() { ABSL_HARDENING_ASSERT(!empty()); - return at(size() - 1); + return data()[size() - 1]; } // Overload of `InlinedVector::back()` that returns a `const_reference` to the // last element of the inlined vector. const_reference back() const { ABSL_HARDENING_ASSERT(!empty()); - return at(size() - 1); + return data()[size() - 1]; } // `InlinedVector::begin()` @@ -440,7 +451,7 @@ class InlinedVector { // `InlinedVector::get_allocator()` // // Returns a copy of the inlined vector's allocator. - allocator_type get_allocator() const { return *storage_.GetAllocPtr(); } + allocator_type get_allocator() const { return storage_.GetAllocator(); } // --------------------------------------------------------------------------- // InlinedVector Member Mutators @@ -474,16 +485,16 @@ class InlinedVector { // unspecified state. InlinedVector& operator=(InlinedVector&& other) { if (ABSL_PREDICT_TRUE(this != std::addressof(other))) { - if (IsMemcpyOk::value || other.storage_.GetIsAllocated()) { - inlined_vector_internal::DestroyElements(storage_.GetAllocPtr(), data(), - size()); + if (IsMemcpyOk::value || other.storage_.GetIsAllocated()) { + inlined_vector_internal::DestroyElements(storage_.GetAllocator(), + data(), size()); storage_.DeallocateIfAllocated(); storage_.MemcpyFrom(other.storage_); other.storage_.SetInlinedSize(0); } else { - storage_.Assign(IteratorValueAdapter( - MoveIterator(other.storage_.GetInlinedData())), + storage_.Assign(IteratorValueAdapter>( + MoveIterator(other.storage_.GetInlinedData())), other.size()); } } @@ -495,7 +506,7 @@ class InlinedVector { // // Replaces the contents of the inlined vector with `n` copies of `v`. void assign(size_type n, const_reference v) { - storage_.Assign(CopyValueAdapter(v), n); + storage_.Assign(CopyValueAdapter(std::addressof(v)), n); } // Overload of `InlinedVector::assign(...)` that replaces the contents of the @@ -509,9 +520,9 @@ class InlinedVector { // // NOTE: this overload is for iterators that are "forward" category or better. template * = nullptr> + EnableIfAtLeastForwardIterator = 0> void assign(ForwardIterator first, ForwardIterator last) { - storage_.Assign(IteratorValueAdapter(first), + storage_.Assign(IteratorValueAdapter(first), std::distance(first, last)); } @@ -520,11 +531,11 @@ class InlinedVector { // // NOTE: this overload is for iterators that are "input" category. template * = nullptr> + DisableIfAtLeastForwardIterator = 0> void assign(InputIterator first, InputIterator last) { size_type i = 0; for (; i < size() && first != last; ++i, static_cast(++first)) { - at(i) = *first; + data()[i] = *first; } erase(data() + i, data() + size()); @@ -535,9 +546,12 @@ class InlinedVector { // // Resizes the inlined vector to contain `n` elements. // - // NOTE: if `n` is smaller than `size()`, extra elements are destroyed. If `n` + // NOTE: If `n` is smaller than `size()`, extra elements are destroyed. If `n` // is larger than `size()`, new elements are value-initialized. - void resize(size_type n) { storage_.Resize(DefaultValueAdapter(), n); } + void resize(size_type n) { + ABSL_HARDENING_ASSERT(n <= max_size()); + storage_.Resize(DefaultValueAdapter(), n); + } // Overload of `InlinedVector::resize(...)` that resizes the inlined vector to // contain `n` elements. @@ -545,7 +559,8 @@ class InlinedVector { // NOTE: if `n` is smaller than `size()`, extra elements are destroyed. If `n` // is larger than `size()`, new elements are copied-constructed from `v`. void resize(size_type n, const_reference v) { - storage_.Resize(CopyValueAdapter(v), n); + ABSL_HARDENING_ASSERT(n <= max_size()); + storage_.Resize(CopyValueAdapter(std::addressof(v)), n); } // `InlinedVector::insert(...)` @@ -558,7 +573,7 @@ class InlinedVector { // Overload of `InlinedVector::insert(...)` that inserts `v` at `pos` using // move semantics, returning an `iterator` to the newly inserted element. - iterator insert(const_iterator pos, RValueReference v) { + iterator insert(const_iterator pos, value_type&& v) { return emplace(pos, std::move(v)); } @@ -571,7 +586,8 @@ class InlinedVector { if (ABSL_PREDICT_TRUE(n != 0)) { value_type dealias = v; - return storage_.Insert(pos, CopyValueAdapter(dealias), n); + return storage_.Insert(pos, CopyValueAdapter(std::addressof(dealias)), + n); } else { return const_cast(pos); } @@ -590,14 +606,15 @@ class InlinedVector { // // NOTE: this overload is for iterators that are "forward" category or better. template * = nullptr> + EnableIfAtLeastForwardIterator = 0> iterator insert(const_iterator pos, ForwardIterator first, ForwardIterator last) { ABSL_HARDENING_ASSERT(pos >= begin()); ABSL_HARDENING_ASSERT(pos <= end()); if (ABSL_PREDICT_TRUE(first != last)) { - return storage_.Insert(pos, IteratorValueAdapter(first), + return storage_.Insert(pos, + IteratorValueAdapter(first), std::distance(first, last)); } else { return const_cast(pos); @@ -610,7 +627,7 @@ class InlinedVector { // // NOTE: this overload is for iterators that are "input" category. template * = nullptr> + DisableIfAtLeastForwardIterator = 0> iterator insert(const_iterator pos, InputIterator first, InputIterator last) { ABSL_HARDENING_ASSERT(pos >= begin()); ABSL_HARDENING_ASSERT(pos <= end()); @@ -634,8 +651,8 @@ class InlinedVector { value_type dealias(std::forward(args)...); return storage_.Insert(pos, - IteratorValueAdapter( - MoveIterator(std::addressof(dealias))), + IteratorValueAdapter>( + MoveIterator(std::addressof(dealias))), 1); } @@ -655,7 +672,7 @@ class InlinedVector { // Overload of `InlinedVector::push_back(...)` for inserting `v` at `end()` // using move semantics. - void push_back(RValueReference v) { + void push_back(value_type&& v) { static_cast(emplace_back(std::move(v))); } @@ -665,7 +682,7 @@ class InlinedVector { void pop_back() noexcept { ABSL_HARDENING_ASSERT(!empty()); - AllocatorTraits::destroy(*storage_.GetAllocPtr(), data() + (size() - 1)); + AllocatorTraits::destroy(storage_.GetAllocator(), data() + (size() - 1)); storage_.SubtractSize(1); } @@ -704,8 +721,8 @@ class InlinedVector { // Destroys all elements in the inlined vector, setting the size to `0` and // deallocating any held memory. void clear() noexcept { - inlined_vector_internal::DestroyElements(storage_.GetAllocPtr(), data(), - size()); + inlined_vector_internal::DestroyElements(storage_.GetAllocator(), data(), + size()); storage_.DeallocateIfAllocated(); storage_.SetInlinedSize(0); diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/inlined_vector_benchmark.cc b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/inlined_vector_benchmark.cc index b8dafe9323..e256fad60f 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/inlined_vector_benchmark.cc +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/inlined_vector_benchmark.cc @@ -534,6 +534,28 @@ void BM_ConstructFromMove(benchmark::State& state) { ABSL_INTERNAL_BENCHMARK_ONE_SIZE(BM_ConstructFromMove, TrivialType); ABSL_INTERNAL_BENCHMARK_ONE_SIZE(BM_ConstructFromMove, NontrivialType); +// Measure cost of copy-constructor+destructor. +void BM_CopyTrivial(benchmark::State& state) { + const int n = state.range(0); + InlVec src(n); + for (auto s : state) { + InlVec copy(src); + benchmark::DoNotOptimize(copy); + } +} +BENCHMARK(BM_CopyTrivial)->Arg(0)->Arg(1)->Arg(kLargeSize); + +// Measure cost of copy-constructor+destructor. +void BM_CopyNonTrivial(benchmark::State& state) { + const int n = state.range(0); + InlVec> src(n); + for (auto s : state) { + InlVec> copy(src); + benchmark::DoNotOptimize(copy); + } +} +BENCHMARK(BM_CopyNonTrivial)->Arg(0)->Arg(1)->Arg(kLargeSize); + template void BM_AssignSizeRef(benchmark::State& state) { auto size = ToSize; diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/inlined_vector_test.cc b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/inlined_vector_test.cc index 415c60d9f1..98aff33498 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/inlined_vector_test.cc +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/inlined_vector_test.cc @@ -736,22 +736,26 @@ TEST(OverheadTest, Storage) { // In particular, ensure that std::allocator doesn't cost anything to store. // The union should be absorbing some of the allocation bookkeeping overhead // in the larger vectors, leaving only the size_ field as overhead. - EXPECT_EQ(2 * sizeof(int*), - sizeof(absl::InlinedVector) - 1 * sizeof(int*)); - EXPECT_EQ(1 * sizeof(int*), - sizeof(absl::InlinedVector) - 2 * sizeof(int*)); - EXPECT_EQ(1 * sizeof(int*), - sizeof(absl::InlinedVector) - 3 * sizeof(int*)); - EXPECT_EQ(1 * sizeof(int*), - sizeof(absl::InlinedVector) - 4 * sizeof(int*)); - EXPECT_EQ(1 * sizeof(int*), - sizeof(absl::InlinedVector) - 5 * sizeof(int*)); - EXPECT_EQ(1 * sizeof(int*), - sizeof(absl::InlinedVector) - 6 * sizeof(int*)); - EXPECT_EQ(1 * sizeof(int*), - sizeof(absl::InlinedVector) - 7 * sizeof(int*)); - EXPECT_EQ(1 * sizeof(int*), - sizeof(absl::InlinedVector) - 8 * sizeof(int*)); + + struct T { void* val; }; + size_t expected_overhead = sizeof(T); + + EXPECT_EQ((2 * expected_overhead), + sizeof(absl::InlinedVector) - sizeof(T[1])); + EXPECT_EQ(expected_overhead, + sizeof(absl::InlinedVector) - sizeof(T[2])); + EXPECT_EQ(expected_overhead, + sizeof(absl::InlinedVector) - sizeof(T[3])); + EXPECT_EQ(expected_overhead, + sizeof(absl::InlinedVector) - sizeof(T[4])); + EXPECT_EQ(expected_overhead, + sizeof(absl::InlinedVector) - sizeof(T[5])); + EXPECT_EQ(expected_overhead, + sizeof(absl::InlinedVector) - sizeof(T[6])); + EXPECT_EQ(expected_overhead, + sizeof(absl::InlinedVector) - sizeof(T[7])); + EXPECT_EQ(expected_overhead, + sizeof(absl::InlinedVector) - sizeof(T[8])); } TEST(IntVec, Clear) { diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/btree.h b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/btree.h index 4504e9ce66..f636c5fc73 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/btree.h +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/btree.h @@ -88,7 +88,12 @@ struct StringBtreeDefaultLess { // Compatibility constructor. StringBtreeDefaultLess(std::less) {} // NOLINT - StringBtreeDefaultLess(std::less) {} // NOLINT + StringBtreeDefaultLess(std::less) {} // NOLINT + + // Allow converting to std::less for use in key_comp()/value_comp(). + explicit operator std::less() const { return {}; } + explicit operator std::less() const { return {}; } + explicit operator std::less() const { return {}; } absl::weak_ordering operator()(absl::string_view lhs, absl::string_view rhs) const { @@ -115,7 +120,12 @@ struct StringBtreeDefaultGreater { StringBtreeDefaultGreater() = default; StringBtreeDefaultGreater(std::greater) {} // NOLINT - StringBtreeDefaultGreater(std::greater) {} // NOLINT + StringBtreeDefaultGreater(std::greater) {} // NOLINT + + // Allow converting to std::greater for use in key_comp()/value_comp(). + explicit operator std::greater() const { return {}; } + explicit operator std::greater() const { return {}; } + explicit operator std::greater() const { return {}; } absl::weak_ordering operator()(absl::string_view lhs, absl::string_view rhs) const { @@ -137,15 +147,14 @@ struct StringBtreeDefaultGreater { }; // A helper class to convert a boolean comparison into a three-way "compare-to" -// comparison that returns a negative value to indicate less-than, zero to -// indicate equality and a positive value to indicate greater-than. This helper +// comparison that returns an `absl::weak_ordering`. This helper // class is specialized for less, greater, // less, greater, less, and // greater. // // key_compare_to_adapter is provided so that btree users // automatically get the more efficient compare-to code when using common -// google string types with common comparison functors. +// Abseil string types with common comparison functors. // These string-like specializations also turn on heterogeneous lookup by // default. template @@ -183,9 +192,43 @@ struct key_compare_to_adapter> { using type = StringBtreeDefaultGreater; }; +// Detects an 'absl_btree_prefer_linear_node_search' member. This is +// a protocol used as an opt-in or opt-out of linear search. +// +// For example, this would be useful for key types that wrap an integer +// and define their own cheap operator<(). For example: +// +// class K { +// public: +// using absl_btree_prefer_linear_node_search = std::true_type; +// ... +// private: +// friend bool operator<(K a, K b) { return a.k_ < b.k_; } +// int k_; +// }; +// +// btree_map m; // Uses linear search +// +// If T has the preference tag, then it has a preference. +// Btree will use the tag's truth value. +template +struct has_linear_node_search_preference : std::false_type {}; +template +struct prefers_linear_node_search : std::false_type {}; +template +struct has_linear_node_search_preference< + T, absl::void_t> + : std::true_type {}; +template +struct prefers_linear_node_search< + T, absl::void_t> + : T::absl_btree_prefer_linear_node_search {}; + template struct common_params { + using original_key_compare = Compare; + // If Compare is a common comparator for a string-like type, then we adapt it // to use heterogeneous lookup and to be a key-compare-to comparator. using key_compare = typename key_compare_to_adapter::type; @@ -198,9 +241,6 @@ struct common_params { using size_type = std::make_signed::type; using difference_type = ptrdiff_t; - // True if this is a multiset or multimap. - using is_multi_container = std::integral_constant; - using slot_policy = SlotPolicy; using slot_type = typename slot_policy::slot_type; using value_type = typename slot_policy::value_type; @@ -210,6 +250,23 @@ struct common_params { using reference = value_type &; using const_reference = const value_type &; + // For the given lookup key type, returns whether we can have multiple + // equivalent keys in the btree. If this is a multi-container, then we can. + // Otherwise, we can have multiple equivalent keys only if all of the + // following conditions are met: + // - The comparator is transparent. + // - The lookup key type is not the same as key_type. + // - The comparator is not a StringBtreeDefault{Less,Greater} comparator + // that we know has the same equivalence classes for all lookup types. + template + constexpr static bool can_have_multiple_equivalent_keys() { + return Multi || + (IsTransparent::value && + !std::is_same::value && + !std::is_same::value && + !std::is_same::value); + } + enum { kTargetNodeSize = TargetNodeSize, @@ -255,10 +312,6 @@ struct common_params { static void move(Alloc *alloc, slot_type *src, slot_type *dest) { slot_policy::move(alloc, src, dest); } - static void move(Alloc *alloc, slot_type *first, slot_type *last, - slot_type *result) { - slot_policy::move(alloc, first, last, result); - } }; // A parameters structure for holding the type parameters for a btree_map. @@ -276,23 +329,36 @@ struct map_params : common_params + friend class btree; - template - auto operator()(const T &left, const U &right) const - -> decltype(std::declval()(left.first, right.first)) { - return key_compare::operator()(left.first, right.first); + protected: + explicit value_compare(original_key_compare c) : comp(std::move(c)) {} + + original_key_compare comp; // NOLINT + + public: + auto operator()(const value_type &lhs, const value_type &rhs) const + -> decltype(comp(lhs.first, rhs.first)) { + return comp(lhs.first, rhs.first); } }; using is_map_container = std::true_type; - static const Key &key(const value_type &value) { return value.first; } - static const Key &key(const init_type &init) { return init.first; } + template + static auto key(const V &value) -> decltype(value.first) { + return value.first; + } static const Key &key(const slot_type *s) { return slot_policy::key(s); } + static const Key &key(slot_type *s) { return slot_policy::key(s); } + // For use in node handle. + static auto mutable_key(slot_type *s) + -> decltype(slot_policy::mutable_key(s)) { + return slot_policy::mutable_key(s); + } static mapped_type &value(value_type *value) { return value->second; } }; @@ -333,13 +399,6 @@ struct set_slot_policy { static void move(Alloc * /*alloc*/, slot_type *src, slot_type *dest) { *dest = std::move(*src); } - - template - static void move(Alloc *alloc, slot_type *first, slot_type *last, - slot_type *result) { - for (slot_type *src = first, *dest = result; src != last; ++src, ++dest) - move(alloc, src, dest); - } }; // A parameters structure for holding the type parameters for a btree_set. @@ -350,11 +409,14 @@ struct set_params : common_params> { using value_type = Key; using slot_type = typename set_params::common_params::slot_type; - using value_compare = typename set_params::common_params::key_compare; + using value_compare = + typename set_params::common_params::original_key_compare; using is_map_container = std::false_type; - static const Key &key(const value_type &value) { return value; } + template + static const V &key(const V &value) { return value; } static const Key &key(const slot_type *slot) { return *slot; } + static const Key &key(slot_type *slot) { return *slot; } }; // An adapter class that converts a lower-bound compare into an upper-bound @@ -390,6 +452,10 @@ struct SearchResult { // useful information. template struct SearchResult { + SearchResult() {} + explicit SearchResult(V value) : value(value) {} + SearchResult(V value, MatchKind /*match*/) : value(value) {} + V value; static constexpr bool HasMatch() { return false; } @@ -402,7 +468,6 @@ struct SearchResult { template class btree_node { using is_key_compare_to = typename Params::is_key_compare_to; - using is_multi_container = typename Params::is_multi_container; using field_type = typename Params::node_count_type; using allocator_type = typename Params::allocator_type; using slot_type = typename Params::slot_type; @@ -420,18 +485,25 @@ class btree_node { using difference_type = typename Params::difference_type; // Btree decides whether to use linear node search as follows: + // - If the comparator expresses a preference, use that. + // - If the key expresses a preference, use that. // - If the key is arithmetic and the comparator is std::less or // std::greater, choose linear. // - Otherwise, choose binary. // TODO(ezb): Might make sense to add condition(s) based on node-size. using use_linear_search = std::integral_constant< bool, - std::is_arithmetic::value && - (std::is_same, key_compare>::value || - std::is_same, key_compare>::value)>; + has_linear_node_search_preference::value + ? prefers_linear_node_search::value + : has_linear_node_search_preference::value + ? prefers_linear_node_search::value + : std::is_arithmetic::value && + (std::is_same, key_compare>::value || + std::is_same, + key_compare>::value)>; - // This class is organized by gtl::Layout as if it had the following - // structure: + // This class is organized by absl::container_internal::Layout as if it had + // the following structure: // // A pointer to the node's parent. // btree_node *parent; // @@ -445,23 +517,23 @@ class btree_node { // // is the same as the count of values. // field_type finish; // // The maximum number of values the node can hold. This is an integer in - // // [1, kNodeValues] for root leaf nodes, kNodeValues for non-root leaf + // // [1, kNodeSlots] for root leaf nodes, kNodeSlots for non-root leaf // // nodes, and kInternalNodeMaxCount (as a sentinel value) for internal - // // nodes (even though there are still kNodeValues values in the node). + // // nodes (even though there are still kNodeSlots values in the node). // // TODO(ezb): make max_count use only 4 bits and record log2(capacity) // // to free extra bits for is_root, etc. // field_type max_count; // // // The array of values. The capacity is `max_count` for leaf nodes and - // // kNodeValues for internal nodes. Only the values in + // // kNodeSlots for internal nodes. Only the values in // // [start, finish) have been initialized and are valid. // slot_type values[max_count]; // // // The array of child pointers. The keys in children[i] are all less // // than key(i). The keys in children[i + 1] are all greater than key(i). - // // There are 0 children for leaf nodes and kNodeValues + 1 children for + // // There are 0 children for leaf nodes and kNodeSlots + 1 children for // // internal nodes. - // btree_node *children[kNodeValues + 1]; + // btree_node *children[kNodeSlots + 1]; // // This class is only constructed by EmptyNodeType. Normally, pointers to the // layout above are allocated, cast to btree_node*, and de-allocated within @@ -483,57 +555,62 @@ class btree_node { private: using layout_type = absl::container_internal::Layout; - constexpr static size_type SizeWithNValues(size_type n) { + constexpr static size_type SizeWithNSlots(size_type n) { return layout_type(/*parent*/ 1, /*position, start, finish, max_count*/ 4, - /*values*/ n, + /*slots*/ n, /*children*/ 0) .AllocSize(); } // A lower bound for the overhead of fields other than values in a leaf node. constexpr static size_type MinimumOverhead() { - return SizeWithNValues(1) - sizeof(value_type); + return SizeWithNSlots(1) - sizeof(value_type); } // Compute how many values we can fit onto a leaf node taking into account // padding. - constexpr static size_type NodeTargetValues(const int begin, const int end) { + constexpr static size_type NodeTargetSlots(const int begin, const int end) { return begin == end ? begin - : SizeWithNValues((begin + end) / 2 + 1) > + : SizeWithNSlots((begin + end) / 2 + 1) > params_type::kTargetNodeSize - ? NodeTargetValues(begin, (begin + end) / 2) - : NodeTargetValues((begin + end) / 2 + 1, end); + ? NodeTargetSlots(begin, (begin + end) / 2) + : NodeTargetSlots((begin + end) / 2 + 1, end); } enum { kTargetNodeSize = params_type::kTargetNodeSize, - kNodeTargetValues = NodeTargetValues(0, params_type::kTargetNodeSize), + kNodeTargetSlots = NodeTargetSlots(0, params_type::kTargetNodeSize), - // We need a minimum of 3 values per internal node in order to perform + // We need a minimum of 3 slots per internal node in order to perform // splitting (1 value for the two nodes involved in the split and 1 value - // propagated to the parent as the delimiter for the split). - kNodeValues = kNodeTargetValues >= 3 ? kNodeTargetValues : 3, + // propagated to the parent as the delimiter for the split). For performance + // reasons, we don't allow 3 slots-per-node due to bad worst case occupancy + // of 1/3 (for a node, not a b-tree). + kMinNodeSlots = 4, + + kNodeSlots = + kNodeTargetSlots >= kMinNodeSlots ? kNodeTargetSlots : kMinNodeSlots, // The node is internal (i.e. is not a leaf node) if and only if `max_count` // has this value. kInternalNodeMaxCount = 0, }; - // Leaves can have less than kNodeValues values. - constexpr static layout_type LeafLayout(const int max_values = kNodeValues) { + // Leaves can have less than kNodeSlots values. + constexpr static layout_type LeafLayout(const int slot_count = kNodeSlots) { return layout_type(/*parent*/ 1, /*position, start, finish, max_count*/ 4, - /*values*/ max_values, + /*slots*/ slot_count, /*children*/ 0); } constexpr static layout_type InternalLayout() { return layout_type(/*parent*/ 1, /*position, start, finish, max_count*/ 4, - /*values*/ kNodeValues, - /*children*/ kNodeValues + 1); + /*slots*/ kNodeSlots, + /*children*/ kNodeSlots + 1); } - constexpr static size_type LeafSize(const int max_values = kNodeValues) { - return LeafLayout(max_values).AllocSize(); + constexpr static size_type LeafSize(const int slot_count = kNodeSlots) { + return LeafLayout(slot_count).AllocSize(); } constexpr static size_type InternalSize() { return InternalLayout().AllocSize(); @@ -590,10 +667,10 @@ class btree_node { } field_type max_count() const { // Internal nodes have max_count==kInternalNodeMaxCount. - // Leaf nodes have max_count in [1, kNodeValues]. + // Leaf nodes have max_count in [1, kNodeSlots]. const field_type max_count = GetField<1>()[3]; return max_count == field_type{kInternalNodeMaxCount} - ? field_type{kNodeValues} + ? field_type{kNodeSlots} : max_count; } @@ -671,7 +748,7 @@ class btree_node { } ++s; } - return {s}; + return SearchResult{s}; } // Returns the position of the first value whose key is not less than k using @@ -706,7 +783,7 @@ class btree_node { e = mid; } } - return {s}; + return SearchResult{s}; } // Returns the position of the first value whose key is not less than k using @@ -715,7 +792,7 @@ class btree_node { SearchResult binary_search_impl( const K &k, int s, int e, const CompareTo &comp, std::true_type /* IsCompareTo */) const { - if (is_multi_container::value) { + if (params_type::template can_have_multiple_equivalent_keys()) { MatchKind exact_match = MatchKind::kNe; while (s != e) { const int mid = (s + e) >> 1; @@ -726,14 +803,14 @@ class btree_node { e = mid; if (c == 0) { // Need to return the first value whose key is not less than k, - // which requires continuing the binary search if this is a - // multi-container. + // which requires continuing the binary search if there could be + // multiple equivalent keys. exact_match = MatchKind::kEq; } } } return {s, exact_match}; - } else { // Not a multi-container. + } else { // Can't have multiple equivalent keys. while (s != e) { const int mid = (s + e) >> 1; const absl::weak_ordering c = comp(key(mid), k); @@ -754,14 +831,10 @@ class btree_node { template void emplace_value(size_type i, allocator_type *alloc, Args &&... args); - // Removes the value at position i, shifting all existing values and children - // at positions > i to the left by 1. - void remove_value(int i, allocator_type *alloc); - - // Removes the values at positions [i, i + to_erase), shifting all values - // after that range to the left by to_erase. Does not change children at all. - void remove_values_ignore_children(int i, int to_erase, - allocator_type *alloc); + // Removes the values at positions [i, i + to_erase), shifting all existing + // values and children after that range to the left by to_erase. Clears all + // children between [i, i + to_erase). + void remove_values(field_type i, field_type to_erase, allocator_type *alloc); // Rebalances a node with its right sibling. void rebalance_right_to_left(int to_move, btree_node *right, @@ -773,7 +846,7 @@ class btree_node { void split(int insert_position, btree_node *dest, allocator_type *alloc); // Merges a node with its right sibling, moving all of the values and the - // delimiting key in the parent node onto itself. + // delimiting key in the parent node onto itself, and deleting the src node. void merge(btree_node *src, allocator_type *alloc); // Node allocation/deletion routines. @@ -787,62 +860,73 @@ class btree_node { start_slot(), max_count * sizeof(slot_type)); } void init_internal(btree_node *parent) { - init_leaf(parent, kNodeValues); + init_leaf(parent, kNodeSlots); // Set `max_count` to a sentinel value to indicate that this node is // internal. set_max_count(kInternalNodeMaxCount); absl::container_internal::SanitizerPoisonMemoryRegion( - &mutable_child(start()), (kNodeValues + 1) * sizeof(btree_node *)); - } - void destroy(allocator_type *alloc) { - for (int i = start(); i < finish(); ++i) { - value_destroy(i, alloc); - } + &mutable_child(start()), (kNodeSlots + 1) * sizeof(btree_node *)); } - public: - // Exposed only for tests. - static bool testonly_uses_linear_node_search() { - return use_linear_search::value; + static void deallocate(const size_type size, btree_node *node, + allocator_type *alloc) { + absl::container_internal::Deallocate(alloc, node, size); } + // Deletes a node and all of its children. + static void clear_and_delete(btree_node *node, allocator_type *alloc); + private: template - void value_init(const size_type i, allocator_type *alloc, Args &&... args) { + void value_init(const field_type i, allocator_type *alloc, Args &&... args) { absl::container_internal::SanitizerUnpoisonObject(slot(i)); params_type::construct(alloc, slot(i), std::forward(args)...); } - void value_destroy(const size_type i, allocator_type *alloc) { + void value_destroy(const field_type i, allocator_type *alloc) { params_type::destroy(alloc, slot(i)); absl::container_internal::SanitizerPoisonObject(slot(i)); } - - // Transfers value from slot `src_i` in `src` to slot `dest_i` in `this`. - void transfer(const size_type dest_i, const size_type src_i, btree_node *src, - allocator_type *alloc) { - absl::container_internal::SanitizerUnpoisonObject(slot(dest_i)); - params_type::transfer(alloc, slot(dest_i), src->slot(src_i)); - absl::container_internal::SanitizerPoisonObject(src->slot(src_i)); - } - - // Move n values starting at value i in this node into the values starting at - // value j in dest_node. - void uninitialized_move_n(const size_type n, const size_type i, - const size_type j, btree_node *dest_node, - allocator_type *alloc) { - absl::container_internal::SanitizerUnpoisonMemoryRegion( - dest_node->slot(j), n * sizeof(slot_type)); - for (slot_type *src = slot(i), *end = src + n, *dest = dest_node->slot(j); - src != end; ++src, ++dest) { - params_type::construct(alloc, dest, src); + void value_destroy_n(const field_type i, const field_type n, + allocator_type *alloc) { + for (slot_type *s = slot(i), *end = slot(i + n); s != end; ++s) { + params_type::destroy(alloc, s); + absl::container_internal::SanitizerPoisonObject(s); } } - // Destroys a range of n values, starting at index i. - void value_destroy_n(const size_type i, const size_type n, - allocator_type *alloc) { - for (int j = 0; j < n; ++j) { - value_destroy(i + j, alloc); + static void transfer(slot_type *dest, slot_type *src, allocator_type *alloc) { + absl::container_internal::SanitizerUnpoisonObject(dest); + params_type::transfer(alloc, dest, src); + absl::container_internal::SanitizerPoisonObject(src); + } + + // Transfers value from slot `src_i` in `src_node` to slot `dest_i` in `this`. + void transfer(const size_type dest_i, const size_type src_i, + btree_node *src_node, allocator_type *alloc) { + transfer(slot(dest_i), src_node->slot(src_i), alloc); + } + + // Transfers `n` values starting at value `src_i` in `src_node` into the + // values starting at value `dest_i` in `this`. + void transfer_n(const size_type n, const size_type dest_i, + const size_type src_i, btree_node *src_node, + allocator_type *alloc) { + for (slot_type *src = src_node->slot(src_i), *end = src + n, + *dest = slot(dest_i); + src != end; ++src, ++dest) { + transfer(dest, src, alloc); + } + } + + // Same as above, except that we start at the end and work our way to the + // beginning. + void transfer_n_backward(const size_type n, const size_type dest_i, + const size_type src_i, btree_node *src_node, + allocator_type *alloc) { + for (slot_type *src = src_node->slot(src_i + n - 1), *end = src - n, + *dest = slot(dest_i + n - 1); + src != end; --src, --dest) { + transfer(dest, src, alloc); } } @@ -859,6 +943,7 @@ struct btree_iterator { using key_type = typename Node::key_type; using size_type = typename Node::size_type; using params_type = typename Node::params_type; + using is_map_container = typename params_type::is_map_container; using node_type = Node; using normal_node = typename std::remove_const::type; @@ -870,7 +955,7 @@ struct btree_iterator { using slot_type = typename params_type::slot_type; using iterator = - btree_iterator; + btree_iterator; using const_iterator = btree_iterator; @@ -887,20 +972,19 @@ struct btree_iterator { btree_iterator(Node *n, int p) : node(n), position(p) {} // NOTE: this SFINAE allows for implicit conversions from iterator to - // const_iterator, but it specifically avoids defining copy constructors so - // that btree_iterator can be trivially copyable. This is for performance and - // binary size reasons. + // const_iterator, but it specifically avoids hiding the copy constructor so + // that the trivial one will be used when possible. template , iterator>::value && std::is_same::value, int> = 0> - btree_iterator(const btree_iterator &other) // NOLINT + btree_iterator(const btree_iterator other) // NOLINT : node(other.node), position(other.position) {} private: // This SFINAE allows explicit conversions from const_iterator to - // iterator, but also avoids defining a copy constructor. + // iterator, but also avoids hiding the copy constructor. // NOTE: the const_cast is safe because this constructor is only called by // non-const methods and the container owns the nodes. template , const_iterator>::value && std::is_same::value, int> = 0> - explicit btree_iterator(const btree_iterator &other) + explicit btree_iterator(const btree_iterator other) : node(const_cast(other.node)), position(other.position) {} // Increment/decrement the iterator. @@ -929,9 +1013,15 @@ struct btree_iterator { void decrement_slow(); public: + bool operator==(const iterator &other) const { + return node == other.node && position == other.position; + } bool operator==(const const_iterator &other) const { return node == other.node && position == other.position; } + bool operator!=(const iterator &other) const { + return node != other.node || position != other.position; + } bool operator!=(const const_iterator &other) const { return node != other.node || position != other.position; } @@ -965,6 +1055,8 @@ struct btree_iterator { } private: + friend iterator; + friend const_iterator; template friend class btree; template @@ -975,8 +1067,6 @@ struct btree_iterator { friend class btree_map_container; template friend class btree_multiset_container; - template - friend struct btree_iterator; template friend class base_checker; @@ -995,6 +1085,8 @@ template class btree { using node_type = btree_node; using is_key_compare_to = typename Params::is_key_compare_to; + using init_type = typename Params::init_type; + using field_type = typename node_type::field_type; // We use a static empty node for the root/leftmost/rightmost of empty btrees // in order to avoid branching in begin()/end(). @@ -1029,9 +1121,9 @@ class btree { #endif } - enum { - kNodeValues = node_type::kNodeValues, - kMinNodeValues = kNodeValues / 2, + enum : uint32_t { + kNodeSlots = node_type::kNodeSlots, + kMinNodeValues = kNodeSlots / 2, }; struct node_stats { @@ -1055,13 +1147,15 @@ class btree { using size_type = typename Params::size_type; using difference_type = typename Params::difference_type; using key_compare = typename Params::key_compare; + using original_key_compare = typename Params::original_key_compare; using value_compare = typename Params::value_compare; using allocator_type = typename Params::allocator_type; using reference = typename Params::reference; using const_reference = typename Params::const_reference; using pointer = typename Params::pointer; using const_pointer = typename Params::const_pointer; - using iterator = btree_iterator; + using iterator = + typename btree_iterator::iterator; using const_iterator = typename iterator::const_iterator; using reverse_iterator = std::reverse_iterator; using const_reverse_iterator = std::reverse_iterator; @@ -1074,28 +1168,46 @@ class btree { private: // For use in copy_or_move_values_in_order. const value_type &maybe_move_from_iterator(const_iterator it) { return *it; } - value_type &&maybe_move_from_iterator(iterator it) { return std::move(*it); } + value_type &&maybe_move_from_iterator(iterator it) { + // This is a destructive operation on the other container so it's safe for + // us to const_cast and move from the keys here even if it's a set. + return std::move(const_cast(*it)); + } // Copies or moves (depending on the template parameter) the values in // other into this btree in their order in other. This btree must be empty // before this method is called. This method is used in copy construction, // copy assignment, and move assignment. template - void copy_or_move_values_in_order(Btree *other); + void copy_or_move_values_in_order(Btree &other); // Validates that various assumptions/requirements are true at compile time. constexpr static bool static_assert_validation(); public: - btree(const key_compare &comp, const allocator_type &alloc); + btree(const key_compare &comp, const allocator_type &alloc) + : root_(comp, alloc, EmptyNode()), rightmost_(EmptyNode()), size_(0) {} - btree(const btree &other); + btree(const btree &other) : btree(other, other.allocator()) {} + btree(const btree &other, const allocator_type &alloc) + : btree(other.key_comp(), alloc) { + copy_or_move_values_in_order(other); + } btree(btree &&other) noexcept : root_(std::move(other.root_)), rightmost_(absl::exchange(other.rightmost_, EmptyNode())), size_(absl::exchange(other.size_, 0)) { other.mutable_root() = EmptyNode(); } + btree(btree &&other, const allocator_type &alloc) + : btree(other.key_comp(), alloc) { + if (alloc == other.allocator()) { + swap(other); + } else { + // Move values from `other` one at a time when allocators are different. + copy_or_move_values_in_order(other); + } + } ~btree() { // Put static_asserts in destructor to avoid triggering them before the type @@ -1123,17 +1235,22 @@ class btree { return const_reverse_iterator(begin()); } - // Finds the first element whose key is not less than key. + // Finds the first element whose key is not less than `key`. template iterator lower_bound(const K &key) { - return internal_end(internal_lower_bound(key)); + return internal_end(internal_lower_bound(key).value); } template const_iterator lower_bound(const K &key) const { - return internal_end(internal_lower_bound(key)); + return internal_end(internal_lower_bound(key).value); } - // Finds the first element whose key is greater than key. + // Finds the first element whose key is not less than `key` and also returns + // whether that element is equal to `key`. + template + std::pair lower_bound_equal(const K &key) const; + + // Finds the first element whose key is greater than `key`. template iterator upper_bound(const K &key) { return internal_end(internal_upper_bound(key)); @@ -1144,23 +1261,21 @@ class btree { } // Finds the range of values which compare equal to key. The first member of - // the returned pair is equal to lower_bound(key). The second member pair of - // the pair is equal to upper_bound(key). + // the returned pair is equal to lower_bound(key). The second member of the + // pair is equal to upper_bound(key). template - std::pair equal_range(const K &key) { - return {lower_bound(key), upper_bound(key)}; - } + std::pair equal_range(const K &key); template std::pair equal_range(const K &key) const { - return {lower_bound(key), upper_bound(key)}; + return const_cast(this)->equal_range(key); } // Inserts a value into the btree only if it does not already exist. The // boolean return value indicates whether insertion succeeded or failed. // Requirement: if `key` already exists in the btree, does not consume `args`. // Requirement: `key` is never referenced after consuming `args`. - template - std::pair insert_unique(const key_type &key, Args &&... args); + template + std::pair insert_unique(const K &key, Args &&... args); // Inserts with hint. Checks to see if the value should be placed immediately // before `position` in the tree. If so, then the insertion will take @@ -1168,14 +1283,23 @@ class btree { // logarithmic time as if a call to insert_unique() were made. // Requirement: if `key` already exists in the btree, does not consume `args`. // Requirement: `key` is never referenced after consuming `args`. - template + template std::pair insert_hint_unique(iterator position, - const key_type &key, + const K &key, Args &&... args); // Insert a range of values into the btree. + // Note: the first overload avoids constructing a value_type if the key + // already exists in the btree. + template ()( + params_type::key(*std::declval()), + std::declval()))> + void insert_iterator_unique(InputIterator b, InputIterator e, int); + // We need the second overload for cases in which we need to construct a + // value_type in order to compare it with the keys already in the btree. template - void insert_iterator_unique(InputIterator b, InputIterator e); + void insert_iterator_unique(InputIterator b, InputIterator e, char); // Inserts a value into the btree. template @@ -1208,18 +1332,8 @@ class btree { // to the element after the last erased element. std::pair erase_range(iterator begin, iterator end); - // Erases the specified key from the btree. Returns 1 if an element was - // erased and 0 otherwise. - template - size_type erase_unique(const K &key); - - // Erases all of the entries matching the specified key from the - // btree. Returns the number of elements erased. - template - size_type erase_multi(const K &key); - - // Finds the iterator corresponding to a key or returns end() if the key is - // not present. + // Finds an element with key equivalent to `key` or returns `end()` if `key` + // is not present. template iterator find(const K &key) { return internal_end(internal_find(key)); @@ -1229,23 +1343,6 @@ class btree { return internal_end(internal_find(key)); } - // Returns a count of the number of times the key appears in the btree. - template - size_type count_unique(const K &key) const { - const iterator begin = internal_find(key); - if (begin.node == nullptr) { - // The key doesn't exist in the tree. - return 0; - } - return 1; - } - // Returns a count of the number of times the key appears in the btree. - template - size_type count_multi(const K &key) const { - const auto range = equal_range(key); - return std::distance(range.first, range.second); - } - // Clear the btree, deleting all of the values it contains. void clear(); @@ -1260,7 +1357,9 @@ class btree { return compare_internal::compare_result_as_less_than(key_comp()(a, b)); } - value_compare value_comp() const { return value_compare(key_comp()); } + value_compare value_comp() const { + return value_compare(original_key_compare(key_comp())); + } // Verifies the structure of the btree. void verify() const; @@ -1308,12 +1407,14 @@ class btree { } } - // The average number of bytes used per value stored in the btree. + // The average number of bytes used per value stored in the btree assuming + // random insertion order. static double average_bytes_per_value() { - // Returns the number of bytes per value on a leaf node that is 75% - // full. Experimentally, this matches up nicely with the computed number of - // bytes per value in trees that had their values inserted in random order. - return node_type::LeafSize() / (kNodeValues * 0.75); + // The expected number of values per node with random insertion order is the + // average of the maximum and minimum numbers of values per node. + const double expected_values_per_node = + (kNodeSlots + kMinNodeValues) / 2.0; + return node_type::LeafSize() / expected_values_per_node; } // The fullness of the btree. Computed as the number of elements in the btree @@ -1323,7 +1424,7 @@ class btree { // Returns 0 for empty trees. double fullness() const { if (empty()) return 0.0; - return static_cast(size()) / (nodes() * kNodeValues); + return static_cast(size()) / (nodes() * kNodeSlots); } // The overhead of the btree structure in bytes per node. Computed as the // total number of bytes used by the btree minus the number of bytes used for @@ -1373,7 +1474,7 @@ class btree { } node_type *new_leaf_node(node_type *parent) { node_type *n = allocate(node_type::LeafSize()); - n->init_leaf(parent, kNodeValues); + n->init_leaf(parent, kNodeSlots); return n; } node_type *new_leaf_root_node(const int max_count) { @@ -1383,25 +1484,8 @@ class btree { } // Deletion helper routines. - void erase_same_node(iterator begin, iterator end); - iterator erase_from_leaf_node(iterator begin, size_type to_erase); iterator rebalance_after_delete(iterator iter); - // Deallocates a node of a certain size in bytes using the allocator. - void deallocate(const size_type size, node_type *node) { - absl::container_internal::Deallocate( - mutable_allocator(), node, size); - } - - void delete_internal_node(node_type *node) { - node->destroy(mutable_allocator()); - deallocate(node_type::InternalSize(), node); - } - void delete_leaf_node(node_type *node) { - node->destroy(mutable_allocator()); - deallocate(node_type::LeafSize(node->max_count()), node); - } - // Rebalances or splits the node iter points to. void rebalance_or_split(iterator *iter); @@ -1439,28 +1523,19 @@ class btree { static IterType internal_last(IterType iter); // Returns an iterator pointing to the leaf position at which key would - // reside in the tree. We provide 2 versions of internal_locate. The first - // version uses a less-than comparator and is incapable of distinguishing when - // there is an exact match. The second version is for the key-compare-to - // specialization and distinguishes exact matches. The key-compare-to - // specialization allows the caller to avoid a subsequent comparison to - // determine if an exact match was made, which is important for keys with - // expensive comparison, such as strings. + // reside in the tree, unless there is an exact match - in which case, the + // result may not be on a leaf. When there's a three-way comparator, we can + // return whether there was an exact match. This allows the caller to avoid a + // subsequent comparison to determine if an exact match was made, which is + // important for keys with expensive comparison, such as strings. template SearchResult internal_locate( const K &key) const; - template - SearchResult internal_locate_impl( - const K &key, std::false_type /* IsCompareTo */) const; - - template - SearchResult internal_locate_impl( - const K &key, std::true_type /* IsCompareTo */) const; - // Internal routine which implements lower_bound(). template - iterator internal_lower_bound(const K &key) const; + SearchResult internal_lower_bound( + const K &key) const; // Internal routine which implements upper_bound(). template @@ -1470,9 +1545,6 @@ class btree { template iterator internal_find(const K &key) const; - // Deletes a node and all of its children. - void internal_clear(node_type *node); - // Verifies the tree structure of node. int internal_verify(const node_type *node, const key_type *lo, const key_type *hi) const; @@ -1492,13 +1564,6 @@ class btree { return res; } - public: - // Exposed only for tests. - static bool testonly_uses_linear_node_search() { - return node_type::testonly_uses_linear_node_search(); - } - - private: // We use compressed tuple in order to save space because key_compare and // allocator_type are usually empty. absl::container_internal::CompressedTuple::emplace_value(const size_type i, // Shift old values to create space for new value and then construct it in // place. if (i < finish()) { - value_init(finish(), alloc, slot(finish() - 1)); - for (size_type j = finish() - 1; j > i; --j) - params_type::move(alloc, slot(j - 1), slot(j)); - value_destroy(i, alloc); + transfer_n_backward(finish() - i, /*dest_i=*/i + 1, /*src_i=*/i, this, + alloc); } value_init(i, alloc, std::forward(args)...); set_finish(finish() + 1); @@ -1542,24 +1605,27 @@ inline void btree_node

::emplace_value(const size_type i, } template -inline void btree_node

::remove_value(const int i, allocator_type *alloc) { - if (!leaf() && finish() > i + 1) { - assert(child(i + 1)->count() == 0); - for (size_type j = i + 1; j < finish(); ++j) { - set_child(j, child(j + 1)); +inline void btree_node

::remove_values(const field_type i, + const field_type to_erase, + allocator_type *alloc) { + // Transfer values after the removed range into their new places. + value_destroy_n(i, to_erase, alloc); + const field_type orig_finish = finish(); + const field_type src_i = i + to_erase; + transfer_n(orig_finish - src_i, i, src_i, this, alloc); + + if (!leaf()) { + // Delete all children between begin and end. + for (int j = 0; j < to_erase; ++j) { + clear_and_delete(child(i + j + 1), alloc); + } + // Rotate children after end into new positions. + for (int j = i + to_erase + 1; j <= orig_finish; ++j) { + set_child(j - to_erase, child(j)); + clear_child(j); } - clear_child(finish()); } - - remove_values_ignore_children(i, /*to_erase=*/1, alloc); -} - -template -inline void btree_node

::remove_values_ignore_children( - const int i, const int to_erase, allocator_type *alloc) { - params_type::move(alloc, slot(i + to_erase), finish_slot(), slot(i)); - value_destroy_n(finish() - to_erase, to_erase, alloc); - set_finish(finish() - to_erase); + set_finish(orig_finish - to_erase); } template @@ -1573,22 +1639,17 @@ void btree_node

::rebalance_right_to_left(const int to_move, assert(to_move <= right->count()); // 1) Move the delimiting value in the parent to the left node. - value_init(finish(), alloc, parent()->slot(position())); + transfer(finish(), position(), parent(), alloc); // 2) Move the (to_move - 1) values from the right node to the left node. - right->uninitialized_move_n(to_move - 1, right->start(), finish() + 1, this, - alloc); + transfer_n(to_move - 1, finish() + 1, right->start(), right, alloc); // 3) Move the new delimiting value to the parent from the right node. - params_type::move(alloc, right->slot(to_move - 1), - parent()->slot(position())); + parent()->transfer(position(), right->start() + to_move - 1, right, alloc); - // 4) Shift the values in the right node to their correct position. - params_type::move(alloc, right->slot(to_move), right->finish_slot(), - right->start_slot()); - - // 5) Destroy the now-empty to_move entries in the right node. - right->value_destroy_n(right->finish() - to_move, to_move, alloc); + // 4) Shift the values in the right node to their correct positions. + right->transfer_n(right->count() - to_move, right->start(), + right->start() + to_move, right, alloc); if (!leaf()) { // Move the child pointers from the right to the left node. @@ -1623,54 +1684,19 @@ void btree_node

::rebalance_left_to_right(const int to_move, // Lastly, a new delimiting value is moved from the left node into the // parent, and the remaining empty left node entries are destroyed. - if (right->count() >= to_move) { - // The original location of the right->count() values are sufficient to hold - // the new to_move entries from the parent and left node. + // 1) Shift existing values in the right node to their correct positions. + right->transfer_n_backward(right->count(), right->start() + to_move, + right->start(), right, alloc); - // 1) Shift existing values in the right node to their correct positions. - right->uninitialized_move_n(to_move, right->finish() - to_move, - right->finish(), right, alloc); - for (slot_type *src = right->slot(right->finish() - to_move - 1), - *dest = right->slot(right->finish() - 1), - *end = right->start_slot(); - src >= end; --src, --dest) { - params_type::move(alloc, src, dest); - } + // 2) Move the delimiting value in the parent to the right node. + right->transfer(right->start() + to_move - 1, position(), parent(), alloc); - // 2) Move the delimiting value in the parent to the right node. - params_type::move(alloc, parent()->slot(position()), - right->slot(to_move - 1)); - - // 3) Move the (to_move - 1) values from the left node to the right node. - params_type::move(alloc, slot(finish() - (to_move - 1)), finish_slot(), - right->start_slot()); - } else { - // The right node does not have enough initialized space to hold the new - // to_move entries, so part of them will move to uninitialized space. - - // 1) Shift existing values in the right node to their correct positions. - right->uninitialized_move_n(right->count(), right->start(), - right->start() + to_move, right, alloc); - - // 2) Move the delimiting value in the parent to the right node. - right->value_init(to_move - 1, alloc, parent()->slot(position())); - - // 3) Move the (to_move - 1) values from the left node to the right node. - const size_type uninitialized_remaining = to_move - right->count() - 1; - uninitialized_move_n(uninitialized_remaining, - finish() - uninitialized_remaining, right->finish(), - right, alloc); - params_type::move(alloc, slot(finish() - (to_move - 1)), - slot(finish() - uninitialized_remaining), - right->start_slot()); - } + // 3) Move the (to_move - 1) values from the left node to the right node. + right->transfer_n(to_move - 1, right->start(), finish() - (to_move - 1), this, + alloc); // 4) Move the new delimiting value to the parent from the left node. - params_type::move(alloc, slot(finish() - to_move), - parent()->slot(position())); - - // 5) Destroy the now-empty to_move entries in the left node. - value_destroy_n(finish() - to_move, to_move, alloc); + parent()->transfer(position(), finish() - to_move, this, alloc); if (!leaf()) { // Move the child pointers from the left to the right node. @@ -1693,7 +1719,7 @@ template void btree_node

::split(const int insert_position, btree_node *dest, allocator_type *alloc) { assert(dest->count() == 0); - assert(max_count() == kNodeValues); + assert(max_count() == kNodeSlots); // We bias the split based on the position being inserted. If we're // inserting at the beginning of the left node then bias the split to put @@ -1701,7 +1727,7 @@ void btree_node

::split(const int insert_position, btree_node *dest, // right node then bias the split to put more values on the left node. if (insert_position == start()) { dest->set_finish(dest->start() + finish() - 1); - } else if (insert_position == kNodeValues) { + } else if (insert_position == kNodeSlots) { dest->set_finish(dest->start()); } else { dest->set_finish(dest->start() + count() / 2); @@ -1710,10 +1736,7 @@ void btree_node

::split(const int insert_position, btree_node *dest, assert(count() >= 1); // Move values from the left sibling to the right sibling. - uninitialized_move_n(dest->count(), finish(), dest->start(), dest, alloc); - - // Destroy the now-empty entries in the left node. - value_destroy_n(finish(), dest->count(), alloc); + dest->transfer_n(dest->count(), dest->start(), finish(), this, alloc); // The split key is the largest value in the left sibling. --mutable_finish(); @@ -1740,11 +1763,7 @@ void btree_node

::merge(btree_node *src, allocator_type *alloc) { value_init(finish(), alloc, parent()->slot(position())); // Move the values from the right to the left node. - src->uninitialized_move_n(src->count(), src->start(), finish() + 1, this, - alloc); - - // Destroy the now-empty entries in the right node. - src->value_destroy_n(src->start(), src->count(), alloc); + transfer_n(src->count(), finish() + 1, src->start(), src, alloc); if (!leaf()) { // Move the child pointers from the right to the left node. @@ -1758,8 +1777,59 @@ void btree_node

::merge(btree_node *src, allocator_type *alloc) { set_finish(start() + 1 + count() + src->count()); src->set_finish(src->start()); - // Remove the value on the parent node. - parent()->remove_value(position(), alloc); + // Remove the value on the parent node and delete the src node. + parent()->remove_values(position(), /*to_erase=*/1, alloc); +} + +template +void btree_node

::clear_and_delete(btree_node *node, allocator_type *alloc) { + if (node->leaf()) { + node->value_destroy_n(node->start(), node->count(), alloc); + deallocate(LeafSize(node->max_count()), node, alloc); + return; + } + if (node->count() == 0) { + deallocate(InternalSize(), node, alloc); + return; + } + + // The parent of the root of the subtree we are deleting. + btree_node *delete_root_parent = node->parent(); + + // Navigate to the leftmost leaf under node, and then delete upwards. + while (!node->leaf()) node = node->start_child(); + // Use `int` because `pos` needs to be able to hold `kNodeSlots+1`, which + // isn't guaranteed to be a valid `field_type`. + int pos = node->position(); + btree_node *parent = node->parent(); + for (;;) { + // In each iteration of the next loop, we delete one leaf node and go right. + assert(pos <= parent->finish()); + do { + node = parent->child(pos); + if (!node->leaf()) { + // Navigate to the leftmost leaf under node. + while (!node->leaf()) node = node->start_child(); + pos = node->position(); + parent = node->parent(); + } + node->value_destroy_n(node->start(), node->count(), alloc); + deallocate(LeafSize(node->max_count()), node, alloc); + ++pos; + } while (pos <= parent->finish()); + + // Once we've deleted all children of parent, delete parent and go up/right. + assert(pos > parent->finish()); + do { + node = parent; + pos = node->position(); + parent = node->parent(); + node->value_destroy_n(node->start(), node->count(), alloc); + deallocate(InternalSize(), node, alloc); + if (parent == delete_root_parent) return; + ++pos; + } while (pos > parent->finish()); + } } //// @@ -1816,7 +1886,7 @@ void btree_iterator::decrement_slow() { // btree methods template template -void btree

::copy_or_move_values_in_order(Btree *other) { +void btree

::copy_or_move_values_in_order(Btree &other) { static_assert(std::is_same::value || std::is_same::value, "Btree type must be same or const."); @@ -1824,11 +1894,11 @@ void btree

::copy_or_move_values_in_order(Btree *other) { // We can avoid key comparisons because we know the order of the // values is the same order we'll store them in. - auto iter = other->begin(); - if (iter == other->end()) return; + auto iter = other.begin(); + if (iter == other.end()) return; insert_multi(maybe_move_from_iterator(iter)); ++iter; - for (; iter != other->end(); ++iter) { + for (; iter != other.end(); ++iter) { // If the btree is not empty, we can just insert the new value at the end // of the tree. internal_emplace(end(), maybe_move_from_iterator(iter)); @@ -1847,7 +1917,7 @@ constexpr bool btree

::static_assert_validation() { // Note: We assert that kTargetValues, which is computed from // Params::kTargetNodeSize, must fit the node_type::field_type. static_assert( - kNodeValues < (1 << (8 * sizeof(typename node_type::field_type))), + kNodeSlots < (1 << (8 * sizeof(typename node_type::field_type))), "target node size too large"); // Verify that key_compare returns an absl::{weak,strong}_ordering or bool. @@ -1867,25 +1937,57 @@ constexpr bool btree

::static_assert_validation() { } template -btree

::btree(const key_compare &comp, const allocator_type &alloc) - : root_(comp, alloc, EmptyNode()), rightmost_(EmptyNode()), size_(0) {} - -template -btree

::btree(const btree &other) - : btree(other.key_comp(), other.allocator()) { - copy_or_move_values_in_order(&other); +template +auto btree

::lower_bound_equal(const K &key) const + -> std::pair { + const SearchResult res = + internal_lower_bound(key); + const iterator lower = iterator(internal_end(res.value)); + const bool equal = res.HasMatch() + ? res.IsEq() + : lower != end() && !compare_keys(key, lower.key()); + return {lower, equal}; } template -template -auto btree

::insert_unique(const key_type &key, Args &&... args) +template +auto btree

::equal_range(const K &key) -> std::pair { + const std::pair lower_and_equal = lower_bound_equal(key); + const iterator lower = lower_and_equal.first; + if (!lower_and_equal.second) { + return {lower, lower}; + } + + const iterator next = std::next(lower); + if (!params_type::template can_have_multiple_equivalent_keys()) { + // The next iterator after lower must point to a key greater than `key`. + // Note: if this assert fails, then it may indicate that the comparator does + // not meet the equivalence requirements for Compare + // (see https://en.cppreference.com/w/cpp/named_req/Compare). + assert(next == end() || compare_keys(key, next.key())); + return {lower, next}; + } + // Try once more to avoid the call to upper_bound() if there's only one + // equivalent key. This should prevent all calls to upper_bound() in cases of + // unique-containers with heterogeneous comparators in which all comparison + // operators have the same equivalence classes. + if (next == end() || compare_keys(key, next.key())) return {lower, next}; + + // In this case, we need to call upper_bound() to avoid worst case O(N) + // behavior if we were to iterate over equal keys. + return {lower, upper_bound(key)}; +} + +template +template +auto btree

::insert_unique(const K &key, Args &&... args) -> std::pair { if (empty()) { mutable_root() = rightmost_ = new_leaf_root_node(1); } - auto res = internal_locate(key); - iterator &iter = res.value; + SearchResult res = internal_locate(key); + iterator iter = res.value; if (res.HasMatch()) { if (res.IsEq()) { @@ -1903,8 +2005,8 @@ auto btree

::insert_unique(const key_type &key, Args &&... args) } template -template -inline auto btree

::insert_hint_unique(iterator position, const key_type &key, +template +inline auto btree

::insert_hint_unique(iterator position, const K &key, Args &&... args) -> std::pair { if (!empty()) { @@ -1928,13 +2030,22 @@ inline auto btree

::insert_hint_unique(iterator position, const key_type &key, } template -template -void btree

::insert_iterator_unique(InputIterator b, InputIterator e) { +template +void btree

::insert_iterator_unique(InputIterator b, InputIterator e, int) { for (; b != e; ++b) { insert_hint_unique(end(), params_type::key(*b), *b); } } +template +template +void btree

::insert_iterator_unique(InputIterator b, InputIterator e, char) { + for (; b != e; ++b) { + init_type value(*b); + insert_hint_unique(end(), params_type::key(value), std::move(value)); + } +} + template template auto btree

::insert_multi(const key_type &key, ValueType &&v) -> iterator { @@ -1990,7 +2101,7 @@ auto btree

::operator=(const btree &other) -> btree & { *mutable_allocator() = other.allocator(); } - copy_or_move_values_in_order(&other); + copy_or_move_values_in_order(other); } return *this; } @@ -2020,7 +2131,7 @@ auto btree

::operator=(btree &&other) noexcept -> btree & { // comparator while moving the values so we can't swap the key // comparators. *mutable_key_comp() = other.key_comp(); - copy_or_move_values_in_order(&other); + copy_or_move_values_in_order(other); } } } @@ -2032,7 +2143,7 @@ auto btree

::erase(iterator iter) -> iterator { bool internal_delete = false; if (!iter.node->leaf()) { // Deletion of a value on an internal node. First, move the largest value - // from our left child here, then delete that position (in remove_value() + // from our left child here, then delete that position (in remove_values() // below). We can get to the largest value from our left child by // decrementing iter. iterator internal_iter(iter); @@ -2044,7 +2155,7 @@ auto btree

::erase(iterator iter) -> iterator { } // Delete the key from the leaf. - iter.node->remove_value(iter.position, mutable_allocator()); + iter.node->remove_values(iter.position, /*to_erase=*/1, mutable_allocator()); --size_; // We want to return the next value after the one we just erased. If we @@ -2119,7 +2230,9 @@ auto btree

::erase_range(iterator begin, iterator end) } if (begin.node == end.node) { - erase_same_node(begin, end); + assert(end.position > begin.position); + begin.node->remove_values(begin.position, end.position - begin.position, + mutable_allocator()); size_ -= count; return {count, rebalance_after_delete(begin)}; } @@ -2129,8 +2242,11 @@ auto btree

::erase_range(iterator begin, iterator end) if (begin.node->leaf()) { const size_type remaining_to_erase = size_ - target_size; const size_type remaining_in_node = begin.node->finish() - begin.position; - begin = erase_from_leaf_node( - begin, (std::min)(remaining_to_erase, remaining_in_node)); + const size_type to_erase = + (std::min)(remaining_to_erase, remaining_in_node); + begin.node->remove_values(begin.position, to_erase, mutable_allocator()); + size_ -= to_erase; + begin = rebalance_after_delete(begin); } else { begin = erase(begin); } @@ -2138,80 +2254,10 @@ auto btree

::erase_range(iterator begin, iterator end) return {count, begin}; } -template -void btree

::erase_same_node(iterator begin, iterator end) { - assert(begin.node == end.node); - assert(end.position > begin.position); - - node_type *node = begin.node; - size_type to_erase = end.position - begin.position; - if (!node->leaf()) { - // Delete all children between begin and end. - for (size_type i = 0; i < to_erase; ++i) { - internal_clear(node->child(begin.position + i + 1)); - } - // Rotate children after end into new positions. - for (size_type i = begin.position + to_erase + 1; i <= node->finish(); - ++i) { - node->set_child(i - to_erase, node->child(i)); - node->clear_child(i); - } - } - node->remove_values_ignore_children(begin.position, to_erase, - mutable_allocator()); - - // Do not need to update rightmost_, because - // * either end == this->end(), and therefore node == rightmost_, and still - // exists - // * or end != this->end(), and therefore rightmost_ hasn't been erased, since - // it wasn't covered in [begin, end) -} - -template -auto btree

::erase_from_leaf_node(iterator begin, size_type to_erase) - -> iterator { - node_type *node = begin.node; - assert(node->leaf()); - assert(node->finish() > begin.position); - assert(begin.position + to_erase <= node->finish()); - - node->remove_values_ignore_children(begin.position, to_erase, - mutable_allocator()); - - size_ -= to_erase; - - return rebalance_after_delete(begin); -} - -template -template -auto btree

::erase_unique(const K &key) -> size_type { - const iterator iter = internal_find(key); - if (iter.node == nullptr) { - // The key doesn't exist in the tree, return nothing done. - return 0; - } - erase(iter); - return 1; -} - -template -template -auto btree

::erase_multi(const K &key) -> size_type { - const iterator begin = internal_lower_bound(key); - if (begin.node == nullptr) { - // The key doesn't exist in the tree, return nothing done. - return 0; - } - // Delete all of the keys between begin and upper_bound(key). - const iterator end = internal_end(internal_upper_bound(key)); - return erase_range(begin, end).first; -} - template void btree

::clear() { if (!empty()) { - internal_clear(root()); + node_type::clear_and_delete(root(), mutable_allocator()); } mutable_root() = EmptyNode(); rightmost_ = EmptyNode(); @@ -2252,7 +2298,7 @@ void btree

::rebalance_or_split(iterator *iter) { node_type *&node = iter->node; int &insert_position = iter->position; assert(node->count() == node->max_count()); - assert(kNodeValues == node->max_count()); + assert(kNodeSlots == node->max_count()); // First try to make room on the node by rebalancing. node_type *parent = node->parent(); @@ -2260,17 +2306,17 @@ void btree

::rebalance_or_split(iterator *iter) { if (node->position() > parent->start()) { // Try rebalancing with our left sibling. node_type *left = parent->child(node->position() - 1); - assert(left->max_count() == kNodeValues); - if (left->count() < kNodeValues) { + assert(left->max_count() == kNodeSlots); + if (left->count() < kNodeSlots) { // We bias rebalancing based on the position being inserted. If we're // inserting at the end of the right node then we bias rebalancing to // fill up the left node. - int to_move = (kNodeValues - left->count()) / - (1 + (insert_position < kNodeValues)); + int to_move = (kNodeSlots - left->count()) / + (1 + (insert_position < static_cast(kNodeSlots))); to_move = (std::max)(1, to_move); if (insert_position - to_move >= node->start() || - left->count() + to_move < kNodeValues) { + left->count() + to_move < static_cast(kNodeSlots)) { left->rebalance_right_to_left(to_move, node, mutable_allocator()); assert(node->max_count() - node->count() == to_move); @@ -2289,17 +2335,17 @@ void btree

::rebalance_or_split(iterator *iter) { if (node->position() < parent->finish()) { // Try rebalancing with our right sibling. node_type *right = parent->child(node->position() + 1); - assert(right->max_count() == kNodeValues); - if (right->count() < kNodeValues) { + assert(right->max_count() == kNodeSlots); + if (right->count() < kNodeSlots) { // We bias rebalancing based on the position being inserted. If we're // inserting at the beginning of the left node then we bias rebalancing // to fill up the right node. - int to_move = (kNodeValues - right->count()) / + int to_move = (static_cast(kNodeSlots) - right->count()) / (1 + (insert_position > node->start())); to_move = (std::max)(1, to_move); if (insert_position <= node->finish() - to_move || - right->count() + to_move < kNodeValues) { + right->count() + to_move < static_cast(kNodeSlots)) { node->rebalance_left_to_right(to_move, right, mutable_allocator()); if (insert_position > node->finish()) { @@ -2315,8 +2361,8 @@ void btree

::rebalance_or_split(iterator *iter) { // Rebalancing failed, make sure there is room on the parent node for a new // value. - assert(parent->max_count() == kNodeValues); - if (parent->count() == kNodeValues) { + assert(parent->max_count() == kNodeSlots); + if (parent->count() == kNodeSlots) { iterator parent_iter(node->parent(), node->position()); rebalance_or_split(&parent_iter); } @@ -2352,12 +2398,7 @@ void btree

::rebalance_or_split(iterator *iter) { template void btree

::merge_nodes(node_type *left, node_type *right) { left->merge(right, mutable_allocator()); - if (right->leaf()) { - if (rightmost_ == right) rightmost_ = left; - delete_leaf_node(right); - } else { - delete_internal_node(right); - } + if (rightmost_ == right) rightmost_ = left; } template @@ -2366,8 +2407,8 @@ bool btree

::try_merge_or_rebalance(iterator *iter) { if (iter->node->position() > parent->start()) { // Try merging with our left sibling. node_type *left = parent->child(iter->node->position() - 1); - assert(left->max_count() == kNodeValues); - if (1 + left->count() + iter->node->count() <= kNodeValues) { + assert(left->max_count() == kNodeSlots); + if (1U + left->count() + iter->node->count() <= kNodeSlots) { iter->position += 1 + left->count(); merge_nodes(left, iter->node); iter->node = left; @@ -2377,8 +2418,8 @@ bool btree

::try_merge_or_rebalance(iterator *iter) { if (iter->node->position() < parent->finish()) { // Try merging with our right sibling. node_type *right = parent->child(iter->node->position() + 1); - assert(right->max_count() == kNodeValues); - if (1 + iter->node->count() + right->count() <= kNodeValues) { + assert(right->max_count() == kNodeSlots); + if (1U + iter->node->count() + right->count() <= kNodeSlots) { merge_nodes(iter->node, right); return true; } @@ -2414,20 +2455,20 @@ bool btree

::try_merge_or_rebalance(iterator *iter) { template void btree

::try_shrink() { - if (root()->count() > 0) { + node_type *orig_root = root(); + if (orig_root->count() > 0) { return; } // Deleted the last item on the root node, shrink the height of the tree. - if (root()->leaf()) { + if (orig_root->leaf()) { assert(size() == 0); - delete_leaf_node(root()); mutable_root() = rightmost_ = EmptyNode(); } else { - node_type *child = root()->start_child(); + node_type *child = orig_root->start_child(); child->make_root(); - delete_internal_node(root()); mutable_root() = child; } + node_type::clear_and_delete(orig_root, mutable_allocator()); } template @@ -2455,25 +2496,24 @@ inline auto btree

::internal_emplace(iterator iter, Args &&... args) --iter; ++iter.position; } - const int max_count = iter.node->max_count(); + const field_type max_count = iter.node->max_count(); allocator_type *alloc = mutable_allocator(); if (iter.node->count() == max_count) { // Make room in the leaf for the new item. - if (max_count < kNodeValues) { + if (max_count < kNodeSlots) { // Insertion into the root where the root is smaller than the full node // size. Simply grow the size of the root node. assert(iter.node == root()); iter.node = - new_leaf_root_node((std::min)(kNodeValues, 2 * max_count)); + new_leaf_root_node((std::min)(kNodeSlots, 2 * max_count)); // Transfer the values from the old root to the new root. node_type *old_root = root(); node_type *new_root = iter.node; - for (int i = old_root->start(), f = old_root->finish(); i < f; ++i) { - new_root->transfer(i, i, old_root, alloc); - } + new_root->transfer_n(old_root->count(), new_root->start(), + old_root->start(), old_root, alloc); new_root->set_finish(old_root->finish()); old_root->set_finish(old_root->start()); - delete_leaf_node(old_root); + node_type::clear_and_delete(old_root, alloc); mutable_root() = rightmost_ = new_root; } else { rebalance_or_split(&iter); @@ -2488,61 +2528,51 @@ template template inline auto btree

::internal_locate(const K &key) const -> SearchResult { - return internal_locate_impl(key, is_key_compare_to()); -} - -template -template -inline auto btree

::internal_locate_impl( - const K &key, std::false_type /* IsCompareTo */) const - -> SearchResult { iterator iter(const_cast(root())); for (;;) { - iter.position = iter.node->lower_bound(key, key_comp()).value; - // NOTE: we don't need to walk all the way down the tree if the keys are - // equal, but determining equality would require doing an extra comparison - // on each node on the way down, and we will need to go all the way to the - // leaf node in the expected case. - if (iter.node->leaf()) { - break; - } - iter.node = iter.node->child(iter.position); - } - return {iter}; -} - -template -template -inline auto btree

::internal_locate_impl( - const K &key, std::true_type /* IsCompareTo */) const - -> SearchResult { - iterator iter(const_cast(root())); - for (;;) { - SearchResult res = iter.node->lower_bound(key, key_comp()); + SearchResult res = + iter.node->lower_bound(key, key_comp()); iter.position = res.value; - if (res.match == MatchKind::kEq) { + if (res.IsEq()) { return {iter, MatchKind::kEq}; } + // Note: in the non-key-compare-to case, we don't need to walk all the way + // down the tree if the keys are equal, but determining equality would + // require doing an extra comparison on each node on the way down, and we + // will need to go all the way to the leaf node in the expected case. if (iter.node->leaf()) { break; } iter.node = iter.node->child(iter.position); } + // Note: in the non-key-compare-to case, the key may actually be equivalent + // here (and the MatchKind::kNe is ignored). return {iter, MatchKind::kNe}; } template template -auto btree

::internal_lower_bound(const K &key) const -> iterator { +auto btree

::internal_lower_bound(const K &key) const + -> SearchResult { + if (!params_type::template can_have_multiple_equivalent_keys()) { + SearchResult ret = internal_locate(key); + ret.value = internal_last(ret.value); + return ret; + } iterator iter(const_cast(root())); + SearchResult res; + bool seen_eq = false; for (;;) { - iter.position = iter.node->lower_bound(key, key_comp()).value; + res = iter.node->lower_bound(key, key_comp()); + iter.position = res.value; if (iter.node->leaf()) { break; } + seen_eq = seen_eq || res.IsEq(); iter.node = iter.node->child(iter.position); } - return internal_last(iter); + if (res.IsEq()) return {iter, MatchKind::kEq}; + return {internal_last(iter), seen_eq ? MatchKind::kEq : MatchKind::kNe}; } template @@ -2562,7 +2592,7 @@ auto btree

::internal_upper_bound(const K &key) const -> iterator { template template auto btree

::internal_find(const K &key) const -> iterator { - auto res = internal_locate(key); + SearchResult res = internal_locate(key); if (res.HasMatch()) { if (res.IsEq()) { return res.value; @@ -2576,18 +2606,6 @@ auto btree

::internal_find(const K &key) const -> iterator { return {nullptr, 0}; } -template -void btree

::internal_clear(node_type *node) { - if (!node->leaf()) { - for (int i = node->start(); i <= node->finish(); ++i) { - internal_clear(node->child(i)); - } - delete_internal_node(node); - } else { - delete_leaf_node(node); - } -} - template int btree

::internal_verify(const node_type *node, const key_type *lo, const key_type *hi) const { diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/btree_container.h b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/btree_container.h index 734c90ef3d..a99668c713 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/btree_container.h +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/btree_container.h @@ -20,9 +20,11 @@ #include #include +#include "absl/base/attributes.h" #include "absl/base/internal/throw_delegate.h" #include "absl/container/internal/btree.h" // IWYU pragma: export #include "absl/container/internal/common.h" +#include "absl/memory/memory.h" #include "absl/meta/type_traits.h" namespace absl { @@ -50,7 +52,7 @@ class btree_container { using value_type = typename Tree::value_type; using size_type = typename Tree::size_type; using difference_type = typename Tree::difference_type; - using key_compare = typename Tree::key_compare; + using key_compare = typename Tree::original_key_compare; using value_compare = typename Tree::value_compare; using allocator_type = typename Tree::allocator_type; using reference = typename Tree::reference; @@ -68,8 +70,21 @@ class btree_container { explicit btree_container(const key_compare &comp, const allocator_type &alloc = allocator_type()) : tree_(comp, alloc) {} - btree_container(const btree_container &other) = default; - btree_container(btree_container &&other) noexcept = default; + explicit btree_container(const allocator_type &alloc) + : tree_(key_compare(), alloc) {} + + btree_container(const btree_container &other) + : btree_container(other, absl::allocator_traits:: + select_on_container_copy_construction( + other.get_allocator())) {} + btree_container(const btree_container &other, const allocator_type &alloc) + : tree_(other.tree_, alloc) {} + + btree_container(btree_container &&other) noexcept( + std::is_nothrow_move_constructible::value) = default; + btree_container(btree_container &&other, const allocator_type &alloc) + : tree_(std::move(other.tree_), alloc) {} + btree_container &operator=(const btree_container &other) = default; btree_container &operator=(btree_container &&other) noexcept( std::is_nothrow_move_assignable::value) = default; @@ -90,6 +105,11 @@ class btree_container { // Lookup routines. template + size_type count(const key_arg &key) const { + auto equal_range = this->equal_range(key); + return std::distance(equal_range.first, equal_range.second); + } + template iterator find(const key_arg &key) { return tree_.find(key); } @@ -138,6 +158,11 @@ class btree_container { iterator erase(const_iterator first, const_iterator last) { return tree_.erase_range(iterator(first), iterator(last)).second; } + template + size_type erase(const key_arg &key) { + auto equal_range = this->equal_range(key); + return tree_.erase_range(equal_range.first, equal_range.second).first; + } // Extract routines. node_type extract(iterator position) { @@ -151,9 +176,8 @@ class btree_container { return extract(iterator(position)); } - public: // Utility routines. - void clear() { tree_.clear(); } + ABSL_ATTRIBUTE_REINITIALIZES void clear() { tree_.clear(); } void swap(btree_container &other) { tree_.swap(other.tree_); } void verify() const { tree_.verify(); } @@ -191,7 +215,7 @@ class btree_container { allocator_type get_allocator() const { return tree_.get_allocator(); } // The key comparator used by the btree. - key_compare key_comp() const { return tree_.key_comp(); } + key_compare key_comp() const { return key_compare(tree_.key_comp()); } value_compare value_comp() const { return tree_.value_comp(); } // Support absl::Hash. @@ -224,7 +248,7 @@ class btree_set_container : public btree_container { using key_type = typename Tree::key_type; using value_type = typename Tree::value_type; using size_type = typename Tree::size_type; - using key_compare = typename Tree::key_compare; + using key_compare = typename Tree::original_key_compare; using allocator_type = typename Tree::allocator_type; using iterator = typename Tree::iterator; using const_iterator = typename Tree::const_iterator; @@ -235,7 +259,7 @@ class btree_set_container : public btree_container { using super_type::super_type; btree_set_container() {} - // Range constructor. + // Range constructors. template btree_set_container(InputIterator b, InputIterator e, const key_compare &comp = key_compare(), @@ -243,18 +267,19 @@ class btree_set_container : public btree_container { : super_type(comp, alloc) { insert(b, e); } + template + btree_set_container(InputIterator b, InputIterator e, + const allocator_type &alloc) + : btree_set_container(b, e, key_compare(), alloc) {} - // Initializer list constructor. + // Initializer list constructors. btree_set_container(std::initializer_list init, const key_compare &comp = key_compare(), const allocator_type &alloc = allocator_type()) : btree_set_container(init.begin(), init.end(), comp, alloc) {} - - // Lookup routines. - template - size_type count(const key_arg &key) const { - return this->tree_.count_unique(key); - } + btree_set_container(std::initializer_list init, + const allocator_type &alloc) + : btree_set_container(init.begin(), init.end(), alloc) {} // Insertion routines. std::pair insert(const value_type &v) { @@ -268,31 +293,29 @@ class btree_set_container : public btree_container { init_type v(std::forward(args)...); return this->tree_.insert_unique(params_type::key(v), std::move(v)); } - iterator insert(const_iterator position, const value_type &v) { + iterator insert(const_iterator hint, const value_type &v) { return this->tree_ - .insert_hint_unique(iterator(position), params_type::key(v), v) + .insert_hint_unique(iterator(hint), params_type::key(v), v) .first; } - iterator insert(const_iterator position, value_type &&v) { + iterator insert(const_iterator hint, value_type &&v) { return this->tree_ - .insert_hint_unique(iterator(position), params_type::key(v), - std::move(v)) + .insert_hint_unique(iterator(hint), params_type::key(v), std::move(v)) .first; } template - iterator emplace_hint(const_iterator position, Args &&... args) { + iterator emplace_hint(const_iterator hint, Args &&... args) { init_type v(std::forward(args)...); return this->tree_ - .insert_hint_unique(iterator(position), params_type::key(v), - std::move(v)) + .insert_hint_unique(iterator(hint), params_type::key(v), std::move(v)) .first; } template void insert(InputIterator b, InputIterator e) { - this->tree_.insert_iterator_unique(b, e); + this->tree_.insert_iterator_unique(b, e, 0); } void insert(std::initializer_list init) { - this->tree_.insert_iterator_unique(init.begin(), init.end()); + this->tree_.insert_iterator_unique(init.begin(), init.end(), 0); } insert_return_type insert(node_type &&node) { if (!node) return {this->end(), false, node_type()}; @@ -315,18 +338,13 @@ class btree_set_container : public btree_container { return res.first; } - // Deletion routines. - template - size_type erase(const key_arg &key) { - return this->tree_.erase_unique(key); - } - using super_type::erase; - // Node extraction routines. template node_type extract(const key_arg &key) { - auto it = this->find(key); - return it == this->end() ? node_type() : extract(it); + const std::pair lower_and_equal = + this->tree_.lower_bound_equal(key); + return lower_and_equal.second ? extract(lower_and_equal.first) + : node_type(); } using super_type::extract; @@ -344,7 +362,7 @@ class btree_set_container : public btree_container { int> = 0> void merge(btree_container &src) { // NOLINT for (auto src_it = src.begin(); src_it != src.end();) { - if (insert(std::move(*src_it)).second) { + if (insert(std::move(params_type::element(src_it.slot()))).second) { src_it = src.erase(src_it); } else { ++src_it; @@ -371,6 +389,7 @@ template class btree_map_container : public btree_set_container { using super_type = btree_set_container; using params_type = typename Tree::params_type; + friend class BtreeNodePeer; private: template @@ -380,7 +399,7 @@ class btree_map_container : public btree_set_container { using key_type = typename Tree::key_type; using mapped_type = typename params_type::mapped_type; using value_type = typename Tree::value_type; - using key_compare = typename Tree::key_compare; + using key_compare = typename Tree::original_key_compare; using allocator_type = typename Tree::allocator_type; using iterator = typename Tree::iterator; using const_iterator = typename Tree::const_iterator; @@ -392,111 +411,72 @@ class btree_map_container : public btree_set_container { // Insertion routines. // Note: the nullptr template arguments and extra `const M&` overloads allow // for supporting bitfield arguments. - // Note: when we call `std::forward(obj)` twice, it's safe because - // insert_unique/insert_hint_unique are guaranteed to not consume `obj` when - // `ret.second` is false. - template - std::pair insert_or_assign(const key_type &k, const M &obj) { - const std::pair ret = this->tree_.insert_unique(k, k, obj); - if (!ret.second) ret.first->second = obj; - return ret; + template + std::pair insert_or_assign(const key_arg &k, + const M &obj) { + return insert_or_assign_impl(k, obj); } - template - std::pair insert_or_assign(key_type &&k, const M &obj) { - const std::pair ret = - this->tree_.insert_unique(k, std::move(k), obj); - if (!ret.second) ret.first->second = obj; - return ret; + template + std::pair insert_or_assign(key_arg &&k, const M &obj) { + return insert_or_assign_impl(std::forward(k), obj); } - template - std::pair insert_or_assign(const key_type &k, M &&obj) { - const std::pair ret = - this->tree_.insert_unique(k, k, std::forward(obj)); - if (!ret.second) ret.first->second = std::forward(obj); - return ret; + template + std::pair insert_or_assign(const key_arg &k, M &&obj) { + return insert_or_assign_impl(k, std::forward(obj)); } - template - std::pair insert_or_assign(key_type &&k, M &&obj) { - const std::pair ret = - this->tree_.insert_unique(k, std::move(k), std::forward(obj)); - if (!ret.second) ret.first->second = std::forward(obj); - return ret; + template + std::pair insert_or_assign(key_arg &&k, M &&obj) { + return insert_or_assign_impl(std::forward(k), std::forward(obj)); } - template - iterator insert_or_assign(const_iterator position, const key_type &k, + template + iterator insert_or_assign(const_iterator hint, const key_arg &k, const M &obj) { - const std::pair ret = - this->tree_.insert_hint_unique(iterator(position), k, k, obj); - if (!ret.second) ret.first->second = obj; - return ret.first; + return insert_or_assign_hint_impl(hint, k, obj); } - template - iterator insert_or_assign(const_iterator position, key_type &&k, - const M &obj) { - const std::pair ret = this->tree_.insert_hint_unique( - iterator(position), k, std::move(k), obj); - if (!ret.second) ret.first->second = obj; - return ret.first; + template + iterator insert_or_assign(const_iterator hint, key_arg &&k, const M &obj) { + return insert_or_assign_hint_impl(hint, std::forward(k), obj); } - template - iterator insert_or_assign(const_iterator position, const key_type &k, - M &&obj) { - const std::pair ret = this->tree_.insert_hint_unique( - iterator(position), k, k, std::forward(obj)); - if (!ret.second) ret.first->second = std::forward(obj); - return ret.first; + template + iterator insert_or_assign(const_iterator hint, const key_arg &k, M &&obj) { + return insert_or_assign_hint_impl(hint, k, std::forward(obj)); } - template - iterator insert_or_assign(const_iterator position, key_type &&k, M &&obj) { - const std::pair ret = this->tree_.insert_hint_unique( - iterator(position), k, std::move(k), std::forward(obj)); - if (!ret.second) ret.first->second = std::forward(obj); - return ret.first; + template + iterator insert_or_assign(const_iterator hint, key_arg &&k, M &&obj) { + return insert_or_assign_hint_impl(hint, std::forward(k), + std::forward(obj)); } - template - std::pair try_emplace(const key_type &k, Args &&... args) { - return this->tree_.insert_unique( - k, std::piecewise_construct, std::forward_as_tuple(k), - std::forward_as_tuple(std::forward(args)...)); + + template ::value, int> = 0> + std::pair try_emplace(const key_arg &k, Args &&... args) { + return try_emplace_impl(k, std::forward(args)...); } - template - std::pair try_emplace(key_type &&k, Args &&... args) { - // Note: `key_ref` exists to avoid a ClangTidy warning about moving from `k` - // and then using `k` unsequenced. This is safe because the move is into a - // forwarding reference and insert_unique guarantees that `key` is never - // referenced after consuming `args`. - const key_type &key_ref = k; - return this->tree_.insert_unique( - key_ref, std::piecewise_construct, std::forward_as_tuple(std::move(k)), - std::forward_as_tuple(std::forward(args)...)); + template ::value, int> = 0> + std::pair try_emplace(key_arg &&k, Args &&... args) { + return try_emplace_impl(std::forward(k), std::forward(args)...); } - template - iterator try_emplace(const_iterator hint, const key_type &k, + template + iterator try_emplace(const_iterator hint, const key_arg &k, Args &&... args) { - return this->tree_ - .insert_hint_unique(iterator(hint), k, std::piecewise_construct, - std::forward_as_tuple(k), - std::forward_as_tuple(std::forward(args)...)) - .first; + return try_emplace_hint_impl(hint, k, std::forward(args)...); } - template - iterator try_emplace(const_iterator hint, key_type &&k, Args &&... args) { - // Note: `key_ref` exists to avoid a ClangTidy warning about moving from `k` - // and then using `k` unsequenced. This is safe because the move is into a - // forwarding reference and insert_hint_unique guarantees that `key` is - // never referenced after consuming `args`. - const key_type &key_ref = k; - return this->tree_ - .insert_hint_unique(iterator(hint), key_ref, std::piecewise_construct, - std::forward_as_tuple(std::move(k)), - std::forward_as_tuple(std::forward(args)...)) - .first; + template + iterator try_emplace(const_iterator hint, key_arg &&k, Args &&... args) { + return try_emplace_hint_impl(hint, std::forward(k), + std::forward(args)...); } - mapped_type &operator[](const key_type &k) { + + template + mapped_type &operator[](const key_arg &k) { return try_emplace(k).first->second; } - mapped_type &operator[](key_type &&k) { - return try_emplace(std::move(k)).first->second; + template + mapped_type &operator[](key_arg &&k) { + return try_emplace(std::forward(k)).first->second; } template @@ -513,6 +493,40 @@ class btree_map_container : public btree_set_container { base_internal::ThrowStdOutOfRange("absl::btree_map::at"); return it->second; } + + private: + // Note: when we call `std::forward(obj)` twice, it's safe because + // insert_unique/insert_hint_unique are guaranteed to not consume `obj` when + // `ret.second` is false. + template + std::pair insert_or_assign_impl(K &&k, M &&obj) { + const std::pair ret = + this->tree_.insert_unique(k, std::forward(k), std::forward(obj)); + if (!ret.second) ret.first->second = std::forward(obj); + return ret; + } + template + iterator insert_or_assign_hint_impl(const_iterator hint, K &&k, M &&obj) { + const std::pair ret = this->tree_.insert_hint_unique( + iterator(hint), k, std::forward(k), std::forward(obj)); + if (!ret.second) ret.first->second = std::forward(obj); + return ret.first; + } + + template + std::pair try_emplace_impl(K &&k, Args &&... args) { + return this->tree_.insert_unique( + k, std::piecewise_construct, std::forward_as_tuple(std::forward(k)), + std::forward_as_tuple(std::forward(args)...)); + } + template + iterator try_emplace_hint_impl(const_iterator hint, K &&k, Args &&... args) { + return this->tree_ + .insert_hint_unique(iterator(hint), k, std::piecewise_construct, + std::forward_as_tuple(std::forward(k)), + std::forward_as_tuple(std::forward(args)...)) + .first; + } }; // A common base class for btree_multiset and btree_multimap. @@ -530,7 +544,7 @@ class btree_multiset_container : public btree_container { using key_type = typename Tree::key_type; using value_type = typename Tree::value_type; using size_type = typename Tree::size_type; - using key_compare = typename Tree::key_compare; + using key_compare = typename Tree::original_key_compare; using allocator_type = typename Tree::allocator_type; using iterator = typename Tree::iterator; using const_iterator = typename Tree::const_iterator; @@ -540,7 +554,7 @@ class btree_multiset_container : public btree_container { using super_type::super_type; btree_multiset_container() {} - // Range constructor. + // Range constructors. template btree_multiset_container(InputIterator b, InputIterator e, const key_compare &comp = key_compare(), @@ -548,29 +562,30 @@ class btree_multiset_container : public btree_container { : super_type(comp, alloc) { insert(b, e); } + template + btree_multiset_container(InputIterator b, InputIterator e, + const allocator_type &alloc) + : btree_multiset_container(b, e, key_compare(), alloc) {} - // Initializer list constructor. + // Initializer list constructors. btree_multiset_container(std::initializer_list init, const key_compare &comp = key_compare(), const allocator_type &alloc = allocator_type()) : btree_multiset_container(init.begin(), init.end(), comp, alloc) {} - - // Lookup routines. - template - size_type count(const key_arg &key) const { - return this->tree_.count_multi(key); - } + btree_multiset_container(std::initializer_list init, + const allocator_type &alloc) + : btree_multiset_container(init.begin(), init.end(), alloc) {} // Insertion routines. iterator insert(const value_type &v) { return this->tree_.insert_multi(v); } iterator insert(value_type &&v) { return this->tree_.insert_multi(std::move(v)); } - iterator insert(const_iterator position, const value_type &v) { - return this->tree_.insert_hint_multi(iterator(position), v); + iterator insert(const_iterator hint, const value_type &v) { + return this->tree_.insert_hint_multi(iterator(hint), v); } - iterator insert(const_iterator position, value_type &&v) { - return this->tree_.insert_hint_multi(iterator(position), std::move(v)); + iterator insert(const_iterator hint, value_type &&v) { + return this->tree_.insert_hint_multi(iterator(hint), std::move(v)); } template void insert(InputIterator b, InputIterator e) { @@ -584,9 +599,9 @@ class btree_multiset_container : public btree_container { return this->tree_.insert_multi(init_type(std::forward(args)...)); } template - iterator emplace_hint(const_iterator position, Args &&... args) { + iterator emplace_hint(const_iterator hint, Args &&... args) { return this->tree_.insert_hint_multi( - iterator(position), init_type(std::forward(args)...)); + iterator(hint), init_type(std::forward(args)...)); } iterator insert(node_type &&node) { if (!node) return this->end(); @@ -605,18 +620,13 @@ class btree_multiset_container : public btree_container { return res; } - // Deletion routines. - template - size_type erase(const key_arg &key) { - return this->tree_.erase_multi(key); - } - using super_type::erase; - // Node extraction routines. template node_type extract(const key_arg &key) { - auto it = this->find(key); - return it == this->end() ? node_type() : extract(it); + const std::pair lower_and_equal = + this->tree_.lower_bound_equal(key); + return lower_and_equal.second ? extract(lower_and_equal.first) + : node_type(); } using super_type::extract; @@ -632,8 +642,9 @@ class btree_multiset_container : public btree_container { typename T::params_type::is_map_container>>::value, int> = 0> void merge(btree_container &src) { // NOLINT - insert(std::make_move_iterator(src.begin()), - std::make_move_iterator(src.end())); + for (auto src_it = src.begin(), end = src.end(); src_it != end; ++src_it) { + insert(std::move(params_type::element(src_it.slot()))); + } src.clear(); } diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/common.h b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/common.h index 8990f29472..030e9d4ab0 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/common.h +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/common.h @@ -146,8 +146,11 @@ class node_handle decltype(PolicyTraits::key(std::declval())) { - return PolicyTraits::key(this->slot()); + // When C++17 is available, we can use std::launder to provide mutable + // access to the key. Otherwise, we provide const access. + auto key() const + -> decltype(PolicyTraits::mutable_key(std::declval())) { + return PolicyTraits::mutable_key(this->slot()); } mapped_type& mapped() const { diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/compressed_tuple.h b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/compressed_tuple.h index 02bfd03f6c..5ebe164942 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/compressed_tuple.h +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/compressed_tuple.h @@ -257,7 +257,7 @@ class ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC CompressedTuple template ElemT& get() & { - return internal_compressed_tuple::Storage, I>::get(); + return StorageT::get(); } template diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/container_memory.h b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/container_memory.h index 3487ac1899..e67529ecb6 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/container_memory.h +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/container_memory.h @@ -15,25 +15,27 @@ #ifndef ABSL_CONTAINER_INTERNAL_CONTAINER_MEMORY_H_ #define ABSL_CONTAINER_INTERNAL_CONTAINER_MEMORY_H_ -#ifdef ADDRESS_SANITIZER -#include -#endif - -#ifdef MEMORY_SANITIZER -#include -#endif - #include #include #include +#include #include #include #include +#include "absl/base/config.h" #include "absl/memory/memory.h" #include "absl/meta/type_traits.h" #include "absl/utility/utility.h" +#ifdef ABSL_HAVE_ADDRESS_SANITIZER +#include +#endif + +#ifdef ABSL_HAVE_MEMORY_SANITIZER +#include +#endif + namespace absl { ABSL_NAMESPACE_BEGIN namespace container_internal { @@ -55,8 +57,11 @@ void* Allocate(Alloc* alloc, size_t n) { using M = AlignedType; using A = typename absl::allocator_traits::template rebind_alloc; using AT = typename absl::allocator_traits::template rebind_traits; - A mem_alloc(*alloc); - void* p = AT::allocate(mem_alloc, (n + sizeof(M) - 1) / sizeof(M)); + // On macOS, "mem_alloc" is a #define with one argument defined in + // rpc/types.h, so we can't name the variable "mem_alloc" and initialize it + // with the "foo(bar)" syntax. + A my_mem_alloc(*alloc); + void* p = AT::allocate(my_mem_alloc, (n + sizeof(M) - 1) / sizeof(M)); assert(reinterpret_cast(p) % Alignment == 0 && "allocator does not respect alignment"); return p; @@ -71,8 +76,11 @@ void Deallocate(Alloc* alloc, void* p, size_t n) { using M = AlignedType; using A = typename absl::allocator_traits::template rebind_alloc; using AT = typename absl::allocator_traits::template rebind_traits; - A mem_alloc(*alloc); - AT::deallocate(mem_alloc, static_cast(p), + // On macOS, "mem_alloc" is a #define with one argument defined in + // rpc/types.h, so we can't name the variable "mem_alloc" and initialize it + // with the "foo(bar)" syntax. + A my_mem_alloc(*alloc); + AT::deallocate(my_mem_alloc, static_cast(p), (n + sizeof(M) - 1) / sizeof(M)); } @@ -209,10 +217,10 @@ DecomposeValue(F&& f, Arg&& arg) { // Helper functions for asan and msan. inline void SanitizerPoisonMemoryRegion(const void* m, size_t s) { -#ifdef ADDRESS_SANITIZER +#ifdef ABSL_HAVE_ADDRESS_SANITIZER ASAN_POISON_MEMORY_REGION(m, s); #endif -#ifdef MEMORY_SANITIZER +#ifdef ABSL_HAVE_MEMORY_SANITIZER __msan_poison(m, s); #endif (void)m; @@ -220,10 +228,10 @@ inline void SanitizerPoisonMemoryRegion(const void* m, size_t s) { } inline void SanitizerUnpoisonMemoryRegion(const void* m, size_t s) { -#ifdef ADDRESS_SANITIZER +#ifdef ABSL_HAVE_ADDRESS_SANITIZER ASAN_UNPOISON_MEMORY_REGION(m, s); #endif -#ifdef MEMORY_SANITIZER +#ifdef ABSL_HAVE_MEMORY_SANITIZER __msan_unpoison(m, s); #endif (void)m; @@ -250,8 +258,8 @@ namespace memory_internal { // type, which is non-portable. template struct OffsetOf { - static constexpr size_t kFirst = -1; - static constexpr size_t kSecond = -1; + static constexpr size_t kFirst = static_cast(-1); + static constexpr size_t kSecond = static_cast(-1); }; template @@ -351,6 +359,20 @@ struct map_slot_policy { return slot->value; } + // When C++17 is available, we can use std::launder to provide mutable + // access to the key for use in node handle. +#if defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606 + static K& mutable_key(slot_type* slot) { + // Still check for kMutableKeys so that we can avoid calling std::launder + // unless necessary because it can interfere with optimizations. + return kMutableKeys::value ? slot->key + : *std::launder(const_cast( + std::addressof(slot->value.first))); + } +#else // !(defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606) + static const K& mutable_key(slot_type* slot) { return key(slot); } +#endif + static const K& key(const slot_type* slot) { return kMutableKeys::value ? slot->key : slot->value.first; } @@ -429,13 +451,6 @@ struct map_slot_policy { std::move(src->value)); } } - - template - static void move(Allocator* alloc, slot_type* first, slot_type* last, - slot_type* result) { - for (slot_type *src = first, *dest = result; src != last; ++src, ++dest) - move(alloc, src, dest); - } }; } // namespace container_internal diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/container_memory_test.cc b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/container_memory_test.cc index 6a7fcd29ba..fb9c4ddede 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/container_memory_test.cc +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/container_memory_test.cc @@ -166,7 +166,7 @@ TryDecomposeValue(F&& f, Arg&& arg) { } TEST(DecomposeValue, Decomposable) { - auto f = [](const int& x, int&& y) { + auto f = [](const int& x, int&& y) { // NOLINT EXPECT_EQ(&x, &y); EXPECT_EQ(42, x); return 'A'; @@ -200,7 +200,8 @@ TryDecomposePair(F&& f, Args&&... args) { } TEST(DecomposePair, Decomposable) { - auto f = [](const int& x, std::piecewise_construct_t, std::tuple k, + auto f = [](const int& x, // NOLINT + std::piecewise_construct_t, std::tuple k, std::tuple&& v) { EXPECT_EQ(&x, &std::get<0>(k)); EXPECT_EQ(42, x); diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/counting_allocator.h b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/counting_allocator.h index 9efdc66213..927cf08255 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/counting_allocator.h +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/counting_allocator.h @@ -15,7 +15,6 @@ #ifndef ABSL_CONTAINER_INTERNAL_COUNTING_ALLOCATOR_H_ #define ABSL_CONTAINER_INTERNAL_COUNTING_ALLOCATOR_H_ -#include #include #include @@ -31,33 +30,63 @@ namespace container_internal { // containers - that chain of allocators uses the same state and is // thus easier to query for aggregate allocation information. template -class CountingAllocator : public std::allocator { +class CountingAllocator { public: - using Alloc = std::allocator; - using pointer = typename Alloc::pointer; - using size_type = typename Alloc::size_type; + using Allocator = std::allocator; + using AllocatorTraits = std::allocator_traits; + using value_type = typename AllocatorTraits::value_type; + using pointer = typename AllocatorTraits::pointer; + using const_pointer = typename AllocatorTraits::const_pointer; + using size_type = typename AllocatorTraits::size_type; + using difference_type = typename AllocatorTraits::difference_type; - CountingAllocator() : bytes_used_(nullptr) {} - explicit CountingAllocator(int64_t* b) : bytes_used_(b) {} + CountingAllocator() = default; + explicit CountingAllocator(int64_t* bytes_used) : bytes_used_(bytes_used) {} + CountingAllocator(int64_t* bytes_used, int64_t* instance_count) + : bytes_used_(bytes_used), instance_count_(instance_count) {} template CountingAllocator(const CountingAllocator& x) - : Alloc(x), bytes_used_(x.bytes_used_) {} + : bytes_used_(x.bytes_used_), instance_count_(x.instance_count_) {} - pointer allocate(size_type n, - std::allocator::const_pointer hint = nullptr) { - assert(bytes_used_ != nullptr); - *bytes_used_ += n * sizeof(T); - return Alloc::allocate(n, hint); + pointer allocate( + size_type n, + typename AllocatorTraits::const_void_pointer hint = nullptr) { + Allocator allocator; + pointer ptr = AllocatorTraits::allocate(allocator, n, hint); + if (bytes_used_ != nullptr) { + *bytes_used_ += n * sizeof(T); + } + return ptr; } void deallocate(pointer p, size_type n) { - Alloc::deallocate(p, n); - assert(bytes_used_ != nullptr); - *bytes_used_ -= n * sizeof(T); + Allocator allocator; + AllocatorTraits::deallocate(allocator, p, n); + if (bytes_used_ != nullptr) { + *bytes_used_ -= n * sizeof(T); + } } - template + template + void construct(U* p, Args&&... args) { + Allocator allocator; + AllocatorTraits::construct(allocator, p, std::forward(args)...); + if (instance_count_ != nullptr) { + *instance_count_ += 1; + } + } + + template + void destroy(U* p) { + Allocator allocator; + AllocatorTraits::destroy(allocator, p); + if (instance_count_ != nullptr) { + *instance_count_ -= 1; + } + } + + template class rebind { public: using other = CountingAllocator; @@ -65,7 +94,8 @@ class CountingAllocator : public std::allocator { friend bool operator==(const CountingAllocator& a, const CountingAllocator& b) { - return a.bytes_used_ == b.bytes_used_; + return a.bytes_used_ == b.bytes_used_ && + a.instance_count_ == b.instance_count_; } friend bool operator!=(const CountingAllocator& a, @@ -73,7 +103,8 @@ class CountingAllocator : public std::allocator { return !(a == b); } - int64_t* bytes_used_; + int64_t* bytes_used_ = nullptr; + int64_t* instance_count_ = nullptr; }; } // namespace container_internal diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/hash_function_defaults.h b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/hash_function_defaults.h index 0683422ad8..250e662c9d 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/hash_function_defaults.h +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/hash_function_defaults.h @@ -78,24 +78,26 @@ struct StringHash { } }; +struct StringEq { + using is_transparent = void; + bool operator()(absl::string_view lhs, absl::string_view rhs) const { + return lhs == rhs; + } + bool operator()(const absl::Cord& lhs, const absl::Cord& rhs) const { + return lhs == rhs; + } + bool operator()(const absl::Cord& lhs, absl::string_view rhs) const { + return lhs == rhs; + } + bool operator()(absl::string_view lhs, const absl::Cord& rhs) const { + return lhs == rhs; + } +}; + // Supports heterogeneous lookup for string-like elements. struct StringHashEq { using Hash = StringHash; - struct Eq { - using is_transparent = void; - bool operator()(absl::string_view lhs, absl::string_view rhs) const { - return lhs == rhs; - } - bool operator()(const absl::Cord& lhs, const absl::Cord& rhs) const { - return lhs == rhs; - } - bool operator()(const absl::Cord& lhs, absl::string_view rhs) const { - return lhs == rhs; - } - bool operator()(absl::string_view lhs, const absl::Cord& rhs) const { - return lhs == rhs; - } - }; + using Eq = StringEq; }; template <> diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/hash_function_defaults_test.cc b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/hash_function_defaults_test.cc index 2d05a0b72a..59576b8ede 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/hash_function_defaults_test.cc +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/hash_function_defaults_test.cc @@ -337,11 +337,11 @@ ABSL_NAMESPACE_END } // namespace absl enum Hash : size_t { - kStd = 0x2, // std::hash + kStd = 0x1, // std::hash #ifdef _MSC_VER kExtension = kStd, // In MSVC, std::hash == ::hash #else // _MSC_VER - kExtension = 0x4, // ::hash (GCC extension) + kExtension = 0x2, // ::hash (GCC extension) #endif // _MSC_VER }; diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/hash_generator_testing.cc b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/hash_generator_testing.cc index 75c4db6c36..59cc5aac7a 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/hash_generator_testing.cc +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/hash_generator_testing.cc @@ -41,8 +41,10 @@ class RandomDeviceSeedSeq { } // namespace std::mt19937_64* GetSharedRng() { - RandomDeviceSeedSeq seed_seq; - static auto* rng = new std::mt19937_64(seed_seq); + static auto* rng = [] { + RandomDeviceSeedSeq seed_seq; + return new std::mt19937_64(seed_seq); + }(); return rng; } diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/hash_generator_testing.h b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/hash_generator_testing.h index 6869fe45e8..f1f555a5c1 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/hash_generator_testing.h +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/hash_generator_testing.h @@ -21,11 +21,13 @@ #include #include +#include #include #include #include #include #include +#include #include "absl/container/internal/hash_policy_testing.h" #include "absl/memory/memory.h" @@ -153,6 +155,25 @@ using GeneratedType = decltype( typename Container::value_type, typename Container::key_type>::type>&>()()); +// Naive wrapper that performs a linear search of previous values. +// Beware this is O(SQR), which is reasonable for smaller kMaxValues. +template +struct UniqueGenerator { + Generator gen; + std::vector values; + + T operator()() { + assert(values.size() < kMaxValues); + for (;;) { + T value = gen(); + if (std::find(values.begin(), values.end(), value) == values.end()) { + values.push_back(value); + return value; + } + } + } +}; + } // namespace hash_internal } // namespace container_internal ABSL_NAMESPACE_END diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/hash_policy_traits.h b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/hash_policy_traits.h index 3e1209c6eb..46c97b18a2 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/hash_policy_traits.h +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/hash_policy_traits.h @@ -17,6 +17,7 @@ #include #include +#include #include #include @@ -29,15 +30,34 @@ namespace container_internal { // Defines how slots are initialized/destroyed/moved. template struct hash_policy_traits { + // The type of the keys stored in the hashtable. + using key_type = typename Policy::key_type; + private: struct ReturnKey { - // We return `Key` here. + // When C++17 is available, we can use std::launder to provide mutable + // access to the key for use in node handle. +#if defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606 + template ::value, int> = 0> + static key_type& Impl(Key&& k, int) { + return *std::launder( + const_cast(std::addressof(std::forward(k)))); + } +#endif + + template + static Key Impl(Key&& k, char) { + return std::forward(k); + } + // When Key=T&, we forward the lvalue reference. // When Key=T, we return by value to avoid a dangling reference. // eg, for string_hash_map. template - Key operator()(Key&& k, const Args&...) const { - return std::forward(k); + auto operator()(Key&& k, const Args&...) const + -> decltype(Impl(std::forward(k), 0)) { + return Impl(std::forward(k), 0); } }; @@ -52,9 +72,6 @@ struct hash_policy_traits { // The actual object stored in the hash table. using slot_type = typename Policy::slot_type; - // The type of the keys stored in the hashtable. - using key_type = typename Policy::key_type; - // The argument type for insertions into the hashtable. This is different // from value_type for increased performance. See initializer_list constructor // and insert() member functions for more details. @@ -156,7 +173,7 @@ struct hash_policy_traits { // Returns the "key" portion of the slot. // Used for node handle manipulation. template - static auto key(slot_type* slot) + static auto mutable_key(slot_type* slot) -> decltype(P::apply(ReturnKey(), element(slot))) { return P::apply(ReturnKey(), element(slot)); } diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/hashtablez_sampler.cc b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/hashtablez_sampler.cc index 886524f180..4b1337051f 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/hashtablez_sampler.cc +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/hashtablez_sampler.cc @@ -25,6 +25,7 @@ #include "absl/container/internal/have_sse.h" #include "absl/debugging/stacktrace.h" #include "absl/memory/memory.h" +#include "absl/profiling/internal/sample_recorder.h" #include "absl/synchronization/mutex.h" namespace absl { @@ -37,7 +38,6 @@ ABSL_CONST_INIT std::atomic g_hashtablez_enabled{ false }; ABSL_CONST_INIT std::atomic g_hashtablez_sample_parameter{1 << 10}; -ABSL_CONST_INIT std::atomic g_hashtablez_max_samples{1 << 20}; #if defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE) ABSL_PER_THREAD_TLS_KEYWORD absl::base_internal::ExponentialBiased @@ -50,16 +50,11 @@ ABSL_PER_THREAD_TLS_KEYWORD absl::base_internal::ExponentialBiased ABSL_PER_THREAD_TLS_KEYWORD int64_t global_next_sample = 0; #endif // defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE) -HashtablezSampler& HashtablezSampler::Global() { +HashtablezSampler& GlobalHashtablezSampler() { static auto* sampler = new HashtablezSampler(); return *sampler; } -HashtablezSampler::DisposeCallback HashtablezSampler::SetDisposeCallback( - DisposeCallback f) { - return dispose_.exchange(f, std::memory_order_relaxed); -} - HashtablezInfo::HashtablezInfo() { PrepareForSampling(); } HashtablezInfo::~HashtablezInfo() = default; @@ -67,10 +62,13 @@ void HashtablezInfo::PrepareForSampling() { capacity.store(0, std::memory_order_relaxed); size.store(0, std::memory_order_relaxed); num_erases.store(0, std::memory_order_relaxed); + num_rehashes.store(0, std::memory_order_relaxed); max_probe_length.store(0, std::memory_order_relaxed); total_probe_length.store(0, std::memory_order_relaxed); hashes_bitwise_or.store(0, std::memory_order_relaxed); hashes_bitwise_and.store(~size_t{}, std::memory_order_relaxed); + hashes_bitwise_xor.store(0, std::memory_order_relaxed); + max_reserve.store(0, std::memory_order_relaxed); create_time = absl::Now(); // The inliner makes hardcoded skip_count difficult (especially when combined @@ -78,93 +76,6 @@ void HashtablezInfo::PrepareForSampling() { // instead. depth = absl::GetStackTrace(stack, HashtablezInfo::kMaxStackDepth, /* skip_count= */ 0); - dead = nullptr; -} - -HashtablezSampler::HashtablezSampler() - : dropped_samples_(0), size_estimate_(0), all_(nullptr), dispose_(nullptr) { - absl::MutexLock l(&graveyard_.init_mu); - graveyard_.dead = &graveyard_; -} - -HashtablezSampler::~HashtablezSampler() { - HashtablezInfo* s = all_.load(std::memory_order_acquire); - while (s != nullptr) { - HashtablezInfo* next = s->next; - delete s; - s = next; - } -} - -void HashtablezSampler::PushNew(HashtablezInfo* sample) { - sample->next = all_.load(std::memory_order_relaxed); - while (!all_.compare_exchange_weak(sample->next, sample, - std::memory_order_release, - std::memory_order_relaxed)) { - } -} - -void HashtablezSampler::PushDead(HashtablezInfo* sample) { - if (auto* dispose = dispose_.load(std::memory_order_relaxed)) { - dispose(*sample); - } - - absl::MutexLock graveyard_lock(&graveyard_.init_mu); - absl::MutexLock sample_lock(&sample->init_mu); - sample->dead = graveyard_.dead; - graveyard_.dead = sample; -} - -HashtablezInfo* HashtablezSampler::PopDead() { - absl::MutexLock graveyard_lock(&graveyard_.init_mu); - - // The list is circular, so eventually it collapses down to - // graveyard_.dead == &graveyard_ - // when it is empty. - HashtablezInfo* sample = graveyard_.dead; - if (sample == &graveyard_) return nullptr; - - absl::MutexLock sample_lock(&sample->init_mu); - graveyard_.dead = sample->dead; - sample->PrepareForSampling(); - return sample; -} - -HashtablezInfo* HashtablezSampler::Register() { - int64_t size = size_estimate_.fetch_add(1, std::memory_order_relaxed); - if (size > g_hashtablez_max_samples.load(std::memory_order_relaxed)) { - size_estimate_.fetch_sub(1, std::memory_order_relaxed); - dropped_samples_.fetch_add(1, std::memory_order_relaxed); - return nullptr; - } - - HashtablezInfo* sample = PopDead(); - if (sample == nullptr) { - // Resurrection failed. Hire a new warlock. - sample = new HashtablezInfo(); - PushNew(sample); - } - - return sample; -} - -void HashtablezSampler::Unregister(HashtablezInfo* sample) { - PushDead(sample); - size_estimate_.fetch_sub(1, std::memory_order_relaxed); -} - -int64_t HashtablezSampler::Iterate( - const std::function& f) { - HashtablezInfo* s = all_.load(std::memory_order_acquire); - while (s != nullptr) { - absl::MutexLock l(&s->init_mu); - if (s->dead == nullptr) { - f(*s); - } - s = s->next; - } - - return dropped_samples_.load(std::memory_order_relaxed); } static bool ShouldForceSampling() { @@ -179,7 +90,9 @@ static bool ShouldForceSampling() { if (ABSL_PREDICT_TRUE(state == kDontForce)) return false; if (state == kUninitialized) { - state = AbslContainerInternalSampleEverything() ? kForce : kDontForce; + state = ABSL_INTERNAL_C_SYMBOL(AbslContainerInternalSampleEverything)() + ? kForce + : kDontForce; global_state.store(state, std::memory_order_relaxed); } return state == kForce; @@ -188,7 +101,7 @@ static bool ShouldForceSampling() { HashtablezInfo* SampleSlow(int64_t* next_sample) { if (ABSL_PREDICT_FALSE(ShouldForceSampling())) { *next_sample = 1; - return HashtablezSampler::Global().Register(); + return GlobalHashtablezSampler().Register(); } #if !defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE) @@ -213,12 +126,12 @@ HashtablezInfo* SampleSlow(int64_t* next_sample) { return SampleSlow(next_sample); } - return HashtablezSampler::Global().Register(); + return GlobalHashtablezSampler().Register(); #endif } void UnsampleSlow(HashtablezInfo* info) { - HashtablezSampler::Global().Unregister(info); + GlobalHashtablezSampler().Unregister(info); } void RecordInsertSlow(HashtablezInfo* info, size_t hash, @@ -234,6 +147,7 @@ void RecordInsertSlow(HashtablezInfo* info, size_t hash, info->hashes_bitwise_and.fetch_and(hash, std::memory_order_relaxed); info->hashes_bitwise_or.fetch_or(hash, std::memory_order_relaxed); + info->hashes_bitwise_xor.fetch_xor(hash, std::memory_order_relaxed); info->max_probe_length.store( std::max(info->max_probe_length.load(std::memory_order_relaxed), probe_length), @@ -257,7 +171,7 @@ void SetHashtablezSampleParameter(int32_t rate) { void SetHashtablezMaxSamples(int32_t max) { if (max > 0) { - g_hashtablez_max_samples.store(max, std::memory_order_release); + GlobalHashtablezSampler().SetMaxSamples(max); } else { ABSL_RAW_LOG(ERROR, "Invalid hashtablez max samples: %lld", static_cast(max)); // NOLINT(runtime/int) diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/hashtablez_sampler.h b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/hashtablez_sampler.h index 8aaffc35a2..812118e3a9 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/hashtablez_sampler.h +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/hashtablez_sampler.h @@ -47,6 +47,7 @@ #include "absl/base/internal/per_thread_tls.h" #include "absl/base/optimization.h" #include "absl/container/internal/have_sse.h" +#include "absl/profiling/internal/sample_recorder.h" #include "absl/synchronization/mutex.h" #include "absl/utility/utility.h" @@ -57,7 +58,7 @@ namespace container_internal { // Stores information about a sampled hashtable. All mutations to this *must* // be made through `Record*` functions below. All reads from this *must* only // occur in the callback to `HashtablezSampler::Iterate`. -struct HashtablezInfo { +struct HashtablezInfo : public profiling_internal::Sample { // Constructs the object but does not fill in any fields. HashtablezInfo(); ~HashtablezInfo(); @@ -73,18 +74,13 @@ struct HashtablezInfo { std::atomic capacity; std::atomic size; std::atomic num_erases; + std::atomic num_rehashes; std::atomic max_probe_length; std::atomic total_probe_length; std::atomic hashes_bitwise_or; std::atomic hashes_bitwise_and; - - // `HashtablezSampler` maintains intrusive linked lists for all samples. See - // comments on `HashtablezSampler::all_` for details on these. `init_mu` - // guards the ability to restore the sample to a pristine state. This - // prevents races with sampling and resurrecting an object. - absl::Mutex init_mu; - HashtablezInfo* next; - HashtablezInfo* dead ABSL_GUARDED_BY(init_mu); + std::atomic hashes_bitwise_xor; + std::atomic max_reserve; // All of the fields below are set by `PrepareForSampling`, they must not be // mutated in `Record*` functions. They are logically `const` in that sense. @@ -105,6 +101,23 @@ inline void RecordRehashSlow(HashtablezInfo* info, size_t total_probe_length) { #endif info->total_probe_length.store(total_probe_length, std::memory_order_relaxed); info->num_erases.store(0, std::memory_order_relaxed); + // There is only one concurrent writer, so `load` then `store` is sufficient + // instead of using `fetch_add`. + info->num_rehashes.store( + 1 + info->num_rehashes.load(std::memory_order_relaxed), + std::memory_order_relaxed); +} + +inline void RecordReservationSlow(HashtablezInfo* info, + size_t target_capacity) { + info->max_reserve.store( + (std::max)(info->max_reserve.load(std::memory_order_relaxed), + target_capacity), + std::memory_order_relaxed); +} + +inline void RecordClearedReservationSlow(HashtablezInfo* info) { + info->max_reserve.store(0, std::memory_order_relaxed); } inline void RecordStorageChangedSlow(HashtablezInfo* info, size_t size, @@ -113,7 +126,8 @@ inline void RecordStorageChangedSlow(HashtablezInfo* info, size_t size, info->capacity.store(capacity, std::memory_order_relaxed); if (size == 0) { // This is a clear, reset the total/num_erases too. - RecordRehashSlow(info, 0); + info->total_probe_length.store(0, std::memory_order_relaxed); + info->num_erases.store(0, std::memory_order_relaxed); } } @@ -122,12 +136,21 @@ void RecordInsertSlow(HashtablezInfo* info, size_t hash, inline void RecordEraseSlow(HashtablezInfo* info) { info->size.fetch_sub(1, std::memory_order_relaxed); - info->num_erases.fetch_add(1, std::memory_order_relaxed); + // There is only one concurrent writer, so `load` then `store` is sufficient + // instead of using `fetch_add`. + info->num_erases.store( + 1 + info->num_erases.load(std::memory_order_relaxed), + std::memory_order_relaxed); } HashtablezInfo* SampleSlow(int64_t* next_sample); void UnsampleSlow(HashtablezInfo* info); +#if defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE) +#error ABSL_INTERNAL_HASHTABLEZ_SAMPLE cannot be directly set +#endif // defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE) + +#if defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE) class HashtablezInfoHandle { public: explicit HashtablezInfoHandle() : info_(nullptr) {} @@ -160,6 +183,16 @@ class HashtablezInfoHandle { RecordRehashSlow(info_, total_probe_length); } + inline void RecordReservation(size_t target_capacity) { + if (ABSL_PREDICT_TRUE(info_ == nullptr)) return; + RecordReservationSlow(info_, target_capacity); + } + + inline void RecordClearedReservation() { + if (ABSL_PREDICT_TRUE(info_ == nullptr)) return; + RecordClearedReservationSlow(info_); + } + inline void RecordInsert(size_t hash, size_t distance_from_desired) { if (ABSL_PREDICT_TRUE(info_ == nullptr)) return; RecordInsertSlow(info_, hash, distance_from_desired); @@ -179,19 +212,29 @@ class HashtablezInfoHandle { friend class HashtablezInfoHandlePeer; HashtablezInfo* info_; }; +#else +// Ensure that when Hashtablez is turned off at compile time, HashtablezInfo can +// be removed by the linker, in order to reduce the binary size. +class HashtablezInfoHandle { + public: + explicit HashtablezInfoHandle() = default; + explicit HashtablezInfoHandle(std::nullptr_t) {} -#if defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE) -#error ABSL_INTERNAL_HASHTABLEZ_SAMPLE cannot be directly set + inline void RecordStorageChanged(size_t /*size*/, size_t /*capacity*/) {} + inline void RecordRehash(size_t /*total_probe_length*/) {} + inline void RecordReservation(size_t /*target_capacity*/) {} + inline void RecordClearedReservation() {} + inline void RecordInsert(size_t /*hash*/, size_t /*distance_from_desired*/) {} + inline void RecordErase() {} + + friend inline void swap(HashtablezInfoHandle& /*lhs*/, + HashtablezInfoHandle& /*rhs*/) {} +}; #endif // defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE) -#if (ABSL_PER_THREAD_TLS == 1) && !defined(ABSL_BUILD_DLL) && \ - !defined(ABSL_CONSUME_DLL) -#define ABSL_INTERNAL_HASHTABLEZ_SAMPLE -#endif - #if defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE) extern ABSL_PER_THREAD_TLS_KEYWORD int64_t global_next_sample; -#endif // ABSL_PER_THREAD_TLS +#endif // defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE) // Returns an RAII sampling handle that manages registration and unregistation // with the global sampler. @@ -206,73 +249,11 @@ inline HashtablezInfoHandle Sample() { #endif // !ABSL_PER_THREAD_TLS } -// Holds samples and their associated stack traces with a soft limit of -// `SetHashtablezMaxSamples()`. -// -// Thread safe. -class HashtablezSampler { - public: - // Returns a global Sampler. - static HashtablezSampler& Global(); +using HashtablezSampler = + ::absl::profiling_internal::SampleRecorder; - HashtablezSampler(); - ~HashtablezSampler(); - - // Registers for sampling. Returns an opaque registration info. - HashtablezInfo* Register(); - - // Unregisters the sample. - void Unregister(HashtablezInfo* sample); - - // The dispose callback will be called on all samples the moment they are - // being unregistered. Only affects samples that are unregistered after the - // callback has been set. - // Returns the previous callback. - using DisposeCallback = void (*)(const HashtablezInfo&); - DisposeCallback SetDisposeCallback(DisposeCallback f); - - // Iterates over all the registered `StackInfo`s. Returning the number of - // samples that have been dropped. - int64_t Iterate(const std::function& f); - - private: - void PushNew(HashtablezInfo* sample); - void PushDead(HashtablezInfo* sample); - HashtablezInfo* PopDead(); - - std::atomic dropped_samples_; - std::atomic size_estimate_; - - // Intrusive lock free linked lists for tracking samples. - // - // `all_` records all samples (they are never removed from this list) and is - // terminated with a `nullptr`. - // - // `graveyard_.dead` is a circular linked list. When it is empty, - // `graveyard_.dead == &graveyard`. The list is circular so that - // every item on it (even the last) has a non-null dead pointer. This allows - // `Iterate` to determine if a given sample is live or dead using only - // information on the sample itself. - // - // For example, nodes [A, B, C, D, E] with [A, C, E] alive and [B, D] dead - // looks like this (G is the Graveyard): - // - // +---+ +---+ +---+ +---+ +---+ - // all -->| A |--->| B |--->| C |--->| D |--->| E | - // | | | | | | | | | | - // +---+ | | +->| |-+ | | +->| |-+ | | - // | G | +---+ | +---+ | +---+ | +---+ | +---+ - // | | | | | | - // | | --------+ +--------+ | - // +---+ | - // ^ | - // +--------------------------------------+ - // - std::atomic all_; - HashtablezInfo graveyard_; - - std::atomic dispose_; -}; +// Returns a global Sampler. +HashtablezSampler& GlobalHashtablezSampler(); // Enables or disables sampling for Swiss tables. void SetHashtablezEnabled(bool enabled); @@ -288,7 +269,7 @@ void SetHashtablezMaxSamples(int32_t max); // initialization of static storage duration objects. // The definition of this constant is weak, which allows us to inject a // different value for it at link time. -extern "C" bool AbslContainerInternalSampleEverything(); +extern "C" bool ABSL_INTERNAL_C_SYMBOL(AbslContainerInternalSampleEverything)(); } // namespace container_internal ABSL_NAMESPACE_END diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/hashtablez_sampler_force_weak_definition.cc b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/hashtablez_sampler_force_weak_definition.cc index 78b9d362ac..ed35a7eec3 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/hashtablez_sampler_force_weak_definition.cc +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/hashtablez_sampler_force_weak_definition.cc @@ -21,7 +21,8 @@ ABSL_NAMESPACE_BEGIN namespace container_internal { // See hashtablez_sampler.h for details. -extern "C" ABSL_ATTRIBUTE_WEAK bool AbslContainerInternalSampleEverything() { +extern "C" ABSL_ATTRIBUTE_WEAK bool ABSL_INTERNAL_C_SYMBOL( + AbslContainerInternalSampleEverything)() { return false; } diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/hashtablez_sampler_test.cc b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/hashtablez_sampler_test.cc index b4c4ff92e7..f053c19ba3 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/hashtablez_sampler_test.cc +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/hashtablez_sampler_test.cc @@ -22,6 +22,7 @@ #include "gtest/gtest.h" #include "absl/base/attributes.h" #include "absl/container/internal/have_sse.h" +#include "absl/profiling/internal/sample_recorder.h" #include "absl/synchronization/blocking_counter.h" #include "absl/synchronization/internal/thread_pool.h" #include "absl/synchronization/mutex.h" @@ -38,6 +39,7 @@ constexpr int kProbeLength = 8; namespace absl { ABSL_NAMESPACE_BEGIN namespace container_internal { +#if defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE) class HashtablezInfoHandlePeer { public: static bool IsSampled(const HashtablezInfoHandle& h) { @@ -46,6 +48,13 @@ class HashtablezInfoHandlePeer { static HashtablezInfo* GetInfo(HashtablezInfoHandle* h) { return h->info_; } }; +#else +class HashtablezInfoHandlePeer { + public: + static bool IsSampled(const HashtablezInfoHandle&) { return false; } + static HashtablezInfo* GetInfo(HashtablezInfoHandle*) { return nullptr; } +}; +#endif // defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE) namespace { using ::absl::synchronization_internal::ThreadPool; @@ -76,10 +85,13 @@ TEST(HashtablezInfoTest, PrepareForSampling) { EXPECT_EQ(info.capacity.load(), 0); EXPECT_EQ(info.size.load(), 0); EXPECT_EQ(info.num_erases.load(), 0); + EXPECT_EQ(info.num_rehashes.load(), 0); EXPECT_EQ(info.max_probe_length.load(), 0); EXPECT_EQ(info.total_probe_length.load(), 0); EXPECT_EQ(info.hashes_bitwise_or.load(), 0); EXPECT_EQ(info.hashes_bitwise_and.load(), ~size_t{}); + EXPECT_EQ(info.hashes_bitwise_xor.load(), 0); + EXPECT_EQ(info.max_reserve.load(), 0); EXPECT_GE(info.create_time, test_start); info.capacity.store(1, std::memory_order_relaxed); @@ -89,16 +101,21 @@ TEST(HashtablezInfoTest, PrepareForSampling) { info.total_probe_length.store(1, std::memory_order_relaxed); info.hashes_bitwise_or.store(1, std::memory_order_relaxed); info.hashes_bitwise_and.store(1, std::memory_order_relaxed); + info.hashes_bitwise_xor.store(1, std::memory_order_relaxed); + info.max_reserve.store(1, std::memory_order_relaxed); info.create_time = test_start - absl::Hours(20); info.PrepareForSampling(); EXPECT_EQ(info.capacity.load(), 0); EXPECT_EQ(info.size.load(), 0); EXPECT_EQ(info.num_erases.load(), 0); + EXPECT_EQ(info.num_rehashes.load(), 0); EXPECT_EQ(info.max_probe_length.load(), 0); EXPECT_EQ(info.total_probe_length.load(), 0); EXPECT_EQ(info.hashes_bitwise_or.load(), 0); EXPECT_EQ(info.hashes_bitwise_and.load(), ~size_t{}); + EXPECT_EQ(info.hashes_bitwise_xor.load(), 0); + EXPECT_EQ(info.max_reserve.load(), 0); EXPECT_GE(info.create_time, test_start); } @@ -123,14 +140,17 @@ TEST(HashtablezInfoTest, RecordInsert) { EXPECT_EQ(info.max_probe_length.load(), 6); EXPECT_EQ(info.hashes_bitwise_and.load(), 0x0000FF00); EXPECT_EQ(info.hashes_bitwise_or.load(), 0x0000FF00); + EXPECT_EQ(info.hashes_bitwise_xor.load(), 0x0000FF00); RecordInsertSlow(&info, 0x000FF000, 4 * kProbeLength); EXPECT_EQ(info.max_probe_length.load(), 6); EXPECT_EQ(info.hashes_bitwise_and.load(), 0x0000F000); EXPECT_EQ(info.hashes_bitwise_or.load(), 0x000FFF00); + EXPECT_EQ(info.hashes_bitwise_xor.load(), 0x000F0F00); RecordInsertSlow(&info, 0x00FF0000, 12 * kProbeLength); EXPECT_EQ(info.max_probe_length.load(), 12); EXPECT_EQ(info.hashes_bitwise_and.load(), 0x00000000); EXPECT_EQ(info.hashes_bitwise_or.load(), 0x00FFFF00); + EXPECT_EQ(info.hashes_bitwise_xor.load(), 0x00F00F00); } TEST(HashtablezInfoTest, RecordErase) { @@ -167,9 +187,26 @@ TEST(HashtablezInfoTest, RecordRehash) { EXPECT_EQ(info.size.load(), 2); EXPECT_EQ(info.total_probe_length.load(), 3); EXPECT_EQ(info.num_erases.load(), 0); + EXPECT_EQ(info.num_rehashes.load(), 1); } -#if defined(ABSL_HASHTABLEZ_SAMPLE) +TEST(HashtablezInfoTest, RecordReservation) { + HashtablezInfo info; + absl::MutexLock l(&info.init_mu); + info.PrepareForSampling(); + RecordReservationSlow(&info, 3); + EXPECT_EQ(info.max_reserve.load(), 3); + + RecordReservationSlow(&info, 2); + // High watermark does not change + EXPECT_EQ(info.max_reserve.load(), 3); + + RecordReservationSlow(&info, 10); + // High watermark does change + EXPECT_EQ(info.max_reserve.load(), 10); +} + +#if defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE) TEST(HashtablezSamplerTest, SmallSampleParameter) { SetHashtablezEnabled(true); SetHashtablezSampleParameter(100); @@ -213,10 +250,9 @@ TEST(HashtablezSamplerTest, Sample) { } EXPECT_NEAR(sample_rate, 0.01, 0.005); } -#endif TEST(HashtablezSamplerTest, Handle) { - auto& sampler = HashtablezSampler::Global(); + auto& sampler = GlobalHashtablezSampler(); HashtablezInfoHandle h(sampler.Register()); auto* info = HashtablezInfoHandlePeer::GetInfo(&h); info->hashes_bitwise_and.store(0x12345678, std::memory_order_relaxed); @@ -243,6 +279,8 @@ TEST(HashtablezSamplerTest, Handle) { }); EXPECT_FALSE(found); } +#endif + TEST(HashtablezSamplerTest, Registration) { HashtablezSampler sampler; diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/inlined_vector.h b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/inlined_vector.h index 4d80b727bf..1cfba9b218 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/inlined_vector.h +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/inlined_vector.h @@ -33,96 +33,131 @@ namespace absl { ABSL_NAMESPACE_BEGIN namespace inlined_vector_internal { +// GCC does not deal very well with the below code +#if !defined(__clang__) && defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Warray-bounds" +#pragma GCC diagnostic ignored "-Wmaybe-uninitialized" +#endif + +template +using AllocatorTraits = std::allocator_traits; +template +using ValueType = typename AllocatorTraits::value_type; +template +using SizeType = typename AllocatorTraits::size_type; +template +using Pointer = typename AllocatorTraits::pointer; +template +using ConstPointer = typename AllocatorTraits::const_pointer; +template +using SizeType = typename AllocatorTraits::size_type; +template +using DifferenceType = typename AllocatorTraits::difference_type; +template +using Reference = ValueType&; +template +using ConstReference = const ValueType&; +template +using Iterator = Pointer; +template +using ConstIterator = ConstPointer; +template +using ReverseIterator = typename std::reverse_iterator>; +template +using ConstReverseIterator = typename std::reverse_iterator>; +template +using MoveIterator = typename std::move_iterator>; + template using IsAtLeastForwardIterator = std::is_convertible< typename std::iterator_traits::iterator_category, std::forward_iterator_tag>; -template ::value_type> +template using IsMemcpyOk = - absl::conjunction>, - absl::is_trivially_copy_constructible, - absl::is_trivially_copy_assignable, - absl::is_trivially_destructible>; + absl::conjunction>>, + absl::is_trivially_copy_constructible>, + absl::is_trivially_copy_assignable>, + absl::is_trivially_destructible>>; -template -void DestroyElements(AllocatorType* alloc_ptr, Pointer destroy_first, - SizeType destroy_size) { - using AllocatorTraits = absl::allocator_traits; +template +struct TypeIdentity { + using type = T; +}; +// Used for function arguments in template functions to prevent ADL by forcing +// callers to explicitly specify the template parameter. +template +using NoTypeDeduction = typename TypeIdentity::type; + +template +void DestroyElements(NoTypeDeduction& allocator, Pointer destroy_first, + SizeType destroy_size) { if (destroy_first != nullptr) { for (auto i = destroy_size; i != 0;) { --i; - AllocatorTraits::destroy(*alloc_ptr, destroy_first + i); + AllocatorTraits::destroy(allocator, destroy_first + i); } - -#if !defined(NDEBUG) - { - using ValueType = typename AllocatorTraits::value_type; - - // Overwrite unused memory with `0xab` so we can catch uninitialized - // usage. - // - // Cast to `void*` to tell the compiler that we don't care that we might - // be scribbling on a vtable pointer. - void* memory_ptr = destroy_first; - auto memory_size = destroy_size * sizeof(ValueType); - std::memset(memory_ptr, 0xab, memory_size); - } -#endif // !defined(NDEBUG) } } -template -void ConstructElements(AllocatorType* alloc_ptr, Pointer construct_first, - ValueAdapter* values_ptr, SizeType construct_size) { - for (SizeType i = 0; i < construct_size; ++i) { - ABSL_INTERNAL_TRY { - values_ptr->ConstructNext(alloc_ptr, construct_first + i); - } +// If kUseMemcpy is true, memcpy(dst, src, n); else do nothing. +// Useful to avoid compiler warnings when memcpy() is used for T values +// that are not trivially copyable in non-reachable code. +template +inline void MemcpyIfAllowed(void* dst, const void* src, size_t n); + +// memcpy when allowed. +template <> +inline void MemcpyIfAllowed(void* dst, const void* src, size_t n) { + memcpy(dst, src, n); +} + +// Do nothing for types that are not memcpy-able. This function is only +// called from non-reachable branches. +template <> +inline void MemcpyIfAllowed(void*, const void*, size_t) {} + +template +void ConstructElements(NoTypeDeduction& allocator, + Pointer construct_first, ValueAdapter& values, + SizeType construct_size) { + for (SizeType i = 0; i < construct_size; ++i) { + ABSL_INTERNAL_TRY { values.ConstructNext(allocator, construct_first + i); } ABSL_INTERNAL_CATCH_ANY { - inlined_vector_internal::DestroyElements(alloc_ptr, construct_first, i); + DestroyElements(allocator, construct_first, i); ABSL_INTERNAL_RETHROW; } } } -template -void AssignElements(Pointer assign_first, ValueAdapter* values_ptr, - SizeType assign_size) { - for (SizeType i = 0; i < assign_size; ++i) { - values_ptr->AssignNext(assign_first + i); +template +void AssignElements(Pointer assign_first, ValueAdapter& values, + SizeType assign_size) { + for (SizeType i = 0; i < assign_size; ++i) { + values.AssignNext(assign_first + i); } } -template +template struct StorageView { - using AllocatorTraits = absl::allocator_traits; - using Pointer = typename AllocatorTraits::pointer; - using SizeType = typename AllocatorTraits::size_type; - - Pointer data; - SizeType size; - SizeType capacity; + Pointer data; + SizeType size; + SizeType capacity; }; -template +template class IteratorValueAdapter { - using AllocatorTraits = absl::allocator_traits; - using Pointer = typename AllocatorTraits::pointer; - public: explicit IteratorValueAdapter(const Iterator& it) : it_(it) {} - void ConstructNext(AllocatorType* alloc_ptr, Pointer construct_at) { - AllocatorTraits::construct(*alloc_ptr, construct_at, *it_); + void ConstructNext(A& allocator, Pointer construct_at) { + AllocatorTraits::construct(allocator, construct_at, *it_); ++it_; } - void AssignNext(Pointer assign_at) { + void AssignNext(Pointer assign_at) { *assign_at = *it_; ++it_; } @@ -131,68 +166,55 @@ class IteratorValueAdapter { Iterator it_; }; -template +template class CopyValueAdapter { - using AllocatorTraits = absl::allocator_traits; - using ValueType = typename AllocatorTraits::value_type; - using Pointer = typename AllocatorTraits::pointer; - using ConstPointer = typename AllocatorTraits::const_pointer; - public: - explicit CopyValueAdapter(const ValueType& v) : ptr_(std::addressof(v)) {} + explicit CopyValueAdapter(ConstPointer p) : ptr_(p) {} - void ConstructNext(AllocatorType* alloc_ptr, Pointer construct_at) { - AllocatorTraits::construct(*alloc_ptr, construct_at, *ptr_); + void ConstructNext(A& allocator, Pointer construct_at) { + AllocatorTraits::construct(allocator, construct_at, *ptr_); } - void AssignNext(Pointer assign_at) { *assign_at = *ptr_; } + void AssignNext(Pointer assign_at) { *assign_at = *ptr_; } private: - ConstPointer ptr_; + ConstPointer ptr_; }; -template +template class DefaultValueAdapter { - using AllocatorTraits = absl::allocator_traits; - using ValueType = typename AllocatorTraits::value_type; - using Pointer = typename AllocatorTraits::pointer; - public: explicit DefaultValueAdapter() {} - void ConstructNext(AllocatorType* alloc_ptr, Pointer construct_at) { - AllocatorTraits::construct(*alloc_ptr, construct_at); + void ConstructNext(A& allocator, Pointer construct_at) { + AllocatorTraits::construct(allocator, construct_at); } - void AssignNext(Pointer assign_at) { *assign_at = ValueType(); } + void AssignNext(Pointer assign_at) { *assign_at = ValueType(); } }; -template +template class AllocationTransaction { - using AllocatorTraits = absl::allocator_traits; - using Pointer = typename AllocatorTraits::pointer; - using SizeType = typename AllocatorTraits::size_type; - public: - explicit AllocationTransaction(AllocatorType* alloc_ptr) - : alloc_data_(*alloc_ptr, nullptr) {} + explicit AllocationTransaction(A& allocator) + : allocator_data_(allocator, nullptr), capacity_(0) {} ~AllocationTransaction() { if (DidAllocate()) { - AllocatorTraits::deallocate(GetAllocator(), GetData(), GetCapacity()); + AllocatorTraits::deallocate(GetAllocator(), GetData(), GetCapacity()); } } AllocationTransaction(const AllocationTransaction&) = delete; void operator=(const AllocationTransaction&) = delete; - AllocatorType& GetAllocator() { return alloc_data_.template get<0>(); } - Pointer& GetData() { return alloc_data_.template get<1>(); } - SizeType& GetCapacity() { return capacity_; } + A& GetAllocator() { return allocator_data_.template get<0>(); } + Pointer& GetData() { return allocator_data_.template get<1>(); } + SizeType& GetCapacity() { return capacity_; } bool DidAllocate() { return GetData() != nullptr; } - Pointer Allocate(SizeType capacity) { - GetData() = AllocatorTraits::allocate(GetAllocator(), capacity); + Pointer Allocate(SizeType capacity) { + GetData() = AllocatorTraits::allocate(GetAllocator(), capacity); GetCapacity() = capacity; return GetData(); } @@ -203,39 +225,33 @@ class AllocationTransaction { } private: - container_internal::CompressedTuple alloc_data_; - SizeType capacity_ = 0; + container_internal::CompressedTuple> allocator_data_; + SizeType capacity_; }; -template +template class ConstructionTransaction { - using AllocatorTraits = absl::allocator_traits; - using Pointer = typename AllocatorTraits::pointer; - using SizeType = typename AllocatorTraits::size_type; - public: - explicit ConstructionTransaction(AllocatorType* alloc_ptr) - : alloc_data_(*alloc_ptr, nullptr) {} + explicit ConstructionTransaction(A& allocator) + : allocator_data_(allocator, nullptr), size_(0) {} ~ConstructionTransaction() { if (DidConstruct()) { - inlined_vector_internal::DestroyElements(std::addressof(GetAllocator()), - GetData(), GetSize()); + DestroyElements(GetAllocator(), GetData(), GetSize()); } } ConstructionTransaction(const ConstructionTransaction&) = delete; void operator=(const ConstructionTransaction&) = delete; - AllocatorType& GetAllocator() { return alloc_data_.template get<0>(); } - Pointer& GetData() { return alloc_data_.template get<1>(); } - SizeType& GetSize() { return size_; } + A& GetAllocator() { return allocator_data_.template get<0>(); } + Pointer& GetData() { return allocator_data_.template get<1>(); } + SizeType& GetSize() { return size_; } bool DidConstruct() { return GetData() != nullptr; } template - void Construct(Pointer data, ValueAdapter* values_ptr, SizeType size) { - inlined_vector_internal::ConstructElements(std::addressof(GetAllocator()), - data, values_ptr, size); + void Construct(Pointer data, ValueAdapter& values, SizeType size) { + ConstructElements(GetAllocator(), data, values, size); GetData() = data; GetSize() = size; } @@ -245,52 +261,19 @@ class ConstructionTransaction { } private: - container_internal::CompressedTuple alloc_data_; - SizeType size_ = 0; + container_internal::CompressedTuple> allocator_data_; + SizeType size_; }; template class Storage { public: - using AllocatorTraits = absl::allocator_traits; - using allocator_type = typename AllocatorTraits::allocator_type; - using value_type = typename AllocatorTraits::value_type; - using pointer = typename AllocatorTraits::pointer; - using const_pointer = typename AllocatorTraits::const_pointer; - using size_type = typename AllocatorTraits::size_type; - using difference_type = typename AllocatorTraits::difference_type; - - using reference = value_type&; - using const_reference = const value_type&; - using RValueReference = value_type&&; - using iterator = pointer; - using const_iterator = const_pointer; - using reverse_iterator = std::reverse_iterator; - using const_reverse_iterator = std::reverse_iterator; - using MoveIterator = std::move_iterator; - using IsMemcpyOk = inlined_vector_internal::IsMemcpyOk; - - using StorageView = inlined_vector_internal::StorageView; - - template - using IteratorValueAdapter = - inlined_vector_internal::IteratorValueAdapter; - using CopyValueAdapter = - inlined_vector_internal::CopyValueAdapter; - using DefaultValueAdapter = - inlined_vector_internal::DefaultValueAdapter; - - using AllocationTransaction = - inlined_vector_internal::AllocationTransaction; - using ConstructionTransaction = - inlined_vector_internal::ConstructionTransaction; - - static size_type NextCapacity(size_type current_capacity) { + static SizeType NextCapacity(SizeType current_capacity) { return current_capacity * 2; } - static size_type ComputeCapacity(size_type current_capacity, - size_type requested_capacity) { + static SizeType ComputeCapacity(SizeType current_capacity, + SizeType requested_capacity) { return (std::max)(NextCapacity(current_capacity), requested_capacity); } @@ -298,140 +281,143 @@ class Storage { // Storage Constructors and Destructor // --------------------------------------------------------------------------- - Storage() : metadata_() {} + Storage() : metadata_(A(), /* size and is_allocated */ 0) {} - explicit Storage(const allocator_type& alloc) : metadata_(alloc, {}) {} + explicit Storage(const A& allocator) + : metadata_(allocator, /* size and is_allocated */ 0) {} ~Storage() { - pointer data = GetIsAllocated() ? GetAllocatedData() : GetInlinedData(); - inlined_vector_internal::DestroyElements(GetAllocPtr(), data, GetSize()); - DeallocateIfAllocated(); + if (GetSizeAndIsAllocated() == 0) { + // Empty and not allocated; nothing to do. + } else if (IsMemcpyOk::value) { + // No destructors need to be run; just deallocate if necessary. + DeallocateIfAllocated(); + } else { + DestroyContents(); + } } // --------------------------------------------------------------------------- // Storage Member Accessors // --------------------------------------------------------------------------- - size_type& GetSizeAndIsAllocated() { return metadata_.template get<1>(); } + SizeType& GetSizeAndIsAllocated() { return metadata_.template get<1>(); } - const size_type& GetSizeAndIsAllocated() const { + const SizeType& GetSizeAndIsAllocated() const { return metadata_.template get<1>(); } - size_type GetSize() const { return GetSizeAndIsAllocated() >> 1; } + SizeType GetSize() const { return GetSizeAndIsAllocated() >> 1; } bool GetIsAllocated() const { return GetSizeAndIsAllocated() & 1; } - pointer GetAllocatedData() { return data_.allocated.allocated_data; } + Pointer GetAllocatedData() { return data_.allocated.allocated_data; } - const_pointer GetAllocatedData() const { + ConstPointer GetAllocatedData() const { return data_.allocated.allocated_data; } - pointer GetInlinedData() { - return reinterpret_cast( + Pointer GetInlinedData() { + return reinterpret_cast>( std::addressof(data_.inlined.inlined_data[0])); } - const_pointer GetInlinedData() const { - return reinterpret_cast( + ConstPointer GetInlinedData() const { + return reinterpret_cast>( std::addressof(data_.inlined.inlined_data[0])); } - size_type GetAllocatedCapacity() const { + SizeType GetAllocatedCapacity() const { return data_.allocated.allocated_capacity; } - size_type GetInlinedCapacity() const { return static_cast(N); } + SizeType GetInlinedCapacity() const { return static_cast>(N); } - StorageView MakeStorageView() { - return GetIsAllocated() - ? StorageView{GetAllocatedData(), GetSize(), - GetAllocatedCapacity()} - : StorageView{GetInlinedData(), GetSize(), GetInlinedCapacity()}; + StorageView MakeStorageView() { + return GetIsAllocated() ? StorageView{GetAllocatedData(), GetSize(), + GetAllocatedCapacity()} + : StorageView{GetInlinedData(), GetSize(), + GetInlinedCapacity()}; } - allocator_type* GetAllocPtr() { - return std::addressof(metadata_.template get<0>()); - } + A& GetAllocator() { return metadata_.template get<0>(); } - const allocator_type* GetAllocPtr() const { - return std::addressof(metadata_.template get<0>()); - } + const A& GetAllocator() const { return metadata_.template get<0>(); } // --------------------------------------------------------------------------- // Storage Member Mutators // --------------------------------------------------------------------------- - template - void Initialize(ValueAdapter values, size_type new_size); + ABSL_ATTRIBUTE_NOINLINE void InitFrom(const Storage& other); template - void Assign(ValueAdapter values, size_type new_size); + void Initialize(ValueAdapter values, SizeType new_size); template - void Resize(ValueAdapter values, size_type new_size); + void Assign(ValueAdapter values, SizeType new_size); template - iterator Insert(const_iterator pos, ValueAdapter values, - size_type insert_count); + void Resize(ValueAdapter values, SizeType new_size); + + template + Iterator Insert(ConstIterator pos, ValueAdapter values, + SizeType insert_count); template - reference EmplaceBack(Args&&... args); + Reference EmplaceBack(Args&&... args); - iterator Erase(const_iterator from, const_iterator to); + Iterator Erase(ConstIterator from, ConstIterator to); - void Reserve(size_type requested_capacity); + void Reserve(SizeType requested_capacity); void ShrinkToFit(); void Swap(Storage* other_storage_ptr); void SetIsAllocated() { - GetSizeAndIsAllocated() |= static_cast(1); + GetSizeAndIsAllocated() |= static_cast>(1); } void UnsetIsAllocated() { - GetSizeAndIsAllocated() &= ((std::numeric_limits::max)() - 1); + GetSizeAndIsAllocated() &= ((std::numeric_limits>::max)() - 1); } - void SetSize(size_type size) { + void SetSize(SizeType size) { GetSizeAndIsAllocated() = - (size << 1) | static_cast(GetIsAllocated()); + (size << 1) | static_cast>(GetIsAllocated()); } - void SetAllocatedSize(size_type size) { - GetSizeAndIsAllocated() = (size << 1) | static_cast(1); + void SetAllocatedSize(SizeType size) { + GetSizeAndIsAllocated() = (size << 1) | static_cast>(1); } - void SetInlinedSize(size_type size) { - GetSizeAndIsAllocated() = size << static_cast(1); + void SetInlinedSize(SizeType size) { + GetSizeAndIsAllocated() = size << static_cast>(1); } - void AddSize(size_type count) { - GetSizeAndIsAllocated() += count << static_cast(1); + void AddSize(SizeType count) { + GetSizeAndIsAllocated() += count << static_cast>(1); } - void SubtractSize(size_type count) { + void SubtractSize(SizeType count) { assert(count <= GetSize()); - GetSizeAndIsAllocated() -= count << static_cast(1); + GetSizeAndIsAllocated() -= count << static_cast>(1); } - void SetAllocatedData(pointer data, size_type capacity) { + void SetAllocatedData(Pointer data, SizeType capacity) { data_.allocated.allocated_data = data; data_.allocated.allocated_capacity = capacity; } - void AcquireAllocatedData(AllocationTransaction* allocation_tx_ptr) { - SetAllocatedData(allocation_tx_ptr->GetData(), - allocation_tx_ptr->GetCapacity()); + void AcquireAllocatedData(AllocationTransaction& allocation_tx) { + SetAllocatedData(allocation_tx.GetData(), allocation_tx.GetCapacity()); - allocation_tx_ptr->Reset(); + allocation_tx.Reset(); } void MemcpyFrom(const Storage& other_storage) { - assert(IsMemcpyOk::value || other_storage.GetIsAllocated()); + assert(IsMemcpyOk::value || other_storage.GetIsAllocated()); GetSizeAndIsAllocated() = other_storage.GetSizeAndIsAllocated(); data_ = other_storage.data_; @@ -439,22 +425,23 @@ class Storage { void DeallocateIfAllocated() { if (GetIsAllocated()) { - AllocatorTraits::deallocate(*GetAllocPtr(), GetAllocatedData(), - GetAllocatedCapacity()); + AllocatorTraits::deallocate(GetAllocator(), GetAllocatedData(), + GetAllocatedCapacity()); } } private: - using Metadata = - container_internal::CompressedTuple; + ABSL_ATTRIBUTE_NOINLINE void DestroyContents(); + + using Metadata = container_internal::CompressedTuple>; struct Allocated { - pointer allocated_data; - size_type allocated_capacity; + Pointer allocated_data; + SizeType allocated_capacity; }; struct Inlined { - alignas(value_type) char inlined_data[sizeof(value_type[N])]; + alignas(ValueType) char inlined_data[sizeof(ValueType[N])]; }; union Data { @@ -462,33 +449,69 @@ class Storage { Inlined inlined; }; + template + ABSL_ATTRIBUTE_NOINLINE Reference EmplaceBackSlow(Args&&... args); + Metadata metadata_; Data data_; }; +template +void Storage::DestroyContents() { + Pointer data = GetIsAllocated() ? GetAllocatedData() : GetInlinedData(); + DestroyElements(GetAllocator(), data, GetSize()); + DeallocateIfAllocated(); +} + +template +void Storage::InitFrom(const Storage& other) { + const auto n = other.GetSize(); + assert(n > 0); // Empty sources handled handled in caller. + ConstPointer src; + Pointer dst; + if (!other.GetIsAllocated()) { + dst = GetInlinedData(); + src = other.GetInlinedData(); + } else { + // Because this is only called from the `InlinedVector` constructors, it's + // safe to take on the allocation with size `0`. If `ConstructElements(...)` + // throws, deallocation will be automatically handled by `~Storage()`. + SizeType new_capacity = ComputeCapacity(GetInlinedCapacity(), n); + dst = AllocatorTraits::allocate(GetAllocator(), new_capacity); + SetAllocatedData(dst, new_capacity); + src = other.GetAllocatedData(); + } + if (IsMemcpyOk::value) { + MemcpyIfAllowed::value>(dst, src, sizeof(dst[0]) * n); + } else { + auto values = IteratorValueAdapter>(src); + ConstructElements(GetAllocator(), dst, values, n); + } + GetSizeAndIsAllocated() = other.GetSizeAndIsAllocated(); +} + template template -auto Storage::Initialize(ValueAdapter values, size_type new_size) +auto Storage::Initialize(ValueAdapter values, SizeType new_size) -> void { // Only callable from constructors! assert(!GetIsAllocated()); assert(GetSize() == 0); - pointer construct_data; + Pointer construct_data; if (new_size > GetInlinedCapacity()) { // Because this is only called from the `InlinedVector` constructors, it's // safe to take on the allocation with size `0`. If `ConstructElements(...)` // throws, deallocation will be automatically handled by `~Storage()`. - size_type new_capacity = ComputeCapacity(GetInlinedCapacity(), new_size); - construct_data = AllocatorTraits::allocate(*GetAllocPtr(), new_capacity); + SizeType new_capacity = ComputeCapacity(GetInlinedCapacity(), new_size); + construct_data = AllocatorTraits::allocate(GetAllocator(), new_capacity); SetAllocatedData(construct_data, new_capacity); SetIsAllocated(); } else { construct_data = GetInlinedData(); } - inlined_vector_internal::ConstructElements(GetAllocPtr(), construct_data, - &values, new_size); + ConstructElements(GetAllocator(), construct_data, values, new_size); // Since the initial size was guaranteed to be `0` and the allocated bit is // already correct for either case, *adding* `new_size` gives us the correct @@ -498,17 +521,18 @@ auto Storage::Initialize(ValueAdapter values, size_type new_size) template template -auto Storage::Assign(ValueAdapter values, size_type new_size) -> void { - StorageView storage_view = MakeStorageView(); +auto Storage::Assign(ValueAdapter values, SizeType new_size) + -> void { + StorageView storage_view = MakeStorageView(); - AllocationTransaction allocation_tx(GetAllocPtr()); + AllocationTransaction allocation_tx(GetAllocator()); - absl::Span assign_loop; - absl::Span construct_loop; - absl::Span destroy_loop; + absl::Span> assign_loop; + absl::Span> construct_loop; + absl::Span> destroy_loop; if (new_size > storage_view.capacity) { - size_type new_capacity = ComputeCapacity(storage_view.capacity, new_size); + SizeType new_capacity = ComputeCapacity(storage_view.capacity, new_size); construct_loop = {allocation_tx.Allocate(new_capacity), new_size}; destroy_loop = {storage_view.data, storage_view.size}; } else if (new_size > storage_view.size) { @@ -520,18 +544,16 @@ auto Storage::Assign(ValueAdapter values, size_type new_size) -> void { destroy_loop = {storage_view.data + new_size, storage_view.size - new_size}; } - inlined_vector_internal::AssignElements(assign_loop.data(), &values, - assign_loop.size()); + AssignElements(assign_loop.data(), values, assign_loop.size()); - inlined_vector_internal::ConstructElements( - GetAllocPtr(), construct_loop.data(), &values, construct_loop.size()); + ConstructElements(GetAllocator(), construct_loop.data(), values, + construct_loop.size()); - inlined_vector_internal::DestroyElements(GetAllocPtr(), destroy_loop.data(), - destroy_loop.size()); + DestroyElements(GetAllocator(), destroy_loop.data(), destroy_loop.size()); if (allocation_tx.DidAllocate()) { DeallocateIfAllocated(); - AcquireAllocatedData(&allocation_tx); + AcquireAllocatedData(allocation_tx); SetIsAllocated(); } @@ -540,125 +562,117 @@ auto Storage::Assign(ValueAdapter values, size_type new_size) -> void { template template -auto Storage::Resize(ValueAdapter values, size_type new_size) -> void { - StorageView storage_view = MakeStorageView(); - - IteratorValueAdapter move_values( - MoveIterator(storage_view.data)); - - AllocationTransaction allocation_tx(GetAllocPtr()); - ConstructionTransaction construction_tx(GetAllocPtr()); - - absl::Span construct_loop; - absl::Span move_construct_loop; - absl::Span destroy_loop; - - if (new_size > storage_view.capacity) { - size_type new_capacity = ComputeCapacity(storage_view.capacity, new_size); - pointer new_data = allocation_tx.Allocate(new_capacity); - construct_loop = {new_data + storage_view.size, - new_size - storage_view.size}; - move_construct_loop = {new_data, storage_view.size}; - destroy_loop = {storage_view.data, storage_view.size}; - } else if (new_size > storage_view.size) { - construct_loop = {storage_view.data + storage_view.size, - new_size - storage_view.size}; +auto Storage::Resize(ValueAdapter values, SizeType new_size) + -> void { + StorageView storage_view = MakeStorageView(); + auto* const base = storage_view.data; + const SizeType size = storage_view.size; + auto& alloc = GetAllocator(); + if (new_size <= size) { + // Destroy extra old elements. + DestroyElements(alloc, base + new_size, size - new_size); + } else if (new_size <= storage_view.capacity) { + // Construct new elements in place. + ConstructElements(alloc, base + size, values, new_size - size); } else { - destroy_loop = {storage_view.data + new_size, storage_view.size - new_size}; - } + // Steps: + // a. Allocate new backing store. + // b. Construct new elements in new backing store. + // c. Move existing elements from old backing store to now. + // d. Destroy all elements in old backing store. + // Use transactional wrappers for the first two steps so we can roll + // back if necessary due to exceptions. + AllocationTransaction allocation_tx(alloc); + SizeType new_capacity = ComputeCapacity(storage_view.capacity, new_size); + Pointer new_data = allocation_tx.Allocate(new_capacity); - construction_tx.Construct(construct_loop.data(), &values, - construct_loop.size()); + ConstructionTransaction construction_tx(alloc); + construction_tx.Construct(new_data + size, values, new_size - size); - inlined_vector_internal::ConstructElements( - GetAllocPtr(), move_construct_loop.data(), &move_values, - move_construct_loop.size()); + IteratorValueAdapter> move_values( + (MoveIterator(base))); + ConstructElements(alloc, new_data, move_values, size); - inlined_vector_internal::DestroyElements(GetAllocPtr(), destroy_loop.data(), - destroy_loop.size()); - - construction_tx.Commit(); - if (allocation_tx.DidAllocate()) { + DestroyElements(alloc, base, size); + construction_tx.Commit(); DeallocateIfAllocated(); - AcquireAllocatedData(&allocation_tx); + AcquireAllocatedData(allocation_tx); SetIsAllocated(); } - SetSize(new_size); } template template -auto Storage::Insert(const_iterator pos, ValueAdapter values, - size_type insert_count) -> iterator { - StorageView storage_view = MakeStorageView(); +auto Storage::Insert(ConstIterator pos, ValueAdapter values, + SizeType insert_count) -> Iterator { + StorageView storage_view = MakeStorageView(); - size_type insert_index = - std::distance(const_iterator(storage_view.data), pos); - size_type insert_end_index = insert_index + insert_count; - size_type new_size = storage_view.size + insert_count; + SizeType insert_index = + std::distance(ConstIterator(storage_view.data), pos); + SizeType insert_end_index = insert_index + insert_count; + SizeType new_size = storage_view.size + insert_count; if (new_size > storage_view.capacity) { - AllocationTransaction allocation_tx(GetAllocPtr()); - ConstructionTransaction construction_tx(GetAllocPtr()); - ConstructionTransaction move_construciton_tx(GetAllocPtr()); + AllocationTransaction allocation_tx(GetAllocator()); + ConstructionTransaction construction_tx(GetAllocator()); + ConstructionTransaction move_construction_tx(GetAllocator()); - IteratorValueAdapter move_values( - MoveIterator(storage_view.data)); + IteratorValueAdapter> move_values( + MoveIterator(storage_view.data)); - size_type new_capacity = ComputeCapacity(storage_view.capacity, new_size); - pointer new_data = allocation_tx.Allocate(new_capacity); + SizeType new_capacity = ComputeCapacity(storage_view.capacity, new_size); + Pointer new_data = allocation_tx.Allocate(new_capacity); - construction_tx.Construct(new_data + insert_index, &values, insert_count); + construction_tx.Construct(new_data + insert_index, values, insert_count); - move_construciton_tx.Construct(new_data, &move_values, insert_index); + move_construction_tx.Construct(new_data, move_values, insert_index); - inlined_vector_internal::ConstructElements( - GetAllocPtr(), new_data + insert_end_index, &move_values, - storage_view.size - insert_index); + ConstructElements(GetAllocator(), new_data + insert_end_index, + move_values, storage_view.size - insert_index); - inlined_vector_internal::DestroyElements(GetAllocPtr(), storage_view.data, - storage_view.size); + DestroyElements(GetAllocator(), storage_view.data, storage_view.size); construction_tx.Commit(); - move_construciton_tx.Commit(); + move_construction_tx.Commit(); DeallocateIfAllocated(); - AcquireAllocatedData(&allocation_tx); + AcquireAllocatedData(allocation_tx); SetAllocatedSize(new_size); - return iterator(new_data + insert_index); + return Iterator(new_data + insert_index); } else { - size_type move_construction_destination_index = + SizeType move_construction_destination_index = (std::max)(insert_end_index, storage_view.size); - ConstructionTransaction move_construction_tx(GetAllocPtr()); + ConstructionTransaction move_construction_tx(GetAllocator()); - IteratorValueAdapter move_construction_values( - MoveIterator(storage_view.data + - (move_construction_destination_index - insert_count))); - absl::Span move_construction = { + IteratorValueAdapter> move_construction_values( + MoveIterator(storage_view.data + + (move_construction_destination_index - insert_count))); + absl::Span> move_construction = { storage_view.data + move_construction_destination_index, new_size - move_construction_destination_index}; - pointer move_assignment_values = storage_view.data + insert_index; - absl::Span move_assignment = { + Pointer move_assignment_values = storage_view.data + insert_index; + absl::Span> move_assignment = { storage_view.data + insert_end_index, move_construction_destination_index - insert_end_index}; - absl::Span insert_assignment = {move_assignment_values, - move_construction.size()}; + absl::Span> insert_assignment = {move_assignment_values, + move_construction.size()}; - absl::Span insert_construction = { + absl::Span> insert_construction = { insert_assignment.data() + insert_assignment.size(), insert_count - insert_assignment.size()}; move_construction_tx.Construct(move_construction.data(), - &move_construction_values, + move_construction_values, move_construction.size()); - for (pointer destination = move_assignment.data() + move_assignment.size(), - last_destination = move_assignment.data(), - source = move_assignment_values + move_assignment.size(); + for (Pointer + destination = move_assignment.data() + move_assignment.size(), + last_destination = move_assignment.data(), + source = move_assignment_values + move_assignment.size(); ;) { --destination; --source; @@ -666,114 +680,115 @@ auto Storage::Insert(const_iterator pos, ValueAdapter values, *destination = std::move(*source); } - inlined_vector_internal::AssignElements(insert_assignment.data(), &values, - insert_assignment.size()); + AssignElements(insert_assignment.data(), values, + insert_assignment.size()); - inlined_vector_internal::ConstructElements( - GetAllocPtr(), insert_construction.data(), &values, - insert_construction.size()); + ConstructElements(GetAllocator(), insert_construction.data(), values, + insert_construction.size()); move_construction_tx.Commit(); AddSize(insert_count); - return iterator(storage_view.data + insert_index); + return Iterator(storage_view.data + insert_index); } } template template -auto Storage::EmplaceBack(Args&&... args) -> reference { - StorageView storage_view = MakeStorageView(); - - AllocationTransaction allocation_tx(GetAllocPtr()); - - IteratorValueAdapter move_values( - MoveIterator(storage_view.data)); - - pointer construct_data; - if (storage_view.size == storage_view.capacity) { - size_type new_capacity = NextCapacity(storage_view.capacity); - construct_data = allocation_tx.Allocate(new_capacity); - } else { - construct_data = storage_view.data; +auto Storage::EmplaceBack(Args&&... args) -> Reference { + StorageView storage_view = MakeStorageView(); + const auto n = storage_view.size; + if (ABSL_PREDICT_TRUE(n != storage_view.capacity)) { + // Fast path; new element fits. + Pointer last_ptr = storage_view.data + n; + AllocatorTraits::construct(GetAllocator(), last_ptr, + std::forward(args)...); + AddSize(1); + return *last_ptr; } + // TODO(b/173712035): Annotate with musttail attribute to prevent regression. + return EmplaceBackSlow(std::forward(args)...); +} - pointer last_ptr = construct_data + storage_view.size; +template +template +auto Storage::EmplaceBackSlow(Args&&... args) -> Reference { + StorageView storage_view = MakeStorageView(); + AllocationTransaction allocation_tx(GetAllocator()); + IteratorValueAdapter> move_values( + MoveIterator(storage_view.data)); + SizeType new_capacity = NextCapacity(storage_view.capacity); + Pointer construct_data = allocation_tx.Allocate(new_capacity); + Pointer last_ptr = construct_data + storage_view.size; - AllocatorTraits::construct(*GetAllocPtr(), last_ptr, - std::forward(args)...); - - if (allocation_tx.DidAllocate()) { - ABSL_INTERNAL_TRY { - inlined_vector_internal::ConstructElements( - GetAllocPtr(), allocation_tx.GetData(), &move_values, - storage_view.size); - } - ABSL_INTERNAL_CATCH_ANY { - AllocatorTraits::destroy(*GetAllocPtr(), last_ptr); - ABSL_INTERNAL_RETHROW; - } - - inlined_vector_internal::DestroyElements(GetAllocPtr(), storage_view.data, - storage_view.size); - - DeallocateIfAllocated(); - AcquireAllocatedData(&allocation_tx); - SetIsAllocated(); + // Construct new element. + AllocatorTraits::construct(GetAllocator(), last_ptr, + std::forward(args)...); + // Move elements from old backing store to new backing store. + ABSL_INTERNAL_TRY { + ConstructElements(GetAllocator(), allocation_tx.GetData(), move_values, + storage_view.size); } + ABSL_INTERNAL_CATCH_ANY { + AllocatorTraits::destroy(GetAllocator(), last_ptr); + ABSL_INTERNAL_RETHROW; + } + // Destroy elements in old backing store. + DestroyElements(GetAllocator(), storage_view.data, storage_view.size); + DeallocateIfAllocated(); + AcquireAllocatedData(allocation_tx); + SetIsAllocated(); AddSize(1); return *last_ptr; } template -auto Storage::Erase(const_iterator from, const_iterator to) - -> iterator { - StorageView storage_view = MakeStorageView(); +auto Storage::Erase(ConstIterator from, ConstIterator to) + -> Iterator { + StorageView storage_view = MakeStorageView(); - size_type erase_size = std::distance(from, to); - size_type erase_index = - std::distance(const_iterator(storage_view.data), from); - size_type erase_end_index = erase_index + erase_size; + SizeType erase_size = std::distance(from, to); + SizeType erase_index = + std::distance(ConstIterator(storage_view.data), from); + SizeType erase_end_index = erase_index + erase_size; - IteratorValueAdapter move_values( - MoveIterator(storage_view.data + erase_end_index)); + IteratorValueAdapter> move_values( + MoveIterator(storage_view.data + erase_end_index)); - inlined_vector_internal::AssignElements(storage_view.data + erase_index, - &move_values, - storage_view.size - erase_end_index); + AssignElements(storage_view.data + erase_index, move_values, + storage_view.size - erase_end_index); - inlined_vector_internal::DestroyElements( - GetAllocPtr(), storage_view.data + (storage_view.size - erase_size), - erase_size); + DestroyElements(GetAllocator(), + storage_view.data + (storage_view.size - erase_size), + erase_size); SubtractSize(erase_size); - return iterator(storage_view.data + erase_index); + return Iterator(storage_view.data + erase_index); } template -auto Storage::Reserve(size_type requested_capacity) -> void { - StorageView storage_view = MakeStorageView(); +auto Storage::Reserve(SizeType requested_capacity) -> void { + StorageView storage_view = MakeStorageView(); if (ABSL_PREDICT_FALSE(requested_capacity <= storage_view.capacity)) return; - AllocationTransaction allocation_tx(GetAllocPtr()); + AllocationTransaction allocation_tx(GetAllocator()); - IteratorValueAdapter move_values( - MoveIterator(storage_view.data)); + IteratorValueAdapter> move_values( + MoveIterator(storage_view.data)); - size_type new_capacity = + SizeType new_capacity = ComputeCapacity(storage_view.capacity, requested_capacity); - pointer new_data = allocation_tx.Allocate(new_capacity); + Pointer new_data = allocation_tx.Allocate(new_capacity); - inlined_vector_internal::ConstructElements(GetAllocPtr(), new_data, - &move_values, storage_view.size); + ConstructElements(GetAllocator(), new_data, move_values, + storage_view.size); - inlined_vector_internal::DestroyElements(GetAllocPtr(), storage_view.data, - storage_view.size); + DestroyElements(GetAllocator(), storage_view.data, storage_view.size); DeallocateIfAllocated(); - AcquireAllocatedData(&allocation_tx); + AcquireAllocatedData(allocation_tx); SetIsAllocated(); } @@ -782,41 +797,40 @@ auto Storage::ShrinkToFit() -> void { // May only be called on allocated instances! assert(GetIsAllocated()); - StorageView storage_view{GetAllocatedData(), GetSize(), - GetAllocatedCapacity()}; + StorageView storage_view{GetAllocatedData(), GetSize(), + GetAllocatedCapacity()}; if (ABSL_PREDICT_FALSE(storage_view.size == storage_view.capacity)) return; - AllocationTransaction allocation_tx(GetAllocPtr()); + AllocationTransaction allocation_tx(GetAllocator()); - IteratorValueAdapter move_values( - MoveIterator(storage_view.data)); + IteratorValueAdapter> move_values( + MoveIterator(storage_view.data)); - pointer construct_data; + Pointer construct_data; if (storage_view.size > GetInlinedCapacity()) { - size_type new_capacity = storage_view.size; + SizeType new_capacity = storage_view.size; construct_data = allocation_tx.Allocate(new_capacity); } else { construct_data = GetInlinedData(); } ABSL_INTERNAL_TRY { - inlined_vector_internal::ConstructElements(GetAllocPtr(), construct_data, - &move_values, storage_view.size); + ConstructElements(GetAllocator(), construct_data, move_values, + storage_view.size); } ABSL_INTERNAL_CATCH_ANY { SetAllocatedData(storage_view.data, storage_view.capacity); ABSL_INTERNAL_RETHROW; } - inlined_vector_internal::DestroyElements(GetAllocPtr(), storage_view.data, - storage_view.size); + DestroyElements(GetAllocator(), storage_view.data, storage_view.size); - AllocatorTraits::deallocate(*GetAllocPtr(), storage_view.data, - storage_view.capacity); + AllocatorTraits::deallocate(GetAllocator(), storage_view.data, + storage_view.capacity); if (allocation_tx.DidAllocate()) { - AcquireAllocatedData(&allocation_tx); + AcquireAllocatedData(allocation_tx); } else { UnsetIsAllocated(); } @@ -834,38 +848,37 @@ auto Storage::Swap(Storage* other_storage_ptr) -> void { Storage* large_ptr = other_storage_ptr; if (small_ptr->GetSize() > large_ptr->GetSize()) swap(small_ptr, large_ptr); - for (size_type i = 0; i < small_ptr->GetSize(); ++i) { + for (SizeType i = 0; i < small_ptr->GetSize(); ++i) { swap(small_ptr->GetInlinedData()[i], large_ptr->GetInlinedData()[i]); } - IteratorValueAdapter move_values( - MoveIterator(large_ptr->GetInlinedData() + small_ptr->GetSize())); + IteratorValueAdapter> move_values( + MoveIterator(large_ptr->GetInlinedData() + small_ptr->GetSize())); - inlined_vector_internal::ConstructElements( - large_ptr->GetAllocPtr(), - small_ptr->GetInlinedData() + small_ptr->GetSize(), &move_values, - large_ptr->GetSize() - small_ptr->GetSize()); + ConstructElements(large_ptr->GetAllocator(), + small_ptr->GetInlinedData() + small_ptr->GetSize(), + move_values, + large_ptr->GetSize() - small_ptr->GetSize()); - inlined_vector_internal::DestroyElements( - large_ptr->GetAllocPtr(), - large_ptr->GetInlinedData() + small_ptr->GetSize(), - large_ptr->GetSize() - small_ptr->GetSize()); + DestroyElements(large_ptr->GetAllocator(), + large_ptr->GetInlinedData() + small_ptr->GetSize(), + large_ptr->GetSize() - small_ptr->GetSize()); } else { Storage* allocated_ptr = this; Storage* inlined_ptr = other_storage_ptr; if (!allocated_ptr->GetIsAllocated()) swap(allocated_ptr, inlined_ptr); - StorageView allocated_storage_view{allocated_ptr->GetAllocatedData(), - allocated_ptr->GetSize(), - allocated_ptr->GetAllocatedCapacity()}; + StorageView allocated_storage_view{ + allocated_ptr->GetAllocatedData(), allocated_ptr->GetSize(), + allocated_ptr->GetAllocatedCapacity()}; - IteratorValueAdapter move_values( - MoveIterator(inlined_ptr->GetInlinedData())); + IteratorValueAdapter> move_values( + MoveIterator(inlined_ptr->GetInlinedData())); ABSL_INTERNAL_TRY { - inlined_vector_internal::ConstructElements( - inlined_ptr->GetAllocPtr(), allocated_ptr->GetInlinedData(), - &move_values, inlined_ptr->GetSize()); + ConstructElements(inlined_ptr->GetAllocator(), + allocated_ptr->GetInlinedData(), move_values, + inlined_ptr->GetSize()); } ABSL_INTERNAL_CATCH_ANY { allocated_ptr->SetAllocatedData(allocated_storage_view.data, @@ -873,18 +886,22 @@ auto Storage::Swap(Storage* other_storage_ptr) -> void { ABSL_INTERNAL_RETHROW; } - inlined_vector_internal::DestroyElements(inlined_ptr->GetAllocPtr(), - inlined_ptr->GetInlinedData(), - inlined_ptr->GetSize()); + DestroyElements(inlined_ptr->GetAllocator(), + inlined_ptr->GetInlinedData(), inlined_ptr->GetSize()); inlined_ptr->SetAllocatedData(allocated_storage_view.data, allocated_storage_view.capacity); } swap(GetSizeAndIsAllocated(), other_storage_ptr->GetSizeAndIsAllocated()); - swap(*GetAllocPtr(), *other_storage_ptr->GetAllocPtr()); + swap(GetAllocator(), other_storage_ptr->GetAllocator()); } +// End ignore "array-bounds" and "maybe-uninitialized" +#if !defined(__clang__) && defined(__GNUC__) +#pragma GCC diagnostic pop +#endif + } // namespace inlined_vector_internal ABSL_NAMESPACE_END } // namespace absl diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/layout.h b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/layout.h index 69cc85dd66..a59a243059 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/layout.h +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/layout.h @@ -163,6 +163,7 @@ #include #include #include + #include #include #include @@ -170,15 +171,16 @@ #include #include -#ifdef ADDRESS_SANITIZER -#include -#endif - +#include "absl/base/config.h" #include "absl/meta/type_traits.h" #include "absl/strings/str_cat.h" #include "absl/types/span.h" #include "absl/utility/utility.h" +#ifdef ABSL_HAVE_ADDRESS_SANITIZER +#include +#endif + #if defined(__GXX_RTTI) #define ABSL_INTERNAL_HAS_CXA_DEMANGLE #endif @@ -402,7 +404,7 @@ class LayoutImpl, absl::index_sequence, constexpr size_t Offset() const { static_assert(N < NumOffsets, "Index out of bounds"); return adl_barrier::Align( - Offset() + SizeOf>() * size_[N - 1], + Offset() + SizeOf>::value * size_[N - 1], ElementAlignment::value); } @@ -595,7 +597,7 @@ class LayoutImpl, absl::index_sequence, constexpr size_t AllocSize() const { static_assert(NumTypes == NumSizes, "You must specify sizes of all fields"); return Offset() + - SizeOf>() * size_[NumTypes - 1]; + SizeOf>::value * size_[NumTypes - 1]; } // If built with --config=asan, poisons padding bytes (if any) in the @@ -614,12 +616,12 @@ class LayoutImpl, absl::index_sequence, void PoisonPadding(const Char* p) const { static_assert(N < NumOffsets, "Index out of bounds"); (void)p; -#ifdef ADDRESS_SANITIZER +#ifdef ABSL_HAVE_ADDRESS_SANITIZER PoisonPadding(p); // The `if` is an optimization. It doesn't affect the observable behaviour. if (ElementAlignment::value % ElementAlignment::value) { size_t start = - Offset() + SizeOf>() * size_[N - 1]; + Offset() + SizeOf>::value * size_[N - 1]; ASAN_POISON_MEMORY_REGION(p + start, Offset() - start); } #endif @@ -643,7 +645,7 @@ class LayoutImpl, absl::index_sequence, // produce "unsigned*" where another produces "unsigned int *". std::string DebugString() const { const auto offsets = Offsets(); - const size_t sizes[] = {SizeOf>()...}; + const size_t sizes[] = {SizeOf>::value...}; const std::string types[] = { adl_barrier::TypeName>()...}; std::string res = absl::StrCat("@0", types[0], "(", sizes[0], ")"); diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/layout_benchmark.cc b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/layout_benchmark.cc new file mode 100644 index 0000000000..d8636e8d5a --- /dev/null +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/layout_benchmark.cc @@ -0,0 +1,122 @@ +// Copyright 2018 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Every benchmark should have the same performance as the corresponding +// headroom benchmark. + +#include "absl/base/internal/raw_logging.h" +#include "absl/container/internal/layout.h" +#include "benchmark/benchmark.h" + +namespace absl { +ABSL_NAMESPACE_BEGIN +namespace container_internal { +namespace { + +using ::benchmark::DoNotOptimize; + +using Int128 = int64_t[2]; + +// This benchmark provides the upper bound on performance for BM_OffsetConstant. +template +void BM_OffsetConstantHeadroom(benchmark::State& state) { + for (auto _ : state) { + DoNotOptimize(Offset); + } +} + +template +void BM_OffsetConstant(benchmark::State& state) { + using L = Layout; + ABSL_RAW_CHECK(L::Partial(3, 5, 7).template Offset<3>() == Offset, + "Invalid offset"); + for (auto _ : state) { + DoNotOptimize(L::Partial(3, 5, 7).template Offset<3>()); + } +} + +template +size_t VariableOffset(size_t n, size_t m, size_t k); + +template <> +size_t VariableOffset(size_t n, size_t m, + size_t k) { + auto Align = [](size_t n, size_t m) { return (n + m - 1) & ~(m - 1); }; + return Align(Align(Align(n * 1, 2) + m * 2, 4) + k * 4, 8); +} + +template <> +size_t VariableOffset(size_t n, size_t m, + size_t k) { + // No alignment is necessary. + return n * 16 + m * 4 + k * 2; +} + +// This benchmark provides the upper bound on performance for BM_OffsetVariable. +template +void BM_OffsetVariableHeadroom(benchmark::State& state) { + size_t n = 3; + size_t m = 5; + size_t k = 7; + ABSL_RAW_CHECK(VariableOffset(n, m, k) == Offset, "Invalid offset"); + for (auto _ : state) { + DoNotOptimize(n); + DoNotOptimize(m); + DoNotOptimize(k); + DoNotOptimize(VariableOffset(n, m, k)); + } +} + +template +void BM_OffsetVariable(benchmark::State& state) { + using L = Layout; + size_t n = 3; + size_t m = 5; + size_t k = 7; + ABSL_RAW_CHECK(L::Partial(n, m, k).template Offset<3>() == Offset, + "Inavlid offset"); + for (auto _ : state) { + DoNotOptimize(n); + DoNotOptimize(m); + DoNotOptimize(k); + DoNotOptimize(L::Partial(n, m, k).template Offset<3>()); + } +} + +// Run all benchmarks in two modes: +// +// Layout with padding: int8_t[3], int16_t[5], int32_t[7], Int128[?]. +// Layout without padding: Int128[3], int32_t[5], int16_t[7], int8_t[?]. + +#define OFFSET_BENCHMARK(NAME, OFFSET, T1, T2, T3, T4) \ + auto& NAME##_##OFFSET##_##T1##_##T2##_##T3##_##T4 = \ + NAME; \ + BENCHMARK(NAME##_##OFFSET##_##T1##_##T2##_##T3##_##T4) + +OFFSET_BENCHMARK(BM_OffsetConstantHeadroom, 48, int8_t, int16_t, int32_t, + Int128); +OFFSET_BENCHMARK(BM_OffsetConstant, 48, int8_t, int16_t, int32_t, Int128); +OFFSET_BENCHMARK(BM_OffsetConstantHeadroom, 82, Int128, int32_t, int16_t, + int8_t); +OFFSET_BENCHMARK(BM_OffsetConstant, 82, Int128, int32_t, int16_t, int8_t); +OFFSET_BENCHMARK(BM_OffsetVariableHeadroom, 48, int8_t, int16_t, int32_t, + Int128); +OFFSET_BENCHMARK(BM_OffsetVariable, 48, int8_t, int16_t, int32_t, Int128); +OFFSET_BENCHMARK(BM_OffsetVariableHeadroom, 82, Int128, int32_t, int16_t, + int8_t); +OFFSET_BENCHMARK(BM_OffsetVariable, 82, Int128, int32_t, int16_t, int8_t); +} // namespace +} // namespace container_internal +ABSL_NAMESPACE_END +} // namespace absl diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/layout_test.cc b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/layout_test.cc index 8f3628a1f1..1d7158ffc0 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/layout_test.cc +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/layout_test.cc @@ -17,6 +17,7 @@ // We need ::max_align_t because some libstdc++ versions don't provide // std::max_align_t #include + #include #include #include @@ -24,6 +25,7 @@ #include "gmock/gmock.h" #include "gtest/gtest.h" +#include "absl/base/config.h" #include "absl/base/internal/raw_logging.h" #include "absl/types/span.h" @@ -126,8 +128,10 @@ TEST(Layout, ElementTypes) { { using L = Layout; SameType, L::ElementTypes>(); - SameType, decltype(L::Partial())::ElementTypes>(); - SameType, decltype(L::Partial(0))::ElementTypes>(); + SameType, + decltype(L::Partial())::ElementTypes>(); + SameType, + decltype(L::Partial(0))::ElementTypes>(); } { using L = Layout; @@ -366,18 +370,21 @@ TEST(Layout, PointerByIndex) { { using L = Layout; EXPECT_EQ(0, Distance(p, Type(L::Partial().Pointer<0>(p)))); - EXPECT_EQ(0, Distance(p, Type(L::Partial(3).Pointer<0>(p)))); + EXPECT_EQ(0, + Distance(p, Type(L::Partial(3).Pointer<0>(p)))); EXPECT_EQ(0, Distance(p, Type(L(3).Pointer<0>(p)))); } { using L = Layout; EXPECT_EQ(0, Distance(p, Type(L::Partial().Pointer<0>(p)))); - EXPECT_EQ(0, Distance(p, Type(L::Partial(3).Pointer<0>(p)))); - EXPECT_EQ(12, Distance(p, Type(L::Partial(3).Pointer<1>(p)))); EXPECT_EQ(0, - Distance(p, Type(L::Partial(3, 5).Pointer<0>(p)))); + Distance(p, Type(L::Partial(3).Pointer<0>(p)))); EXPECT_EQ(12, - Distance(p, Type(L::Partial(3, 5).Pointer<1>(p)))); + Distance(p, Type(L::Partial(3).Pointer<1>(p)))); + EXPECT_EQ( + 0, Distance(p, Type(L::Partial(3, 5).Pointer<0>(p)))); + EXPECT_EQ( + 12, Distance(p, Type(L::Partial(3, 5).Pointer<1>(p)))); EXPECT_EQ(0, Distance(p, Type(L(3, 5).Pointer<0>(p)))); EXPECT_EQ(12, Distance(p, Type(L(3, 5).Pointer<1>(p)))); } @@ -385,39 +392,44 @@ TEST(Layout, PointerByIndex) { using L = Layout; EXPECT_EQ(0, Distance(p, Type(L::Partial().Pointer<0>(p)))); EXPECT_EQ(0, Distance(p, Type(L::Partial(0).Pointer<0>(p)))); - EXPECT_EQ(0, Distance(p, Type(L::Partial(0).Pointer<1>(p)))); + EXPECT_EQ(0, + Distance(p, Type(L::Partial(0).Pointer<1>(p)))); EXPECT_EQ(0, Distance(p, Type(L::Partial(1).Pointer<0>(p)))); - EXPECT_EQ(4, Distance(p, Type(L::Partial(1).Pointer<1>(p)))); + EXPECT_EQ(4, + Distance(p, Type(L::Partial(1).Pointer<1>(p)))); EXPECT_EQ(0, Distance(p, Type(L::Partial(5).Pointer<0>(p)))); - EXPECT_EQ(8, Distance(p, Type(L::Partial(5).Pointer<1>(p)))); + EXPECT_EQ(8, + Distance(p, Type(L::Partial(5).Pointer<1>(p)))); EXPECT_EQ(0, Distance(p, Type(L::Partial(0, 0).Pointer<0>(p)))); - EXPECT_EQ(0, - Distance(p, Type(L::Partial(0, 0).Pointer<1>(p)))); + EXPECT_EQ( + 0, Distance(p, Type(L::Partial(0, 0).Pointer<1>(p)))); EXPECT_EQ(0, Distance(p, Type(L::Partial(0, 0).Pointer<2>(p)))); EXPECT_EQ(0, Distance(p, Type(L::Partial(1, 0).Pointer<0>(p)))); - EXPECT_EQ(4, - Distance(p, Type(L::Partial(1, 0).Pointer<1>(p)))); + EXPECT_EQ( + 4, Distance(p, Type(L::Partial(1, 0).Pointer<1>(p)))); EXPECT_EQ(8, Distance(p, Type(L::Partial(1, 0).Pointer<2>(p)))); EXPECT_EQ(0, Distance(p, Type(L::Partial(5, 3).Pointer<0>(p)))); - EXPECT_EQ(8, - Distance(p, Type(L::Partial(5, 3).Pointer<1>(p)))); + EXPECT_EQ( + 8, Distance(p, Type(L::Partial(5, 3).Pointer<1>(p)))); EXPECT_EQ(24, Distance(p, Type(L::Partial(5, 3).Pointer<2>(p)))); EXPECT_EQ( 0, Distance(p, Type(L::Partial(0, 0, 0).Pointer<0>(p)))); EXPECT_EQ( - 0, Distance(p, Type(L::Partial(0, 0, 0).Pointer<1>(p)))); + 0, + Distance(p, Type(L::Partial(0, 0, 0).Pointer<1>(p)))); EXPECT_EQ( 0, Distance(p, Type(L::Partial(0, 0, 0).Pointer<2>(p)))); EXPECT_EQ( 0, Distance(p, Type(L::Partial(1, 0, 0).Pointer<0>(p)))); EXPECT_EQ( - 4, Distance(p, Type(L::Partial(1, 0, 0).Pointer<1>(p)))); + 4, + Distance(p, Type(L::Partial(1, 0, 0).Pointer<1>(p)))); EXPECT_EQ( 8, Distance(p, Type(L::Partial(1, 0, 0).Pointer<2>(p)))); EXPECT_EQ( @@ -426,7 +438,8 @@ TEST(Layout, PointerByIndex) { 24, Distance(p, Type(L::Partial(5, 3, 1).Pointer<2>(p)))); EXPECT_EQ( - 8, Distance(p, Type(L::Partial(5, 3, 1).Pointer<1>(p)))); + 8, + Distance(p, Type(L::Partial(5, 3, 1).Pointer<1>(p)))); EXPECT_EQ(0, Distance(p, Type(L(5, 3, 1).Pointer<0>(p)))); EXPECT_EQ(24, Distance(p, Type(L(5, 3, 1).Pointer<2>(p)))); EXPECT_EQ(8, Distance(p, Type(L(5, 3, 1).Pointer<1>(p)))); @@ -437,75 +450,78 @@ TEST(Layout, PointerByType) { alignas(max_align_t) const unsigned char p[100] = {}; { using L = Layout; - EXPECT_EQ(0, - Distance(p, Type(L::Partial().Pointer(p)))); - EXPECT_EQ(0, - Distance(p, Type(L::Partial(3).Pointer(p)))); + EXPECT_EQ( + 0, Distance(p, Type(L::Partial().Pointer(p)))); + EXPECT_EQ( + 0, + Distance(p, Type(L::Partial(3).Pointer(p)))); EXPECT_EQ(0, Distance(p, Type(L(3).Pointer(p)))); } { using L = Layout; - EXPECT_EQ(0, Distance(p, Type(L::Partial().Pointer(p)))); - EXPECT_EQ(0, - Distance(p, Type(L::Partial(0).Pointer(p)))); - EXPECT_EQ(0, - Distance(p, Type(L::Partial(0).Pointer(p)))); - EXPECT_EQ(0, - Distance(p, Type(L::Partial(1).Pointer(p)))); - EXPECT_EQ(4, - Distance(p, Type(L::Partial(1).Pointer(p)))); - EXPECT_EQ(0, - Distance(p, Type(L::Partial(5).Pointer(p)))); - EXPECT_EQ(8, - Distance(p, Type(L::Partial(5).Pointer(p)))); EXPECT_EQ( - 0, Distance(p, Type(L::Partial(0, 0).Pointer(p)))); + 0, Distance(p, Type(L::Partial().Pointer(p)))); EXPECT_EQ( - 0, Distance(p, Type(L::Partial(0, 0).Pointer(p)))); + 0, Distance(p, Type(L::Partial(0).Pointer(p)))); + EXPECT_EQ( + 0, + Distance(p, Type(L::Partial(0).Pointer(p)))); + EXPECT_EQ( + 0, Distance(p, Type(L::Partial(1).Pointer(p)))); + EXPECT_EQ( + 4, + Distance(p, Type(L::Partial(1).Pointer(p)))); + EXPECT_EQ( + 0, Distance(p, Type(L::Partial(5).Pointer(p)))); + EXPECT_EQ( + 8, + Distance(p, Type(L::Partial(5).Pointer(p)))); + EXPECT_EQ( + 0, + Distance(p, Type(L::Partial(0, 0).Pointer(p)))); + EXPECT_EQ(0, Distance(p, Type( + L::Partial(0, 0).Pointer(p)))); EXPECT_EQ( 0, Distance(p, Type(L::Partial(0, 0).Pointer(p)))); EXPECT_EQ( - 0, Distance(p, Type(L::Partial(1, 0).Pointer(p)))); - EXPECT_EQ( - 4, Distance(p, Type(L::Partial(1, 0).Pointer(p)))); + 0, + Distance(p, Type(L::Partial(1, 0).Pointer(p)))); + EXPECT_EQ(4, Distance(p, Type( + L::Partial(1, 0).Pointer(p)))); EXPECT_EQ( 8, Distance(p, Type(L::Partial(1, 0).Pointer(p)))); EXPECT_EQ( - 0, Distance(p, Type(L::Partial(5, 3).Pointer(p)))); - EXPECT_EQ( - 8, Distance(p, Type(L::Partial(5, 3).Pointer(p)))); + 0, + Distance(p, Type(L::Partial(5, 3).Pointer(p)))); + EXPECT_EQ(8, Distance(p, Type( + L::Partial(5, 3).Pointer(p)))); EXPECT_EQ( 24, Distance(p, Type(L::Partial(5, 3).Pointer(p)))); - EXPECT_EQ( - 0, - Distance(p, Type(L::Partial(0, 0, 0).Pointer(p)))); - EXPECT_EQ( - 0, - Distance(p, Type(L::Partial(0, 0, 0).Pointer(p)))); + EXPECT_EQ(0, Distance(p, Type( + L::Partial(0, 0, 0).Pointer(p)))); + EXPECT_EQ(0, Distance(p, Type( + L::Partial(0, 0, 0).Pointer(p)))); EXPECT_EQ(0, Distance(p, Type( L::Partial(0, 0, 0).Pointer(p)))); - EXPECT_EQ( - 0, - Distance(p, Type(L::Partial(1, 0, 0).Pointer(p)))); - EXPECT_EQ( - 4, - Distance(p, Type(L::Partial(1, 0, 0).Pointer(p)))); + EXPECT_EQ(0, Distance(p, Type( + L::Partial(1, 0, 0).Pointer(p)))); + EXPECT_EQ(4, Distance(p, Type( + L::Partial(1, 0, 0).Pointer(p)))); EXPECT_EQ(8, Distance(p, Type( L::Partial(1, 0, 0).Pointer(p)))); - EXPECT_EQ( - 0, - Distance(p, Type(L::Partial(5, 3, 1).Pointer(p)))); + EXPECT_EQ(0, Distance(p, Type( + L::Partial(5, 3, 1).Pointer(p)))); EXPECT_EQ(24, Distance(p, Type( L::Partial(5, 3, 1).Pointer(p)))); - EXPECT_EQ( - 8, - Distance(p, Type(L::Partial(5, 3, 1).Pointer(p)))); + EXPECT_EQ(8, Distance(p, Type( + L::Partial(5, 3, 1).Pointer(p)))); EXPECT_EQ(24, Distance(p, Type(L(5, 3, 1).Pointer(p)))); - EXPECT_EQ(8, Distance(p, Type(L(5, 3, 1).Pointer(p)))); + EXPECT_EQ( + 8, Distance(p, Type(L(5, 3, 1).Pointer(p)))); } } @@ -546,15 +562,18 @@ TEST(Layout, MutablePointerByIndex) { EXPECT_EQ(8, Distance(p, Type(L::Partial(5, 3).Pointer<1>(p)))); EXPECT_EQ(24, Distance(p, Type(L::Partial(5, 3).Pointer<2>(p)))); EXPECT_EQ(0, Distance(p, Type(L::Partial(0, 0, 0).Pointer<0>(p)))); - EXPECT_EQ(0, Distance(p, Type(L::Partial(0, 0, 0).Pointer<1>(p)))); + EXPECT_EQ(0, + Distance(p, Type(L::Partial(0, 0, 0).Pointer<1>(p)))); EXPECT_EQ(0, Distance(p, Type(L::Partial(0, 0, 0).Pointer<2>(p)))); EXPECT_EQ(0, Distance(p, Type(L::Partial(1, 0, 0).Pointer<0>(p)))); - EXPECT_EQ(4, Distance(p, Type(L::Partial(1, 0, 0).Pointer<1>(p)))); + EXPECT_EQ(4, + Distance(p, Type(L::Partial(1, 0, 0).Pointer<1>(p)))); EXPECT_EQ(8, Distance(p, Type(L::Partial(1, 0, 0).Pointer<2>(p)))); EXPECT_EQ(0, Distance(p, Type(L::Partial(5, 3, 1).Pointer<0>(p)))); EXPECT_EQ(24, Distance(p, Type(L::Partial(5, 3, 1).Pointer<2>(p)))); - EXPECT_EQ(8, Distance(p, Type(L::Partial(5, 3, 1).Pointer<1>(p)))); + EXPECT_EQ(8, + Distance(p, Type(L::Partial(5, 3, 1).Pointer<1>(p)))); EXPECT_EQ(0, Distance(p, Type(L(5, 3, 1).Pointer<0>(p)))); EXPECT_EQ(24, Distance(p, Type(L(5, 3, 1).Pointer<2>(p)))); EXPECT_EQ(8, Distance(p, Type(L(5, 3, 1).Pointer<1>(p)))); @@ -566,48 +585,61 @@ TEST(Layout, MutablePointerByType) { { using L = Layout; EXPECT_EQ(0, Distance(p, Type(L::Partial().Pointer(p)))); - EXPECT_EQ(0, Distance(p, Type(L::Partial(3).Pointer(p)))); + EXPECT_EQ(0, + Distance(p, Type(L::Partial(3).Pointer(p)))); EXPECT_EQ(0, Distance(p, Type(L(3).Pointer(p)))); } { using L = Layout; EXPECT_EQ(0, Distance(p, Type(L::Partial().Pointer(p)))); EXPECT_EQ(0, Distance(p, Type(L::Partial(0).Pointer(p)))); - EXPECT_EQ(0, Distance(p, Type(L::Partial(0).Pointer(p)))); + EXPECT_EQ(0, + Distance(p, Type(L::Partial(0).Pointer(p)))); EXPECT_EQ(0, Distance(p, Type(L::Partial(1).Pointer(p)))); - EXPECT_EQ(4, Distance(p, Type(L::Partial(1).Pointer(p)))); + EXPECT_EQ(4, + Distance(p, Type(L::Partial(1).Pointer(p)))); EXPECT_EQ(0, Distance(p, Type(L::Partial(5).Pointer(p)))); - EXPECT_EQ(8, Distance(p, Type(L::Partial(5).Pointer(p)))); - EXPECT_EQ(0, Distance(p, Type(L::Partial(0, 0).Pointer(p)))); - EXPECT_EQ(0, Distance(p, Type(L::Partial(0, 0).Pointer(p)))); + EXPECT_EQ(8, + Distance(p, Type(L::Partial(5).Pointer(p)))); + EXPECT_EQ(0, + Distance(p, Type(L::Partial(0, 0).Pointer(p)))); + EXPECT_EQ( + 0, Distance(p, Type(L::Partial(0, 0).Pointer(p)))); EXPECT_EQ(0, Distance(p, Type(L::Partial(0, 0).Pointer(p)))); - EXPECT_EQ(0, Distance(p, Type(L::Partial(1, 0).Pointer(p)))); - EXPECT_EQ(4, Distance(p, Type(L::Partial(1, 0).Pointer(p)))); + EXPECT_EQ(0, + Distance(p, Type(L::Partial(1, 0).Pointer(p)))); + EXPECT_EQ( + 4, Distance(p, Type(L::Partial(1, 0).Pointer(p)))); EXPECT_EQ(8, Distance(p, Type(L::Partial(1, 0).Pointer(p)))); - EXPECT_EQ(0, Distance(p, Type(L::Partial(5, 3).Pointer(p)))); - EXPECT_EQ(8, Distance(p, Type(L::Partial(5, 3).Pointer(p)))); + EXPECT_EQ(0, + Distance(p, Type(L::Partial(5, 3).Pointer(p)))); + EXPECT_EQ( + 8, Distance(p, Type(L::Partial(5, 3).Pointer(p)))); EXPECT_EQ(24, Distance(p, Type(L::Partial(5, 3).Pointer(p)))); - EXPECT_EQ(0, - Distance(p, Type(L::Partial(0, 0, 0).Pointer(p)))); - EXPECT_EQ(0, - Distance(p, Type(L::Partial(0, 0, 0).Pointer(p)))); + EXPECT_EQ( + 0, Distance(p, Type(L::Partial(0, 0, 0).Pointer(p)))); + EXPECT_EQ( + 0, + Distance(p, Type(L::Partial(0, 0, 0).Pointer(p)))); EXPECT_EQ( 0, Distance(p, Type(L::Partial(0, 0, 0).Pointer(p)))); - EXPECT_EQ(0, - Distance(p, Type(L::Partial(1, 0, 0).Pointer(p)))); - EXPECT_EQ(4, - Distance(p, Type(L::Partial(1, 0, 0).Pointer(p)))); + EXPECT_EQ( + 0, Distance(p, Type(L::Partial(1, 0, 0).Pointer(p)))); + EXPECT_EQ( + 4, + Distance(p, Type(L::Partial(1, 0, 0).Pointer(p)))); EXPECT_EQ( 8, Distance(p, Type(L::Partial(1, 0, 0).Pointer(p)))); - EXPECT_EQ(0, - Distance(p, Type(L::Partial(5, 3, 1).Pointer(p)))); + EXPECT_EQ( + 0, Distance(p, Type(L::Partial(5, 3, 1).Pointer(p)))); EXPECT_EQ( 24, Distance(p, Type(L::Partial(5, 3, 1).Pointer(p)))); - EXPECT_EQ(8, - Distance(p, Type(L::Partial(5, 3, 1).Pointer(p)))); + EXPECT_EQ( + 8, + Distance(p, Type(L::Partial(5, 3, 1).Pointer(p)))); EXPECT_EQ(0, Distance(p, Type(L(5, 3, 1).Pointer(p)))); EXPECT_EQ(24, Distance(p, Type(L(5, 3, 1).Pointer(p)))); EXPECT_EQ(8, Distance(p, Type(L(5, 3, 1).Pointer(p)))); @@ -788,67 +820,72 @@ TEST(Layout, SliceByIndexData) { { using L = Layout; EXPECT_EQ( - 0, - Distance(p, Type>(L::Partial(0).Slice<0>(p)).data())); + 0, Distance( + p, Type>(L::Partial(0).Slice<0>(p)).data())); EXPECT_EQ( - 0, - Distance(p, Type>(L::Partial(3).Slice<0>(p)).data())); - EXPECT_EQ(0, Distance(p, Type>(L(3).Slice<0>(p)).data())); + 0, Distance( + p, Type>(L::Partial(3).Slice<0>(p)).data())); + EXPECT_EQ(0, + Distance(p, Type>(L(3).Slice<0>(p)).data())); } { using L = Layout; EXPECT_EQ( - 0, - Distance(p, Type>(L::Partial(3).Slice<0>(p)).data())); + 0, Distance( + p, Type>(L::Partial(3).Slice<0>(p)).data())); EXPECT_EQ( 0, - Distance(p, - Type>(L::Partial(3, 5).Slice<0>(p)).data())); + Distance( + p, Type>(L::Partial(3, 5).Slice<0>(p)).data())); EXPECT_EQ( 12, - Distance(p, - Type>(L::Partial(3, 5).Slice<1>(p)).data())); - EXPECT_EQ(0, - Distance(p, Type>(L(3, 5).Slice<0>(p)).data())); - EXPECT_EQ(12, - Distance(p, Type>(L(3, 5).Slice<1>(p)).data())); + Distance( + p, Type>(L::Partial(3, 5).Slice<1>(p)).data())); + EXPECT_EQ( + 0, Distance(p, Type>(L(3, 5).Slice<0>(p)).data())); + EXPECT_EQ( + 12, Distance(p, Type>(L(3, 5).Slice<1>(p)).data())); } { using L = Layout; EXPECT_EQ( - 0, - Distance(p, Type>(L::Partial(0).Slice<0>(p)).data())); - EXPECT_EQ( - 0, - Distance(p, Type>(L::Partial(1).Slice<0>(p)).data())); - EXPECT_EQ( - 0, - Distance(p, Type>(L::Partial(5).Slice<0>(p)).data())); + 0, Distance( + p, Type>(L::Partial(0).Slice<0>(p)).data())); EXPECT_EQ( 0, Distance( - p, Type>(L::Partial(0, 0).Slice<0>(p)).data())); - EXPECT_EQ( - 0, - Distance(p, - Type>(L::Partial(0, 0).Slice<1>(p)).data())); + p, Type>(L::Partial(1).Slice<0>(p)).data())); EXPECT_EQ( 0, Distance( - p, Type>(L::Partial(1, 0).Slice<0>(p)).data())); - EXPECT_EQ( - 4, - Distance(p, - Type>(L::Partial(1, 0).Slice<1>(p)).data())); - EXPECT_EQ( - 0, Distance( - p, Type>(L::Partial(5, 3).Slice<0>(p)).data())); - EXPECT_EQ( - 8, - Distance(p, - Type>(L::Partial(5, 3).Slice<1>(p)).data())); + p, Type>(L::Partial(5).Slice<0>(p)).data())); EXPECT_EQ( 0, Distance( - p, Type>(L::Partial(0, 0, 0).Slice<0>(p)).data())); + p, Type>(L::Partial(0, 0).Slice<0>(p)).data())); + EXPECT_EQ( + 0, + Distance( + p, Type>(L::Partial(0, 0).Slice<1>(p)).data())); + EXPECT_EQ( + 0, + Distance( + p, Type>(L::Partial(1, 0).Slice<0>(p)).data())); + EXPECT_EQ( + 4, + Distance( + p, Type>(L::Partial(1, 0).Slice<1>(p)).data())); + EXPECT_EQ( + 0, + Distance( + p, Type>(L::Partial(5, 3).Slice<0>(p)).data())); + EXPECT_EQ( + 8, + Distance( + p, Type>(L::Partial(5, 3).Slice<1>(p)).data())); + EXPECT_EQ( + 0, + Distance( + p, + Type>(L::Partial(0, 0, 0).Slice<0>(p)).data())); EXPECT_EQ( 0, Distance( @@ -862,7 +899,8 @@ TEST(Layout, SliceByIndexData) { EXPECT_EQ( 0, Distance( - p, Type>(L::Partial(1, 0, 0).Slice<0>(p)).data())); + p, + Type>(L::Partial(1, 0, 0).Slice<0>(p)).data())); EXPECT_EQ( 4, Distance( @@ -876,7 +914,8 @@ TEST(Layout, SliceByIndexData) { EXPECT_EQ( 0, Distance( - p, Type>(L::Partial(5, 3, 1).Slice<0>(p)).data())); + p, + Type>(L::Partial(5, 3, 1).Slice<0>(p)).data())); EXPECT_EQ( 24, Distance( @@ -888,12 +927,14 @@ TEST(Layout, SliceByIndexData) { p, Type>(L::Partial(5, 3, 1).Slice<1>(p)).data())); EXPECT_EQ( - 0, Distance(p, Type>(L(5, 3, 1).Slice<0>(p)).data())); + 0, + Distance(p, Type>(L(5, 3, 1).Slice<0>(p)).data())); EXPECT_EQ( 24, Distance(p, Type>(L(5, 3, 1).Slice<2>(p)).data())); EXPECT_EQ( - 8, Distance(p, Type>(L(5, 3, 1).Slice<1>(p)).data())); + 8, + Distance(p, Type>(L(5, 3, 1).Slice<1>(p)).data())); } } @@ -904,98 +945,94 @@ TEST(Layout, SliceByTypeData) { EXPECT_EQ( 0, Distance( - p, Type>(L::Partial(0).Slice(p)).data())); + p, + Type>(L::Partial(0).Slice(p)).data())); EXPECT_EQ( 0, Distance( - p, Type>(L::Partial(3).Slice(p)).data())); + p, + Type>(L::Partial(3).Slice(p)).data())); EXPECT_EQ( - 0, Distance(p, Type>(L(3).Slice(p)).data())); + 0, + Distance(p, Type>(L(3).Slice(p)).data())); } { using L = Layout; - EXPECT_EQ( - 0, Distance( - p, Type>(L::Partial(0).Slice(p)).data())); - EXPECT_EQ( - 0, Distance( - p, Type>(L::Partial(1).Slice(p)).data())); - EXPECT_EQ( - 0, Distance( - p, Type>(L::Partial(5).Slice(p)).data())); EXPECT_EQ( 0, Distance( - p, Type>(L::Partial(0, 0).Slice(p)).data())); + p, + Type>(L::Partial(0).Slice(p)).data())); EXPECT_EQ( 0, Distance( p, - Type>(L::Partial(0, 0).Slice(p)).data())); - EXPECT_EQ( - 0, - Distance( - p, Type>(L::Partial(1, 0).Slice(p)).data())); - EXPECT_EQ( - 4, - Distance( - p, - Type>(L::Partial(1, 0).Slice(p)).data())); - EXPECT_EQ( - 0, - Distance( - p, Type>(L::Partial(5, 3).Slice(p)).data())); - EXPECT_EQ( - 8, - Distance( - p, - Type>(L::Partial(5, 3).Slice(p)).data())); + Type>(L::Partial(1).Slice(p)).data())); EXPECT_EQ( 0, Distance( p, - Type>(L::Partial(0, 0, 0).Slice(p)).data())); + Type>(L::Partial(5).Slice(p)).data())); EXPECT_EQ( 0, - Distance(p, Type>(L::Partial(0, 0, 0).Slice(p)) + Distance(p, Type>(L::Partial(0, 0).Slice(p)) .data())); + EXPECT_EQ(0, Distance(p, Type>( + L::Partial(0, 0).Slice(p)) + .data())); + EXPECT_EQ( + 0, + Distance(p, Type>(L::Partial(1, 0).Slice(p)) + .data())); + EXPECT_EQ(4, Distance(p, Type>( + L::Partial(1, 0).Slice(p)) + .data())); + EXPECT_EQ( + 0, + Distance(p, Type>(L::Partial(5, 3).Slice(p)) + .data())); + EXPECT_EQ(8, Distance(p, Type>( + L::Partial(5, 3).Slice(p)) + .data())); + EXPECT_EQ(0, Distance(p, Type>( + L::Partial(0, 0, 0).Slice(p)) + .data())); + EXPECT_EQ(0, Distance(p, Type>( + L::Partial(0, 0, 0).Slice(p)) + .data())); EXPECT_EQ(0, Distance(p, Type>( L::Partial(0, 0, 0).Slice(p)) .data())); - EXPECT_EQ( - 0, - Distance( - p, - Type>(L::Partial(1, 0, 0).Slice(p)).data())); - EXPECT_EQ( - 4, - Distance(p, Type>(L::Partial(1, 0, 0).Slice(p)) - .data())); + EXPECT_EQ(0, Distance(p, Type>( + L::Partial(1, 0, 0).Slice(p)) + .data())); + EXPECT_EQ(4, Distance(p, Type>( + L::Partial(1, 0, 0).Slice(p)) + .data())); EXPECT_EQ(8, Distance(p, Type>( L::Partial(1, 0, 0).Slice(p)) .data())); - EXPECT_EQ( - 0, - Distance( - p, - Type>(L::Partial(5, 3, 1).Slice(p)).data())); + EXPECT_EQ(0, Distance(p, Type>( + L::Partial(5, 3, 1).Slice(p)) + .data())); EXPECT_EQ(24, Distance(p, Type>( L::Partial(5, 3, 1).Slice(p)) .data())); - EXPECT_EQ( - 8, - Distance(p, Type>(L::Partial(5, 3, 1).Slice(p)) - .data())); + EXPECT_EQ(8, Distance(p, Type>( + L::Partial(5, 3, 1).Slice(p)) + .data())); EXPECT_EQ( 0, - Distance(p, Type>(L(5, 3, 1).Slice(p)).data())); + Distance(p, + Type>(L(5, 3, 1).Slice(p)).data())); EXPECT_EQ( 24, Distance(p, Type>(L(5, 3, 1).Slice(p)).data())); EXPECT_EQ( - 8, Distance( - p, Type>(L(5, 3, 1).Slice(p)).data())); + 8, + Distance( + p, Type>(L(5, 3, 1).Slice(p)).data())); } } @@ -1003,18 +1040,19 @@ TEST(Layout, MutableSliceByIndexData) { alignas(max_align_t) unsigned char p[100]; { using L = Layout; - EXPECT_EQ(0, - Distance(p, Type>(L::Partial(0).Slice<0>(p)).data())); - EXPECT_EQ(0, - Distance(p, Type>(L::Partial(3).Slice<0>(p)).data())); + EXPECT_EQ( + 0, Distance(p, Type>(L::Partial(0).Slice<0>(p)).data())); + EXPECT_EQ( + 0, Distance(p, Type>(L::Partial(3).Slice<0>(p)).data())); EXPECT_EQ(0, Distance(p, Type>(L(3).Slice<0>(p)).data())); } { using L = Layout; - EXPECT_EQ(0, - Distance(p, Type>(L::Partial(3).Slice<0>(p)).data())); EXPECT_EQ( - 0, Distance(p, Type>(L::Partial(3, 5).Slice<0>(p)).data())); + 0, Distance(p, Type>(L::Partial(3).Slice<0>(p)).data())); + EXPECT_EQ( + 0, + Distance(p, Type>(L::Partial(3, 5).Slice<0>(p)).data())); EXPECT_EQ( 12, Distance(p, Type>(L::Partial(3, 5).Slice<1>(p)).data())); @@ -1023,55 +1061,63 @@ TEST(Layout, MutableSliceByIndexData) { } { using L = Layout; - EXPECT_EQ(0, - Distance(p, Type>(L::Partial(0).Slice<0>(p)).data())); - EXPECT_EQ(0, - Distance(p, Type>(L::Partial(1).Slice<0>(p)).data())); - EXPECT_EQ(0, - Distance(p, Type>(L::Partial(5).Slice<0>(p)).data())); EXPECT_EQ( - 0, Distance(p, Type>(L::Partial(0, 0).Slice<0>(p)).data())); + 0, Distance(p, Type>(L::Partial(0).Slice<0>(p)).data())); EXPECT_EQ( - 0, Distance(p, Type>(L::Partial(0, 0).Slice<1>(p)).data())); + 0, Distance(p, Type>(L::Partial(1).Slice<0>(p)).data())); EXPECT_EQ( - 0, Distance(p, Type>(L::Partial(1, 0).Slice<0>(p)).data())); - EXPECT_EQ( - 4, Distance(p, Type>(L::Partial(1, 0).Slice<1>(p)).data())); - EXPECT_EQ( - 0, Distance(p, Type>(L::Partial(5, 3).Slice<0>(p)).data())); - EXPECT_EQ( - 8, Distance(p, Type>(L::Partial(5, 3).Slice<1>(p)).data())); + 0, Distance(p, Type>(L::Partial(5).Slice<0>(p)).data())); EXPECT_EQ( 0, - Distance(p, Type>(L::Partial(0, 0, 0).Slice<0>(p)).data())); + Distance(p, Type>(L::Partial(0, 0).Slice<0>(p)).data())); EXPECT_EQ( 0, - Distance(p, Type>(L::Partial(0, 0, 0).Slice<1>(p)).data())); + Distance(p, Type>(L::Partial(0, 0).Slice<1>(p)).data())); + EXPECT_EQ( + 0, + Distance(p, Type>(L::Partial(1, 0).Slice<0>(p)).data())); + EXPECT_EQ( + 4, + Distance(p, Type>(L::Partial(1, 0).Slice<1>(p)).data())); + EXPECT_EQ( + 0, + Distance(p, Type>(L::Partial(5, 3).Slice<0>(p)).data())); + EXPECT_EQ( + 8, + Distance(p, Type>(L::Partial(5, 3).Slice<1>(p)).data())); + EXPECT_EQ( + 0, Distance( + p, Type>(L::Partial(0, 0, 0).Slice<0>(p)).data())); + EXPECT_EQ( + 0, Distance( + p, Type>(L::Partial(0, 0, 0).Slice<1>(p)).data())); EXPECT_EQ( 0, Distance( p, Type>(L::Partial(0, 0, 0).Slice<2>(p)).data())); EXPECT_EQ( - 0, - Distance(p, Type>(L::Partial(1, 0, 0).Slice<0>(p)).data())); + 0, Distance( + p, Type>(L::Partial(1, 0, 0).Slice<0>(p)).data())); EXPECT_EQ( - 4, - Distance(p, Type>(L::Partial(1, 0, 0).Slice<1>(p)).data())); + 4, Distance( + p, Type>(L::Partial(1, 0, 0).Slice<1>(p)).data())); EXPECT_EQ( 8, Distance( p, Type>(L::Partial(1, 0, 0).Slice<2>(p)).data())); EXPECT_EQ( - 0, - Distance(p, Type>(L::Partial(5, 3, 1).Slice<0>(p)).data())); + 0, Distance( + p, Type>(L::Partial(5, 3, 1).Slice<0>(p)).data())); EXPECT_EQ( 24, Distance( p, Type>(L::Partial(5, 3, 1).Slice<2>(p)).data())); EXPECT_EQ( - 8, - Distance(p, Type>(L::Partial(5, 3, 1).Slice<1>(p)).data())); - EXPECT_EQ(0, Distance(p, Type>(L(5, 3, 1).Slice<0>(p)).data())); + 8, Distance( + p, Type>(L::Partial(5, 3, 1).Slice<1>(p)).data())); + EXPECT_EQ(0, + Distance(p, Type>(L(5, 3, 1).Slice<0>(p)).data())); EXPECT_EQ(24, Distance(p, Type>(L(5, 3, 1).Slice<2>(p)).data())); - EXPECT_EQ(8, Distance(p, Type>(L(5, 3, 1).Slice<1>(p)).data())); + EXPECT_EQ(8, + Distance(p, Type>(L(5, 3, 1).Slice<1>(p)).data())); } } @@ -1080,66 +1126,84 @@ TEST(Layout, MutableSliceByTypeData) { { using L = Layout; EXPECT_EQ( - 0, - Distance(p, Type>(L::Partial(0).Slice(p)).data())); + 0, Distance( + p, Type>(L::Partial(0).Slice(p)).data())); EXPECT_EQ( - 0, - Distance(p, Type>(L::Partial(3).Slice(p)).data())); - EXPECT_EQ(0, Distance(p, Type>(L(3).Slice(p)).data())); + 0, Distance( + p, Type>(L::Partial(3).Slice(p)).data())); + EXPECT_EQ(0, + Distance(p, Type>(L(3).Slice(p)).data())); } { using L = Layout; EXPECT_EQ( - 0, Distance(p, Type>(L::Partial(0).Slice(p)).data())); - EXPECT_EQ( - 0, Distance(p, Type>(L::Partial(1).Slice(p)).data())); - EXPECT_EQ( - 0, Distance(p, Type>(L::Partial(5).Slice(p)).data())); + 0, + Distance(p, Type>(L::Partial(0).Slice(p)).data())); EXPECT_EQ( 0, - Distance(p, Type>(L::Partial(0, 0).Slice(p)).data())); - EXPECT_EQ( - 0, Distance( - p, Type>(L::Partial(0, 0).Slice(p)).data())); + Distance(p, Type>(L::Partial(1).Slice(p)).data())); EXPECT_EQ( 0, - Distance(p, Type>(L::Partial(1, 0).Slice(p)).data())); - EXPECT_EQ( - 4, Distance( - p, Type>(L::Partial(1, 0).Slice(p)).data())); + Distance(p, Type>(L::Partial(5).Slice(p)).data())); EXPECT_EQ( 0, - Distance(p, Type>(L::Partial(5, 3).Slice(p)).data())); - EXPECT_EQ( - 8, Distance( - p, Type>(L::Partial(5, 3).Slice(p)).data())); - EXPECT_EQ( - 0, Distance( - p, Type>(L::Partial(0, 0, 0).Slice(p)).data())); + Distance(p, + Type>(L::Partial(0, 0).Slice(p)).data())); EXPECT_EQ( 0, Distance( - p, Type>(L::Partial(0, 0, 0).Slice(p)).data())); + p, Type>(L::Partial(0, 0).Slice(p)).data())); + EXPECT_EQ( + 0, + Distance(p, + Type>(L::Partial(1, 0).Slice(p)).data())); + EXPECT_EQ( + 4, + Distance( + p, Type>(L::Partial(1, 0).Slice(p)).data())); + EXPECT_EQ( + 0, + Distance(p, + Type>(L::Partial(5, 3).Slice(p)).data())); + EXPECT_EQ( + 8, + Distance( + p, Type>(L::Partial(5, 3).Slice(p)).data())); + EXPECT_EQ( + 0, + Distance( + p, + Type>(L::Partial(0, 0, 0).Slice(p)).data())); + EXPECT_EQ( + 0, + Distance( + p, + Type>(L::Partial(0, 0, 0).Slice(p)).data())); EXPECT_EQ( 0, Distance( p, Type>(L::Partial(0, 0, 0).Slice(p)).data())); EXPECT_EQ( - 0, Distance( - p, Type>(L::Partial(1, 0, 0).Slice(p)).data())); + 0, + Distance( + p, + Type>(L::Partial(1, 0, 0).Slice(p)).data())); EXPECT_EQ( 4, Distance( - p, Type>(L::Partial(1, 0, 0).Slice(p)).data())); + p, + Type>(L::Partial(1, 0, 0).Slice(p)).data())); EXPECT_EQ( 8, Distance( p, Type>(L::Partial(1, 0, 0).Slice(p)).data())); EXPECT_EQ( - 0, Distance( - p, Type>(L::Partial(5, 3, 1).Slice(p)).data())); + 0, + Distance( + p, + Type>(L::Partial(5, 3, 1).Slice(p)).data())); EXPECT_EQ( 24, Distance( @@ -1148,14 +1212,16 @@ TEST(Layout, MutableSliceByTypeData) { EXPECT_EQ( 8, Distance( - p, Type>(L::Partial(5, 3, 1).Slice(p)).data())); - EXPECT_EQ(0, - Distance(p, Type>(L(5, 3, 1).Slice(p)).data())); + p, + Type>(L::Partial(5, 3, 1).Slice(p)).data())); + EXPECT_EQ( + 0, Distance(p, Type>(L(5, 3, 1).Slice(p)).data())); EXPECT_EQ( 24, Distance(p, Type>(L(5, 3, 1).Slice(p)).data())); EXPECT_EQ( - 8, Distance(p, Type>(L(5, 3, 1).Slice(p)).data())); + 8, + Distance(p, Type>(L(5, 3, 1).Slice(p)).data())); } } @@ -1254,17 +1320,17 @@ TEST(Layout, MutableSlices) { } { const auto x = L::Partial(1, 2, 3); - EXPECT_THAT( - (Type, Span, Span>>(x.Slices(p))), - Tuple(IsSameSlice(x.Slice<0>(p)), IsSameSlice(x.Slice<1>(p)), - IsSameSlice(x.Slice<2>(p)))); + EXPECT_THAT((Type, Span, Span>>( + x.Slices(p))), + Tuple(IsSameSlice(x.Slice<0>(p)), IsSameSlice(x.Slice<1>(p)), + IsSameSlice(x.Slice<2>(p)))); } { const L x(1, 2, 3); - EXPECT_THAT( - (Type, Span, Span>>(x.Slices(p))), - Tuple(IsSameSlice(x.Slice<0>(p)), IsSameSlice(x.Slice<1>(p)), - IsSameSlice(x.Slice<2>(p)))); + EXPECT_THAT((Type, Span, Span>>( + x.Slices(p))), + Tuple(IsSameSlice(x.Slice<0>(p)), IsSameSlice(x.Slice<1>(p)), + IsSameSlice(x.Slice<2>(p)))); } } @@ -1314,7 +1380,7 @@ struct Region { }; void ExpectRegionPoisoned(const unsigned char* p, size_t n, bool poisoned) { -#ifdef ADDRESS_SANITIZER +#ifdef ABSL_HAVE_ADDRESS_SANITIZER for (size_t i = 0; i != n; ++i) { EXPECT_EQ(poisoned, __asan_address_is_poisoned(p + i)); } @@ -1396,7 +1462,8 @@ TEST(Layout, DebugString) { x.DebugString()); } { - constexpr auto x = Layout::Partial(1, 2, 3); + constexpr auto x = + Layout::Partial(1, 2, 3); EXPECT_EQ( "@0(1)[1]; @4(4)[2]; @12(1)[3]; " "@16" + @@ -1404,7 +1471,8 @@ TEST(Layout, DebugString) { x.DebugString()); } { - constexpr auto x = Layout::Partial(1, 2, 3, 4); + constexpr auto x = + Layout::Partial(1, 2, 3, 4); EXPECT_EQ( "@0(1)[1]; @4(4)[2]; @12(1)[3]; " "@16" + diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/raw_hash_map.h b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/raw_hash_map.h index 0a02757ddf..c7df2efc62 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/raw_hash_map.h +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/raw_hash_map.h @@ -51,8 +51,9 @@ class raw_hash_map : public raw_hash_set { using key_arg = typename KeyArgImpl::template type; static_assert(!std::is_reference::value, ""); - // TODO(alkis): remove this assertion and verify that reference mapped_type is - // supported. + + // TODO(b/187807849): Evaluate whether to support reference mapped_type and + // remove this assertion if/when it is supported. static_assert(!std::is_reference::value, ""); using iterator = typename raw_hash_map::raw_hash_set::iterator; diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/raw_hash_set.cc b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/raw_hash_set.cc index 919ac07405..687bcb8a4d 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/raw_hash_set.cc +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/raw_hash_set.cc @@ -23,11 +23,17 @@ namespace absl { ABSL_NAMESPACE_BEGIN namespace container_internal { +alignas(16) ABSL_CONST_INIT ABSL_DLL const ctrl_t kEmptyGroup[16] = { + ctrl_t::kSentinel, ctrl_t::kEmpty, ctrl_t::kEmpty, ctrl_t::kEmpty, + ctrl_t::kEmpty, ctrl_t::kEmpty, ctrl_t::kEmpty, ctrl_t::kEmpty, + ctrl_t::kEmpty, ctrl_t::kEmpty, ctrl_t::kEmpty, ctrl_t::kEmpty, + ctrl_t::kEmpty, ctrl_t::kEmpty, ctrl_t::kEmpty, ctrl_t::kEmpty}; + constexpr size_t Group::kWidth; // Returns "random" seed. inline size_t RandomSeed() { -#if ABSL_HAVE_THREAD_LOCAL +#ifdef ABSL_HAVE_THREAD_LOCAL static thread_local size_t counter = 0; size_t value = ++counter; #else // ABSL_HAVE_THREAD_LOCAL @@ -37,12 +43,25 @@ inline size_t RandomSeed() { return value ^ static_cast(reinterpret_cast(&counter)); } -bool ShouldInsertBackwards(size_t hash, ctrl_t* ctrl) { +bool ShouldInsertBackwards(size_t hash, const ctrl_t* ctrl) { // To avoid problems with weak hashes and single bit tests, we use % 13. // TODO(kfm,sbenza): revisit after we do unconditional mixing return (H1(hash, ctrl) ^ RandomSeed()) % 13 > 6; } +void ConvertDeletedToEmptyAndFullToDeleted(ctrl_t* ctrl, size_t capacity) { + assert(ctrl[capacity] == ctrl_t::kSentinel); + assert(IsValidCapacity(capacity)); + for (ctrl_t* pos = ctrl; pos < ctrl + capacity; pos += Group::kWidth) { + Group{pos}.ConvertSpecialToEmptyAndFullToDeleted(pos); + } + // Copy the cloned ctrl bytes. + std::memcpy(ctrl + capacity + 1, ctrl, NumClonedBytes()); + ctrl[capacity] = ctrl_t::kSentinel; +} +// Extern template instantiotion for inline function. +template FindInfo find_first_non_full(const ctrl_t*, size_t, size_t); + } // namespace container_internal ABSL_NAMESPACE_END } // namespace absl diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/raw_hash_set.h b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/raw_hash_set.h index e47e1fedf7..212052ea74 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/raw_hash_set.h +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/raw_hash_set.h @@ -102,9 +102,8 @@ #include #include -#include "absl/base/internal/bits.h" #include "absl/base/internal/endian.h" -#include "absl/base/macros.h" +#include "absl/base/optimization.h" #include "absl/base/port.h" #include "absl/container/internal/common.h" #include "absl/container/internal/compressed_tuple.h" @@ -113,15 +112,25 @@ #include "absl/container/internal/hashtable_debug_hooks.h" #include "absl/container/internal/hashtablez_sampler.h" #include "absl/container/internal/have_sse.h" -#include "absl/container/internal/layout.h" #include "absl/memory/memory.h" #include "absl/meta/type_traits.h" +#include "absl/numeric/bits.h" #include "absl/utility/utility.h" namespace absl { ABSL_NAMESPACE_BEGIN namespace container_internal { +template +void SwapAlloc(AllocType& lhs, AllocType& rhs, + std::true_type /* propagate_on_container_swap */) { + using std::swap; + swap(lhs, rhs); +} +template +void SwapAlloc(AllocType& /*lhs*/, AllocType& /*rhs*/, + std::false_type /* propagate_on_container_swap */) {} + template class probe_seq { public: @@ -169,24 +178,19 @@ struct IsDecomposable< // TODO(alkis): Switch to std::is_nothrow_swappable when gcc/clang supports it. template -constexpr bool IsNoThrowSwappable() { +constexpr bool IsNoThrowSwappable(std::true_type = {} /* is_swappable */) { using std::swap; return noexcept(swap(std::declval(), std::declval())); } - -template -int TrailingZeros(T x) { - return sizeof(T) == 8 ? base_internal::CountTrailingZerosNonZero64( - static_cast(x)) - : base_internal::CountTrailingZerosNonZero32( - static_cast(x)); +template +constexpr bool IsNoThrowSwappable(std::false_type /* is_swappable */) { + return false; } template -int LeadingZeros(T x) { - return sizeof(T) == 8 - ? base_internal::CountLeadingZeros64(static_cast(x)) - : base_internal::CountLeadingZeros32(static_cast(x)); +uint32_t TrailingZeros(T x) { + ABSL_INTERNAL_ASSUME(x != 0); + return countr_zero(x); } // An abstraction over a bitmask. It provides an easy way to iterate through the @@ -216,26 +220,24 @@ class BitMask { } explicit operator bool() const { return mask_ != 0; } int operator*() const { return LowestBitSet(); } - int LowestBitSet() const { + uint32_t LowestBitSet() const { return container_internal::TrailingZeros(mask_) >> Shift; } - int HighestBitSet() const { - return (sizeof(T) * CHAR_BIT - container_internal::LeadingZeros(mask_) - - 1) >> - Shift; + uint32_t HighestBitSet() const { + return static_cast((bit_width(mask_) - 1) >> Shift); } BitMask begin() const { return *this; } BitMask end() const { return BitMask(0); } - int TrailingZeros() const { + uint32_t TrailingZeros() const { return container_internal::TrailingZeros(mask_) >> Shift; } - int LeadingZeros() const { + uint32_t LeadingZeros() const { constexpr int total_significant_bits = SignificantBits << Shift; constexpr int extra_bits = sizeof(T) * 8 - total_significant_bits; - return container_internal::LeadingZeros(mask_ << extra_bits) >> Shift; + return countl_zero(mask_ << extra_bits) >> Shift; } private: @@ -249,48 +251,53 @@ class BitMask { T mask_; }; -using ctrl_t = signed char; using h2_t = uint8_t; // The values here are selected for maximum performance. See the static asserts -// below for details. -enum Ctrl : ctrl_t { +// below for details. We use an enum class so that when strict aliasing is +// enabled, the compiler knows ctrl_t doesn't alias other types. +enum class ctrl_t : int8_t { kEmpty = -128, // 0b10000000 kDeleted = -2, // 0b11111110 kSentinel = -1, // 0b11111111 }; static_assert( - kEmpty & kDeleted & kSentinel & 0x80, + (static_cast(ctrl_t::kEmpty) & + static_cast(ctrl_t::kDeleted) & + static_cast(ctrl_t::kSentinel) & 0x80) != 0, "Special markers need to have the MSB to make checking for them efficient"); -static_assert(kEmpty < kSentinel && kDeleted < kSentinel, - "kEmpty and kDeleted must be smaller than kSentinel to make the " - "SIMD test of IsEmptyOrDeleted() efficient"); -static_assert(kSentinel == -1, - "kSentinel must be -1 to elide loading it from memory into SIMD " - "registers (pcmpeqd xmm, xmm)"); -static_assert(kEmpty == -128, - "kEmpty must be -128 to make the SIMD check for its " +static_assert( + ctrl_t::kEmpty < ctrl_t::kSentinel && ctrl_t::kDeleted < ctrl_t::kSentinel, + "ctrl_t::kEmpty and ctrl_t::kDeleted must be smaller than " + "ctrl_t::kSentinel to make the SIMD test of IsEmptyOrDeleted() efficient"); +static_assert( + ctrl_t::kSentinel == static_cast(-1), + "ctrl_t::kSentinel must be -1 to elide loading it from memory into SIMD " + "registers (pcmpeqd xmm, xmm)"); +static_assert(ctrl_t::kEmpty == static_cast(-128), + "ctrl_t::kEmpty must be -128 to make the SIMD check for its " "existence efficient (psignb xmm, xmm)"); -static_assert(~kEmpty & ~kDeleted & kSentinel & 0x7F, - "kEmpty and kDeleted must share an unset bit that is not shared " - "by kSentinel to make the scalar test for MatchEmptyOrDeleted() " - "efficient"); -static_assert(kDeleted == -2, - "kDeleted must be -2 to make the implementation of " +static_assert( + (~static_cast(ctrl_t::kEmpty) & + ~static_cast(ctrl_t::kDeleted) & + static_cast(ctrl_t::kSentinel) & 0x7F) != 0, + "ctrl_t::kEmpty and ctrl_t::kDeleted must share an unset bit that is not " + "shared by ctrl_t::kSentinel to make the scalar test for " + "MatchEmptyOrDeleted() efficient"); +static_assert(ctrl_t::kDeleted == static_cast(-2), + "ctrl_t::kDeleted must be -2 to make the implementation of " "ConvertSpecialToEmptyAndFullToDeleted efficient"); // A single block of empty control bytes for tables without any slots allocated. // This enables removing a branch in the hot path of find(). +ABSL_DLL extern const ctrl_t kEmptyGroup[16]; inline ctrl_t* EmptyGroup() { - alignas(16) static constexpr ctrl_t empty_group[] = { - kSentinel, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, - kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty}; - return const_cast(empty_group); + return const_cast(kEmptyGroup); } // Mixes a randomly generated per-process seed with `hash` and `ctrl` to // randomize insertion order within groups. -bool ShouldInsertBackwards(size_t hash, ctrl_t* ctrl); +bool ShouldInsertBackwards(size_t hash, const ctrl_t* ctrl); // Returns a hash seed. // @@ -306,12 +313,12 @@ inline size_t HashSeed(const ctrl_t* ctrl) { inline size_t H1(size_t hash, const ctrl_t* ctrl) { return (hash >> 7) ^ HashSeed(ctrl); } -inline ctrl_t H2(size_t hash) { return hash & 0x7F; } +inline h2_t H2(size_t hash) { return hash & 0x7F; } -inline bool IsEmpty(ctrl_t c) { return c == kEmpty; } -inline bool IsFull(ctrl_t c) { return c >= 0; } -inline bool IsDeleted(ctrl_t c) { return c == kDeleted; } -inline bool IsEmptyOrDeleted(ctrl_t c) { return c < kSentinel; } +inline bool IsEmpty(ctrl_t c) { return c == ctrl_t::kEmpty; } +inline bool IsFull(ctrl_t c) { return c >= static_cast(0); } +inline bool IsDeleted(ctrl_t c) { return c == ctrl_t::kDeleted; } +inline bool IsEmptyOrDeleted(ctrl_t c) { return c < ctrl_t::kSentinel; } #if ABSL_INTERNAL_RAW_HASH_SET_HAVE_SSE2 @@ -348,26 +355,26 @@ struct GroupSse2Impl { // Returns a bitmask representing the positions of empty slots. BitMask MatchEmpty() const { #if ABSL_INTERNAL_RAW_HASH_SET_HAVE_SSSE3 - // This only works because kEmpty is -128. + // This only works because ctrl_t::kEmpty is -128. return BitMask( _mm_movemask_epi8(_mm_sign_epi8(ctrl, ctrl))); #else - return Match(static_cast(kEmpty)); + return Match(static_cast(ctrl_t::kEmpty)); #endif } // Returns a bitmask representing the positions of empty or deleted slots. BitMask MatchEmptyOrDeleted() const { - auto special = _mm_set1_epi8(kSentinel); + auto special = _mm_set1_epi8(static_cast(ctrl_t::kSentinel)); return BitMask( _mm_movemask_epi8(_mm_cmpgt_epi8_fixed(special, ctrl))); } // Returns the number of trailing empty or deleted elements in the group. uint32_t CountLeadingEmptyOrDeleted() const { - auto special = _mm_set1_epi8(kSentinel); - return TrailingZeros( - _mm_movemask_epi8(_mm_cmpgt_epi8_fixed(special, ctrl)) + 1); + auto special = _mm_set1_epi8(static_cast(ctrl_t::kSentinel)); + return TrailingZeros(static_cast( + _mm_movemask_epi8(_mm_cmpgt_epi8_fixed(special, ctrl)) + 1)); } void ConvertSpecialToEmptyAndFullToDeleted(ctrl_t* dst) const { @@ -400,7 +407,7 @@ struct GroupPortableImpl { // // Caveat: there are false positives but: // - they only occur if there is a real match - // - they never occur on kEmpty, kDeleted, kSentinel + // - they never occur on ctrl_t::kEmpty, ctrl_t::kDeleted, ctrl_t::kSentinel // - they will be handled gracefully by subsequent checks in code // // Example: @@ -445,6 +452,10 @@ using Group = GroupSse2Impl; using Group = GroupPortableImpl; #endif +// The number of cloned control bytes that we copy from the beginning to the +// end of the control bytes array. +constexpr size_t NumClonedBytes() { return Group::kWidth - 1; } + template class raw_hash_set; @@ -452,31 +463,29 @@ inline bool IsValidCapacity(size_t n) { return ((n + 1) & n) == 0 && n > 0; } // PRECONDITION: // IsValidCapacity(capacity) -// ctrl[capacity] == kSentinel -// ctrl[i] != kSentinel for all i < capacity +// ctrl[capacity] == ctrl_t::kSentinel +// ctrl[i] != ctrl_t::kSentinel for all i < capacity // Applies mapping for every byte in ctrl: // DELETED -> EMPTY // EMPTY -> EMPTY // FULL -> DELETED -inline void ConvertDeletedToEmptyAndFullToDeleted( - ctrl_t* ctrl, size_t capacity) { - assert(ctrl[capacity] == kSentinel); - assert(IsValidCapacity(capacity)); - for (ctrl_t* pos = ctrl; pos != ctrl + capacity + 1; pos += Group::kWidth) { - Group{pos}.ConvertSpecialToEmptyAndFullToDeleted(pos); - } - // Copy the cloned ctrl bytes. - std::memcpy(ctrl + capacity + 1, ctrl, Group::kWidth); - ctrl[capacity] = kSentinel; -} +void ConvertDeletedToEmptyAndFullToDeleted(ctrl_t* ctrl, size_t capacity); // Rounds up the capacity to the next power of 2 minus 1, with a minimum of 1. inline size_t NormalizeCapacity(size_t n) { - return n ? ~size_t{} >> LeadingZeros(n) : 1; + return n ? ~size_t{} >> countl_zero(n) : 1; } -// We use 7/8th as maximum load factor. -// For 16-wide groups, that gives an average of two empty slots per group. +// General notes on capacity/growth methods below: +// - We use 7/8th as maximum load factor. For 16-wide groups, that gives an +// average of two empty slots per group. +// - For (capacity+1) >= Group::kWidth, growth is 7/8*capacity. +// - For (capacity+1) < Group::kWidth, growth == capacity. In this case, we +// never need to probe (the whole table fits in one group) so we don't need a +// load factor less than 1. + +// Given `capacity` of the table, returns the size (i.e. number of full slots) +// at which we should grow the capacity. inline size_t CapacityToGrowth(size_t capacity) { assert(IsValidCapacity(capacity)); // `capacity*7/8` @@ -487,7 +496,7 @@ inline size_t CapacityToGrowth(size_t capacity) { return capacity - capacity / 8; } // From desired "growth" to a lowerbound of the necessary capacity. -// Might not be a valid one and required NormalizeCapacity(). +// Might not be a valid one and requires NormalizeCapacity(). inline size_t GrowthToLowerboundCapacity(size_t growth) { // `growth*8/7` if (Group::kWidth == 8 && growth == 7) { @@ -497,6 +506,144 @@ inline size_t GrowthToLowerboundCapacity(size_t growth) { return growth + static_cast((static_cast(growth) - 1) / 7); } +template +size_t SelectBucketCountForIterRange(InputIter first, InputIter last, + size_t bucket_count) { + if (bucket_count != 0) { + return bucket_count; + } + using InputIterCategory = + typename std::iterator_traits::iterator_category; + if (std::is_base_of::value) { + return GrowthToLowerboundCapacity( + static_cast(std::distance(first, last))); + } + return 0; +} + +inline void AssertIsFull(ctrl_t* ctrl) { + ABSL_HARDENING_ASSERT((ctrl != nullptr && IsFull(*ctrl)) && + "Invalid operation on iterator. The element might have " + "been erased, or the table might have rehashed."); +} + +inline void AssertIsValid(ctrl_t* ctrl) { + ABSL_HARDENING_ASSERT((ctrl == nullptr || IsFull(*ctrl)) && + "Invalid operation on iterator. The element might have " + "been erased, or the table might have rehashed."); +} + +struct FindInfo { + size_t offset; + size_t probe_length; +}; + +// The representation of the object has two modes: +// - small: For capacities < kWidth-1 +// - large: For the rest. +// +// Differences: +// - In small mode we are able to use the whole capacity. The extra control +// bytes give us at least one "empty" control byte to stop the iteration. +// This is important to make 1 a valid capacity. +// +// - In small mode only the first `capacity()` control bytes after the +// sentinel are valid. The rest contain dummy ctrl_t::kEmpty values that do not +// represent a real slot. This is important to take into account on +// find_first_non_full(), where we never try ShouldInsertBackwards() for +// small tables. +inline bool is_small(size_t capacity) { return capacity < Group::kWidth - 1; } + +inline probe_seq probe(const ctrl_t* ctrl, size_t hash, + size_t capacity) { + return probe_seq(H1(hash, ctrl), capacity); +} + +// Probes the raw_hash_set with the probe sequence for hash and returns the +// pointer to the first empty or deleted slot. +// NOTE: this function must work with tables having both ctrl_t::kEmpty and +// ctrl_t::kDeleted in one group. Such tables appears during +// drop_deletes_without_resize. +// +// This function is very useful when insertions happen and: +// - the input is already a set +// - there are enough slots +// - the element with the hash is not in the table +template +inline FindInfo find_first_non_full(const ctrl_t* ctrl, size_t hash, + size_t capacity) { + auto seq = probe(ctrl, hash, capacity); + while (true) { + Group g{ctrl + seq.offset()}; + auto mask = g.MatchEmptyOrDeleted(); + if (mask) { +#if !defined(NDEBUG) + // We want to add entropy even when ASLR is not enabled. + // In debug build we will randomly insert in either the front or back of + // the group. + // TODO(kfm,sbenza): revisit after we do unconditional mixing + if (!is_small(capacity) && ShouldInsertBackwards(hash, ctrl)) { + return {seq.offset(mask.HighestBitSet()), seq.index()}; + } +#endif + return {seq.offset(mask.LowestBitSet()), seq.index()}; + } + seq.next(); + assert(seq.index() <= capacity && "full table!"); + } +} + +// Extern template for inline function keep possibility of inlining. +// When compiler decided to not inline, no symbols will be added to the +// corresponding translation unit. +extern template FindInfo find_first_non_full(const ctrl_t*, size_t, size_t); + +// Reset all ctrl bytes back to ctrl_t::kEmpty, except the sentinel. +inline void ResetCtrl(size_t capacity, ctrl_t* ctrl, const void* slot, + size_t slot_size) { + std::memset(ctrl, static_cast(ctrl_t::kEmpty), + capacity + 1 + NumClonedBytes()); + ctrl[capacity] = ctrl_t::kSentinel; + SanitizerPoisonMemoryRegion(slot, slot_size * capacity); +} + +// Sets the control byte, and if `i < NumClonedBytes()`, set the cloned byte +// at the end too. +inline void SetCtrl(size_t i, ctrl_t h, size_t capacity, ctrl_t* ctrl, + const void* slot, size_t slot_size) { + assert(i < capacity); + + auto* slot_i = static_cast(slot) + i * slot_size; + if (IsFull(h)) { + SanitizerUnpoisonMemoryRegion(slot_i, slot_size); + } else { + SanitizerPoisonMemoryRegion(slot_i, slot_size); + } + + ctrl[i] = h; + ctrl[((i - NumClonedBytes()) & capacity) + (NumClonedBytes() & capacity)] = h; +} + +inline void SetCtrl(size_t i, h2_t h, size_t capacity, ctrl_t* ctrl, + const void* slot, size_t slot_size) { + SetCtrl(i, static_cast(h), capacity, ctrl, slot, slot_size); +} + +// The allocated block consists of `capacity + 1 + NumClonedBytes()` control +// bytes followed by `capacity` slots, which must be aligned to `slot_align`. +// SlotOffset returns the offset of the slots into the allocated block. +inline size_t SlotOffset(size_t capacity, size_t slot_align) { + assert(IsValidCapacity(capacity)); + const size_t num_control_bytes = capacity + 1 + NumClonedBytes(); + return (num_control_bytes + slot_align - 1) & (~slot_align + 1); +} + +// Returns the size of the allocated block. See also above comment. +inline size_t AllocSize(size_t capacity, size_t slot_size, size_t slot_align) { + return SlotOffset(capacity, slot_align) + capacity * slot_size; +} + // Policy: a policy defines how to perform different operations on // the slots of the hashtable (see hash_policy_traits.h for the full interface // of policy). @@ -511,7 +658,8 @@ inline size_t GrowthToLowerboundCapacity(size_t growth) { // if they are equal, false if they are not. If two keys compare equal, then // their hash values as defined by Hash MUST be equal. // -// Allocator: an Allocator [https://devdocs.io/cpp/concept/allocator] with which +// Allocator: an Allocator +// [https://en.cppreference.com/w/cpp/named_req/Allocator] with which // the storage of the hashtable will be allocated and the elements will be // constructed and destroyed. template @@ -552,13 +700,6 @@ class raw_hash_set { auto KeyTypeCanBeHashed(const Hash& h, const key_type& k) -> decltype(h(k)); auto KeyTypeCanBeEq(const Eq& eq, const key_type& k) -> decltype(eq(k, k)); - using Layout = absl::container_internal::Layout; - - static Layout MakeLayout(size_t capacity) { - assert(IsValidCapacity(capacity)); - return Layout(capacity + Group::kWidth + 1, capacity); - } - using AllocTraits = absl::allocator_traits; using SlotAlloc = typename absl::allocator_traits< allocator_type>::template rebind_alloc; @@ -617,7 +758,7 @@ class raw_hash_set { // PRECONDITION: not an end() iterator. reference operator*() const { - assert_is_full(); + AssertIsFull(ctrl_); return PolicyTraits::element(slot_); } @@ -626,7 +767,7 @@ class raw_hash_set { // PRECONDITION: not an end() iterator. iterator& operator++() { - assert_is_full(); + AssertIsFull(ctrl_); ++ctrl_; ++slot_; skip_empty_or_deleted(); @@ -640,8 +781,8 @@ class raw_hash_set { } friend bool operator==(const iterator& a, const iterator& b) { - a.assert_is_valid(); - b.assert_is_valid(); + AssertIsValid(a.ctrl_); + AssertIsValid(b.ctrl_); return a.ctrl_ == b.ctrl_; } friend bool operator!=(const iterator& a, const iterator& b) { @@ -649,24 +790,19 @@ class raw_hash_set { } private: - iterator(ctrl_t* ctrl) : ctrl_(ctrl) {} // for end() - iterator(ctrl_t* ctrl, slot_type* slot) : ctrl_(ctrl), slot_(slot) {} - - void assert_is_full() const { ABSL_HARDENING_ASSERT(IsFull(*ctrl_)); } - void assert_is_valid() const { - ABSL_HARDENING_ASSERT(!ctrl_ || IsFull(*ctrl_) || *ctrl_ == kSentinel); + iterator(ctrl_t* ctrl, slot_type* slot) : ctrl_(ctrl), slot_(slot) { + // This assumption helps the compiler know that any non-end iterator is + // not equal to any end iterator. + ABSL_INTERNAL_ASSUME(ctrl != nullptr); } void skip_empty_or_deleted() { while (IsEmptyOrDeleted(*ctrl_)) { - // ctrl is not necessarily aligned to Group::kWidth. It is also likely - // to read past the space for ctrl bytes and into slots. This is ok - // because ctrl has sizeof() == 1 and slot has sizeof() >= 1 so there - // is no way to read outside the combined slot array. uint32_t shift = Group{ctrl_}.CountLeadingEmptyOrDeleted(); ctrl_ += shift; slot_ += shift; } + if (ABSL_PREDICT_FALSE(*ctrl_ == ctrl_t::kSentinel)) ctrl_ = nullptr; } ctrl_t* ctrl_ = nullptr; @@ -725,10 +861,10 @@ class raw_hash_set { explicit raw_hash_set(size_t bucket_count, const hasher& hash = hasher(), const key_equal& eq = key_equal(), const allocator_type& alloc = allocator_type()) - : ctrl_(EmptyGroup()), settings_(0, hash, eq, alloc) { + : ctrl_(EmptyGroup()), + settings_(0, HashtablezInfoHandle(), hash, eq, alloc) { if (bucket_count) { capacity_ = NormalizeCapacity(bucket_count); - reset_growth_left(); initialize_slots(); } } @@ -747,7 +883,8 @@ class raw_hash_set { raw_hash_set(InputIter first, InputIter last, size_t bucket_count = 0, const hasher& hash = hasher(), const key_equal& eq = key_equal(), const allocator_type& alloc = allocator_type()) - : raw_hash_set(bucket_count, hash, eq, alloc) { + : raw_hash_set(SelectBucketCountForIterRange(first, last, bucket_count), + hash, eq, alloc) { insert(first, last); } @@ -834,10 +971,11 @@ class raw_hash_set { // than a full `insert`. for (const auto& v : that) { const size_t hash = PolicyTraits::apply(HashElement{hash_ref()}, v); - auto target = find_first_non_full(hash); - set_ctrl(target.offset, H2(hash)); + auto target = find_first_non_full(ctrl_, hash, capacity_); + SetCtrl(target.offset, H2(hash), capacity_, ctrl_, slots_, + sizeof(slot_type)); emplace_at(target.offset, v); - infoz_.RecordInsert(hash, target.probe_length); + infoz().RecordInsert(hash, target.probe_length); } size_ = that.size(); growth_left() -= that.size(); @@ -851,28 +989,27 @@ class raw_hash_set { slots_(absl::exchange(that.slots_, nullptr)), size_(absl::exchange(that.size_, 0)), capacity_(absl::exchange(that.capacity_, 0)), - infoz_(absl::exchange(that.infoz_, HashtablezInfoHandle())), // Hash, equality and allocator are copied instead of moved because // `that` must be left valid. If Hash is std::function, moving it // would create a nullptr functor that cannot be called. - settings_(that.settings_) { - // growth_left was copied above, reset the one from `that`. - that.growth_left() = 0; - } + settings_(absl::exchange(that.growth_left(), 0), + absl::exchange(that.infoz(), HashtablezInfoHandle()), + that.hash_ref(), that.eq_ref(), that.alloc_ref()) {} raw_hash_set(raw_hash_set&& that, const allocator_type& a) : ctrl_(EmptyGroup()), slots_(nullptr), size_(0), capacity_(0), - settings_(0, that.hash_ref(), that.eq_ref(), a) { + settings_(0, HashtablezInfoHandle(), that.hash_ref(), that.eq_ref(), + a) { if (a == that.alloc_ref()) { std::swap(ctrl_, that.ctrl_); std::swap(slots_, that.slots_); std::swap(size_, that.size_); std::swap(capacity_, that.capacity_); std::swap(growth_left(), that.growth_left()); - std::swap(infoz_, that.infoz_); + std::swap(infoz(), that.infoz()); } else { reserve(that.size()); // Note: this will copy elements of dense_set and unordered_set instead of @@ -908,12 +1045,12 @@ class raw_hash_set { it.skip_empty_or_deleted(); return it; } - iterator end() { return {ctrl_ + capacity_}; } + iterator end() { return {}; } const_iterator begin() const { return const_cast(this)->begin(); } - const_iterator end() const { return const_cast(this)->end(); } + const_iterator end() const { return {}; } const_iterator cbegin() const { return begin(); } const_iterator cend() const { return end(); } @@ -932,6 +1069,8 @@ class raw_hash_set { // past that we simply deallocate the array. if (capacity_ > 127) { destroy_slots(); + + infoz().RecordClearedReservation(); } else if (capacity_) { for (size_t i = 0; i != capacity_; ++i) { if (IsFull(ctrl_[i])) { @@ -939,11 +1078,11 @@ class raw_hash_set { } } size_ = 0; - reset_ctrl(); + ResetCtrl(capacity_, ctrl_, slots_, sizeof(slot_type)); reset_growth_left(); } assert(empty()); - infoz_.RecordStorageChanged(0, capacity_); + infoz().RecordStorageChanged(0, capacity_); } // This overload kicks in when the argument is an rvalue of insertable and @@ -1016,7 +1155,7 @@ class raw_hash_set { template void insert(InputIt first, InputIt last) { - for (; first != last; ++first) insert(*first); + for (; first != last; ++first) emplace(*first); } template = 0, RequiresInsertable = 0> @@ -1043,7 +1182,9 @@ class raw_hash_set { } iterator insert(const_iterator, node_type&& node) { - return insert(std::move(node)).first; + auto res = insert(std::move(node)); + node = std::move(res.node); + return res.position; } // This overload kicks in if we can deduce the key from args. This enables us @@ -1172,7 +1313,7 @@ class raw_hash_set { // This overload is necessary because otherwise erase(const K&) would be // a better match if non-const iterator is passed as an argument. void erase(iterator it) { - it.assert_is_full(); + AssertIsFull(it.ctrl_); PolicyTraits::destroy(&alloc_ref(), it.slot_); erase_meta_only(it); } @@ -1206,7 +1347,7 @@ class raw_hash_set { } node_type extract(const_iterator position) { - position.inner_.assert_is_full(); + AssertIsFull(position.inner_.ctrl_); auto node = CommonAccess::Transfer(alloc_ref(), position.inner_.slot_); erase_meta_only(position); @@ -1223,8 +1364,8 @@ class raw_hash_set { void swap(raw_hash_set& that) noexcept( IsNoThrowSwappable() && IsNoThrowSwappable() && - (!AllocTraits::propagate_on_container_swap::value || - IsNoThrowSwappable())) { + IsNoThrowSwappable( + typename AllocTraits::propagate_on_container_swap{})) { using std::swap; swap(ctrl_, that.ctrl_); swap(slots_, that.slots_); @@ -1233,32 +1374,43 @@ class raw_hash_set { swap(growth_left(), that.growth_left()); swap(hash_ref(), that.hash_ref()); swap(eq_ref(), that.eq_ref()); - swap(infoz_, that.infoz_); - if (AllocTraits::propagate_on_container_swap::value) { - swap(alloc_ref(), that.alloc_ref()); - } else { - // If the allocators do not compare equal it is officially undefined - // behavior. We choose to do nothing. - } + swap(infoz(), that.infoz()); + SwapAlloc(alloc_ref(), that.alloc_ref(), + typename AllocTraits::propagate_on_container_swap{}); } void rehash(size_t n) { if (n == 0 && capacity_ == 0) return; if (n == 0 && size_ == 0) { destroy_slots(); - infoz_.RecordStorageChanged(0, 0); + infoz().RecordStorageChanged(0, 0); + infoz().RecordClearedReservation(); return; } + // bitor is a faster way of doing `max` here. We will round up to the next // power-of-2-minus-1, so bitor is good enough. auto m = NormalizeCapacity(n | GrowthToLowerboundCapacity(size())); // n == 0 unconditionally rehashes as per the standard. if (n == 0 || m > capacity_) { resize(m); + + // This is after resize, to ensure that we have completed the allocation + // and have potentially sampled the hashtable. + infoz().RecordReservation(n); } } - void reserve(size_t n) { rehash(GrowthToLowerboundCapacity(n)); } + void reserve(size_t n) { + if (n > size() + growth_left()) { + size_t m = GrowthToLowerboundCapacity(n); + resize(NormalizeCapacity(m)); + + // This is after resize, to ensure that we have completed the allocation + // and have potentially sampled the hashtable. + infoz().RecordReservation(n); + } + } // Extension API: support for heterogeneous keys. // @@ -1283,7 +1435,7 @@ class raw_hash_set { void prefetch(const key_arg& key) const { (void)key; #if defined(__GNUC__) - auto seq = probe(hash_ref()(key)); + auto seq = probe(ctrl_, hash_ref()(key), capacity_); __builtin_prefetch(static_cast(ctrl_ + seq.offset())); __builtin_prefetch(static_cast(slots_ + seq.offset())); #endif // __GNUC__ @@ -1298,7 +1450,7 @@ class raw_hash_set { // called heterogeneous key support. template iterator find(const key_arg& key, size_t hash) { - auto seq = probe(hash); + auto seq = probe(ctrl_, hash, capacity_); while (true) { Group g{ctrl_ + seq.offset()}; for (int i : g.Match(H2(hash))) { @@ -1309,6 +1461,7 @@ class raw_hash_set { } if (ABSL_PREDICT_TRUE(g.MatchEmpty())) return end(); seq.next(); + assert(seq.index() <= capacity_ && "full table!"); } } template @@ -1456,9 +1609,10 @@ class raw_hash_set { static_cast(empty_after.TrailingZeros() + empty_before.LeadingZeros()) < Group::kWidth; - set_ctrl(index, was_never_full ? kEmpty : kDeleted); + SetCtrl(index, was_never_full ? ctrl_t::kEmpty : ctrl_t::kDeleted, + capacity_, ctrl_, slots_, sizeof(slot_type)); growth_left() += was_never_full; - infoz_.RecordErase(); + infoz().RecordErase(); } void initialize_slots() { @@ -1475,17 +1629,18 @@ class raw_hash_set { // bound more carefully. if (std::is_same>::value && slots_ == nullptr) { - infoz_ = Sample(); + infoz() = Sample(); } - auto layout = MakeLayout(capacity_); - char* mem = static_cast( - Allocate(&alloc_ref(), layout.AllocSize())); - ctrl_ = reinterpret_cast(layout.template Pointer<0>(mem)); - slots_ = layout.template Pointer<1>(mem); - reset_ctrl(); + char* mem = static_cast(Allocate( + &alloc_ref(), + AllocSize(capacity_, sizeof(slot_type), alignof(slot_type)))); + ctrl_ = reinterpret_cast(mem); + slots_ = reinterpret_cast( + mem + SlotOffset(capacity_, alignof(slot_type))); + ResetCtrl(capacity_, ctrl_, slots_, sizeof(slot_type)); reset_growth_left(); - infoz_.RecordStorageChanged(size_, capacity_); + infoz().RecordStorageChanged(size_, capacity_); } void destroy_slots() { @@ -1495,10 +1650,12 @@ class raw_hash_set { PolicyTraits::destroy(&alloc_ref(), slots_ + i); } } - auto layout = MakeLayout(capacity_); + // Unpoison before returning the memory to the allocator. SanitizerUnpoisonMemoryRegion(slots_, sizeof(slot_type) * capacity_); - Deallocate(&alloc_ref(), ctrl_, layout.AllocSize()); + Deallocate( + &alloc_ref(), ctrl_, + AllocSize(capacity_, sizeof(slot_type), alignof(slot_type))); ctrl_ = EmptyGroup(); slots_ = nullptr; size_ = 0; @@ -1519,26 +1676,26 @@ class raw_hash_set { if (IsFull(old_ctrl[i])) { size_t hash = PolicyTraits::apply(HashElement{hash_ref()}, PolicyTraits::element(old_slots + i)); - auto target = find_first_non_full(hash); + auto target = find_first_non_full(ctrl_, hash, capacity_); size_t new_i = target.offset; total_probe_length += target.probe_length; - set_ctrl(new_i, H2(hash)); + SetCtrl(new_i, H2(hash), capacity_, ctrl_, slots_, sizeof(slot_type)); PolicyTraits::transfer(&alloc_ref(), slots_ + new_i, old_slots + i); } } if (old_capacity) { SanitizerUnpoisonMemoryRegion(old_slots, sizeof(slot_type) * old_capacity); - auto layout = MakeLayout(old_capacity); - Deallocate(&alloc_ref(), old_ctrl, - layout.AllocSize()); + Deallocate( + &alloc_ref(), old_ctrl, + AllocSize(old_capacity, sizeof(slot_type), alignof(slot_type))); } - infoz_.RecordRehash(total_probe_length); + infoz().RecordRehash(total_probe_length); } void drop_deletes_without_resize() ABSL_ATTRIBUTE_NOINLINE { assert(IsValidCapacity(capacity_)); - assert(!is_small()); + assert(!is_small(capacity_)); // Algorithm: // - mark all DELETED slots as EMPTY // - mark all FULL slots as DELETED @@ -1561,34 +1718,35 @@ class raw_hash_set { slot_type* slot = reinterpret_cast(&raw); for (size_t i = 0; i != capacity_; ++i) { if (!IsDeleted(ctrl_[i])) continue; - size_t hash = PolicyTraits::apply(HashElement{hash_ref()}, - PolicyTraits::element(slots_ + i)); - auto target = find_first_non_full(hash); - size_t new_i = target.offset; + const size_t hash = PolicyTraits::apply( + HashElement{hash_ref()}, PolicyTraits::element(slots_ + i)); + const FindInfo target = find_first_non_full(ctrl_, hash, capacity_); + const size_t new_i = target.offset; total_probe_length += target.probe_length; // Verify if the old and new i fall within the same group wrt the hash. // If they do, we don't need to move the object as it falls already in the // best probe we can. - const auto probe_index = [&](size_t pos) { - return ((pos - probe(hash).offset()) & capacity_) / Group::kWidth; + const size_t probe_offset = probe(ctrl_, hash, capacity_).offset(); + const auto probe_index = [probe_offset, this](size_t pos) { + return ((pos - probe_offset) & capacity_) / Group::kWidth; }; // Element doesn't move. if (ABSL_PREDICT_TRUE(probe_index(new_i) == probe_index(i))) { - set_ctrl(i, H2(hash)); + SetCtrl(i, H2(hash), capacity_, ctrl_, slots_, sizeof(slot_type)); continue; } if (IsEmpty(ctrl_[new_i])) { // Transfer element to the empty spot. - // set_ctrl poisons/unpoisons the slots so we have to call it at the + // SetCtrl poisons/unpoisons the slots so we have to call it at the // right time. - set_ctrl(new_i, H2(hash)); + SetCtrl(new_i, H2(hash), capacity_, ctrl_, slots_, sizeof(slot_type)); PolicyTraits::transfer(&alloc_ref(), slots_ + new_i, slots_ + i); - set_ctrl(i, kEmpty); + SetCtrl(i, ctrl_t::kEmpty, capacity_, ctrl_, slots_, sizeof(slot_type)); } else { assert(IsDeleted(ctrl_[new_i])); - set_ctrl(new_i, H2(hash)); + SetCtrl(new_i, H2(hash), capacity_, ctrl_, slots_, sizeof(slot_type)); // Until we are done rehashing, DELETED marks previously FULL slots. // Swap i and new_i elements. PolicyTraits::transfer(&alloc_ref(), slot, slots_ + i); @@ -1598,14 +1756,56 @@ class raw_hash_set { } } reset_growth_left(); - infoz_.RecordRehash(total_probe_length); + infoz().RecordRehash(total_probe_length); } void rehash_and_grow_if_necessary() { if (capacity_ == 0) { resize(1); - } else if (size() <= CapacityToGrowth(capacity()) / 2) { + } else if (capacity_ > Group::kWidth && + // Do these calcuations in 64-bit to avoid overflow. + size() * uint64_t{32} <= capacity_ * uint64_t{25}) { // Squash DELETED without growing if there is enough capacity. + // + // Rehash in place if the current size is <= 25/32 of capacity_. + // Rationale for such a high factor: 1) drop_deletes_without_resize() is + // faster than resize, and 2) it takes quite a bit of work to add + // tombstones. In the worst case, seems to take approximately 4 + // insert/erase pairs to create a single tombstone and so if we are + // rehashing because of tombstones, we can afford to rehash-in-place as + // long as we are reclaiming at least 1/8 the capacity without doing more + // than 2X the work. (Where "work" is defined to be size() for rehashing + // or rehashing in place, and 1 for an insert or erase.) But rehashing in + // place is faster per operation than inserting or even doubling the size + // of the table, so we actually afford to reclaim even less space from a + // resize-in-place. The decision is to rehash in place if we can reclaim + // at about 1/8th of the usable capacity (specifically 3/28 of the + // capacity) which means that the total cost of rehashing will be a small + // fraction of the total work. + // + // Here is output of an experiment using the BM_CacheInSteadyState + // benchmark running the old case (where we rehash-in-place only if we can + // reclaim at least 7/16*capacity_) vs. this code (which rehashes in place + // if we can recover 3/32*capacity_). + // + // Note that although in the worst-case number of rehashes jumped up from + // 15 to 190, but the number of operations per second is almost the same. + // + // Abridged output of running BM_CacheInSteadyState benchmark from + // raw_hash_set_benchmark. N is the number of insert/erase operations. + // + // | OLD (recover >= 7/16 | NEW (recover >= 3/32) + // size | N/s LoadFactor NRehashes | N/s LoadFactor NRehashes + // 448 | 145284 0.44 18 | 140118 0.44 19 + // 493 | 152546 0.24 11 | 151417 0.48 28 + // 538 | 151439 0.26 11 | 151152 0.53 38 + // 583 | 151765 0.28 11 | 150572 0.57 50 + // 628 | 150241 0.31 11 | 150853 0.61 66 + // 672 | 149602 0.33 12 | 150110 0.66 90 + // 717 | 149998 0.35 12 | 149531 0.70 129 + // 762 | 149836 0.37 13 | 148559 0.74 190 + // 807 | 149736 0.39 14 | 151107 0.39 14 + // 852 | 150204 0.42 15 | 151019 0.42 15 drop_deletes_without_resize(); } else { // Otherwise grow the container. @@ -1615,7 +1815,7 @@ class raw_hash_set { bool has_element(const value_type& elem) const { size_t hash = PolicyTraits::apply(HashElement{hash_ref()}, elem); - auto seq = probe(hash); + auto seq = probe(ctrl_, hash, capacity_); while (true) { Group g{ctrl_ + seq.offset()}; for (int i : g.Match(H2(hash))) { @@ -1625,46 +1825,11 @@ class raw_hash_set { } if (ABSL_PREDICT_TRUE(g.MatchEmpty())) return false; seq.next(); - assert(seq.index() < capacity_ && "full table!"); + assert(seq.index() <= capacity_ && "full table!"); } return false; } - // Probes the raw_hash_set with the probe sequence for hash and returns the - // pointer to the first empty or deleted slot. - // NOTE: this function must work with tables having both kEmpty and kDelete - // in one group. Such tables appears during drop_deletes_without_resize. - // - // This function is very useful when insertions happen and: - // - the input is already a set - // - there are enough slots - // - the element with the hash is not in the table - struct FindInfo { - size_t offset; - size_t probe_length; - }; - FindInfo find_first_non_full(size_t hash) { - auto seq = probe(hash); - while (true) { - Group g{ctrl_ + seq.offset()}; - auto mask = g.MatchEmptyOrDeleted(); - if (mask) { -#if !defined(NDEBUG) - // We want to add entropy even when ASLR is not enabled. - // In debug build we will randomly insert in either the front or back of - // the group. - // TODO(kfm,sbenza): revisit after we do unconditional mixing - if (!is_small() && ShouldInsertBackwards(hash, ctrl_)) { - return {seq.offset(mask.HighestBitSet()), seq.index()}; - } -#endif - return {seq.offset(mask.LowestBitSet()), seq.index()}; - } - assert(seq.index() < capacity_ && "full table!"); - seq.next(); - } - } - // TODO(alkis): Optimize this assuming *this and that don't overlap. raw_hash_set& move_assign(raw_hash_set&& that, std::true_type) { raw_hash_set tmp(std::move(that)); @@ -1681,7 +1846,7 @@ class raw_hash_set { template std::pair find_or_prepare_insert(const K& key) { auto hash = hash_ref()(key); - auto seq = probe(hash); + auto seq = probe(ctrl_, hash, capacity_); while (true) { Group g{ctrl_ + seq.offset()}; for (int i : g.Match(H2(hash))) { @@ -1692,21 +1857,23 @@ class raw_hash_set { } if (ABSL_PREDICT_TRUE(g.MatchEmpty())) break; seq.next(); + assert(seq.index() <= capacity_ && "full table!"); } return {prepare_insert(hash), true}; } size_t prepare_insert(size_t hash) ABSL_ATTRIBUTE_NOINLINE { - auto target = find_first_non_full(hash); + auto target = find_first_non_full(ctrl_, hash, capacity_); if (ABSL_PREDICT_FALSE(growth_left() == 0 && !IsDeleted(ctrl_[target.offset]))) { rehash_and_grow_if_necessary(); - target = find_first_non_full(hash); + target = find_first_non_full(ctrl_, hash, capacity_); } ++size_; growth_left() -= IsEmpty(ctrl_[target.offset]); - set_ctrl(target.offset, H2(hash)); - infoz_.RecordInsert(hash, target.probe_length); + SetCtrl(target.offset, H2(hash), capacity_, ctrl_, slots_, + sizeof(slot_type)); + infoz().RecordInsert(hash, target.probe_length); return target.offset; } @@ -1734,84 +1901,45 @@ class raw_hash_set { private: friend struct RawHashSetTestOnlyAccess; - probe_seq probe(size_t hash) const { - return probe_seq(H1(hash, ctrl_), capacity_); - } - - // Reset all ctrl bytes back to kEmpty, except the sentinel. - void reset_ctrl() { - std::memset(ctrl_, kEmpty, capacity_ + Group::kWidth); - ctrl_[capacity_] = kSentinel; - SanitizerPoisonMemoryRegion(slots_, sizeof(slot_type) * capacity_); - } - void reset_growth_left() { growth_left() = CapacityToGrowth(capacity()) - size_; } - // Sets the control byte, and if `i < Group::kWidth`, set the cloned byte at - // the end too. - void set_ctrl(size_t i, ctrl_t h) { - assert(i < capacity_); - - if (IsFull(h)) { - SanitizerUnpoisonObject(slots_ + i); - } else { - SanitizerPoisonObject(slots_ + i); - } - - ctrl_[i] = h; - ctrl_[((i - Group::kWidth) & capacity_) + 1 + - ((Group::kWidth - 1) & capacity_)] = h; - } - size_t& growth_left() { return settings_.template get<0>(); } - // The representation of the object has two modes: - // - small: For capacities < kWidth-1 - // - large: For the rest. - // - // Differences: - // - In small mode we are able to use the whole capacity. The extra control - // bytes give us at least one "empty" control byte to stop the iteration. - // This is important to make 1 a valid capacity. - // - // - In small mode only the first `capacity()` control bytes after the - // sentinel are valid. The rest contain dummy kEmpty values that do not - // represent a real slot. This is important to take into account on - // find_first_non_full(), where we never try ShouldInsertBackwards() for - // small tables. - bool is_small() const { return capacity_ < Group::kWidth - 1; } + HashtablezInfoHandle& infoz() { return settings_.template get<1>(); } - hasher& hash_ref() { return settings_.template get<1>(); } - const hasher& hash_ref() const { return settings_.template get<1>(); } - key_equal& eq_ref() { return settings_.template get<2>(); } - const key_equal& eq_ref() const { return settings_.template get<2>(); } - allocator_type& alloc_ref() { return settings_.template get<3>(); } + hasher& hash_ref() { return settings_.template get<2>(); } + const hasher& hash_ref() const { return settings_.template get<2>(); } + key_equal& eq_ref() { return settings_.template get<3>(); } + const key_equal& eq_ref() const { return settings_.template get<3>(); } + allocator_type& alloc_ref() { return settings_.template get<4>(); } const allocator_type& alloc_ref() const { - return settings_.template get<3>(); + return settings_.template get<4>(); } // TODO(alkis): Investigate removing some of these fields: // - ctrl/slots can be derived from each other // - size can be moved into the slot array - ctrl_t* ctrl_ = EmptyGroup(); // [(capacity + 1) * ctrl_t] - slot_type* slots_ = nullptr; // [capacity * slot_type] - size_t size_ = 0; // number of full slots - size_t capacity_ = 0; // total number of slots - HashtablezInfoHandle infoz_; - absl::container_internal::CompressedTuple - settings_{0, hasher{}, key_equal{}, allocator_type{}}; + settings_{0, HashtablezInfoHandle{}, hasher{}, key_equal{}, + allocator_type{}}; }; // Erases all elements that satisfy the predicate `pred` from the container `c`. template -void EraseIf(Predicate pred, raw_hash_set* c) { +void EraseIf(Predicate& pred, raw_hash_set* c) { for (auto it = c->begin(), last = c->end(); it != last;) { - auto copy_it = it++; - if (pred(*copy_it)) { - c->erase(copy_it); + if (pred(*it)) { + c->erase(it++); + } else { + ++it; } } } @@ -1826,7 +1954,7 @@ struct HashtableDebugAccess> { const typename Set::key_type& key) { size_t num_probes = 0; size_t hash = set.hash_ref()(key); - auto seq = set.probe(hash); + auto seq = probe(set.ctrl_, hash, set.capacity_); while (true) { container_internal::Group g{set.ctrl_ + seq.offset()}; for (int i : g.Match(container_internal::H2(hash))) { @@ -1846,8 +1974,7 @@ struct HashtableDebugAccess> { static size_t AllocatedByteSize(const Set& c) { size_t capacity = c.capacity_; if (capacity == 0) return 0; - auto layout = Set::MakeLayout(capacity); - size_t m = layout.AllocSize(); + size_t m = AllocSize(capacity, sizeof(Slot), alignof(Slot)); size_t per_slot = Traits::space_used(static_cast(nullptr)); if (per_slot != ~size_t{}) { @@ -1865,8 +1992,8 @@ struct HashtableDebugAccess> { static size_t LowerBoundAllocatedByteSize(size_t size) { size_t capacity = GrowthToLowerboundCapacity(size); if (capacity == 0) return 0; - auto layout = Set::MakeLayout(NormalizeCapacity(capacity)); - size_t m = layout.AllocSize(); + size_t m = + AllocSize(NormalizeCapacity(capacity), sizeof(Slot), alignof(Slot)); size_t per_slot = Traits::space_used(static_cast(nullptr)); if (per_slot != ~size_t{}) { m += per_slot * size; diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/raw_hash_set_allocator_test.cc b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/raw_hash_set_allocator_test.cc index 7ac4b9f7df..e73f53fd63 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/raw_hash_set_allocator_test.cc +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/raw_hash_set_allocator_test.cc @@ -424,6 +424,81 @@ TEST_F(PropagateOnAll, Swap) { EXPECT_EQ(0, it->num_copies()); } +// This allocator is similar to std::pmr::polymorphic_allocator. +// Note the disabled assignment. +template +class PAlloc { + template + friend class PAlloc; + + public: + // types + using value_type = T; + + // traits + using propagate_on_container_swap = std::false_type; + + PAlloc() noexcept = default; + explicit PAlloc(size_t id) noexcept : id_(id) {} + PAlloc(const PAlloc&) noexcept = default; + PAlloc& operator=(const PAlloc&) noexcept = delete; + + template + PAlloc(const PAlloc& that) noexcept : id_(that.id_) {} // NOLINT + + template + struct rebind { + using other = PAlloc; + }; + + constexpr PAlloc select_on_container_copy_construction() const { return {}; } + + // public member functions + T* allocate(size_t) { return new T; } + void deallocate(T* p, size_t) { delete p; } + + friend bool operator==(const PAlloc& a, const PAlloc& b) { + return a.id_ == b.id_; + } + friend bool operator!=(const PAlloc& a, const PAlloc& b) { return !(a == b); } + + private: + size_t id_ = std::numeric_limits::max(); +}; + +// This doesn't compile with GCC 5.4 and 5.5 due to a bug in noexcept handing. +#if !defined(__GNUC__) || __GNUC__ != 5 || (__GNUC_MINOR__ != 4 && \ + __GNUC_MINOR__ != 5) +TEST(NoPropagateOn, Swap) { + using PA = PAlloc; + using Table = raw_hash_set, PA>; + + Table t1(PA{1}), t2(PA{2}); + swap(t1, t2); + EXPECT_EQ(t1.get_allocator(), PA(1)); + EXPECT_EQ(t2.get_allocator(), PA(2)); +} +#endif + +TEST(NoPropagateOn, CopyConstruct) { + using PA = PAlloc; + using Table = raw_hash_set, PA>; + + Table t1(PA{1}), t2(t1); + EXPECT_EQ(t1.get_allocator(), PA(1)); + EXPECT_EQ(t2.get_allocator(), PA()); +} + +TEST(NoPropagateOn, Assignment) { + using PA = PAlloc; + using Table = raw_hash_set, PA>; + + Table t1(PA{1}), t2(PA{2}); + t1 = t2; + EXPECT_EQ(t1.get_allocator(), PA(1)); + EXPECT_EQ(t2.get_allocator(), PA(2)); +} + } // namespace } // namespace container_internal ABSL_NAMESPACE_END diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/raw_hash_set_benchmark.cc b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/raw_hash_set_benchmark.cc new file mode 100644 index 0000000000..c886d3ad43 --- /dev/null +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/raw_hash_set_benchmark.cc @@ -0,0 +1,431 @@ +// Copyright 2018 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "absl/container/internal/raw_hash_set.h" + +#include +#include + +#include "absl/base/internal/raw_logging.h" +#include "absl/container/internal/hash_function_defaults.h" +#include "absl/strings/str_format.h" +#include "benchmark/benchmark.h" + +namespace absl { +ABSL_NAMESPACE_BEGIN +namespace container_internal { + +struct RawHashSetTestOnlyAccess { + template + static auto GetSlots(const C& c) -> decltype(c.slots_) { + return c.slots_; + } +}; + +namespace { + +struct IntPolicy { + using slot_type = int64_t; + using key_type = int64_t; + using init_type = int64_t; + + static void construct(void*, int64_t* slot, int64_t v) { *slot = v; } + static void destroy(void*, int64_t*) {} + static void transfer(void*, int64_t* new_slot, int64_t* old_slot) { + *new_slot = *old_slot; + } + + static int64_t& element(slot_type* slot) { return *slot; } + + template + static auto apply(F&& f, int64_t x) -> decltype(std::forward(f)(x, x)) { + return std::forward(f)(x, x); + } +}; + +class StringPolicy { + template ::value>::type> + decltype(std::declval()( + std::declval(), std::piecewise_construct, + std::declval>(), + std::declval())) static apply_impl(F&& f, + std::pair, V> p) { + const absl::string_view& key = std::get<0>(p.first); + return std::forward(f)(key, std::piecewise_construct, std::move(p.first), + std::move(p.second)); + } + + public: + struct slot_type { + struct ctor {}; + + template + slot_type(ctor, Ts&&... ts) : pair(std::forward(ts)...) {} + + std::pair pair; + }; + + using key_type = std::string; + using init_type = std::pair; + + template + static void construct(allocator_type* alloc, slot_type* slot, Args... args) { + std::allocator_traits::construct( + *alloc, slot, typename slot_type::ctor(), std::forward(args)...); + } + + template + static void destroy(allocator_type* alloc, slot_type* slot) { + std::allocator_traits::destroy(*alloc, slot); + } + + template + static void transfer(allocator_type* alloc, slot_type* new_slot, + slot_type* old_slot) { + construct(alloc, new_slot, std::move(old_slot->pair)); + destroy(alloc, old_slot); + } + + static std::pair& element(slot_type* slot) { + return slot->pair; + } + + template + static auto apply(F&& f, Args&&... args) + -> decltype(apply_impl(std::forward(f), + PairArgs(std::forward(args)...))) { + return apply_impl(std::forward(f), + PairArgs(std::forward(args)...)); + } +}; + +struct StringHash : container_internal::hash_default_hash { + using is_transparent = void; +}; +struct StringEq : std::equal_to { + using is_transparent = void; +}; + +struct StringTable + : raw_hash_set> { + using Base = typename StringTable::raw_hash_set; + StringTable() {} + using Base::Base; +}; + +struct IntTable + : raw_hash_set, + std::equal_to, std::allocator> { + using Base = typename IntTable::raw_hash_set; + IntTable() {} + using Base::Base; +}; + +struct string_generator { + template + std::string operator()(RNG& rng) const { + std::string res; + res.resize(12); + std::uniform_int_distribution printable_ascii(0x20, 0x7E); + std::generate(res.begin(), res.end(), [&] { return printable_ascii(rng); }); + return res; + } + + size_t size; +}; + +// Model a cache in steady state. +// +// On a table of size N, keep deleting the LRU entry and add a random one. +void BM_CacheInSteadyState(benchmark::State& state) { + std::random_device rd; + std::mt19937 rng(rd()); + string_generator gen{12}; + StringTable t; + std::deque keys; + while (t.size() < state.range(0)) { + auto x = t.emplace(gen(rng), gen(rng)); + if (x.second) keys.push_back(x.first->first); + } + ABSL_RAW_CHECK(state.range(0) >= 10, ""); + while (state.KeepRunning()) { + // Some cache hits. + std::deque::const_iterator it; + for (int i = 0; i != 90; ++i) { + if (i % 10 == 0) it = keys.end(); + ::benchmark::DoNotOptimize(t.find(*--it)); + } + // Some cache misses. + for (int i = 0; i != 10; ++i) ::benchmark::DoNotOptimize(t.find(gen(rng))); + ABSL_RAW_CHECK(t.erase(keys.front()), keys.front().c_str()); + keys.pop_front(); + while (true) { + auto x = t.emplace(gen(rng), gen(rng)); + if (x.second) { + keys.push_back(x.first->first); + break; + } + } + } + state.SetItemsProcessed(state.iterations()); + state.SetLabel(absl::StrFormat("load_factor=%.2f", t.load_factor())); +} + +template +void CacheInSteadyStateArgs(Benchmark* bm) { + // The default. + const float max_load_factor = 0.875; + // When the cache is at the steady state, the probe sequence will equal + // capacity if there is no reclamation of deleted slots. Pick a number large + // enough to make the benchmark slow for that case. + const size_t capacity = 1 << 10; + + // Check N data points to cover load factors in [0.4, 0.8). + const size_t kNumPoints = 10; + for (size_t i = 0; i != kNumPoints; ++i) + bm->Arg(std::ceil( + capacity * (max_load_factor + i * max_load_factor / kNumPoints) / 2)); +} +BENCHMARK(BM_CacheInSteadyState)->Apply(CacheInSteadyStateArgs); + +void BM_EndComparison(benchmark::State& state) { + std::random_device rd; + std::mt19937 rng(rd()); + string_generator gen{12}; + StringTable t; + while (t.size() < state.range(0)) { + t.emplace(gen(rng), gen(rng)); + } + + for (auto _ : state) { + for (auto it = t.begin(); it != t.end(); ++it) { + benchmark::DoNotOptimize(it); + benchmark::DoNotOptimize(t); + benchmark::DoNotOptimize(it != t.end()); + } + } +} +BENCHMARK(BM_EndComparison)->Arg(400); + +void BM_CopyCtor(benchmark::State& state) { + std::random_device rd; + std::mt19937 rng(rd()); + IntTable t; + std::uniform_int_distribution dist(0, ~uint64_t{}); + + while (t.size() < state.range(0)) { + t.emplace(dist(rng)); + } + + for (auto _ : state) { + IntTable t2 = t; + benchmark::DoNotOptimize(t2); + } +} +BENCHMARK(BM_CopyCtor)->Range(128, 4096); + +void BM_CopyAssign(benchmark::State& state) { + std::random_device rd; + std::mt19937 rng(rd()); + IntTable t; + std::uniform_int_distribution dist(0, ~uint64_t{}); + while (t.size() < state.range(0)) { + t.emplace(dist(rng)); + } + + IntTable t2; + for (auto _ : state) { + t2 = t; + benchmark::DoNotOptimize(t2); + } +} +BENCHMARK(BM_CopyAssign)->Range(128, 4096); + +void BM_RangeCtor(benchmark::State& state) { + std::random_device rd; + std::mt19937 rng(rd()); + std::uniform_int_distribution dist(0, ~uint64_t{}); + std::vector values; + const size_t desired_size = state.range(0); + while (values.size() < desired_size) { + values.emplace_back(dist(rng)); + } + + for (auto unused : state) { + IntTable t{values.begin(), values.end()}; + benchmark::DoNotOptimize(t); + } +} +BENCHMARK(BM_RangeCtor)->Range(128, 65536); + +void BM_NoOpReserveIntTable(benchmark::State& state) { + IntTable t; + t.reserve(100000); + for (auto _ : state) { + benchmark::DoNotOptimize(t); + t.reserve(100000); + } +} +BENCHMARK(BM_NoOpReserveIntTable); + +void BM_NoOpReserveStringTable(benchmark::State& state) { + StringTable t; + t.reserve(100000); + for (auto _ : state) { + benchmark::DoNotOptimize(t); + t.reserve(100000); + } +} +BENCHMARK(BM_NoOpReserveStringTable); + +void BM_ReserveIntTable(benchmark::State& state) { + int reserve_size = state.range(0); + for (auto _ : state) { + state.PauseTiming(); + IntTable t; + state.ResumeTiming(); + benchmark::DoNotOptimize(t); + t.reserve(reserve_size); + } +} +BENCHMARK(BM_ReserveIntTable)->Range(128, 4096); + +void BM_ReserveStringTable(benchmark::State& state) { + int reserve_size = state.range(0); + for (auto _ : state) { + state.PauseTiming(); + StringTable t; + state.ResumeTiming(); + benchmark::DoNotOptimize(t); + t.reserve(reserve_size); + } +} +BENCHMARK(BM_ReserveStringTable)->Range(128, 4096); + +// Like std::iota, except that ctrl_t doesn't support operator++. +template +void Iota(CtrlIter begin, CtrlIter end, int value) { + for (; begin != end; ++begin, ++value) { + *begin = static_cast(value); + } +} + +void BM_Group_Match(benchmark::State& state) { + std::array group; + Iota(group.begin(), group.end(), -4); + Group g{group.data()}; + h2_t h = 1; + for (auto _ : state) { + ::benchmark::DoNotOptimize(h); + ::benchmark::DoNotOptimize(g.Match(h)); + } +} +BENCHMARK(BM_Group_Match); + +void BM_Group_MatchEmpty(benchmark::State& state) { + std::array group; + Iota(group.begin(), group.end(), -4); + Group g{group.data()}; + for (auto _ : state) ::benchmark::DoNotOptimize(g.MatchEmpty()); +} +BENCHMARK(BM_Group_MatchEmpty); + +void BM_Group_MatchEmptyOrDeleted(benchmark::State& state) { + std::array group; + Iota(group.begin(), group.end(), -4); + Group g{group.data()}; + for (auto _ : state) ::benchmark::DoNotOptimize(g.MatchEmptyOrDeleted()); +} +BENCHMARK(BM_Group_MatchEmptyOrDeleted); + +void BM_Group_CountLeadingEmptyOrDeleted(benchmark::State& state) { + std::array group; + Iota(group.begin(), group.end(), -2); + Group g{group.data()}; + for (auto _ : state) + ::benchmark::DoNotOptimize(g.CountLeadingEmptyOrDeleted()); +} +BENCHMARK(BM_Group_CountLeadingEmptyOrDeleted); + +void BM_Group_MatchFirstEmptyOrDeleted(benchmark::State& state) { + std::array group; + Iota(group.begin(), group.end(), -2); + Group g{group.data()}; + for (auto _ : state) ::benchmark::DoNotOptimize(*g.MatchEmptyOrDeleted()); +} +BENCHMARK(BM_Group_MatchFirstEmptyOrDeleted); + +void BM_DropDeletes(benchmark::State& state) { + constexpr size_t capacity = (1 << 20) - 1; + std::vector ctrl(capacity + 1 + Group::kWidth); + ctrl[capacity] = ctrl_t::kSentinel; + std::vector pattern = {ctrl_t::kEmpty, static_cast(2), + ctrl_t::kDeleted, static_cast(2), + ctrl_t::kEmpty, static_cast(1), + ctrl_t::kDeleted}; + for (size_t i = 0; i != capacity; ++i) { + ctrl[i] = pattern[i % pattern.size()]; + } + while (state.KeepRunning()) { + state.PauseTiming(); + std::vector ctrl_copy = ctrl; + state.ResumeTiming(); + ConvertDeletedToEmptyAndFullToDeleted(ctrl_copy.data(), capacity); + ::benchmark::DoNotOptimize(ctrl_copy[capacity]); + } +} +BENCHMARK(BM_DropDeletes); + +} // namespace +} // namespace container_internal +ABSL_NAMESPACE_END +} // namespace absl + +// These methods are here to make it easy to examine the assembly for targeted +// parts of the API. +auto CodegenAbslRawHashSetInt64Find(absl::container_internal::IntTable* table, + int64_t key) -> decltype(table->find(key)) { + return table->find(key); +} + +bool CodegenAbslRawHashSetInt64FindNeEnd( + absl::container_internal::IntTable* table, int64_t key) { + return table->find(key) != table->end(); +} + +auto CodegenAbslRawHashSetInt64Insert(absl::container_internal::IntTable* table, + int64_t key) + -> decltype(table->insert(key)) { + return table->insert(key); +} + +bool CodegenAbslRawHashSetInt64Contains( + absl::container_internal::IntTable* table, int64_t key) { + return table->contains(key); +} + +void CodegenAbslRawHashSetInt64Iterate( + absl::container_internal::IntTable* table) { + for (auto x : *table) benchmark::DoNotOptimize(x); +} + +int odr = + (::benchmark::DoNotOptimize(std::make_tuple( + &CodegenAbslRawHashSetInt64Find, &CodegenAbslRawHashSetInt64FindNeEnd, + &CodegenAbslRawHashSetInt64Insert, + &CodegenAbslRawHashSetInt64Contains, + &CodegenAbslRawHashSetInt64Iterate)), + 1); diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/raw_hash_set_probe_benchmark.cc b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/raw_hash_set_probe_benchmark.cc new file mode 100644 index 0000000000..7169a2e206 --- /dev/null +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/raw_hash_set_probe_benchmark.cc @@ -0,0 +1,590 @@ +// Copyright 2018 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Generates probe length statistics for many combinations of key types and key +// distributions, all using the default hash function for swisstable. + +#include +#include // NOLINT +#include + +#include "absl/container/flat_hash_map.h" +#include "absl/container/internal/hash_function_defaults.h" +#include "absl/container/internal/hashtable_debug.h" +#include "absl/container/internal/raw_hash_set.h" +#include "absl/random/distributions.h" +#include "absl/random/random.h" +#include "absl/strings/str_cat.h" +#include "absl/strings/str_format.h" +#include "absl/strings/string_view.h" +#include "absl/strings/strip.h" + +namespace { + +enum class OutputStyle { kRegular, kBenchmark }; + +// The --benchmark command line flag. +// This is populated from main(). +// When run in "benchmark" mode, we have different output. This allows +// A/B comparisons with tools like `benchy`. +absl::string_view benchmarks; + +OutputStyle output() { + return !benchmarks.empty() ? OutputStyle::kBenchmark : OutputStyle::kRegular; +} + +template +struct Policy { + using slot_type = T; + using key_type = T; + using init_type = T; + + template + static void construct(allocator_type* alloc, slot_type* slot, + const Arg& arg) { + std::allocator_traits::construct(*alloc, slot, arg); + } + + template + static void destroy(allocator_type* alloc, slot_type* slot) { + std::allocator_traits::destroy(*alloc, slot); + } + + static slot_type& element(slot_type* slot) { return *slot; } + + template + static auto apply(F&& f, const slot_type& arg) + -> decltype(std::forward(f)(arg, arg)) { + return std::forward(f)(arg, arg); + } +}; + +absl::BitGen& GlobalBitGen() { + static auto* value = new absl::BitGen; + return *value; +} + +// Keeps a pool of allocations and randomly gives one out. +// This introduces more randomization to the addresses given to swisstable and +// should help smooth out this factor from probe length calculation. +template +class RandomizedAllocator { + public: + using value_type = T; + + RandomizedAllocator() = default; + template + RandomizedAllocator(RandomizedAllocator) {} // NOLINT + + static T* allocate(size_t n) { + auto& pointers = GetPointers(n); + // Fill the pool + while (pointers.size() < kRandomPool) { + pointers.push_back(std::allocator{}.allocate(n)); + } + + // Choose a random one. + size_t i = absl::Uniform(GlobalBitGen(), 0, pointers.size()); + T* result = pointers[i]; + pointers[i] = pointers.back(); + pointers.pop_back(); + return result; + } + + static void deallocate(T* p, size_t n) { + // Just put it back on the pool. No need to release the memory. + GetPointers(n).push_back(p); + } + + private: + // We keep at least kRandomPool allocations for each size. + static constexpr size_t kRandomPool = 20; + + static std::vector& GetPointers(size_t n) { + static auto* m = new absl::flat_hash_map>(); + return (*m)[n]; + } +}; + +template +struct DefaultHash { + using type = absl::container_internal::hash_default_hash; +}; + +template +using DefaultHashT = typename DefaultHash::type; + +template +struct Table : absl::container_internal::raw_hash_set< + Policy, DefaultHashT, + absl::container_internal::hash_default_eq, + RandomizedAllocator> {}; + +struct LoadSizes { + size_t min_load; + size_t max_load; +}; + +LoadSizes GetMinMaxLoadSizes() { + static const auto sizes = [] { + Table t; + + // First, fill enough to have a good distribution. + constexpr size_t kMinSize = 10000; + while (t.size() < kMinSize) t.insert(t.size()); + + const auto reach_min_load_factor = [&] { + const double lf = t.load_factor(); + while (lf <= t.load_factor()) t.insert(t.size()); + }; + + // Then, insert until we reach min load factor. + reach_min_load_factor(); + const size_t min_load_size = t.size(); + + // Keep going until we hit min load factor again, then go back one. + t.insert(t.size()); + reach_min_load_factor(); + + return LoadSizes{min_load_size, t.size() - 1}; + }(); + return sizes; +} + +struct Ratios { + double min_load; + double avg_load; + double max_load; +}; + +// See absl/container/internal/hashtable_debug.h for details on +// probe length calculation. +template +Ratios CollectMeanProbeLengths() { + const auto min_max_sizes = GetMinMaxLoadSizes(); + + ElemFn elem; + using Key = decltype(elem()); + Table t; + + Ratios result; + while (t.size() < min_max_sizes.min_load) t.insert(elem()); + result.min_load = + absl::container_internal::GetHashtableDebugProbeSummary(t).mean; + + while (t.size() < (min_max_sizes.min_load + min_max_sizes.max_load) / 2) + t.insert(elem()); + result.avg_load = + absl::container_internal::GetHashtableDebugProbeSummary(t).mean; + + while (t.size() < min_max_sizes.max_load) t.insert(elem()); + result.max_load = + absl::container_internal::GetHashtableDebugProbeSummary(t).mean; + + return result; +} + +template +uintptr_t PointerForAlignment() { + alignas(Align) static constexpr uintptr_t kInitPointer = 0; + return reinterpret_cast(&kInitPointer); +} + +// This incomplete type is used for testing hash of pointers of different +// alignments. +// NOTE: We are generating invalid pointer values on the fly with +// reinterpret_cast. There are not "safely derived" pointers so using them is +// technically UB. It is unlikely to be a problem, though. +template +struct Ptr; + +template +Ptr* MakePtr(uintptr_t v) { + if (sizeof(v) == 8) { + constexpr int kCopyBits = 16; + // Ensure high bits are all the same. + v = static_cast(static_cast(v << kCopyBits) >> + kCopyBits); + } + return reinterpret_cast*>(v); +} + +struct IntIdentity { + uint64_t i; + friend bool operator==(IntIdentity a, IntIdentity b) { return a.i == b.i; } + IntIdentity operator++(int) { return IntIdentity{i++}; } +}; + +template +struct PtrIdentity { + explicit PtrIdentity(uintptr_t val = PointerForAlignment()) : i(val) {} + uintptr_t i; + friend bool operator==(PtrIdentity a, PtrIdentity b) { return a.i == b.i; } + PtrIdentity operator++(int) { + PtrIdentity p(i); + i += Align; + return p; + } +}; + +constexpr char kStringFormat[] = "/path/to/file/name-%07d-of-9999999.txt"; + +template +struct String { + std::string value; + static std::string Make(uint32_t v) { + return {small ? absl::StrCat(v) : absl::StrFormat(kStringFormat, v)}; + } +}; + +template <> +struct DefaultHash { + struct type { + size_t operator()(IntIdentity t) const { return t.i; } + }; +}; + +template +struct DefaultHash> { + struct type { + size_t operator()(PtrIdentity t) const { return t.i; } + }; +}; + +template +struct Sequential { + T operator()() const { return current++; } + mutable T current{}; +}; + +template +struct Sequential*> { + Ptr* operator()() const { + auto* result = MakePtr(current); + current += Align; + return result; + } + mutable uintptr_t current = PointerForAlignment(); +}; + + +template +struct Sequential> { + std::string operator()() const { return String::Make(current++); } + mutable uint32_t current = 0; +}; + +template +struct Sequential> { + mutable Sequential tseq; + mutable Sequential useq; + + using RealT = decltype(tseq()); + using RealU = decltype(useq()); + + mutable std::vector ts; + mutable std::vector us; + mutable size_t ti = 0, ui = 0; + + std::pair operator()() const { + std::pair value{get_t(), get_u()}; + if (ti == 0) { + ti = ui + 1; + ui = 0; + } else { + --ti; + ++ui; + } + return value; + } + + RealT get_t() const { + while (ti >= ts.size()) ts.push_back(tseq()); + return ts[ti]; + } + + RealU get_u() const { + while (ui >= us.size()) us.push_back(useq()); + return us[ui]; + } +}; + +template +struct AlmostSequential { + mutable Sequential current; + + auto operator()() const -> decltype(current()) { + while (absl::Uniform(GlobalBitGen(), 0.0, 1.0) <= percent_skip / 100.) + current(); + return current(); + } +}; + +struct Uniform { + template + T operator()(T) const { + return absl::Uniform(absl::IntervalClosed, GlobalBitGen(), T{0}, ~T{0}); + } +}; + +struct Gaussian { + template + T operator()(T) const { + double d; + do { + d = absl::Gaussian(GlobalBitGen(), 1e6, 1e4); + } while (d <= 0 || d > std::numeric_limits::max() / 2); + return static_cast(d); + } +}; + +struct Zipf { + template + T operator()(T) const { + return absl::Zipf(GlobalBitGen(), std::numeric_limits::max(), 1.6); + } +}; + +template +struct Random { + T operator()() const { return Dist{}(T{}); } +}; + +template +struct Random*, Dist> { + Ptr* operator()() const { + return MakePtr(Random{}() * Align); + } +}; + +template +struct Random { + IntIdentity operator()() const { + return IntIdentity{Random{}()}; + } +}; + +template +struct Random, Dist> { + PtrIdentity operator()() const { + return PtrIdentity{Random{}() * Align}; + } +}; + +template +struct Random, Dist> { + std::string operator()() const { + return String::Make(Random{}()); + } +}; + +template +struct Random, Dist> { + auto operator()() const + -> decltype(std::make_pair(Random{}(), Random{}())) { + return std::make_pair(Random{}(), Random{}()); + } +}; + +template +std::string Name(); + +std::string Name(uint32_t*) { return "u32"; } +std::string Name(uint64_t*) { return "u64"; } +std::string Name(IntIdentity*) { return "IntIdentity"; } + +template +std::string Name(Ptr**) { + return absl::StrCat("Ptr", Align); +} + +template +std::string Name(PtrIdentity*) { + return absl::StrCat("PtrIdentity", Align); +} + +template +std::string Name(String*) { + return small ? "StrS" : "StrL"; +} + +template +std::string Name(std::pair*) { + if (output() == OutputStyle::kBenchmark) + return absl::StrCat("P_", Name(), "_", Name()); + return absl::StrCat("P<", Name(), ",", Name(), ">"); +} + +template +std::string Name(Sequential*) { + return "Sequential"; +} + +template +std::string Name(AlmostSequential*) { + return absl::StrCat("AlmostSeq_", P); +} + +template +std::string Name(Random*) { + return "UnifRand"; +} + +template +std::string Name(Random*) { + return "GausRand"; +} + +template +std::string Name(Random*) { + return "ZipfRand"; +} + +template +std::string Name() { + return Name(static_cast(nullptr)); +} + +constexpr int kNameWidth = 15; +constexpr int kDistWidth = 16; + +bool CanRunBenchmark(absl::string_view name) { + static std::regex* const filter = []() -> std::regex* { + return benchmarks.empty() || benchmarks == "all" + ? nullptr + : new std::regex(std::string(benchmarks)); + }(); + return filter == nullptr || std::regex_search(std::string(name), *filter); +} + +struct Result { + std::string name; + std::string dist_name; + Ratios ratios; +}; + +template +void RunForTypeAndDistribution(std::vector& results) { + std::string name = absl::StrCat(Name(), "/", Name()); + // We have to check against all three names (min/avg/max) before we run it. + // If any of them is enabled, we run it. + if (!CanRunBenchmark(absl::StrCat(name, "/min")) && + !CanRunBenchmark(absl::StrCat(name, "/avg")) && + !CanRunBenchmark(absl::StrCat(name, "/max"))) { + return; + } + results.push_back({Name(), Name(), CollectMeanProbeLengths()}); +} + +template +void RunForType(std::vector& results) { + RunForTypeAndDistribution>(results); + RunForTypeAndDistribution>(results); + RunForTypeAndDistribution>(results); + RunForTypeAndDistribution>(results); +#ifdef NDEBUG + // Disable these in non-opt mode because they take too long. + RunForTypeAndDistribution>(results); + RunForTypeAndDistribution>(results); +#endif // NDEBUG +} + +} // namespace + +int main(int argc, char** argv) { + // Parse the benchmark flags. Ignore all of them except the regex pattern. + for (int i = 1; i < argc; ++i) { + absl::string_view arg = argv[i]; + const auto next = [&] { return argv[std::min(i + 1, argc - 1)]; }; + + if (absl::ConsumePrefix(&arg, "--benchmark_filter")) { + if (arg == "") { + // --benchmark_filter X + benchmarks = next(); + } else if (absl::ConsumePrefix(&arg, "=")) { + // --benchmark_filter=X + benchmarks = arg; + } + } + + // Any --benchmark flag turns on the mode. + if (absl::ConsumePrefix(&arg, "--benchmark")) { + if (benchmarks.empty()) benchmarks="all"; + } + } + + std::vector results; + RunForType(results); + RunForType(results); + RunForType*>(results); + RunForType*>(results); + RunForType*>(results); + RunForType*>(results); + RunForType>(results); + RunForType>(results); + RunForType>(results); + RunForType>(results); + RunForType>(results); + RunForType>(results); + RunForType>(results); + RunForType>>(results); + RunForType, uint64_t>>(results); + RunForType>>(results); + RunForType, uint64_t>>(results); + + switch (output()) { + case OutputStyle::kRegular: + absl::PrintF("%-*s%-*s Min Avg Max\n%s\n", kNameWidth, + "Type", kDistWidth, "Distribution", + std::string(kNameWidth + kDistWidth + 10 * 3, '-')); + for (const auto& result : results) { + absl::PrintF("%-*s%-*s %8.4f %8.4f %8.4f\n", kNameWidth, result.name, + kDistWidth, result.dist_name, result.ratios.min_load, + result.ratios.avg_load, result.ratios.max_load); + } + break; + case OutputStyle::kBenchmark: { + absl::PrintF("{\n"); + absl::PrintF(" \"benchmarks\": [\n"); + absl::string_view comma; + for (const auto& result : results) { + auto print = [&](absl::string_view stat, double Ratios::*val) { + std::string name = + absl::StrCat(result.name, "/", result.dist_name, "/", stat); + // Check the regex again. We might had have enabled only one of the + // stats for the benchmark. + if (!CanRunBenchmark(name)) return; + absl::PrintF(" %s{\n", comma); + absl::PrintF(" \"cpu_time\": %f,\n", 1e9 * result.ratios.*val); + absl::PrintF(" \"real_time\": %f,\n", 1e9 * result.ratios.*val); + absl::PrintF(" \"iterations\": 1,\n"); + absl::PrintF(" \"name\": \"%s\",\n", name); + absl::PrintF(" \"time_unit\": \"ns\"\n"); + absl::PrintF(" }\n"); + comma = ","; + }; + print("min", &Ratios::min_load); + print("avg", &Ratios::avg_load); + print("max", &Ratios::max_load); + } + absl::PrintF(" ],\n"); + absl::PrintF(" \"context\": {\n"); + absl::PrintF(" }\n"); + absl::PrintF("}\n"); + break; + } + } + + return 0; +} diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/raw_hash_set_test.cc b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/raw_hash_set_test.cc index 2fc85591ca..b46c492030 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/raw_hash_set_test.cc +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/raw_hash_set_test.cc @@ -14,6 +14,7 @@ #include "absl/container/internal/raw_hash_set.h" +#include #include #include #include @@ -22,10 +23,13 @@ #include #include #include +#include +#include #include "gmock/gmock.h" #include "gtest/gtest.h" #include "absl/base/attributes.h" +#include "absl/base/config.h" #include "absl/base/internal/cycleclock.h" #include "absl/base/internal/raw_logging.h" #include "absl/container/internal/container_memory.h" @@ -47,14 +51,16 @@ struct RawHashSetTestOnlyAccess { namespace { -using ::testing::DoubleNear; using ::testing::ElementsAre; +using ::testing::Eq; using ::testing::Ge; using ::testing::Lt; -using ::testing::Optional; using ::testing::Pair; using ::testing::UnorderedElementsAre; +// Convenience function to static cast to ctrl_t. +ctrl_t CtrlT(int i) { return static_cast(i); } + TEST(Util, NormalizeCapacity) { EXPECT_EQ(1, NormalizeCapacity(0)); EXPECT_EQ(1, NormalizeCapacity(1)); @@ -74,8 +80,14 @@ TEST(Util, GrowthAndCapacity) { for (size_t growth = 0; growth < 10000; ++growth) { SCOPED_TRACE(growth); size_t capacity = NormalizeCapacity(GrowthToLowerboundCapacity(growth)); - // The capacity is large enough for `growth` + // The capacity is large enough for `growth`. EXPECT_THAT(CapacityToGrowth(capacity), Ge(growth)); + // For (capacity+1) < kWidth, growth should equal capacity. + if (capacity + 1 < Group::kWidth) { + EXPECT_THAT(CapacityToGrowth(capacity), Eq(capacity)); + } else { + EXPECT_THAT(CapacityToGrowth(capacity), Lt(capacity)); + } if (growth != 0 && capacity > 1) { // There is no smaller capacity that works. EXPECT_THAT(CapacityToGrowth(capacity / 2), Lt(growth)); @@ -161,15 +173,19 @@ TEST(Group, EmptyGroup) { TEST(Group, Match) { if (Group::kWidth == 16) { - ctrl_t group[] = {kEmpty, 1, kDeleted, 3, kEmpty, 5, kSentinel, 7, - 7, 5, 3, 1, 1, 1, 1, 1}; + ctrl_t group[] = {ctrl_t::kEmpty, CtrlT(1), ctrl_t::kDeleted, CtrlT(3), + ctrl_t::kEmpty, CtrlT(5), ctrl_t::kSentinel, CtrlT(7), + CtrlT(7), CtrlT(5), CtrlT(3), CtrlT(1), + CtrlT(1), CtrlT(1), CtrlT(1), CtrlT(1)}; EXPECT_THAT(Group{group}.Match(0), ElementsAre()); EXPECT_THAT(Group{group}.Match(1), ElementsAre(1, 11, 12, 13, 14, 15)); EXPECT_THAT(Group{group}.Match(3), ElementsAre(3, 10)); EXPECT_THAT(Group{group}.Match(5), ElementsAre(5, 9)); EXPECT_THAT(Group{group}.Match(7), ElementsAre(7, 8)); } else if (Group::kWidth == 8) { - ctrl_t group[] = {kEmpty, 1, 2, kDeleted, 2, 1, kSentinel, 1}; + ctrl_t group[] = {ctrl_t::kEmpty, CtrlT(1), CtrlT(2), + ctrl_t::kDeleted, CtrlT(2), CtrlT(1), + ctrl_t::kSentinel, CtrlT(1)}; EXPECT_THAT(Group{group}.Match(0), ElementsAre()); EXPECT_THAT(Group{group}.Match(1), ElementsAre(1, 5, 7)); EXPECT_THAT(Group{group}.Match(2), ElementsAre(2, 4)); @@ -180,11 +196,15 @@ TEST(Group, Match) { TEST(Group, MatchEmpty) { if (Group::kWidth == 16) { - ctrl_t group[] = {kEmpty, 1, kDeleted, 3, kEmpty, 5, kSentinel, 7, - 7, 5, 3, 1, 1, 1, 1, 1}; + ctrl_t group[] = {ctrl_t::kEmpty, CtrlT(1), ctrl_t::kDeleted, CtrlT(3), + ctrl_t::kEmpty, CtrlT(5), ctrl_t::kSentinel, CtrlT(7), + CtrlT(7), CtrlT(5), CtrlT(3), CtrlT(1), + CtrlT(1), CtrlT(1), CtrlT(1), CtrlT(1)}; EXPECT_THAT(Group{group}.MatchEmpty(), ElementsAre(0, 4)); } else if (Group::kWidth == 8) { - ctrl_t group[] = {kEmpty, 1, 2, kDeleted, 2, 1, kSentinel, 1}; + ctrl_t group[] = {ctrl_t::kEmpty, CtrlT(1), CtrlT(2), + ctrl_t::kDeleted, CtrlT(2), CtrlT(1), + ctrl_t::kSentinel, CtrlT(1)}; EXPECT_THAT(Group{group}.MatchEmpty(), ElementsAre(0)); } else { FAIL() << "No test coverage for Group::kWidth==" << Group::kWidth; @@ -193,11 +213,15 @@ TEST(Group, MatchEmpty) { TEST(Group, MatchEmptyOrDeleted) { if (Group::kWidth == 16) { - ctrl_t group[] = {kEmpty, 1, kDeleted, 3, kEmpty, 5, kSentinel, 7, - 7, 5, 3, 1, 1, 1, 1, 1}; + ctrl_t group[] = {ctrl_t::kEmpty, CtrlT(1), ctrl_t::kDeleted, CtrlT(3), + ctrl_t::kEmpty, CtrlT(5), ctrl_t::kSentinel, CtrlT(7), + CtrlT(7), CtrlT(5), CtrlT(3), CtrlT(1), + CtrlT(1), CtrlT(1), CtrlT(1), CtrlT(1)}; EXPECT_THAT(Group{group}.MatchEmptyOrDeleted(), ElementsAre(0, 2, 4)); } else if (Group::kWidth == 8) { - ctrl_t group[] = {kEmpty, 1, 2, kDeleted, 2, 1, kSentinel, 1}; + ctrl_t group[] = {ctrl_t::kEmpty, CtrlT(1), CtrlT(2), + ctrl_t::kDeleted, CtrlT(2), CtrlT(1), + ctrl_t::kSentinel, CtrlT(1)}; EXPECT_THAT(Group{group}.MatchEmptyOrDeleted(), ElementsAre(0, 3)); } else { FAIL() << "No test coverage for Group::kWidth==" << Group::kWidth; @@ -208,28 +232,32 @@ TEST(Batch, DropDeletes) { constexpr size_t kCapacity = 63; constexpr size_t kGroupWidth = container_internal::Group::kWidth; std::vector ctrl(kCapacity + 1 + kGroupWidth); - ctrl[kCapacity] = kSentinel; - std::vector pattern = {kEmpty, 2, kDeleted, 2, kEmpty, 1, kDeleted}; + ctrl[kCapacity] = ctrl_t::kSentinel; + std::vector pattern = { + ctrl_t::kEmpty, CtrlT(2), ctrl_t::kDeleted, CtrlT(2), + ctrl_t::kEmpty, CtrlT(1), ctrl_t::kDeleted}; for (size_t i = 0; i != kCapacity; ++i) { ctrl[i] = pattern[i % pattern.size()]; if (i < kGroupWidth - 1) ctrl[i + kCapacity + 1] = pattern[i % pattern.size()]; } ConvertDeletedToEmptyAndFullToDeleted(ctrl.data(), kCapacity); - ASSERT_EQ(ctrl[kCapacity], kSentinel); - for (size_t i = 0; i < kCapacity + 1 + kGroupWidth; ++i) { + ASSERT_EQ(ctrl[kCapacity], ctrl_t::kSentinel); + for (size_t i = 0; i < kCapacity + kGroupWidth; ++i) { ctrl_t expected = pattern[i % (kCapacity + 1) % pattern.size()]; - if (i == kCapacity) expected = kSentinel; - if (expected == kDeleted) expected = kEmpty; - if (IsFull(expected)) expected = kDeleted; + if (i == kCapacity) expected = ctrl_t::kSentinel; + if (expected == ctrl_t::kDeleted) expected = ctrl_t::kEmpty; + if (IsFull(expected)) expected = ctrl_t::kDeleted; EXPECT_EQ(ctrl[i], expected) - << i << " " << int{pattern[i % pattern.size()]}; + << i << " " << static_cast(pattern[i % pattern.size()]); } } TEST(Group, CountLeadingEmptyOrDeleted) { - const std::vector empty_examples = {kEmpty, kDeleted}; - const std::vector full_examples = {0, 1, 2, 3, 5, 9, 127, kSentinel}; + const std::vector empty_examples = {ctrl_t::kEmpty, ctrl_t::kDeleted}; + const std::vector full_examples = { + CtrlT(0), CtrlT(1), CtrlT(2), CtrlT(3), + CtrlT(5), CtrlT(9), CtrlT(127), ctrl_t::kSentinel}; for (ctrl_t empty : empty_examples) { std::vector e(Group::kWidth, empty); @@ -249,25 +277,44 @@ TEST(Group, CountLeadingEmptyOrDeleted) { } } -struct IntPolicy { - using slot_type = int64_t; - using key_type = int64_t; - using init_type = int64_t; +template +struct ValuePolicy { + using slot_type = T; + using key_type = T; + using init_type = T; - static void construct(void*, int64_t* slot, int64_t v) { *slot = v; } - static void destroy(void*, int64_t*) {} - static void transfer(void*, int64_t* new_slot, int64_t* old_slot) { - *new_slot = *old_slot; + template + static void construct(Allocator* alloc, slot_type* slot, Args&&... args) { + absl::allocator_traits::construct(*alloc, slot, + std::forward(args)...); } - static int64_t& element(slot_type* slot) { return *slot; } + template + static void destroy(Allocator* alloc, slot_type* slot) { + absl::allocator_traits::destroy(*alloc, slot); + } - template - static auto apply(F&& f, int64_t x) -> decltype(std::forward(f)(x, x)) { - return std::forward(f)(x, x); + template + static void transfer(Allocator* alloc, slot_type* new_slot, + slot_type* old_slot) { + construct(alloc, new_slot, std::move(*old_slot)); + destroy(alloc, old_slot); + } + + static T& element(slot_type* slot) { return *slot; } + + template + static decltype(absl::container_internal::DecomposeValue( + std::declval(), std::declval()...)) + apply(F&& f, Args&&... args) { + return absl::container_internal::DecomposeValue( + std::forward(f), std::forward(args)...); } }; +using IntPolicy = ValuePolicy; +using Uint8Policy = ValuePolicy; + class StringPolicy { template , + std::equal_to, std::allocator> { + using Base = typename Uint8Table::raw_hash_set; + using Base::Base; +}; + template struct CustomAlloc : std::allocator { CustomAlloc() {} @@ -392,6 +446,13 @@ TEST(Table, EmptyFunctorOptimization) { size_t growth_left; void* infoz; }; + struct MockTableInfozDisabled { + void* ctrl; + void* slots; + size_t size; + size_t capacity; + size_t growth_left; + }; struct StatelessHash { size_t operator()(absl::string_view) const { return 0; } }; @@ -399,17 +460,27 @@ TEST(Table, EmptyFunctorOptimization) { size_t dummy; }; - EXPECT_EQ( - sizeof(MockTable), - sizeof( - raw_hash_set, std::allocator>)); + if (std::is_empty::value) { + EXPECT_EQ(sizeof(MockTableInfozDisabled), + sizeof(raw_hash_set, + std::allocator>)); - EXPECT_EQ( - sizeof(MockTable) + sizeof(StatefulHash), - sizeof( - raw_hash_set, std::allocator>)); + EXPECT_EQ(sizeof(MockTableInfozDisabled) + sizeof(StatefulHash), + sizeof(raw_hash_set, + std::allocator>)); + } else { + EXPECT_EQ(sizeof(MockTable), + sizeof(raw_hash_set, + std::allocator>)); + + EXPECT_EQ(sizeof(MockTable) + sizeof(StatefulHash), + sizeof(raw_hash_set, + std::allocator>)); + } } TEST(Table, Empty) { @@ -497,6 +568,37 @@ TEST(Table, InsertCollisionAndFindAfterDelete) { EXPECT_TRUE(t.empty()); } +TEST(Table, InsertWithinCapacity) { + IntTable t; + t.reserve(10); + const size_t original_capacity = t.capacity(); + const auto addr = [&](int i) { + return reinterpret_cast(&*t.find(i)); + }; + // Inserting an element does not change capacity. + t.insert(0); + EXPECT_THAT(t.capacity(), original_capacity); + const uintptr_t original_addr_0 = addr(0); + // Inserting another element does not rehash. + t.insert(1); + EXPECT_THAT(t.capacity(), original_capacity); + EXPECT_THAT(addr(0), original_addr_0); + // Inserting lots of duplicate elements does not rehash. + for (int i = 0; i < 100; ++i) { + t.insert(i % 10); + } + EXPECT_THAT(t.capacity(), original_capacity); + EXPECT_THAT(addr(0), original_addr_0); + // Inserting a range of duplicate elements does not rehash. + std::vector dup_range; + for (int i = 0; i < 100; ++i) { + dup_range.push_back(i % 10); + } + t.insert(dup_range.begin(), dup_range.end()); + EXPECT_THAT(t.capacity(), original_capacity); + EXPECT_THAT(addr(0), original_addr_0); +} + TEST(Table, LazyEmplace) { StringTable t; bool called = false; @@ -544,28 +646,53 @@ TEST(Table, Contains2) { } int decompose_constructed; +int decompose_copy_constructed; +int decompose_copy_assigned; +int decompose_move_constructed; +int decompose_move_assigned; struct DecomposeType { - DecomposeType(int i) : i(i) { // NOLINT + DecomposeType(int i = 0) : i(i) { // NOLINT ++decompose_constructed; } explicit DecomposeType(const char* d) : DecomposeType(*d) {} + DecomposeType(const DecomposeType& other) : i(other.i) { + ++decompose_copy_constructed; + } + DecomposeType& operator=(const DecomposeType& other) { + ++decompose_copy_assigned; + i = other.i; + return *this; + } + DecomposeType(DecomposeType&& other) : i(other.i) { + ++decompose_move_constructed; + } + DecomposeType& operator=(DecomposeType&& other) { + ++decompose_move_assigned; + i = other.i; + return *this; + } + int i; }; struct DecomposeHash { using is_transparent = void; - size_t operator()(DecomposeType a) const { return a.i; } + size_t operator()(const DecomposeType& a) const { return a.i; } size_t operator()(int a) const { return a; } size_t operator()(const char* a) const { return *a; } }; struct DecomposeEq { using is_transparent = void; - bool operator()(DecomposeType a, DecomposeType b) const { return a.i == b.i; } - bool operator()(DecomposeType a, int b) const { return a.i == b; } - bool operator()(DecomposeType a, const char* b) const { return a.i == *b; } + bool operator()(const DecomposeType& a, const DecomposeType& b) const { + return a.i == b.i; + } + bool operator()(const DecomposeType& a, int b) const { return a.i == b; } + bool operator()(const DecomposeType& a, const char* b) const { + return a.i == *b; + } }; struct DecomposePolicy { @@ -575,9 +702,9 @@ struct DecomposePolicy { template static void construct(void*, DecomposeType* slot, T&& v) { - *slot = DecomposeType(std::forward(v)); + ::new (slot) DecomposeType(std::forward(v)); } - static void destroy(void*, DecomposeType*) {} + static void destroy(void*, DecomposeType* slot) { slot->~DecomposeType(); } static DecomposeType& element(slot_type* slot) { return *slot; } template @@ -592,8 +719,13 @@ void TestDecompose(bool construct_three) { const int one = 1; const char* three_p = "3"; const auto& three = three_p; + const int elem_vector_count = 256; + std::vector elem_vector(elem_vector_count, DecomposeType{0}); + std::iota(elem_vector.begin(), elem_vector.end(), 0); - raw_hash_set> set1; + using DecomposeSet = + raw_hash_set>; + DecomposeSet set1; decompose_constructed = 0; int expected_constructed = 0; @@ -651,20 +783,72 @@ void TestDecompose(bool construct_three) { expected_constructed += construct_three; EXPECT_EQ(expected_constructed, decompose_constructed); } + + decompose_copy_constructed = 0; + decompose_copy_assigned = 0; + decompose_move_constructed = 0; + decompose_move_assigned = 0; + int expected_copy_constructed = 0; + int expected_move_constructed = 0; + { // raw_hash_set(first, last) with random-access iterators + DecomposeSet set2(elem_vector.begin(), elem_vector.end()); + // Expect exactly one copy-constructor call for each element if no + // rehashing is done. + expected_copy_constructed += elem_vector_count; + EXPECT_EQ(expected_copy_constructed, decompose_copy_constructed); + EXPECT_EQ(expected_move_constructed, decompose_move_constructed); + EXPECT_EQ(0, decompose_move_assigned); + EXPECT_EQ(0, decompose_copy_assigned); + } + + { // raw_hash_set(first, last) with forward iterators + std::list elem_list(elem_vector.begin(), elem_vector.end()); + expected_copy_constructed = decompose_copy_constructed; + DecomposeSet set2(elem_list.begin(), elem_list.end()); + // Expect exactly N elements copied into set, expect at most 2*N elements + // moving internally for all resizing needed (for a growth factor of 2). + expected_copy_constructed += elem_vector_count; + EXPECT_EQ(expected_copy_constructed, decompose_copy_constructed); + expected_move_constructed += elem_vector_count; + EXPECT_LT(expected_move_constructed, decompose_move_constructed); + expected_move_constructed += elem_vector_count; + EXPECT_GE(expected_move_constructed, decompose_move_constructed); + EXPECT_EQ(0, decompose_move_assigned); + EXPECT_EQ(0, decompose_copy_assigned); + expected_copy_constructed = decompose_copy_constructed; + expected_move_constructed = decompose_move_constructed; + } + + { // insert(first, last) + DecomposeSet set2; + set2.insert(elem_vector.begin(), elem_vector.end()); + // Expect exactly N elements copied into set, expect at most 2*N elements + // moving internally for all resizing needed (for a growth factor of 2). + const int expected_new_elements = elem_vector_count; + const int expected_max_element_moves = 2 * elem_vector_count; + expected_copy_constructed += expected_new_elements; + EXPECT_EQ(expected_copy_constructed, decompose_copy_constructed); + expected_move_constructed += expected_max_element_moves; + EXPECT_GE(expected_move_constructed, decompose_move_constructed); + EXPECT_EQ(0, decompose_move_assigned); + EXPECT_EQ(0, decompose_copy_assigned); + expected_copy_constructed = decompose_copy_constructed; + expected_move_constructed = decompose_move_constructed; + } } TEST(Table, Decompose) { TestDecompose(false); struct TransparentHashIntOverload { - size_t operator()(DecomposeType a) const { return a.i; } + size_t operator()(const DecomposeType& a) const { return a.i; } size_t operator()(int a) const { return a; } }; struct TransparentEqIntOverload { - bool operator()(DecomposeType a, DecomposeType b) const { + bool operator()(const DecomposeType& a, const DecomposeType& b) const { return a.i == b.i; } - bool operator()(DecomposeType a, int b) const { return a.i == b; } + bool operator()(const DecomposeType& a, int b) const { return a.i == b; } }; TestDecompose(true); TestDecompose(true); @@ -706,7 +890,7 @@ TEST(Table, RehashWithNoResize) { const size_t capacity = t.capacity(); // Remove elements from all groups except the first and the last one. - // All elements removed from full groups will be marked as kDeleted. + // All elements removed from full groups will be marked as ctrl_t::kDeleted. const size_t erase_begin = Group::kWidth / 2; const size_t erase_end = (t.size() / Group::kWidth - 1) * Group::kWidth; for (size_t i = erase_begin; i < erase_end; ++i) { @@ -846,7 +1030,8 @@ TEST(Table, EraseMaintainsValidIterator) { std::vector CollectBadMergeKeys(size_t N) { static constexpr int kGroupSize = Group::kWidth - 1; - auto topk_range = [](size_t b, size_t e, IntTable* t) -> std::vector { + auto topk_range = [](size_t b, size_t e, + IntTable* t) -> std::vector { for (size_t i = b; i != e; ++i) { t->emplace(i); } @@ -1000,8 +1185,8 @@ using ProbeStatsPerSize = std::map; // 1. Create new table and reserve it to keys.size() * 2 // 2. Insert all keys xored with seed // 3. Collect ProbeStats from final table. -ProbeStats CollectProbeStatsOnKeysXoredWithSeed(const std::vector& keys, - size_t num_iters) { +ProbeStats CollectProbeStatsOnKeysXoredWithSeed( + const std::vector& keys, size_t num_iters) { const size_t reserve_size = keys.size() * 2; ProbeStats stats; @@ -1655,6 +1840,38 @@ TEST(Table, Merge) { EXPECT_THAT(t2, UnorderedElementsAre(Pair("0", "~0"))); } +TEST(Table, IteratorEmplaceConstructibleRequirement) { + struct Value { + explicit Value(absl::string_view view) : value(view) {} + std::string value; + + bool operator==(const Value& other) const { return value == other.value; } + }; + struct H { + size_t operator()(const Value& v) const { + return absl::Hash{}(v.value); + } + }; + + struct Table : raw_hash_set, H, std::equal_to, + std::allocator> { + using Base = typename Table::raw_hash_set; + using Base::Base; + }; + + std::string input[3]{"A", "B", "C"}; + + Table t(std::begin(input), std::end(input)); + EXPECT_THAT(t, UnorderedElementsAre(Value{"A"}, Value{"B"}, Value{"C"})); + + input[0] = "D"; + input[1] = "E"; + input[2] = "F"; + t.insert(std::begin(input), std::end(input)); + EXPECT_THAT(t, UnorderedElementsAre(Value{"A"}, Value{"B"}, Value{"C"}, + Value{"D"}, Value{"E"}, Value{"F"})); +} + TEST(Nodes, EmptyNodeType) { using node_type = StringTable::node_type; node_type n; @@ -1709,6 +1926,26 @@ TEST(Nodes, ExtractInsert) { EXPECT_FALSE(node); } +TEST(Nodes, HintInsert) { + IntTable t = {1, 2, 3}; + auto node = t.extract(1); + EXPECT_THAT(t, UnorderedElementsAre(2, 3)); + auto it = t.insert(t.begin(), std::move(node)); + EXPECT_THAT(t, UnorderedElementsAre(1, 2, 3)); + EXPECT_EQ(*it, 1); + EXPECT_FALSE(node); + + node = t.extract(2); + EXPECT_THAT(t, UnorderedElementsAre(1, 3)); + // reinsert 2 to make the next insert fail. + t.insert(2); + EXPECT_THAT(t, UnorderedElementsAre(1, 2, 3)); + it = t.insert(t.begin(), std::move(node)); + EXPECT_EQ(*it, 2); + // The node was not emptied by the insert call. + EXPECT_TRUE(node); +} + IntTable MakeSimpleTable(size_t size) { IntTable t; while (t.size() < size) t.insert(t.size()); @@ -1791,39 +2028,80 @@ TEST(TableDeathTest, EraseOfEndAsserts) { IntTable t; // Extra simple "regexp" as regexp support is highly varied across platforms. - constexpr char kDeathMsg[] = "IsFull"; + constexpr char kDeathMsg[] = "Invalid operation on iterator"; EXPECT_DEATH_IF_SUPPORTED(t.erase(t.end()), kDeathMsg); } -#if defined(ABSL_HASHTABLEZ_SAMPLE) +#if defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE) TEST(RawHashSamplerTest, Sample) { // Enable the feature even if the prod default is off. SetHashtablezEnabled(true); SetHashtablezSampleParameter(100); - auto& sampler = HashtablezSampler::Global(); + auto& sampler = GlobalHashtablezSampler(); size_t start_size = 0; - start_size += sampler.Iterate([&](const HashtablezInfo&) { ++start_size; }); + std::unordered_set preexisting_info; + start_size += sampler.Iterate([&](const HashtablezInfo& info) { + preexisting_info.insert(&info); + ++start_size; + }); std::vector tables; for (int i = 0; i < 1000000; ++i) { tables.emplace_back(); + + const bool do_reserve = (i % 10 > 5); + const bool do_rehash = !do_reserve && (i % 10 > 0); + + if (do_reserve) { + // Don't reserve on all tables. + tables.back().reserve(10 * (i % 10)); + } + tables.back().insert(1); + tables.back().insert(i % 5); + + if (do_rehash) { + // Rehash some other tables. + tables.back().rehash(10 * (i % 10)); + } } size_t end_size = 0; - end_size += sampler.Iterate([&](const HashtablezInfo&) { ++end_size; }); + std::unordered_map observed_checksums; + std::unordered_map reservations; + end_size += sampler.Iterate([&](const HashtablezInfo& info) { + if (preexisting_info.count(&info) == 0) { + observed_checksums[info.hashes_bitwise_xor.load( + std::memory_order_relaxed)]++; + reservations[info.max_reserve.load(std::memory_order_relaxed)]++; + } + ++end_size; + }); EXPECT_NEAR((end_size - start_size) / static_cast(tables.size()), 0.01, 0.005); + EXPECT_EQ(observed_checksums.size(), 5); + for (const auto& [_, count] : observed_checksums) { + EXPECT_NEAR((100 * count) / static_cast(tables.size()), 0.2, 0.05); + } + + EXPECT_EQ(reservations.size(), 10); + for (const auto& [reservation, count] : reservations) { + EXPECT_GE(reservation, 0); + EXPECT_LT(reservation, 100); + + EXPECT_NEAR((100 * count) / static_cast(tables.size()), 0.1, 0.05) + << reservation; + } } -#endif // ABSL_HASHTABLEZ_SAMPLER +#endif // ABSL_INTERNAL_HASHTABLEZ_SAMPLE TEST(RawHashSamplerTest, DoNotSampleCustomAllocators) { // Enable the feature even if the prod default is off. SetHashtablezEnabled(true); SetHashtablezSampleParameter(100); - auto& sampler = HashtablezSampler::Global(); + auto& sampler = GlobalHashtablezSampler(); size_t start_size = 0; start_size += sampler.Iterate([&](const HashtablezInfo&) { ++start_size; }); @@ -1839,7 +2117,7 @@ TEST(RawHashSamplerTest, DoNotSampleCustomAllocators) { 0.00, 0.001); } -#ifdef ADDRESS_SANITIZER +#ifdef ABSL_HAVE_ADDRESS_SANITIZER TEST(Sanitizer, PoisoningUnused) { IntTable t; t.reserve(5); @@ -1863,7 +2141,37 @@ TEST(Sanitizer, PoisoningOnErase) { t.erase(0); EXPECT_TRUE(__asan_address_is_poisoned(&v)); } -#endif // ADDRESS_SANITIZER +#endif // ABSL_HAVE_ADDRESS_SANITIZER + +TEST(Table, AlignOne) { + // We previously had a bug in which we were copying a control byte over the + // first slot when alignof(value_type) is 1. We test repeated + // insertions/erases and verify that the behavior is correct. + Uint8Table t; + std::unordered_set verifier; // NOLINT + + // Do repeated insertions/erases from the table. + for (int64_t i = 0; i < 100000; ++i) { + SCOPED_TRACE(i); + const uint8_t u = (i * -i) & 0xFF; + auto it = t.find(u); + auto verifier_it = verifier.find(u); + if (it == t.end()) { + ASSERT_EQ(verifier_it, verifier.end()); + t.insert(u); + verifier.insert(u); + } else { + ASSERT_NE(verifier_it, verifier.end()); + t.erase(it); + verifier.erase(verifier_it); + } + } + + EXPECT_EQ(t.size(), verifier.size()); + for (uint8_t u : t) { + EXPECT_EQ(verifier.count(u), 1); + } +} } // namespace } // namespace container_internal diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/unordered_map_constructor_test.h b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/unordered_map_constructor_test.h index 76ee95e6ab..c1d20f3c52 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/unordered_map_constructor_test.h +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/unordered_map_constructor_test.h @@ -16,6 +16,7 @@ #define ABSL_CONTAINER_INTERNAL_UNORDERED_MAP_CONSTRUCTOR_TEST_H_ #include +#include #include #include "gmock/gmock.h" @@ -178,7 +179,7 @@ TYPED_TEST_P(ConstructorTest, InputIteratorBucketHashEqualAlloc) { A alloc(0); std::vector values; std::generate_n(std::back_inserter(values), 10, - hash_internal::Generator()); + hash_internal::UniqueGenerator()); TypeParam m(values.begin(), values.end(), 123, hasher, equal, alloc); EXPECT_EQ(m.hash_function(), hasher); EXPECT_EQ(m.key_eq(), equal); @@ -197,7 +198,7 @@ void InputIteratorBucketAllocTest(std::true_type) { A alloc(0); std::vector values; std::generate_n(std::back_inserter(values), 10, - hash_internal::Generator()); + hash_internal::UniqueGenerator()); TypeParam m(values.begin(), values.end(), 123, alloc); EXPECT_EQ(m.get_allocator(), alloc); EXPECT_THAT(items(m), ::testing::UnorderedElementsAreArray(values)); @@ -220,7 +221,7 @@ void InputIteratorBucketHashAllocTest(std::true_type) { A alloc(0); std::vector values; std::generate_n(std::back_inserter(values), 10, - hash_internal::Generator()); + hash_internal::UniqueGenerator()); TypeParam m(values.begin(), values.end(), 123, hasher, alloc); EXPECT_EQ(m.hash_function(), hasher); EXPECT_EQ(m.get_allocator(), alloc); @@ -240,8 +241,9 @@ TYPED_TEST_P(ConstructorTest, CopyConstructor) { H hasher; E equal; A alloc(0); + hash_internal::UniqueGenerator gen; TypeParam m(123, hasher, equal, alloc); - for (size_t i = 0; i != 10; ++i) m.insert(hash_internal::Generator()()); + for (size_t i = 0; i != 10; ++i) m.insert(gen()); TypeParam n(m); EXPECT_EQ(m.hash_function(), n.hash_function()); EXPECT_EQ(m.key_eq(), n.key_eq()); @@ -261,8 +263,9 @@ void CopyConstructorAllocTest(std::true_type) { H hasher; E equal; A alloc(0); + hash_internal::UniqueGenerator gen; TypeParam m(123, hasher, equal, alloc); - for (size_t i = 0; i != 10; ++i) m.insert(hash_internal::Generator()()); + for (size_t i = 0; i != 10; ++i) m.insert(gen()); TypeParam n(m, A(11)); EXPECT_EQ(m.hash_function(), n.hash_function()); EXPECT_EQ(m.key_eq(), n.key_eq()); @@ -284,8 +287,9 @@ TYPED_TEST_P(ConstructorTest, MoveConstructor) { H hasher; E equal; A alloc(0); + hash_internal::UniqueGenerator gen; TypeParam m(123, hasher, equal, alloc); - for (size_t i = 0; i != 10; ++i) m.insert(hash_internal::Generator()()); + for (size_t i = 0; i != 10; ++i) m.insert(gen()); TypeParam t(m); TypeParam n(std::move(t)); EXPECT_EQ(m.hash_function(), n.hash_function()); @@ -306,8 +310,9 @@ void MoveConstructorAllocTest(std::true_type) { H hasher; E equal; A alloc(0); + hash_internal::UniqueGenerator gen; TypeParam m(123, hasher, equal, alloc); - for (size_t i = 0; i != 10; ++i) m.insert(hash_internal::Generator()()); + for (size_t i = 0; i != 10; ++i) m.insert(gen()); TypeParam t(m); TypeParam n(std::move(t), A(1)); EXPECT_EQ(m.hash_function(), n.hash_function()); @@ -324,7 +329,7 @@ TYPED_TEST_P(ConstructorTest, MoveConstructorAlloc) { TYPED_TEST_P(ConstructorTest, InitializerListBucketHashEqualAlloc) { using T = hash_internal::GeneratedType; - hash_internal::Generator gen; + hash_internal::UniqueGenerator gen; std::initializer_list values = {gen(), gen(), gen(), gen(), gen()}; using H = typename TypeParam::hasher; using E = typename TypeParam::key_equal; @@ -347,7 +352,7 @@ template void InitializerListBucketAllocTest(std::true_type) { using T = hash_internal::GeneratedType; using A = typename TypeParam::allocator_type; - hash_internal::Generator gen; + hash_internal::UniqueGenerator gen; std::initializer_list values = {gen(), gen(), gen(), gen(), gen()}; A alloc(0); TypeParam m(values, 123, alloc); @@ -370,7 +375,7 @@ void InitializerListBucketHashAllocTest(std::true_type) { using A = typename TypeParam::allocator_type; H hasher; A alloc(0); - hash_internal::Generator gen; + hash_internal::UniqueGenerator gen; std::initializer_list values = {gen(), gen(), gen(), gen(), gen()}; TypeParam m(values, 123, hasher, alloc); EXPECT_EQ(m.hash_function(), hasher); @@ -391,7 +396,7 @@ TYPED_TEST_P(ConstructorTest, Assignment) { H hasher; E equal; A alloc(0); - hash_internal::Generator gen; + hash_internal::UniqueGenerator gen; TypeParam m({gen(), gen(), gen()}, 123, hasher, equal, alloc); TypeParam n; n = m; @@ -411,7 +416,7 @@ TYPED_TEST_P(ConstructorTest, MoveAssignment) { H hasher; E equal; A alloc(0); - hash_internal::Generator gen; + hash_internal::UniqueGenerator gen; TypeParam m({gen(), gen(), gen()}, 123, hasher, equal, alloc); TypeParam t(m); TypeParam n; @@ -423,7 +428,7 @@ TYPED_TEST_P(ConstructorTest, MoveAssignment) { TYPED_TEST_P(ConstructorTest, AssignmentFromInitializerList) { using T = hash_internal::GeneratedType; - hash_internal::Generator gen; + hash_internal::UniqueGenerator gen; std::initializer_list values = {gen(), gen(), gen(), gen(), gen()}; TypeParam m; m = values; @@ -432,7 +437,7 @@ TYPED_TEST_P(ConstructorTest, AssignmentFromInitializerList) { TYPED_TEST_P(ConstructorTest, AssignmentOverwritesExisting) { using T = hash_internal::GeneratedType; - hash_internal::Generator gen; + hash_internal::UniqueGenerator gen; TypeParam m({gen(), gen(), gen()}); TypeParam n({gen()}); n = m; @@ -441,7 +446,7 @@ TYPED_TEST_P(ConstructorTest, AssignmentOverwritesExisting) { TYPED_TEST_P(ConstructorTest, MoveAssignmentOverwritesExisting) { using T = hash_internal::GeneratedType; - hash_internal::Generator gen; + hash_internal::UniqueGenerator gen; TypeParam m({gen(), gen(), gen()}); TypeParam t(m); TypeParam n({gen()}); @@ -451,7 +456,7 @@ TYPED_TEST_P(ConstructorTest, MoveAssignmentOverwritesExisting) { TYPED_TEST_P(ConstructorTest, AssignmentFromInitializerListOverwritesExisting) { using T = hash_internal::GeneratedType; - hash_internal::Generator gen; + hash_internal::UniqueGenerator gen; std::initializer_list values = {gen(), gen(), gen(), gen(), gen()}; TypeParam m; m = values; @@ -460,7 +465,7 @@ TYPED_TEST_P(ConstructorTest, AssignmentFromInitializerListOverwritesExisting) { TYPED_TEST_P(ConstructorTest, AssignmentOnSelf) { using T = hash_internal::GeneratedType; - hash_internal::Generator gen; + hash_internal::UniqueGenerator gen; std::initializer_list values = {gen(), gen(), gen(), gen(), gen()}; TypeParam m(values); m = *&m; // Avoid -Wself-assign diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/unordered_map_modifiers_test.h b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/unordered_map_modifiers_test.h index b8c513f157..d3543936f7 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/unordered_map_modifiers_test.h +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/unordered_map_modifiers_test.h @@ -81,6 +81,38 @@ TYPED_TEST_P(ModifiersTest, InsertRange) { ASSERT_THAT(items(m), ::testing::UnorderedElementsAreArray(values)); } +TYPED_TEST_P(ModifiersTest, InsertWithinCapacity) { + using T = hash_internal::GeneratedType; + using V = typename TypeParam::mapped_type; + T val = hash_internal::Generator()(); + TypeParam m; + m.reserve(10); + const size_t original_capacity = m.bucket_count(); + m.insert(val); + EXPECT_EQ(m.bucket_count(), original_capacity); + T val2 = {val.first, hash_internal::Generator()()}; + m.insert(val2); + EXPECT_EQ(m.bucket_count(), original_capacity); +} + +TYPED_TEST_P(ModifiersTest, InsertRangeWithinCapacity) { +#if !defined(__GLIBCXX__) + using T = hash_internal::GeneratedType; + std::vector base_values; + std::generate_n(std::back_inserter(base_values), 10, + hash_internal::Generator()); + std::vector values; + while (values.size() != 100) { + std::copy_n(base_values.begin(), 10, std::back_inserter(values)); + } + TypeParam m; + m.reserve(10); + const size_t original_capacity = m.bucket_count(); + m.insert(values.begin(), values.end()); + EXPECT_EQ(m.bucket_count(), original_capacity); +#endif +} + TYPED_TEST_P(ModifiersTest, InsertOrAssign) { #ifdef UNORDERED_MAP_CXX17 using std::get; @@ -266,9 +298,10 @@ TYPED_TEST_P(ModifiersTest, Swap) { // TODO(alkis): Write tests for merge. REGISTER_TYPED_TEST_CASE_P(ModifiersTest, Clear, Insert, InsertHint, - InsertRange, InsertOrAssign, InsertOrAssignHint, - Emplace, EmplaceHint, TryEmplace, TryEmplaceHint, - Erase, EraseRange, EraseKey, Swap); + InsertRange, InsertWithinCapacity, + InsertRangeWithinCapacity, InsertOrAssign, + InsertOrAssignHint, Emplace, EmplaceHint, TryEmplace, + TryEmplaceHint, Erase, EraseRange, EraseKey, Swap); template struct is_unique_ptr : std::false_type {}; @@ -286,6 +319,8 @@ class UniquePtrModifiersTest : public ::testing::Test { } }; +GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(UniquePtrModifiersTest); + TYPED_TEST_SUITE_P(UniquePtrModifiersTest); // Test that we do not move from rvalue arguments if an insertion does not diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/unordered_set_modifiers_test.h b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/unordered_set_modifiers_test.h index 26be58d99f..6e473e45da 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/unordered_set_modifiers_test.h +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/internal/unordered_set_modifiers_test.h @@ -74,6 +74,36 @@ TYPED_TEST_P(ModifiersTest, InsertRange) { ASSERT_THAT(keys(m), ::testing::UnorderedElementsAreArray(values)); } +TYPED_TEST_P(ModifiersTest, InsertWithinCapacity) { + using T = hash_internal::GeneratedType; + T val = hash_internal::Generator()(); + TypeParam m; + m.reserve(10); + const size_t original_capacity = m.bucket_count(); + m.insert(val); + EXPECT_EQ(m.bucket_count(), original_capacity); + m.insert(val); + EXPECT_EQ(m.bucket_count(), original_capacity); +} + +TYPED_TEST_P(ModifiersTest, InsertRangeWithinCapacity) { +#if !defined(__GLIBCXX__) + using T = hash_internal::GeneratedType; + std::vector base_values; + std::generate_n(std::back_inserter(base_values), 10, + hash_internal::Generator()); + std::vector values; + while (values.size() != 100) { + values.insert(values.end(), base_values.begin(), base_values.end()); + } + TypeParam m; + m.reserve(10); + const size_t original_capacity = m.bucket_count(); + m.insert(values.begin(), values.end()); + EXPECT_EQ(m.bucket_count(), original_capacity); +#endif +} + TYPED_TEST_P(ModifiersTest, Emplace) { using T = hash_internal::GeneratedType; T val = hash_internal::Generator()(); @@ -180,8 +210,9 @@ TYPED_TEST_P(ModifiersTest, Swap) { // TODO(alkis): Write tests for merge. REGISTER_TYPED_TEST_CASE_P(ModifiersTest, Clear, Insert, InsertHint, - InsertRange, Emplace, EmplaceHint, Erase, EraseRange, - EraseKey, Swap); + InsertRange, InsertWithinCapacity, + InsertRangeWithinCapacity, Emplace, EmplaceHint, + Erase, EraseRange, EraseKey, Swap); } // namespace container_internal ABSL_NAMESPACE_END diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/node_hash_map.h b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/node_hash_map.h index fccea1841c..7a39f6284c 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/node_hash_map.h +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/node_hash_map.h @@ -225,7 +225,8 @@ class node_hash_map // // size_type erase(const key_type& key): // - // Erases the element with the matching key, if it exists. + // Erases the element with the matching key, if it exists, returning the + // number of elements erased (0 or 1). using Base::erase; // node_hash_map::insert() @@ -374,6 +375,11 @@ class node_hash_map // key value and returns a node handle owning that extracted data. If the // `node_hash_map` does not contain an element with a matching key, this // function returns an empty node handle. + // + // NOTE: when compiled in an earlier version of C++ than C++17, + // `node_type::key()` returns a const reference to the key instead of a + // mutable reference. We cannot safely return a mutable reference without + // std::launder (which is not available before C++17). using Base::extract; // node_hash_map::merge() @@ -514,12 +520,6 @@ class node_hash_map // // Returns the function used for comparing keys equality. using Base::key_eq; - - ABSL_DEPRECATED("Call `hash_function()` instead.") - typename Base::hasher hash_funct() { return this->hash_function(); } - - ABSL_DEPRECATED("Call `rehash()` instead.") - void resize(typename Base::size_type hint) { this->rehash(hint); } }; // erase_if(node_hash_map<>, Pred) diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/node_hash_map_test.cc b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/node_hash_map_test.cc index 5d74b814b5..8f59a1e4a2 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/node_hash_map_test.cc +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/node_hash_map_test.cc @@ -254,6 +254,21 @@ TEST(NodeHashMap, EraseIf) { } } +// This test requires std::launder for mutable key access in node handles. +#if defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606 +TEST(NodeHashMap, NodeHandleMutableKeyAccess) { + node_hash_map map; + + map["key1"] = "mapped"; + + auto nh = map.extract(map.begin()); + nh.key().resize(3); + map.insert(std::move(nh)); + + EXPECT_THAT(map, testing::ElementsAre(Pair("key", "mapped"))); +} +#endif + } // namespace } // namespace container_internal ABSL_NAMESPACE_END diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/node_hash_set.h b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/node_hash_set.h index ad54b6dccb..93b15f4681 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/node_hash_set.h +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/container/node_hash_set.h @@ -18,7 +18,7 @@ // // An `absl::node_hash_set` is an unordered associative container designed to // be a more efficient replacement for `std::unordered_set`. Like -// `unordered_set`, search, insertion, and deletion of map elements can be done +// `unordered_set`, search, insertion, and deletion of set elements can be done // as an `O(1)` operation. However, `node_hash_set` (and other unordered // associative containers known as the collection of Abseil "Swiss tables") // contain other optimizations that result in both memory and computation @@ -60,7 +60,7 @@ struct NodeHashSetPolicy; // following notable differences: // // * Supports heterogeneous lookup, through `find()`, `operator[]()` and -// `insert()`, provided that the map is provided a compatible heterogeneous +// `insert()`, provided that the set is provided a compatible heterogeneous // hashing function and equality operator. // * Contains a `capacity()` member function indicating the number of element // slots (open, deleted, and empty) within the hash set. @@ -76,13 +76,13 @@ struct NodeHashSetPolicy; // Example: // // // Create a node hash set of three strings -// absl::node_hash_map ducks = +// absl::node_hash_set ducks = // {"huey", "dewey", "louie"}; // -// // Insert a new element into the node hash map -// ducks.insert("donald"}; +// // Insert a new element into the node hash set +// ducks.insert("donald"); // -// // Force a rehash of the node hash map +// // Force a rehash of the node hash set // ducks.rehash(0); // // // See if "dewey" is present @@ -100,7 +100,7 @@ class node_hash_set public: // Constructors and Assignment Operators // - // A node_hash_set supports the same overload set as `std::unordered_map` + // A node_hash_set supports the same overload set as `std::unordered_set` // for construction and assignment: // // * Default constructor @@ -167,7 +167,7 @@ class node_hash_set // available within the `node_hash_set`. // // NOTE: this member function is particular to `absl::node_hash_set` and is - // not provided in the `std::unordered_map` API. + // not provided in the `std::unordered_set` API. using Base::capacity; // node_hash_set::empty() @@ -208,7 +208,7 @@ class node_hash_set // `void`. // // NOTE: this return behavior is different than that of STL containers in - // general and `std::unordered_map` in particular. + // general and `std::unordered_set` in particular. // // iterator erase(const_iterator first, const_iterator last): // @@ -217,7 +217,8 @@ class node_hash_set // // size_type erase(const key_type& key): // - // Erases the element with the matching key, if it exists. + // Erases the element with the matching key, if it exists, returning the + // number of elements erased (0 or 1). using Base::erase; // node_hash_set::insert() @@ -313,7 +314,7 @@ class node_hash_set // node_hash_set::merge() // - // Extracts elements from a given `source` flat hash map into this + // Extracts elements from a given `source` node hash set into this // `node_hash_set`. If the destination `node_hash_set` already contains an // element with an equivalent key, that element is not extracted. using Base::merge; @@ -321,15 +322,15 @@ class node_hash_set // node_hash_set::swap(node_hash_set& other) // // Exchanges the contents of this `node_hash_set` with those of the `other` - // flat hash map, avoiding invocation of any move, copy, or swap operations on + // node hash set, avoiding invocation of any move, copy, or swap operations on // individual elements. // // All iterators and references on the `node_hash_set` remain valid, excepting // for the past-the-end iterator, which is invalidated. // - // `swap()` requires that the flat hash set's hashing and key equivalence + // `swap()` requires that the node hash set's hashing and key equivalence // functions be Swappable, and are exchaged using unqualified calls to - // non-member `swap()`. If the map's allocator has + // non-member `swap()`. If the set's allocator has // `std::allocator_traits::propagate_on_container_swap::value` // set to `true`, the allocators are also exchanged using an unqualified call // to non-member `swap()`; otherwise, the allocators are not swapped. @@ -384,14 +385,14 @@ class node_hash_set // node_hash_set::bucket_count() // // Returns the number of "buckets" within the `node_hash_set`. Note that - // because a flat hash map contains all elements within its internal storage, + // because a node hash set contains all elements within its internal storage, // this value simply equals the current capacity of the `node_hash_set`. using Base::bucket_count; // node_hash_set::load_factor() // // Returns the current load factor of the `node_hash_set` (the average number - // of slots occupied with a value within the hash map). + // of slots occupied with a value within the hash set). using Base::load_factor; // node_hash_set::max_load_factor() @@ -427,12 +428,6 @@ class node_hash_set // // Returns the function used for comparing keys equality. using Base::key_eq; - - ABSL_DEPRECATED("Call `hash_function()` instead.") - typename Base::hasher hash_funct() { return this->hash_function(); } - - ABSL_DEPRECATED("Call `rehash()` instead.") - void resize(typename Base::size_type hint) { this->rehash(hint); } }; // erase_if(node_hash_set<>, Pred) diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/copts/AbseilConfigureCopts.cmake b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/copts/AbseilConfigureCopts.cmake index 9557e36f68..942ce90a4d 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/copts/AbseilConfigureCopts.cmake +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/copts/AbseilConfigureCopts.cmake @@ -12,16 +12,16 @@ else() set(ABSL_BUILD_DLL FALSE) endif() -if("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "x86_64" OR "${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "AMD64") +if(CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64|amd64|AMD64") if (MSVC) set(ABSL_RANDOM_RANDEN_COPTS "${ABSL_RANDOM_HWAES_MSVC_X64_FLAGS}") else() set(ABSL_RANDOM_RANDEN_COPTS "${ABSL_RANDOM_HWAES_X64_FLAGS}") endif() -elseif("${CMAKE_SYSTEM_PROCESSOR}" MATCHES "arm.*|aarch64") - if ("${CMAKE_SIZEOF_VOID_P}" STREQUAL "8") +elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "arm.*|aarch64") + if (CMAKE_SIZEOF_VOID_P STREQUAL "8") set(ABSL_RANDOM_RANDEN_COPTS "${ABSL_RANDOM_HWAES_ARM64_FLAGS}") - elseif("${CMAKE_SIZEOF_VOID_P}" STREQUAL "4") + elseif(CMAKE_SIZEOF_VOID_P STREQUAL "4") set(ABSL_RANDOM_RANDEN_COPTS "${ABSL_RANDOM_HWAES_ARM32_FLAGS}") else() message(WARNING "Value of CMAKE_SIZEOF_VOID_P (${CMAKE_SIZEOF_VOID_P}) is not supported.") @@ -32,20 +32,18 @@ else() endif() -if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") +if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") set(ABSL_DEFAULT_COPTS "${ABSL_GCC_FLAGS}") set(ABSL_TEST_COPTS "${ABSL_GCC_FLAGS};${ABSL_GCC_TEST_FLAGS}") -elseif("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") - # MATCHES so we get both Clang and AppleClang +elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang") # MATCHES so we get both Clang and AppleClang if(MSVC) # clang-cl is half MSVC, half LLVM set(ABSL_DEFAULT_COPTS "${ABSL_CLANG_CL_FLAGS}") set(ABSL_TEST_COPTS "${ABSL_CLANG_CL_FLAGS};${ABSL_CLANG_CL_TEST_FLAGS}") - set(ABSL_DEFAULT_LINKOPTS "${ABSL_MSVC_LINKOPTS}") else() set(ABSL_DEFAULT_COPTS "${ABSL_LLVM_FLAGS}") set(ABSL_TEST_COPTS "${ABSL_LLVM_FLAGS};${ABSL_LLVM_TEST_FLAGS}") - if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") + if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang") # AppleClang doesn't have lsan # https://developer.apple.com/documentation/code_diagnostics if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 3.5) @@ -54,7 +52,7 @@ elseif("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") endif() endif() endif() -elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") +elseif(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") set(ABSL_DEFAULT_COPTS "${ABSL_MSVC_FLAGS}") set(ABSL_TEST_COPTS "${ABSL_MSVC_FLAGS};${ABSL_MSVC_TEST_FLAGS}") set(ABSL_DEFAULT_LINKOPTS "${ABSL_MSVC_LINKOPTS}") diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/copts/GENERATED_AbseilCopts.cmake b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/copts/GENERATED_AbseilCopts.cmake index 7ef6339be2..a4ab1aa204 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/copts/GENERATED_AbseilCopts.cmake +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/copts/GENERATED_AbseilCopts.cmake @@ -5,47 +5,6 @@ list(APPEND ABSL_CLANG_CL_FLAGS "/W3" - "-Wno-c++98-compat-pedantic" - "-Wno-conversion" - "-Wno-covered-switch-default" - "-Wno-deprecated" - "-Wno-disabled-macro-expansion" - "-Wno-double-promotion" - "-Wno-comma" - "-Wno-extra-semi" - "-Wno-extra-semi-stmt" - "-Wno-packed" - "-Wno-padded" - "-Wno-sign-compare" - "-Wno-float-conversion" - "-Wno-float-equal" - "-Wno-format-nonliteral" - "-Wno-gcc-compat" - "-Wno-global-constructors" - "-Wno-exit-time-destructors" - "-Wno-non-modular-include-in-module" - "-Wno-old-style-cast" - "-Wno-range-loop-analysis" - "-Wno-reserved-id-macro" - "-Wno-shorten-64-to-32" - "-Wno-switch-enum" - "-Wno-thread-safety-negative" - "-Wno-unknown-warning-option" - "-Wno-unreachable-code" - "-Wno-unused-macros" - "-Wno-weak-vtables" - "-Wno-zero-as-null-pointer-constant" - "-Wbitfield-enum-conversion" - "-Wbool-conversion" - "-Wconstant-conversion" - "-Wenum-conversion" - "-Wint-conversion" - "-Wliteral-conversion" - "-Wnon-literal-null-conversion" - "-Wnull-conversion" - "-Wobjc-literal-conversion" - "-Wno-sign-conversion" - "-Wstring-conversion" "/DNOMINMAX" "/DWIN32_LEAN_AND_MEAN" "/D_CRT_SECURE_NO_WARNINGS" @@ -78,16 +37,17 @@ list(APPEND ABSL_GCC_FLAGS "-Wextra" "-Wcast-qual" "-Wconversion-null" + "-Wformat-security" "-Wmissing-declarations" "-Woverlength-strings" "-Wpointer-arith" + "-Wundef" "-Wunused-local-typedefs" "-Wunused-result" "-Wvarargs" "-Wvla" "-Wwrite-strings" - "-Wno-missing-field-initializers" - "-Wno-sign-compare" + "-DNOMINMAX" ) list(APPEND ABSL_GCC_TEST_FLAGS @@ -103,48 +63,39 @@ list(APPEND ABSL_GCC_TEST_FLAGS list(APPEND ABSL_LLVM_FLAGS "-Wall" "-Wextra" - "-Weverything" - "-Wno-c++98-compat-pedantic" - "-Wno-conversion" - "-Wno-covered-switch-default" - "-Wno-deprecated" - "-Wno-disabled-macro-expansion" - "-Wno-double-promotion" - "-Wno-comma" - "-Wno-extra-semi" - "-Wno-extra-semi-stmt" - "-Wno-packed" - "-Wno-padded" - "-Wno-sign-compare" - "-Wno-float-conversion" - "-Wno-float-equal" - "-Wno-format-nonliteral" - "-Wno-gcc-compat" - "-Wno-global-constructors" - "-Wno-exit-time-destructors" - "-Wno-non-modular-include-in-module" - "-Wno-old-style-cast" - "-Wno-range-loop-analysis" - "-Wno-reserved-id-macro" - "-Wno-shorten-64-to-32" - "-Wno-switch-enum" - "-Wno-thread-safety-negative" - "-Wno-unknown-warning-option" - "-Wno-unreachable-code" - "-Wno-unused-macros" - "-Wno-weak-vtables" - "-Wno-zero-as-null-pointer-constant" - "-Wbitfield-enum-conversion" - "-Wbool-conversion" - "-Wconstant-conversion" - "-Wenum-conversion" - "-Wint-conversion" + "-Wcast-qual" + "-Wconversion" + "-Wfloat-overflow-conversion" + "-Wfloat-zero-conversion" + "-Wfor-loop-analysis" + "-Wformat-security" + "-Wgnu-redeclared-enum" + "-Winfinite-recursion" + "-Winvalid-constexpr" "-Wliteral-conversion" - "-Wnon-literal-null-conversion" - "-Wnull-conversion" - "-Wobjc-literal-conversion" - "-Wno-sign-conversion" + "-Wmissing-declarations" + "-Woverlength-strings" + "-Wpointer-arith" + "-Wself-assign" + "-Wshadow-all" "-Wstring-conversion" + "-Wtautological-overlap-compare" + "-Wundef" + "-Wuninitialized" + "-Wunreachable-code" + "-Wunused-comparison" + "-Wunused-local-typedefs" + "-Wunused-result" + "-Wvla" + "-Wwrite-strings" + "-Wno-float-conversion" + "-Wno-implicit-float-conversion" + "-Wno-implicit-int-float-conversion" + "-Wno-implicit-int-conversion" + "-Wno-shorten-64-to-32" + "-Wno-sign-conversion" + "-Wno-unknown-warning-option" + "-DNOMINMAX" ) list(APPEND ABSL_LLVM_TEST_FLAGS diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/copts/GENERATED_copts.bzl b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/copts/GENERATED_copts.bzl index 3cc487845c..a6efc98e11 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/copts/GENERATED_copts.bzl +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/copts/GENERATED_copts.bzl @@ -6,47 +6,6 @@ ABSL_CLANG_CL_FLAGS = [ "/W3", - "-Wno-c++98-compat-pedantic", - "-Wno-conversion", - "-Wno-covered-switch-default", - "-Wno-deprecated", - "-Wno-disabled-macro-expansion", - "-Wno-double-promotion", - "-Wno-comma", - "-Wno-extra-semi", - "-Wno-extra-semi-stmt", - "-Wno-packed", - "-Wno-padded", - "-Wno-sign-compare", - "-Wno-float-conversion", - "-Wno-float-equal", - "-Wno-format-nonliteral", - "-Wno-gcc-compat", - "-Wno-global-constructors", - "-Wno-exit-time-destructors", - "-Wno-non-modular-include-in-module", - "-Wno-old-style-cast", - "-Wno-range-loop-analysis", - "-Wno-reserved-id-macro", - "-Wno-shorten-64-to-32", - "-Wno-switch-enum", - "-Wno-thread-safety-negative", - "-Wno-unknown-warning-option", - "-Wno-unreachable-code", - "-Wno-unused-macros", - "-Wno-weak-vtables", - "-Wno-zero-as-null-pointer-constant", - "-Wbitfield-enum-conversion", - "-Wbool-conversion", - "-Wconstant-conversion", - "-Wenum-conversion", - "-Wint-conversion", - "-Wliteral-conversion", - "-Wnon-literal-null-conversion", - "-Wnull-conversion", - "-Wobjc-literal-conversion", - "-Wno-sign-conversion", - "-Wstring-conversion", "/DNOMINMAX", "/DWIN32_LEAN_AND_MEAN", "/D_CRT_SECURE_NO_WARNINGS", @@ -79,16 +38,17 @@ ABSL_GCC_FLAGS = [ "-Wextra", "-Wcast-qual", "-Wconversion-null", + "-Wformat-security", "-Wmissing-declarations", "-Woverlength-strings", "-Wpointer-arith", + "-Wundef", "-Wunused-local-typedefs", "-Wunused-result", "-Wvarargs", "-Wvla", "-Wwrite-strings", - "-Wno-missing-field-initializers", - "-Wno-sign-compare", + "-DNOMINMAX", ] ABSL_GCC_TEST_FLAGS = [ @@ -104,48 +64,39 @@ ABSL_GCC_TEST_FLAGS = [ ABSL_LLVM_FLAGS = [ "-Wall", "-Wextra", - "-Weverything", - "-Wno-c++98-compat-pedantic", - "-Wno-conversion", - "-Wno-covered-switch-default", - "-Wno-deprecated", - "-Wno-disabled-macro-expansion", - "-Wno-double-promotion", - "-Wno-comma", - "-Wno-extra-semi", - "-Wno-extra-semi-stmt", - "-Wno-packed", - "-Wno-padded", - "-Wno-sign-compare", - "-Wno-float-conversion", - "-Wno-float-equal", - "-Wno-format-nonliteral", - "-Wno-gcc-compat", - "-Wno-global-constructors", - "-Wno-exit-time-destructors", - "-Wno-non-modular-include-in-module", - "-Wno-old-style-cast", - "-Wno-range-loop-analysis", - "-Wno-reserved-id-macro", - "-Wno-shorten-64-to-32", - "-Wno-switch-enum", - "-Wno-thread-safety-negative", - "-Wno-unknown-warning-option", - "-Wno-unreachable-code", - "-Wno-unused-macros", - "-Wno-weak-vtables", - "-Wno-zero-as-null-pointer-constant", - "-Wbitfield-enum-conversion", - "-Wbool-conversion", - "-Wconstant-conversion", - "-Wenum-conversion", - "-Wint-conversion", + "-Wcast-qual", + "-Wconversion", + "-Wfloat-overflow-conversion", + "-Wfloat-zero-conversion", + "-Wfor-loop-analysis", + "-Wformat-security", + "-Wgnu-redeclared-enum", + "-Winfinite-recursion", + "-Winvalid-constexpr", "-Wliteral-conversion", - "-Wnon-literal-null-conversion", - "-Wnull-conversion", - "-Wobjc-literal-conversion", - "-Wno-sign-conversion", + "-Wmissing-declarations", + "-Woverlength-strings", + "-Wpointer-arith", + "-Wself-assign", + "-Wshadow-all", "-Wstring-conversion", + "-Wtautological-overlap-compare", + "-Wundef", + "-Wuninitialized", + "-Wunreachable-code", + "-Wunused-comparison", + "-Wunused-local-typedefs", + "-Wunused-result", + "-Wvla", + "-Wwrite-strings", + "-Wno-float-conversion", + "-Wno-implicit-float-conversion", + "-Wno-implicit-int-float-conversion", + "-Wno-implicit-int-conversion", + "-Wno-shorten-64-to-32", + "-Wno-sign-conversion", + "-Wno-unknown-warning-option", + "-DNOMINMAX", ] ABSL_LLVM_TEST_FLAGS = [ diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/copts/configure_copts.bzl b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/copts/configure_copts.bzl index ff9a5ea9f4..40d5849a3a 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/copts/configure_copts.bzl +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/copts/configure_copts.bzl @@ -22,21 +22,21 @@ load( ) ABSL_DEFAULT_COPTS = select({ - "//absl:windows": ABSL_MSVC_FLAGS, - "//absl:llvm_compiler": ABSL_LLVM_FLAGS, + "//absl:msvc_compiler": ABSL_MSVC_FLAGS, + "//absl:clang-cl_compiler": ABSL_CLANG_CL_FLAGS, + "//absl:clang_compiler": ABSL_LLVM_FLAGS, "//conditions:default": ABSL_GCC_FLAGS, }) -# in absence of modules (--compiler=gcc or -c opt), cc_tests leak their copts -# to their (included header) dependencies and fail to build outside absl ABSL_TEST_COPTS = ABSL_DEFAULT_COPTS + select({ - "//absl:windows": ABSL_MSVC_TEST_FLAGS, - "//absl:llvm_compiler": ABSL_LLVM_TEST_FLAGS, + "//absl:msvc_compiler": ABSL_MSVC_TEST_FLAGS, + "//absl:clang-cl_compiler": ABSL_CLANG_CL_TEST_FLAGS, + "//absl:clang_compiler": ABSL_LLVM_TEST_FLAGS, "//conditions:default": ABSL_GCC_TEST_FLAGS, }) ABSL_DEFAULT_LINKOPTS = select({ - "//absl:windows": ABSL_MSVC_LINKOPTS, + "//absl:msvc_compiler": ABSL_MSVC_LINKOPTS, "//conditions:default": [], }) @@ -50,6 +50,7 @@ ABSL_RANDOM_RANDEN_COPTS = select({ ":cpu_x64_windows": ABSL_RANDOM_HWAES_MSVC_X64_FLAGS, ":cpu_k8": ABSL_RANDOM_HWAES_X64_FLAGS, ":cpu_ppc": ["-mcrypto"], + ":cpu_aarch64": ABSL_RANDOM_HWAES_ARM64_FLAGS, # Supported by default or unsupported. "//conditions:default": [], @@ -70,6 +71,7 @@ def absl_random_randen_copts_init(): "darwin", "x64_windows_msvc", "x64_windows", + "aarch64", ] for cpu in cpu_configs: native.config_setting( diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/copts/copts.py b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/copts/copts.py index 704ef23450..0d6c1ec3a6 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/copts/copts.py +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/copts/copts.py @@ -16,77 +16,6 @@ MSVC_BIG_WARNING_FLAGS = [ "/W3", ] -LLVM_BIG_WARNING_FLAGS = [ - "-Wall", - "-Wextra", - "-Weverything", -] - -# Docs on single flags is preceded by a comment. -# Docs on groups of flags is preceded by ###. -LLVM_DISABLE_WARNINGS_FLAGS = [ - # Abseil does not support C++98 - "-Wno-c++98-compat-pedantic", - # Turns off all implicit conversion warnings. Most are re-enabled below. - "-Wno-conversion", - "-Wno-covered-switch-default", - "-Wno-deprecated", - "-Wno-disabled-macro-expansion", - "-Wno-double-promotion", - ### - # Turned off as they include valid C++ code. - "-Wno-comma", - "-Wno-extra-semi", - "-Wno-extra-semi-stmt", - "-Wno-packed", - "-Wno-padded", - ### - # Google style does not use unsigned integers, though STL containers - # have unsigned types. - "-Wno-sign-compare", - ### - "-Wno-float-conversion", - "-Wno-float-equal", - "-Wno-format-nonliteral", - # Too aggressive: warns on Clang extensions enclosed in Clang-only - # compilation paths. - "-Wno-gcc-compat", - ### - # Some internal globals are necessary. Don't do this at home. - "-Wno-global-constructors", - "-Wno-exit-time-destructors", - ### - "-Wno-non-modular-include-in-module", - "-Wno-old-style-cast", - # Warns on preferred usage of non-POD types such as string_view - "-Wno-range-loop-analysis", - "-Wno-reserved-id-macro", - "-Wno-shorten-64-to-32", - "-Wno-switch-enum", - "-Wno-thread-safety-negative", - "-Wno-unknown-warning-option", - "-Wno-unreachable-code", - # Causes warnings on include guards - "-Wno-unused-macros", - "-Wno-weak-vtables", - # Causes warnings on usage of types/compare.h comparison operators. - "-Wno-zero-as-null-pointer-constant", - ### - # Implicit conversion warnings turned off by -Wno-conversion - # which are re-enabled below. - "-Wbitfield-enum-conversion", - "-Wbool-conversion", - "-Wconstant-conversion", - "-Wenum-conversion", - "-Wint-conversion", - "-Wliteral-conversion", - "-Wnon-literal-null-conversion", - "-Wnull-conversion", - "-Wobjc-literal-conversion", - "-Wno-sign-conversion", - "-Wstring-conversion", -] - LLVM_TEST_DISABLE_WARNINGS_FLAGS = [ "-Wno-c99-extensions", "-Wno-deprecated-declarations", @@ -125,21 +54,18 @@ COPT_VARS = { "-Wextra", "-Wcast-qual", "-Wconversion-null", + "-Wformat-security", "-Wmissing-declarations", "-Woverlength-strings", "-Wpointer-arith", + "-Wundef", "-Wunused-local-typedefs", "-Wunused-result", "-Wvarargs", "-Wvla", # variable-length array "-Wwrite-strings", - # gcc-4.x has spurious missing field initializer warnings. - # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=36750 - # Remove when gcc-4.x is no longer supported. - "-Wno-missing-field-initializers", - # Google style does not use unsigned integers, though STL containers - # have unsigned types. - "-Wno-sign-compare", + # Don't define min and max macros (Build on Windows using gcc) + "-DNOMINMAX", ], "ABSL_GCC_TEST_FLAGS": [ "-Wno-conversion-null", @@ -150,12 +76,52 @@ COPT_VARS = { "-Wno-unused-parameter", "-Wno-unused-private-field", ], - "ABSL_LLVM_FLAGS": - LLVM_BIG_WARNING_FLAGS + LLVM_DISABLE_WARNINGS_FLAGS, + "ABSL_LLVM_FLAGS": [ + "-Wall", + "-Wextra", + "-Wcast-qual", + "-Wconversion", + "-Wfloat-overflow-conversion", + "-Wfloat-zero-conversion", + "-Wfor-loop-analysis", + "-Wformat-security", + "-Wgnu-redeclared-enum", + "-Winfinite-recursion", + "-Winvalid-constexpr", + "-Wliteral-conversion", + "-Wmissing-declarations", + "-Woverlength-strings", + "-Wpointer-arith", + "-Wself-assign", + "-Wshadow-all", + "-Wstring-conversion", + "-Wtautological-overlap-compare", + "-Wundef", + "-Wuninitialized", + "-Wunreachable-code", + "-Wunused-comparison", + "-Wunused-local-typedefs", + "-Wunused-result", + "-Wvla", + "-Wwrite-strings", + # Warnings that are enabled by group warning flags like -Wall that we + # explicitly disable. + "-Wno-float-conversion", + "-Wno-implicit-float-conversion", + "-Wno-implicit-int-float-conversion", + "-Wno-implicit-int-conversion", + "-Wno-shorten-64-to-32", + "-Wno-sign-conversion", + # Disable warnings on unknown warning flags (when warning flags are + # unknown on older compiler versions) + "-Wno-unknown-warning-option", + # Don't define min and max macros (Build on Windows using clang) + "-DNOMINMAX", + ], "ABSL_LLVM_TEST_FLAGS": LLVM_TEST_DISABLE_WARNINGS_FLAGS, "ABSL_CLANG_CL_FLAGS": - (MSVC_BIG_WARNING_FLAGS + LLVM_DISABLE_WARNINGS_FLAGS + MSVC_DEFINES), + (MSVC_BIG_WARNING_FLAGS + MSVC_DEFINES), "ABSL_CLANG_CL_TEST_FLAGS": LLVM_TEST_DISABLE_WARNINGS_FLAGS, "ABSL_MSVC_FLAGS": diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/copts/generate_copts.py b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/copts/generate_copts.py index 0e5dc9fad2..34be2fc23b 100755 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/copts/generate_copts.py +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/copts/generate_copts.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python3 """Generate Abseil compile compile option configs. Usage: /copts/generate_copts.py diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/BUILD.gn b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/BUILD.gn deleted file mode 100644 index 1681e54d9a..0000000000 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/BUILD.gn +++ /dev/null @@ -1,164 +0,0 @@ -# Copyright 2018 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -import("//build/config/sanitizers/sanitizers.gni") -import("//third_party/abseil-cpp/absl.gni") - -absl_source_set("stacktrace") { - sources = [ - "internal/stacktrace_aarch64-inl.inc", - "internal/stacktrace_arm-inl.inc", - "internal/stacktrace_config.h", - "internal/stacktrace_generic-inl.inc", - "internal/stacktrace_powerpc-inl.inc", - "internal/stacktrace_unimplemented-inl.inc", - "internal/stacktrace_win32-inl.inc", - "internal/stacktrace_x86-inl.inc", - "stacktrace.cc", - ] - public = [ "stacktrace.h" ] - deps = [ - ":debugging_internal", - "../base:config", - "../base:core_headers", - "../base:raw_logging_internal", - ] -} - -absl_source_set("symbolize") { - sources = [ - "symbolize.cc", - "symbolize_elf.inc", - "symbolize_unimplemented.inc", - "symbolize_win32.inc", - ] - public = [ - "internal/symbolize.h", - "symbolize.h", - ] - deps = [ - ":debugging_internal", - ":demangle_internal", - "../base", - "../base:config", - "../base:core_headers", - "../base:dynamic_annotations", - "../base:malloc_internal", - "../base:raw_logging_internal", - ] - - # TODO(mbonadei): The bazel file has: - # -DEFAULTLIB:dbghelp.lib - # evaluate if this needs to be added here as well. -} - -absl_source_set("examine_stack") { - sources = [ "internal/examine_stack.cc" ] - public = [ "internal/examine_stack.h" ] - visibility = [] - visibility += [ ":*" ] - deps = [ - ":stacktrace", - ":symbolize", - "../base:config", - "../base:core_headers", - "../base:raw_logging_internal", - ] -} - -absl_source_set("failure_signal_handler") { - sources = [ "failure_signal_handler.cc" ] - public = [ "failure_signal_handler.h" ] - deps = [ - ":examine_stack", - ":stacktrace", - "../base", - "../base:config", - "../base:core_headers", - "../base:errno_saver", - "../base:raw_logging_internal", - ] -} - -absl_source_set("debugging_internal") { - sources = [ - "internal/address_is_readable.cc", - "internal/elf_mem_image.cc", - "internal/vdso_support.cc", - ] - public = [ - "internal/address_is_readable.h", - "internal/elf_mem_image.h", - "internal/vdso_support.h", - ] - deps = [ - "../base:config", - "../base:core_headers", - "../base:dynamic_annotations", - "../base:errno_saver", - "../base:raw_logging_internal", - ] -} - -absl_source_set("demangle_internal") { - sources = [ "internal/demangle.cc" ] - public = [ "internal/demangle.h" ] - deps = [ - "../base", - "../base:config", - "../base:core_headers", - ] -} - -absl_source_set("leak_check") { - if (is_ios || is_win) { - sources = [] - public = [] - } else { - sources = [ "leak_check.cc" ] - public = [ "leak_check.h" ] - } - deps = [ - "../base:config", - "../base:core_headers", - ] -} - -absl_source_set("leak_check_disable") { - sources = [ "leak_check_disable.cc" ] - deps = [ "../base:config" ] -} - -if (is_lsan) { - absl_source_set("leak_check_api_enabled_for_testing") { - testonly = true - sources = [ "leak_check.cc" ] - public = [ "leak_check.h" ] - visibility = [] - visibility += [ ":*" ] - deps = [ "../base:config" ] - } -} else { - absl_source_set("leak_check_api_disabled_for_testing") { - testonly = true - sources = [ "leak_check.cc" ] - public = [ "leak_check.h" ] - visibility = [] - visibility += [ ":*" ] - deps = [ "../base:config" ] - } -} - -absl_source_set("stack_consumption") { - testonly = true - sources = [ "internal/stack_consumption.cc" ] - public = [ "internal/stack_consumption.h" ] - deps = [ - "../base:config", - "../base:core_headers", - "../base:raw_logging_internal", - ] - visibility = [] - visibility += [ ":*" ] -} diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/CMakeLists.txt b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/CMakeLists.txt index 7733615939..b16fa007e3 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/CMakeLists.txt +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/CMakeLists.txt @@ -22,8 +22,10 @@ absl_cc_library( "internal/stacktrace_aarch64-inl.inc" "internal/stacktrace_arm-inl.inc" "internal/stacktrace_config.h" + "internal/stacktrace_emscripten-inl.inc" "internal/stacktrace_generic-inl.inc" "internal/stacktrace_powerpc-inl.inc" + "internal/stacktrace_riscv-inl.inc" "internal/stacktrace_unimplemented-inl.inc" "internal/stacktrace_win32-inl.inc" "internal/stacktrace_x86-inl.inc" @@ -46,7 +48,9 @@ absl_cc_library( "internal/symbolize.h" SRCS "symbolize.cc" + "symbolize_darwin.inc" "symbolize_elf.inc" + "symbolize_emscripten.inc" "symbolize_unimplemented.inc" "symbolize_win32.inc" COPTS @@ -63,6 +67,7 @@ absl_cc_library( absl::dynamic_annotations absl::malloc_internal absl::raw_logging_internal + absl::strings PUBLIC ) @@ -80,10 +85,12 @@ absl_cc_test( absl::stack_consumption absl::symbolize absl::base + absl::config absl::core_headers absl::memory absl::raw_logging_internal - gmock + absl::strings + GTest::gmock ) absl_cc_library( @@ -137,7 +144,7 @@ absl_cc_test( absl::strings absl::raw_logging_internal Threads::Threads - gmock + GTest::gmock ) absl_cc_library( @@ -186,10 +193,11 @@ absl_cc_test( DEPS absl::demangle_internal absl::stack_consumption + absl::config absl::core_headers absl::memory absl::raw_logging_internal - gmock_main + GTest::gmock_main ) absl_cc_library( @@ -256,7 +264,7 @@ absl_cc_test( DEPS absl::leak_check_api_enabled_for_testing absl::base - gmock_main + GTest::gmock_main ) absl_cc_test( @@ -270,7 +278,7 @@ absl_cc_test( DEPS absl::leak_check_api_disabled_for_testing absl::base - gmock_main + GTest::gmock_main ) absl_cc_test( @@ -287,7 +295,7 @@ absl_cc_test( absl::leak_check_disable absl::base absl::raw_logging_internal - gmock_main + GTest::gmock_main ) absl_cc_library( @@ -317,7 +325,7 @@ absl_cc_test( absl::stack_consumption absl::core_headers absl::raw_logging_internal - gmock_main + GTest::gmock_main ) # component target diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/failure_signal_handler.cc b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/failure_signal_handler.cc index 1f69bfa84d..689e5979e7 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/failure_signal_handler.cc +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/failure_signal_handler.cc @@ -21,6 +21,7 @@ #ifdef _WIN32 #include #else +#include #include #endif @@ -135,9 +136,10 @@ static bool SetupAlternateStackOnce() { #else const size_t page_mask = sysconf(_SC_PAGESIZE) - 1; #endif - size_t stack_size = (std::max(SIGSTKSZ, 65536) + page_mask) & ~page_mask; -#if defined(ADDRESS_SANITIZER) || defined(MEMORY_SANITIZER) || \ - defined(THREAD_SANITIZER) + size_t stack_size = + (std::max(SIGSTKSZ, 65536) + page_mask) & ~page_mask; +#if defined(ABSL_HAVE_ADDRESS_SANITIZER) || \ + defined(ABSL_HAVE_MEMORY_SANITIZER) || defined(ABSL_HAVE_THREAD_SANITIZER) // Account for sanitizer instrumentation requiring additional stack space. stack_size *= 5; #endif @@ -219,17 +221,24 @@ static void WriteToStderr(const char* data) { absl::raw_logging_internal::SafeWriteToStderr(data, strlen(data)); } -static void WriteSignalMessage(int signo, void (*writerfn)(const char*)) { - char buf[64]; +static void WriteSignalMessage(int signo, int cpu, + void (*writerfn)(const char*)) { + char buf[96]; + char on_cpu[32] = {0}; + if (cpu != -1) { + snprintf(on_cpu, sizeof(on_cpu), " on cpu %d", cpu); + } const char* const signal_string = debugging_internal::FailureSignalToString(signo); if (signal_string != nullptr && signal_string[0] != '\0') { - snprintf(buf, sizeof(buf), "*** %s received at time=%ld ***\n", + snprintf(buf, sizeof(buf), "*** %s received at time=%ld%s ***\n", signal_string, - static_cast(time(nullptr))); // NOLINT(runtime/int) + static_cast(time(nullptr)), // NOLINT(runtime/int) + on_cpu); } else { - snprintf(buf, sizeof(buf), "*** Signal %d received at time=%ld ***\n", - signo, static_cast(time(nullptr))); // NOLINT(runtime/int) + snprintf(buf, sizeof(buf), "*** Signal %d received at time=%ld%s ***\n", + signo, static_cast(time(nullptr)), // NOLINT(runtime/int) + on_cpu); } writerfn(buf); } @@ -269,10 +278,10 @@ ABSL_ATTRIBUTE_NOINLINE static void WriteStackTrace( // Called by AbslFailureSignalHandler() to write the failure info. It is // called once with writerfn set to WriteToStderr() and then possibly // with writerfn set to the user provided function. -static void WriteFailureInfo(int signo, void* ucontext, +static void WriteFailureInfo(int signo, void* ucontext, int cpu, void (*writerfn)(const char*)) { WriterFnStruct writerfn_struct{writerfn}; - WriteSignalMessage(signo, writerfn); + WriteSignalMessage(signo, cpu, writerfn); WriteStackTrace(ucontext, fsh_options.symbolize_stacktrace, WriterFnWrapper, &writerfn_struct); } @@ -334,6 +343,14 @@ static void AbslFailureSignalHandler(int signo, siginfo_t*, void* ucontext) { } } + // Increase the chance that the CPU we report was the same CPU on which the + // signal was received by doing this as early as possible, i.e. after + // verifying that this is not a recursive signal handler invocation. + int my_cpu = -1; +#ifdef ABSL_HAVE_SCHED_GETCPU + my_cpu = sched_getcpu(); +#endif + #ifdef ABSL_HAVE_ALARM // Set an alarm to abort the program in case this code hangs or deadlocks. if (fsh_options.alarm_on_failure_secs > 0) { @@ -344,12 +361,13 @@ static void AbslFailureSignalHandler(int signo, siginfo_t*, void* ucontext) { #endif // First write to stderr. - WriteFailureInfo(signo, ucontext, WriteToStderr); + WriteFailureInfo(signo, ucontext, my_cpu, WriteToStderr); // Riskier code (because it is less likely to be async-signal-safe) // goes after this point. if (fsh_options.writerfn != nullptr) { - WriteFailureInfo(signo, ucontext, fsh_options.writerfn); + WriteFailureInfo(signo, ucontext, my_cpu, fsh_options.writerfn); + fsh_options.writerfn(nullptr); } if (fsh_options.call_previous_handler) { diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/failure_signal_handler.h b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/failure_signal_handler.h index 0c0f585d0f..500115c0ab 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/failure_signal_handler.h +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/failure_signal_handler.h @@ -90,7 +90,7 @@ struct FailureSignalHandlerOptions { // If non-null, indicates a pointer to a callback function that will be called // upon failure, with a string argument containing failure data. This function // may be used as a hook to write failure data to a secondary location, such - // as a log file. This function may also be called with null data, as a hint + // as a log file. This function will also be called with null data, as a hint // to flush any buffered data before the program may be terminated. Consider // flushing any buffered data in all calls to this function. // diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/failure_signal_handler_test.cc b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/failure_signal_handler_test.cc index 863fb5149e..6a62428b33 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/failure_signal_handler_test.cc +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/failure_signal_handler_test.cc @@ -55,7 +55,7 @@ TEST_P(FailureSignalHandlerDeathTest, AbslFailureSignal) { exit_regex); #else // Windows doesn't have testing::KilledBySignal(). - EXPECT_DEATH(InstallHandlerAndRaise(signo), exit_regex); + EXPECT_DEATH_IF_SUPPORTED(InstallHandlerAndRaise(signo), exit_regex); #endif } @@ -107,8 +107,8 @@ TEST_P(FailureSignalHandlerDeathTest, AbslFatalSignalsWithWriterFn) { testing::KilledBySignal(signo), exit_regex); #else // Windows doesn't have testing::KilledBySignal(). - EXPECT_DEATH(InstallHandlerWithWriteToFileAndRaise(file.c_str(), signo), - exit_regex); + EXPECT_DEATH_IF_SUPPORTED( + InstallHandlerWithWriteToFileAndRaise(file.c_str(), signo), exit_regex); #endif // Open the file in this process and check its contents. @@ -122,6 +122,12 @@ TEST_P(FailureSignalHandlerDeathTest, AbslFatalSignalsWithWriterFn) { "*** ", absl::debugging_internal::FailureSignalToString(signo), " received at "))); + // On platforms where it is possible to get the current CPU, the + // CPU number is also logged. Check that it is present in output. +#if defined(__linux__) + EXPECT_THAT(error_line, testing::HasSubstr(" on cpu ")); +#endif + if (absl::debugging_internal::StackTraceWorksForTest()) { std::getline(error_output, error_line); EXPECT_THAT(error_line, StartsWith("PC: ")); diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/internal/address_is_readable.cc b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/internal/address_is_readable.cc index 6537606366..329c285f3b 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/internal/address_is_readable.cc +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/internal/address_is_readable.cc @@ -68,6 +68,7 @@ static void Unpack(uint64_t x, int *pid, int *read_fd, int *write_fd) { // unimplemented. // This is a namespace-scoped variable for correct zero-initialization. static std::atomic pid_and_fds; // initially 0, an invalid pid. + bool AddressIsReadable(const void *addr) { absl::base_internal::ErrnoSaver errno_saver; // We test whether a byte is readable by using write(). Normally, this would @@ -86,7 +87,7 @@ bool AddressIsReadable(const void *addr) { int pid; int read_fd; int write_fd; - uint64_t local_pid_and_fds = pid_and_fds.load(std::memory_order_relaxed); + uint64_t local_pid_and_fds = pid_and_fds.load(std::memory_order_acquire); Unpack(local_pid_and_fds, &pid, &read_fd, &write_fd); while (current_pid != pid) { int p[2]; @@ -98,13 +99,13 @@ bool AddressIsReadable(const void *addr) { fcntl(p[1], F_SETFD, FD_CLOEXEC); uint64_t new_pid_and_fds = Pack(current_pid, p[0], p[1]); if (pid_and_fds.compare_exchange_strong( - local_pid_and_fds, new_pid_and_fds, std::memory_order_relaxed, + local_pid_and_fds, new_pid_and_fds, std::memory_order_release, std::memory_order_relaxed)) { local_pid_and_fds = new_pid_and_fds; // fds exposed to other threads } else { // fds not exposed to other threads; we can close them. close(p[0]); close(p[1]); - local_pid_and_fds = pid_and_fds.load(std::memory_order_relaxed); + local_pid_and_fds = pid_and_fds.load(std::memory_order_acquire); } Unpack(local_pid_and_fds, &pid, &read_fd, &write_fd); } @@ -124,7 +125,7 @@ bool AddressIsReadable(const void *addr) { // If pid_and_fds contains the problematic file descriptors we just used, // this call will forget them, and the loop will try again. pid_and_fds.compare_exchange_strong(local_pid_and_fds, 0, - std::memory_order_relaxed, + std::memory_order_release, std::memory_order_relaxed); } } while (errno == EBADF); diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/internal/demangle.cc b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/internal/demangle.cc index fc262e50ae..93ae32796c 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/internal/demangle.cc +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/internal/demangle.cc @@ -126,6 +126,7 @@ static const AbbrevPair kBuiltinTypeList[] = { {"Dn", "std::nullptr_t", 0}, // i.e., decltype(nullptr) {"Df", "decimal32", 0}, // IEEE 754r decimal floating point (32 bits) {"Di", "char32_t", 0}, + {"Du", "char8_t", 0}, {"Ds", "char16_t", 0}, {"Dh", "float16", 0}, // IEEE 754r half-precision float (16 bits) {nullptr, nullptr, 0}, @@ -385,30 +386,35 @@ static bool IsDigit(char c) { return c >= '0' && c <= '9'; } // by GCC 4.5.x and later versions (and our locally-modified version of GCC // 4.4.x) to indicate functions which have been cloned during optimization. // We treat any sequence (.+.+)+ as a function clone suffix. +// Additionally, '_' is allowed along with the alphanumeric sequence. static bool IsFunctionCloneSuffix(const char *str) { size_t i = 0; while (str[i] != '\0') { - // Consume a single .+.+ sequence. - if (str[i] != '.' || !IsAlpha(str[i + 1])) { + bool parsed = false; + // Consume a single [. | _]*[.]* sequence. + if (str[i] == '.' && (IsAlpha(str[i + 1]) || str[i + 1] == '_')) { + parsed = true; + i += 2; + while (IsAlpha(str[i]) || str[i] == '_') { + ++i; + } + } + if (str[i] == '.' && IsDigit(str[i + 1])) { + parsed = true; + i += 2; + while (IsDigit(str[i])) { + ++i; + } + } + if (!parsed) return false; - } - i += 2; - while (IsAlpha(str[i])) { - ++i; - } - if (str[i] != '.' || !IsDigit(str[i + 1])) { - return false; - } - i += 2; - while (IsDigit(str[i])) { - ++i; - } } return true; // Consumed everything in "str". } static bool EndsWith(State *state, const char chr) { return state->parse_state.out_cur_idx > 0 && + state->parse_state.out_cur_idx < state->out_end_idx && chr == state->out[state->parse_state.out_cur_idx - 1]; } @@ -421,8 +427,10 @@ static void MaybeAppendWithLength(State *state, const char *const str, if (str[0] == '<' && EndsWith(state, '<')) { Append(state, " ", 1); } - // Remember the last identifier name for ctors/dtors. - if (IsAlpha(str[0]) || str[0] == '_') { + // Remember the last identifier name for ctors/dtors, + // but only if we haven't yet overflown the buffer. + if (state->parse_state.out_cur_idx < state->out_end_idx && + (IsAlpha(str[0]) || str[0] == '_')) { state->parse_state.prev_name_idx = state->parse_state.out_cur_idx; state->parse_state.prev_name_length = length; } @@ -962,6 +970,7 @@ static bool ParseOperatorName(State *state, int *arity) { // ::= TT // ::= TI // ::= TS +// ::= TH # thread-local // ::= Tc <(base) encoding> // ::= GV <(object) name> // ::= T <(base) encoding> @@ -980,7 +989,7 @@ static bool ParseSpecialName(State *state) { ComplexityGuard guard(state); if (guard.IsTooComplex()) return false; ParseState copy = state->parse_state; - if (ParseOneCharToken(state, 'T') && ParseCharClass(state, "VTIS") && + if (ParseOneCharToken(state, 'T') && ParseCharClass(state, "VTISH") && ParseType(state)) { return true; } @@ -1077,20 +1086,28 @@ static bool ParseVOffset(State *state) { return false; } -// ::= C1 | C2 | C3 +// ::= C1 | C2 | C3 | CI1 | CI2 +// // ::= D0 | D1 | D2 // # GCC extensions: "unified" constructor/destructor. See -// # https://github.com/gcc-mirror/gcc/blob/7ad17b583c3643bd4557f29b8391ca7ef08391f5/gcc/cp/mangle.c#L1847 +// # +// https://github.com/gcc-mirror/gcc/blob/7ad17b583c3643bd4557f29b8391ca7ef08391f5/gcc/cp/mangle.c#L1847 // ::= C4 | D4 static bool ParseCtorDtorName(State *state) { ComplexityGuard guard(state); if (guard.IsTooComplex()) return false; ParseState copy = state->parse_state; - if (ParseOneCharToken(state, 'C') && ParseCharClass(state, "1234")) { - const char *const prev_name = state->out + state->parse_state.prev_name_idx; - MaybeAppendWithLength(state, prev_name, - state->parse_state.prev_name_length); - return true; + if (ParseOneCharToken(state, 'C')) { + if (ParseCharClass(state, "1234")) { + const char *const prev_name = + state->out + state->parse_state.prev_name_idx; + MaybeAppendWithLength(state, prev_name, + state->parse_state.prev_name_length); + return true; + } else if (ParseOneCharToken(state, 'I') && ParseCharClass(state, "12") && + ParseClassEnumType(state)) { + return true; + } } state->parse_state = copy; @@ -1139,6 +1156,7 @@ static bool ParseDecltype(State *state) { // ::= // ::= // ::= Dp # pack expansion of (C++0x) +// ::= Dv _ # GNU vector extension // static bool ParseType(State *state) { ComplexityGuard guard(state); @@ -1205,6 +1223,12 @@ static bool ParseType(State *state) { return true; } + if (ParseTwoCharToken(state, "Dv") && ParseNumber(state, nullptr) && + ParseOneCharToken(state, '_')) { + return true; + } + state->parse_state = copy; + return false; } @@ -1253,13 +1277,42 @@ static bool ParseBuiltinType(State *state) { return false; } -// ::= F [Y] E +// ::= Do # non-throwing +// exception-specification (e.g., +// noexcept, throw()) +// ::= DO E # computed (instantiation-dependent) +// noexcept +// ::= Dw + E # dynamic exception specification +// with instantiation-dependent types +static bool ParseExceptionSpec(State *state) { + ComplexityGuard guard(state); + if (guard.IsTooComplex()) return false; + + if (ParseTwoCharToken(state, "Do")) return true; + + ParseState copy = state->parse_state; + if (ParseTwoCharToken(state, "DO") && ParseExpression(state) && + ParseOneCharToken(state, 'E')) { + return true; + } + state->parse_state = copy; + if (ParseTwoCharToken(state, "Dw") && OneOrMore(ParseType, state) && + ParseOneCharToken(state, 'E')) { + return true; + } + state->parse_state = copy; + + return false; +} + +// ::= [exception-spec] F [Y] [O] E static bool ParseFunctionType(State *state) { ComplexityGuard guard(state); if (guard.IsTooComplex()) return false; ParseState copy = state->parse_state; - if (ParseOneCharToken(state, 'F') && + if (Optional(ParseExceptionSpec(state)) && ParseOneCharToken(state, 'F') && Optional(ParseOneCharToken(state, 'Y')) && ParseBareFunctionType(state) && + Optional(ParseOneCharToken(state, 'O')) && ParseOneCharToken(state, 'E')) { return true; } @@ -1564,6 +1617,7 @@ static bool ParseUnresolvedName(State *state) { // ::= <2-ary operator-name> // ::= <3-ary operator-name> // ::= cl + E +// ::= cp * E # Clang-specific. // ::= cv # type (expression) // ::= cv _ * E # type (expr-list) // ::= st @@ -1586,14 +1640,23 @@ static bool ParseExpression(State *state) { return true; } - // Object/function call expression. ParseState copy = state->parse_state; + + // Object/function call expression. if (ParseTwoCharToken(state, "cl") && OneOrMore(ParseExpression, state) && ParseOneCharToken(state, 'E')) { return true; } state->parse_state = copy; + // Clang-specific "cp * E" + // https://clang.llvm.org/doxygen/ItaniumMangle_8cpp_source.html#l04338 + if (ParseTwoCharToken(state, "cp") && ParseSimpleId(state) && + ZeroOrMore(ParseExpression, state) && ParseOneCharToken(state, 'E')) { + return true; + } + state->parse_state = copy; + // Function-param expression (level 0). if (ParseTwoCharToken(state, "fp") && Optional(ParseCVQualifiers(state)) && Optional(ParseNumber(state, nullptr)) && ParseOneCharToken(state, '_')) { @@ -1887,7 +1950,8 @@ static bool Overflowed(const State *state) { bool Demangle(const char *mangled, char *out, int out_size) { State state; InitState(&state, mangled, out, out_size); - return ParseTopLevelMangledName(&state) && !Overflowed(&state); + return ParseTopLevelMangledName(&state) && !Overflowed(&state) && + state.parse_state.out_cur_idx > 0; } } // namespace debugging_internal diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/internal/demangle_test.cc b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/internal/demangle_test.cc index c6f1ce184c..6b142902ca 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/internal/demangle_test.cc +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/internal/demangle_test.cc @@ -18,6 +18,7 @@ #include #include "gtest/gtest.h" +#include "absl/base/config.h" #include "absl/base/internal/raw_logging.h" #include "absl/debugging/internal/stack_consumption.h" #include "absl/memory/memory.h" @@ -69,12 +70,34 @@ TEST(Demangle, Clones) { EXPECT_STREQ("Foo()", tmp); EXPECT_TRUE(Demangle("_ZL3Foov.isra.2.constprop.18", tmp, sizeof(tmp))); EXPECT_STREQ("Foo()", tmp); - // Invalid (truncated), should not demangle. - EXPECT_FALSE(Demangle("_ZL3Foov.clo", tmp, sizeof(tmp))); + // Demangle suffixes produced by -funique-internal-linkage-names. + EXPECT_TRUE(Demangle("_ZL3Foov.__uniq.12345", tmp, sizeof(tmp))); + EXPECT_STREQ("Foo()", tmp); + EXPECT_TRUE(Demangle("_ZL3Foov.__uniq.12345.isra.2.constprop.18", tmp, + sizeof(tmp))); + EXPECT_STREQ("Foo()", tmp); + // Suffixes without the number should also demangle. + EXPECT_TRUE(Demangle("_ZL3Foov.clo", tmp, sizeof(tmp))); + EXPECT_STREQ("Foo()", tmp); + // Suffixes with just the number should also demangle. + EXPECT_TRUE(Demangle("_ZL3Foov.123", tmp, sizeof(tmp))); + EXPECT_STREQ("Foo()", tmp); + // (.clone. followed by non-number), should also demangle. + EXPECT_TRUE(Demangle("_ZL3Foov.clone.foo", tmp, sizeof(tmp))); + EXPECT_STREQ("Foo()", tmp); + // (.clone. followed by multiple numbers), should also demangle. + EXPECT_TRUE(Demangle("_ZL3Foov.clone.123.456", tmp, sizeof(tmp))); + EXPECT_STREQ("Foo()", tmp); + // (a long valid suffix), should demangle. + EXPECT_TRUE(Demangle("_ZL3Foov.part.9.165493.constprop.775.31805", tmp, + sizeof(tmp))); + EXPECT_STREQ("Foo()", tmp); + // Invalid (. without anything else), should not demangle. + EXPECT_FALSE(Demangle("_ZL3Foov.", tmp, sizeof(tmp))); + // Invalid (. with mix of alpha and digits), should not demangle. + EXPECT_FALSE(Demangle("_ZL3Foov.abc123", tmp, sizeof(tmp))); // Invalid (.clone. not followed by number), should not demangle. EXPECT_FALSE(Demangle("_ZL3Foov.clone.", tmp, sizeof(tmp))); - // Invalid (.clone. followed by non-number), should not demangle. - EXPECT_FALSE(Demangle("_ZL3Foov.clone.foo", tmp, sizeof(tmp))); // Invalid (.constprop. not followed by number), should not demangle. EXPECT_FALSE(Demangle("_ZL3Foov.isra.2.constprop.", tmp, sizeof(tmp))); } @@ -82,9 +105,10 @@ TEST(Demangle, Clones) { // Tests that verify that Demangle footprint is within some limit. // They are not to be run under sanitizers as the sanitizers increase // stack consumption by about 4x. -#if defined(ABSL_INTERNAL_HAVE_DEBUGGING_STACK_CONSUMPTION) && \ - !defined(ADDRESS_SANITIZER) && !defined(MEMORY_SANITIZER) && \ - !defined(THREAD_SANITIZER) +#if defined(ABSL_INTERNAL_HAVE_DEBUGGING_STACK_CONSUMPTION) && \ + !defined(ABSL_HAVE_ADDRESS_SANITIZER) && \ + !defined(ABSL_HAVE_MEMORY_SANITIZER) && \ + !defined(ABSL_HAVE_THREAD_SANITIZER) static const char *g_mangled; static char g_demangle_buffer[4096]; diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/internal/examine_stack.cc b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/internal/examine_stack.cc index a3dd893a9d..589a3ef367 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/internal/examine_stack.cc +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/internal/examine_stack.cc @@ -20,6 +20,10 @@ #include #endif +#ifdef __APPLE__ +#include +#endif + #include #include @@ -42,28 +46,70 @@ void* GetProgramCounter(void* vuc) { ucontext_t* context = reinterpret_cast(vuc); #if defined(__aarch64__) return reinterpret_cast(context->uc_mcontext.pc); +#elif defined(__alpha__) + return reinterpret_cast(context->uc_mcontext.sc_pc); #elif defined(__arm__) return reinterpret_cast(context->uc_mcontext.arm_pc); +#elif defined(__hppa__) + return reinterpret_cast(context->uc_mcontext.sc_iaoq[0]); #elif defined(__i386__) if (14 < ABSL_ARRAYSIZE(context->uc_mcontext.gregs)) return reinterpret_cast(context->uc_mcontext.gregs[14]); +#elif defined(__ia64__) + return reinterpret_cast(context->uc_mcontext.sc_ip); +#elif defined(__m68k__) + return reinterpret_cast(context->uc_mcontext.gregs[16]); #elif defined(__mips__) return reinterpret_cast(context->uc_mcontext.pc); #elif defined(__powerpc64__) return reinterpret_cast(context->uc_mcontext.gp_regs[32]); #elif defined(__powerpc__) - return reinterpret_cast(context->uc_mcontext.regs->nip); + return reinterpret_cast(context->uc_mcontext.uc_regs->gregs[32]); #elif defined(__riscv) return reinterpret_cast(context->uc_mcontext.__gregs[REG_PC]); #elif defined(__s390__) && !defined(__s390x__) return reinterpret_cast(context->uc_mcontext.psw.addr & 0x7fffffff); #elif defined(__s390__) && defined(__s390x__) return reinterpret_cast(context->uc_mcontext.psw.addr); +#elif defined(__sh__) + return reinterpret_cast(context->uc_mcontext.pc); +#elif defined(__sparc__) && !defined(__arch64__) + return reinterpret_cast(context->uc_mcontext.gregs[19]); +#elif defined(__sparc__) && defined(__arch64__) + return reinterpret_cast(context->uc_mcontext.mc_gregs[19]); #elif defined(__x86_64__) if (16 < ABSL_ARRAYSIZE(context->uc_mcontext.gregs)) return reinterpret_cast(context->uc_mcontext.gregs[16]); +#elif defined(__e2k__) + return reinterpret_cast(context->uc_mcontext.cr0_hi); #else #error "Undefined Architecture." +#endif + } +#elif defined(__APPLE__) + if (vuc != nullptr) { + ucontext_t* signal_ucontext = reinterpret_cast(vuc); +#if defined(__aarch64__) + return reinterpret_cast( + __darwin_arm_thread_state64_get_pc(signal_ucontext->uc_mcontext->__ss)); +#elif defined(__arm__) +#if __DARWIN_UNIX03 + return reinterpret_cast(signal_ucontext->uc_mcontext->__ss.__pc); +#else + return reinterpret_cast(signal_ucontext->uc_mcontext->ss.pc); +#endif +#elif defined(__i386__) +#if __DARWIN_UNIX03 + return reinterpret_cast(signal_ucontext->uc_mcontext->__ss.__eip); +#else + return reinterpret_cast(signal_ucontext->uc_mcontext->ss.eip); +#endif +#elif defined(__x86_64__) +#if __DARWIN_UNIX03 + return reinterpret_cast(signal_ucontext->uc_mcontext->__ss.__rip); +#else + return reinterpret_cast(signal_ucontext->uc_mcontext->ss.rip); +#endif #endif } #elif defined(__akaros__) diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/internal/stack_consumption.cc b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/internal/stack_consumption.cc index 875ca6d91f..513486498a 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/internal/stack_consumption.cc +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/internal/stack_consumption.cc @@ -42,7 +42,8 @@ namespace { // one of them is null, the results of pq, p<=q, and p>=q are // unspecified. Therefore, instead we hardcode the direction of the // stack on platforms we know about. -#if defined(__i386__) || defined(__x86_64__) || defined(__ppc__) +#if defined(__i386__) || defined(__x86_64__) || defined(__ppc__) || \ + defined(__aarch64__) || defined(__riscv) constexpr bool kStackGrowsDown = true; #else #error Need to define kStackGrowsDown diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/internal/stack_consumption.h b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/internal/stack_consumption.h index 5e60ec4229..f41b64c39d 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/internal/stack_consumption.h +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/internal/stack_consumption.h @@ -24,8 +24,9 @@ // Use this feature test macro to detect its availability. #ifdef ABSL_INTERNAL_HAVE_DEBUGGING_STACK_CONSUMPTION #error ABSL_INTERNAL_HAVE_DEBUGGING_STACK_CONSUMPTION cannot be set directly -#elif !defined(__APPLE__) && !defined(_WIN32) && \ - (defined(__i386__) || defined(__x86_64__) || defined(__ppc__)) +#elif !defined(__APPLE__) && !defined(_WIN32) && \ + (defined(__i386__) || defined(__x86_64__) || defined(__ppc__) || \ + defined(__aarch64__) || defined(__riscv)) #define ABSL_INTERNAL_HAVE_DEBUGGING_STACK_CONSUMPTION 1 namespace absl { diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/internal/stacktrace_aarch64-inl.inc b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/internal/stacktrace_aarch64-inl.inc index 14a76f1eb5..f4859d7c21 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/internal/stacktrace_aarch64-inl.inc +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/internal/stacktrace_aarch64-inl.inc @@ -37,8 +37,11 @@ static const unsigned char* GetKernelRtSigreturnAddress() { absl::debugging_internal::VDSOSupport vdso; if (vdso.IsPresent()) { absl::debugging_internal::VDSOSupport::SymbolInfo symbol_info; - if (!vdso.LookupSymbol("__kernel_rt_sigreturn", "LINUX_2.6.39", STT_FUNC, - &symbol_info) || + auto lookup = [&](int type) { + return vdso.LookupSymbol("__kernel_rt_sigreturn", "LINUX_2.6.39", type, + &symbol_info); + }; + if ((!lookup(STT_FUNC) && !lookup(STT_NOTYPE)) || symbol_info.address == nullptr) { // Unexpected: VDSO is present, yet the expected symbol is missing // or null. diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/internal/stacktrace_arm-inl.inc b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/internal/stacktrace_arm-inl.inc index fffda968dd..2a1bf2e886 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/internal/stacktrace_arm-inl.inc +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/internal/stacktrace_arm-inl.inc @@ -1,9 +1,18 @@ -// Copyright 2011 and onwards Google Inc. -// All rights reserved. +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. // -// Author: Doug Kwan // This is inspired by Craig Silverstein's PowerPC stacktrace code. -// #ifndef ABSL_DEBUGGING_INTERNAL_STACKTRACE_ARM_INL_H_ #define ABSL_DEBUGGING_INTERNAL_STACKTRACE_ARM_INL_H_ diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/internal/stacktrace_config.h b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/internal/stacktrace_config.h index d4e8480a8e..29b26bdd65 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/internal/stacktrace_config.h +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/internal/stacktrace_config.h @@ -21,6 +21,8 @@ #ifndef ABSL_DEBUGGING_INTERNAL_STACKTRACE_CONFIG_H_ #define ABSL_DEBUGGING_INTERNAL_STACKTRACE_CONFIG_H_ +#include "absl/base/config.h" + #if defined(ABSL_STACKTRACE_INL_HEADER) #error ABSL_STACKTRACE_INL_HEADER cannot be directly set @@ -28,43 +30,57 @@ #define ABSL_STACKTRACE_INL_HEADER \ "absl/debugging/internal/stacktrace_win32-inl.inc" +#elif defined(__APPLE__) +#ifdef ABSL_HAVE_THREAD_LOCAL +// Thread local support required for UnwindImpl. +#define ABSL_STACKTRACE_INL_HEADER \ + "absl/debugging/internal/stacktrace_generic-inl.inc" +#endif + +#elif defined(__EMSCRIPTEN__) +#define ABSL_STACKTRACE_INL_HEADER \ + "absl/debugging/internal/stacktrace_emscripten-inl.inc" + #elif defined(__linux__) && !defined(__ANDROID__) -#if !defined(NO_FRAME_POINTER) -# if defined(__i386__) || defined(__x86_64__) +#if defined(NO_FRAME_POINTER) && \ + (defined(__i386__) || defined(__x86_64__) || defined(__aarch64__)) +// Note: The libunwind-based implementation is not available to open-source +// users. #define ABSL_STACKTRACE_INL_HEADER \ - "absl/debugging/internal/stacktrace_x86-inl.inc" -# elif defined(__ppc__) || defined(__PPC__) -#define ABSL_STACKTRACE_INL_HEADER \ - "absl/debugging/internal/stacktrace_powerpc-inl.inc" -# elif defined(__aarch64__) -#define ABSL_STACKTRACE_INL_HEADER \ - "absl/debugging/internal/stacktrace_aarch64-inl.inc" -# elif defined(__arm__) + "absl/debugging/internal/stacktrace_libunwind-inl.inc" +#define STACKTRACE_USES_LIBUNWIND 1 +#elif defined(NO_FRAME_POINTER) && defined(__has_include) +#if __has_include() // Note: When using glibc this may require -funwind-tables to function properly. #define ABSL_STACKTRACE_INL_HEADER \ "absl/debugging/internal/stacktrace_generic-inl.inc" -# else +#endif +#elif defined(__i386__) || defined(__x86_64__) #define ABSL_STACKTRACE_INL_HEADER \ - "absl/debugging/internal/stacktrace_unimplemented-inl.inc" -# endif -#else // defined(NO_FRAME_POINTER) -# if defined(__i386__) || defined(__x86_64__) || defined(__aarch64__) + "absl/debugging/internal/stacktrace_x86-inl.inc" +#elif defined(__ppc__) || defined(__PPC__) #define ABSL_STACKTRACE_INL_HEADER \ - "absl/debugging/internal/stacktrace_generic-inl.inc" -# elif defined(__ppc__) || defined(__PPC__) + "absl/debugging/internal/stacktrace_powerpc-inl.inc" +#elif defined(__aarch64__) #define ABSL_STACKTRACE_INL_HEADER \ - "absl/debugging/internal/stacktrace_generic-inl.inc" -# else + "absl/debugging/internal/stacktrace_aarch64-inl.inc" +#elif defined(__riscv) #define ABSL_STACKTRACE_INL_HEADER \ - "absl/debugging/internal/stacktrace_unimplemented-inl.inc" -# endif -#endif // NO_FRAME_POINTER + "absl/debugging/internal/stacktrace_riscv-inl.inc" +#elif defined(__has_include) +#if __has_include() +// Note: When using glibc this may require -funwind-tables to function properly. +#define ABSL_STACKTRACE_INL_HEADER \ + "absl/debugging/internal/stacktrace_generic-inl.inc" +#endif +#endif +#endif -#else +// Fallback to the empty implementation. +#if !defined(ABSL_STACKTRACE_INL_HEADER) #define ABSL_STACKTRACE_INL_HEADER \ "absl/debugging/internal/stacktrace_unimplemented-inl.inc" - #endif #endif // ABSL_DEBUGGING_INTERNAL_STACKTRACE_CONFIG_H_ diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/internal/stacktrace_emscripten-inl.inc b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/internal/stacktrace_emscripten-inl.inc new file mode 100644 index 0000000000..0f44451438 --- /dev/null +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/internal/stacktrace_emscripten-inl.inc @@ -0,0 +1,110 @@ +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Portable implementation - just use glibc +// +// Note: The glibc implementation may cause a call to malloc. +// This can cause a deadlock in HeapProfiler. + +#ifndef ABSL_DEBUGGING_INTERNAL_STACKTRACE_EMSCRIPTEN_INL_H_ +#define ABSL_DEBUGGING_INTERNAL_STACKTRACE_EMSCRIPTEN_INL_H_ + +#include + +#include +#include + +#include "absl/base/attributes.h" +#include "absl/debugging/stacktrace.h" + +extern "C" { +uintptr_t emscripten_stack_snapshot(); +uint32_t emscripten_stack_unwind_buffer(uintptr_t pc, void *buffer, + uint32_t depth); +} + +// Sometimes, we can try to get a stack trace from within a stack +// trace, which can cause a self-deadlock. +// Protect against such reentrant call by failing to get a stack trace. +// +// We use __thread here because the code here is extremely low level -- it is +// called while collecting stack traces from within malloc and mmap, and thus +// can not call anything which might call malloc or mmap itself. +static __thread int recursive = 0; + +// The stack trace function might be invoked very early in the program's +// execution (e.g. from the very first malloc). +// As such, we suppress usage of backtrace during this early stage of execution. +static std::atomic disable_stacktraces(true); // Disabled until healthy. +// Waiting until static initializers run seems to be late enough. +// This file is included into stacktrace.cc so this will only run once. +ABSL_ATTRIBUTE_UNUSED static int stacktraces_enabler = []() { + // Check if we can even create stacktraces. If not, bail early and leave + // disable_stacktraces set as-is. + // clang-format off + if (!EM_ASM_INT({ return (typeof wasmOffsetConverter !== 'undefined'); })) { + return 0; + } + // clang-format on + disable_stacktraces.store(false, std::memory_order_relaxed); + return 0; +}(); + +template +static int UnwindImpl(void **result, int *sizes, int max_depth, int skip_count, + const void *ucp, int *min_dropped_frames) { + if (recursive || disable_stacktraces.load(std::memory_order_relaxed)) { + return 0; + } + ++recursive; + + static_cast(ucp); // Unused. + constexpr int kStackLength = 64; + void *stack[kStackLength]; + + int size; + uintptr_t pc = emscripten_stack_snapshot(); + size = emscripten_stack_unwind_buffer(pc, stack, kStackLength); + + int result_count = size - skip_count; + if (result_count < 0) result_count = 0; + if (result_count > max_depth) result_count = max_depth; + for (int i = 0; i < result_count; i++) result[i] = stack[i + skip_count]; + + if (IS_STACK_FRAMES) { + // No implementation for finding out the stack frame sizes yet. + memset(sizes, 0, sizeof(*sizes) * result_count); + } + if (min_dropped_frames != nullptr) { + if (size - skip_count - max_depth > 0) { + *min_dropped_frames = size - skip_count - max_depth; + } else { + *min_dropped_frames = 0; + } + } + + --recursive; + + return result_count; +} + +namespace absl { +ABSL_NAMESPACE_BEGIN +namespace debugging_internal { +bool StackTraceWorksForTest() { return true; } +} // namespace debugging_internal +ABSL_NAMESPACE_END +} // namespace absl + +#endif // ABSL_DEBUGGING_INTERNAL_STACKTRACE_EMSCRIPTEN_INL_H_ diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/internal/stacktrace_generic-inl.inc b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/internal/stacktrace_generic-inl.inc index ac034c9f5b..b2792a1f3a 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/internal/stacktrace_generic-inl.inc +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/internal/stacktrace_generic-inl.inc @@ -1,7 +1,16 @@ -// Copyright 2000 - 2007 Google Inc. -// All rights reserved. +// Copyright 2017 The Abseil Authors. // -// Author: Sanjay Ghemawat +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. // // Portable implementation - just use glibc // diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/internal/stacktrace_powerpc-inl.inc b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/internal/stacktrace_powerpc-inl.inc index 2e7c2f404f..cf8c05160c 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/internal/stacktrace_powerpc-inl.inc +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/internal/stacktrace_powerpc-inl.inc @@ -131,7 +131,12 @@ static void **NextStackFrame(void **old_sp, const void *uc) { const ucontext_t* signal_context = reinterpret_cast(uc); void **const sp_before_signal = - reinterpret_cast(signal_context->uc_mcontext.gp_regs[PT_R1]); +#if defined(__PPC64__) + reinterpret_cast(signal_context->uc_mcontext.gp_regs[PT_R1]); +#else + reinterpret_cast( + signal_context->uc_mcontext.uc_regs->gregs[PT_R1]); +#endif // Check that alleged sp before signal is nonnull and is reasonably // aligned. if (sp_before_signal != nullptr && diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/internal/stacktrace_riscv-inl.inc b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/internal/stacktrace_riscv-inl.inc new file mode 100644 index 0000000000..8cbc78548c --- /dev/null +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/internal/stacktrace_riscv-inl.inc @@ -0,0 +1,234 @@ +// Copyright 2021 The Abseil Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef ABSL_DEBUGGING_INTERNAL_STACKTRACE_RISCV_INL_H_ +#define ABSL_DEBUGGING_INTERNAL_STACKTRACE_RISCV_INL_H_ + +// Generate stack trace for riscv + +#include + +#include "absl/base/config.h" +#if defined(__linux__) +#include +#include +#include +#endif + +#include +#include +#include +#include + +#include "absl/base/attributes.h" +#include "absl/debugging/internal/address_is_readable.h" +#include "absl/debugging/internal/vdso_support.h" +#include "absl/debugging/stacktrace.h" + +static const uintptr_t kUnknownFrameSize = 0; + +#if defined(__linux__) +// Returns the address of the VDSO __kernel_rt_sigreturn function, if present. +static const unsigned char *GetKernelRtSigreturnAddress() { + constexpr uintptr_t kImpossibleAddress = 0; + ABSL_CONST_INIT static std::atomic memoized(kImpossibleAddress); + uintptr_t address = memoized.load(std::memory_order_relaxed); + if (address != kImpossibleAddress) { + return reinterpret_cast(address); + } + + address = reinterpret_cast(nullptr); + +#if ABSL_HAVE_VDSO_SUPPORT + absl::debugging_internal::VDSOSupport vdso; + if (vdso.IsPresent()) { + absl::debugging_internal::VDSOSupport::SymbolInfo symbol_info; + // Symbol versioning pulled from arch/riscv/kernel/vdso/vdso.lds at v5.10. + auto lookup = [&](int type) { + return vdso.LookupSymbol("__kernel_rt_sigreturn", "LINUX_4.15", type, + &symbol_info); + }; + if ((!lookup(STT_FUNC) && !lookup(STT_NOTYPE)) || + symbol_info.address == nullptr) { + // Unexpected: VDSO is present, yet the expected symbol is missing or + // null. + assert(false && "VDSO is present, but doesn't have expected symbol"); + } else { + if (reinterpret_cast(symbol_info.address) != + kImpossibleAddress) { + address = reinterpret_cast(symbol_info.address); + } else { + assert(false && "VDSO returned invalid address"); + } + } + } +#endif + + memoized.store(address, std::memory_order_relaxed); + return reinterpret_cast(address); +} +#endif // __linux__ + +// Compute the size of a stack frame in [low..high). We assume that low < high. +// Return size of kUnknownFrameSize. +template +static inline uintptr_t ComputeStackFrameSize(const T *low, const T *high) { + const char *low_char_ptr = reinterpret_cast(low); + const char *high_char_ptr = reinterpret_cast(high); + return low < high ? high_char_ptr - low_char_ptr : kUnknownFrameSize; +} + +// Given a pointer to a stack frame, locate and return the calling stackframe, +// or return null if no stackframe can be found. Perform sanity checks (the +// strictness of which is controlled by the boolean parameter +// "STRICT_UNWINDING") to reduce the chance that a bad pointer is returned. +template +ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS // May read random elements from stack. +ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY // May read random elements from stack. +static void ** NextStackFrame(void **old_frame_pointer, const void *uc) { + // . + // . + // . + // +-> +----------------+ + // | | return address | + // | | previous fp | + // | | ... | + // | +----------------+ <-+ + // | | return address | | + // +---|- previous fp | | + // | ... | | + // $fp ->|----------------+ | + // | return address | | + // | previous fp -|---+ + // $sp ->| ... | + // +----------------+ + void **new_frame_pointer = reinterpret_cast(old_frame_pointer[-2]); + bool check_frame_size = true; + +#if defined(__linux__) + if (WITH_CONTEXT && uc != nullptr) { + // Check to see if next frame's return address is __kernel_rt_sigreturn. + if (old_frame_pointer[-1] == GetKernelRtSigreturnAddress()) { + const ucontext_t *ucv = static_cast(uc); + // old_frame_pointer is not suitable for unwinding, look at ucontext to + // discover frame pointer before signal. + // + // RISCV ELF psABI has the frame pointer at x8/fp/s0. + // -- RISCV psABI Table 18.2 + void **const pre_signal_frame_pointer = + reinterpret_cast(ucv->uc_mcontext.__gregs[8]); + + // Check the alleged frame pointer is actually readable. This is to + // prevent "double fault" in case we hit the first fault due to stack + // corruption. + if (!absl::debugging_internal::AddressIsReadable( + pre_signal_frame_pointer)) + return nullptr; + + // Alleged frame pointer is readable, use it for further unwinding. + new_frame_pointer = pre_signal_frame_pointer; + + // Skip frame size check if we return from a signal. We may be using an + // alterate stack for signals. + check_frame_size = false; + } + } +#endif + + // The RISCV ELF psABI mandates that the stack pointer is always 16-byte + // aligned. + // FIXME(abdulras) this doesn't hold for ILP32E which only mandates a 4-byte + // alignment. + if ((reinterpret_cast(new_frame_pointer) & 15) != 0) + return nullptr; + + // Check frame size. In strict mode, we assume frames to be under 100,000 + // bytes. In non-strict mode, we relax the limit to 1MB. + if (check_frame_size) { + const uintptr_t max_size = STRICT_UNWINDING ? 100000 : 1000000; + const uintptr_t frame_size = + ComputeStackFrameSize(old_frame_pointer, new_frame_pointer); + if (frame_size == kUnknownFrameSize || frame_size > max_size) + return nullptr; + } + + return new_frame_pointer; +} + +template +ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS // May read random elements from stack. +ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY // May read random elements from stack. +static int UnwindImpl(void **result, int *sizes, int max_depth, int skip_count, + const void *ucp, int *min_dropped_frames) { +#if defined(__GNUC__) + void **frame_pointer = reinterpret_cast(__builtin_frame_address(0)); +#else +#error reading stack pointer not yet supported on this platform +#endif + + skip_count++; // Skip the frame for this function. + int n = 0; + + // The `frame_pointer` that is computed here points to the top of the frame. + // The two words preceding the address are the return address and the previous + // frame pointer. To find a PC value associated with the current frame, we + // need to go down a level in the call chain. So we remember the return + // address of the last frame seen. This does not work for the first stack + // frame, which belongs to `UnwindImp()` but we skip the frame for + // `UnwindImp()` anyway. + void *prev_return_address = nullptr; + + while (frame_pointer && n < max_depth) { + // The absl::GetStackFrames routine si called when we are in some + // informational context (the failure signal handler for example). Use the + // non-strict unwinding rules to produce a stack trace that is as complete + // as possible (even if it contains a few bogus entries in some rare cases). + void **next_frame_pointer = + NextStackFrame(frame_pointer, ucp); + + if (skip_count > 0) { + skip_count--; + } else { + result[n] = prev_return_address; + if (IS_STACK_FRAMES) { + sizes[n] = ComputeStackFrameSize(frame_pointer, next_frame_pointer); + } + n++; + } + prev_return_address = frame_pointer[-1]; + frame_pointer = next_frame_pointer; + } + if (min_dropped_frames != nullptr) { + // Implementation detail: we clamp the max of frames we are willing to + // count, so as not to spend too much time in the loop below. + const int kMaxUnwind = 200; + int j = 0; + for (; frame_pointer != nullptr && j < kMaxUnwind; j++) { + frame_pointer = + NextStackFrame(frame_pointer, ucp); + } + *min_dropped_frames = j; + } + return n; +} + +namespace absl { +ABSL_NAMESPACE_BEGIN +namespace debugging_internal { +bool StackTraceWorksForTest() { return true; } +} // namespace debugging_internal +ABSL_NAMESPACE_END +} // namespace absl + +#endif diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/internal/stacktrace_x86-inl.inc b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/internal/stacktrace_x86-inl.inc index bc320ff75b..70f79dfcb8 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/internal/stacktrace_x86-inl.inc +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/internal/stacktrace_x86-inl.inc @@ -132,9 +132,8 @@ static uintptr_t GetFP(const void *vuc) { const uintptr_t bp = 0; const uintptr_t sp = 0; #endif - // Sanity-check that the base pointer is valid. It should be as long as - // SHRINK_WRAP_FRAME_POINTER is not set, but it's possible that some code in - // the process is compiled with --copt=-fomit-frame-pointer or + // Sanity-check that the base pointer is valid. It's possible that some + // code in the process is compiled with --copt=-fomit-frame-pointer or // --copt=-momit-leaf-frame-pointer. // // TODO(bcmills): -momit-leaf-frame-pointer is currently the default @@ -247,7 +246,7 @@ static void **NextStackFrame(void **old_fp, const void *uc) { // using an alternate signal stack. // // TODO(bcmills): The GetFP call should be completely unnecessary when - // SHRINK_WRAP_FRAME_POINTER is set (because we should be back in the thread's + // ENABLE_COMBINED_UNWINDER is set (because we should be back in the thread's // stack by this point), but it is empirically still needed (e.g. when the // stack includes a call to abort). unw_get_reg returns UNW_EBADREG for some // frames. Figure out why GetValidFrameAddr and/or libunwind isn't doing what diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/internal/symbolize.h b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/internal/symbolize.h index 5d0858b5c7..27d5e6521e 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/internal/symbolize.h +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/internal/symbolize.h @@ -18,15 +18,18 @@ #ifndef ABSL_DEBUGGING_INTERNAL_SYMBOLIZE_H_ #define ABSL_DEBUGGING_INTERNAL_SYMBOLIZE_H_ +#ifdef __cplusplus + #include #include #include "absl/base/config.h" +#include "absl/strings/string_view.h" #ifdef ABSL_INTERNAL_HAVE_ELF_SYMBOLIZE #error ABSL_INTERNAL_HAVE_ELF_SYMBOLIZE cannot be directly set -#elif defined(__ELF__) && defined(__GLIBC__) && !defined(__native_client__) && \ - !defined(__asmjs__) && !defined(__wasm__) +#elif defined(__ELF__) && defined(__GLIBC__) && !defined(__native_client__) \ + && !defined(__asmjs__) && !defined(__wasm__) #define ABSL_INTERNAL_HAVE_ELF_SYMBOLIZE 1 #include @@ -45,7 +48,7 @@ namespace debugging_internal { // // This is not async-signal-safe. bool ForEachSection(int fd, - const std::function& callback); // Gets the section header for the given name, if it exists. Returns true on @@ -59,6 +62,18 @@ ABSL_NAMESPACE_END #endif // ABSL_INTERNAL_HAVE_ELF_SYMBOLIZE +#ifdef ABSL_INTERNAL_HAVE_DARWIN_SYMBOLIZE +#error ABSL_INTERNAL_HAVE_DARWIN_SYMBOLIZE cannot be directly set +#elif defined(__APPLE__) +#define ABSL_INTERNAL_HAVE_DARWIN_SYMBOLIZE 1 +#endif + +#ifdef ABSL_INTERNAL_HAVE_EMSCRIPTEN_SYMBOLIZE +#error ABSL_INTERNAL_HAVE_EMSCRIPTEN_SYMBOLIZE cannot be directly set +#elif defined(__EMSCRIPTEN__) +#define ABSL_INTERNAL_HAVE_EMSCRIPTEN_SYMBOLIZE 1 +#endif + namespace absl { ABSL_NAMESPACE_BEGIN namespace debugging_internal { @@ -109,20 +124,30 @@ bool RemoveAllSymbolDecorators(void); // filename != nullptr // // Returns true if the file was successfully registered. -bool RegisterFileMappingHint( - const void* start, const void* end, uint64_t offset, const char* filename); +bool RegisterFileMappingHint(const void* start, const void* end, + uint64_t offset, const char* filename); // Looks up the file mapping registered by RegisterFileMappingHint for an // address range. If there is one, the file name is stored in *filename and // *start and *end are modified to reflect the registered mapping. Returns // whether any hint was found. -bool GetFileMappingHint(const void** start, - const void** end, - uint64_t * offset, +bool GetFileMappingHint(const void** start, const void** end, uint64_t* offset, const char** filename); } // namespace debugging_internal ABSL_NAMESPACE_END } // namespace absl +#endif // __cplusplus + +#include + +#ifdef __cplusplus +extern "C" +#endif // __cplusplus + + bool + AbslInternalGetFileMappingHint(const void** start, const void** end, + uint64_t* offset, const char** filename); + #endif // ABSL_DEBUGGING_INTERNAL_SYMBOLIZE_H_ diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/internal/vdso_support.cc b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/internal/vdso_support.cc index b960cc47fc..6be16d9072 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/internal/vdso_support.cc +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/internal/vdso_support.cc @@ -76,15 +76,6 @@ const void *VDSOSupport::Init() { } #endif // __GLIBC_PREREQ(2, 16) if (vdso_base_.load(std::memory_order_relaxed) == kInvalidBase) { - // Valgrind zaps AT_SYSINFO_EHDR and friends from the auxv[] - // on stack, and so glibc works as if VDSO was not present. - // But going directly to kernel via /proc/self/auxv below bypasses - // Valgrind zapping. So we check for Valgrind separately. - if (AbslRunningOnValgrind()) { - vdso_base_.store(nullptr, std::memory_order_relaxed); - getcpu_fn_.store(&GetCPUViaSyscall, std::memory_order_relaxed); - return nullptr; - } int fd = open("/proc/self/auxv", O_RDONLY); if (fd == -1) { // Kernel too old to have a VDSO. @@ -175,18 +166,6 @@ int GetCPU() { return ret_code == 0 ? cpu : ret_code; } -// We need to make sure VDSOSupport::Init() is called before -// InitGoogle() does any setuid or chroot calls. If VDSOSupport -// is used in any global constructor, this will happen, since -// VDSOSupport's constructor calls Init. But if not, we need to -// ensure it here, with a global constructor of our own. This -// is an allowed exception to the normal rule against non-trivial -// global constructors. -static class VDSOInitHelper { - public: - VDSOInitHelper() { VDSOSupport::Init(); } -} vdso_init_helper; - } // namespace debugging_internal ABSL_NAMESPACE_END } // namespace absl diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/leak_check.cc b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/leak_check.cc index ff9049559d..764ca0ad00 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/leak_check.cc +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/leak_check.cc @@ -16,6 +16,7 @@ // When lsan is not linked in, these functions are not available, // therefore Abseil code which depends on these functions is conditioned on the // definition of LEAK_SANITIZER. +#include "absl/base/attributes.h" #include "absl/debugging/leak_check.h" #ifndef LEAK_SANITIZER @@ -23,6 +24,7 @@ namespace absl { ABSL_NAMESPACE_BEGIN bool HaveLeakSanitizer() { return false; } +bool LeakCheckerIsActive() { return false; } void DoIgnoreLeak(const void*) { } void RegisterLivePointers(const void*, size_t) { } void UnRegisterLivePointers(const void*, size_t) { } @@ -35,9 +37,23 @@ ABSL_NAMESPACE_END #include +#if ABSL_HAVE_ATTRIBUTE_WEAK +extern "C" ABSL_ATTRIBUTE_WEAK int __lsan_is_turned_off(); +#endif + namespace absl { ABSL_NAMESPACE_BEGIN bool HaveLeakSanitizer() { return true; } + +#if ABSL_HAVE_ATTRIBUTE_WEAK +bool LeakCheckerIsActive() { + return !(&__lsan_is_turned_off && __lsan_is_turned_off()); +} +#else +bool LeakCheckerIsActive() { return true; } +#endif + +bool FindAndReportLeaks() { return __lsan_do_recoverable_leak_check(); } void DoIgnoreLeak(const void* ptr) { __lsan_ignore_object(ptr); } void RegisterLivePointers(const void* ptr, size_t size) { __lsan_register_root_region(ptr, size); diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/leak_check.h b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/leak_check.h index 7a5a22dd1c..5fc2b052e4 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/leak_check.h +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/leak_check.h @@ -43,6 +43,12 @@ ABSL_NAMESPACE_BEGIN // currently built into this target. bool HaveLeakSanitizer(); +// LeakCheckerIsActive() +// +// Returns true if a leak-checking sanitizer (either ASan or standalone LSan) is +// currently built into this target and is turned on. +bool LeakCheckerIsActive(); + // DoIgnoreLeak() // // Implements `IgnoreLeak()` below. This function should usually @@ -62,7 +68,8 @@ void DoIgnoreLeak(const void* ptr); // // If the passed `ptr` does not point to an actively allocated object at the // time `IgnoreLeak()` is called, the call is a no-op; if it is actively -// allocated, the object must not get deallocated later. +// allocated, leak sanitizer will assume this object is referenced even if +// there is no actual reference in user memory. // template T* IgnoreLeak(T* ptr) { @@ -70,6 +77,19 @@ T* IgnoreLeak(T* ptr) { return ptr; } +// FindAndReportLeaks() +// +// If any leaks are detected, prints a leak report and returns true. This +// function may be called repeatedly, and does not affect end-of-process leak +// checking. +// +// Example: +// if (FindAndReportLeaks()) { +// ... diagnostic already printed. Exit with failure code. +// exit(1) +// } +bool FindAndReportLeaks(); + // LeakCheckDisabler // // This helper class indicates that any heap allocations done in the code block diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/leak_check_test.cc b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/leak_check_test.cc index b5cc487488..9fcfc8e50b 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/leak_check_test.cc +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/leak_check_test.cc @@ -23,8 +23,10 @@ namespace { TEST(LeakCheckTest, DetectLeakSanitizer) { #ifdef ABSL_EXPECT_LEAK_SANITIZER EXPECT_TRUE(absl::HaveLeakSanitizer()); + EXPECT_TRUE(absl::LeakCheckerIsActive()); #else EXPECT_FALSE(absl::HaveLeakSanitizer()); + EXPECT_FALSE(absl::LeakCheckerIsActive()); #endif } diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/stacktrace.cc b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/stacktrace.cc index 1f7c7d82b2..ff8069f843 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/stacktrace.cc +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/stacktrace.cc @@ -49,8 +49,10 @@ # include "absl/debugging/internal/stacktrace_aarch64-inl.inc" # include "absl/debugging/internal/stacktrace_arm-inl.inc" +# include "absl/debugging/internal/stacktrace_emscripten-inl.inc" # include "absl/debugging/internal/stacktrace_generic-inl.inc" # include "absl/debugging/internal/stacktrace_powerpc-inl.inc" +# include "absl/debugging/internal/stacktrace_riscv-inl.inc" # include "absl/debugging/internal/stacktrace_unimplemented-inl.inc" # include "absl/debugging/internal/stacktrace_win32-inl.inc" # include "absl/debugging/internal/stacktrace_x86-inl.inc" diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/symbolize.cc b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/symbolize.cc index 54ed97002a..f1abdfda59 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/symbolize.cc +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/symbolize.cc @@ -14,12 +14,25 @@ #include "absl/debugging/symbolize.h" +#ifdef _WIN32 +#include +#if !(WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP)) || \ + WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) +// UWP doesn't have access to win32 APIs. +#define ABSL_INTERNAL_HAVE_SYMBOLIZE_WIN32 +#endif +#endif + #if defined(ABSL_INTERNAL_HAVE_ELF_SYMBOLIZE) #include "absl/debugging/symbolize_elf.inc" -#elif defined(_WIN32) +#elif defined(ABSL_INTERNAL_HAVE_SYMBOLIZE_WIN32) // The Windows Symbolizer only works if PDB files containing the debug info // are available to the program at runtime. #include "absl/debugging/symbolize_win32.inc" +#elif defined(__APPLE__) +#include "absl/debugging/symbolize_darwin.inc" +#elif defined(__EMSCRIPTEN__) +#include "absl/debugging/symbolize_emscripten.inc" #else #include "absl/debugging/symbolize_unimplemented.inc" #endif diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/symbolize_darwin.inc b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/symbolize_darwin.inc new file mode 100644 index 0000000000..443ce9efc4 --- /dev/null +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/symbolize_darwin.inc @@ -0,0 +1,101 @@ +// Copyright 2020 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include + +#include +#include + +#include "absl/base/internal/raw_logging.h" +#include "absl/debugging/internal/demangle.h" +#include "absl/strings/numbers.h" +#include "absl/strings/str_cat.h" +#include "absl/strings/string_view.h" + +namespace absl { +ABSL_NAMESPACE_BEGIN + +void InitializeSymbolizer(const char*) {} + +namespace debugging_internal { +namespace { + +static std::string GetSymbolString(absl::string_view backtrace_line) { + // Example Backtrace lines: + // 0 libimaging_shared.dylib 0x018c152a + // _ZNSt11_Deque_baseIN3nik7mediadb4PageESaIS2_EE17_M_initialize_mapEm + 3478 + // + // or + // 0 libimaging_shared.dylib 0x0000000001895c39 + // _ZN3nik4util19register_shared_ptrINS_3gpu7TextureEEEvPKvS5_ + 39 + // + // or + // 0 mysterious_app 0x0124000120120009 main + 17 + auto address_pos = backtrace_line.find(" 0x"); + if (address_pos == absl::string_view::npos) return std::string(); + absl::string_view symbol_view = backtrace_line.substr(address_pos + 1); + + auto space_pos = symbol_view.find(" "); + if (space_pos == absl::string_view::npos) return std::string(); + symbol_view = symbol_view.substr(space_pos + 1); // to mangled symbol + + auto plus_pos = symbol_view.find(" + "); + if (plus_pos == absl::string_view::npos) return std::string(); + symbol_view = symbol_view.substr(0, plus_pos); // strip remainng + + return std::string(symbol_view); +} + +} // namespace +} // namespace debugging_internal + +bool Symbolize(const void* pc, char* out, int out_size) { + if (out_size <= 0 || pc == nullptr) { + out = nullptr; + return false; + } + + // This allocates a char* array. + char** frame_strings = backtrace_symbols(const_cast(&pc), 1); + + if (frame_strings == nullptr) return false; + + std::string symbol = debugging_internal::GetSymbolString(frame_strings[0]); + free(frame_strings); + + char tmp_buf[1024]; + if (debugging_internal::Demangle(symbol.c_str(), tmp_buf, sizeof(tmp_buf))) { + size_t len = strlen(tmp_buf); + if (len + 1 <= static_cast(out_size)) { // +1 for '\0' + assert(len < sizeof(tmp_buf)); + memmove(out, tmp_buf, len + 1); + } + } else { + strncpy(out, symbol.c_str(), out_size); + } + + if (out[out_size - 1] != '\0') { + // strncpy() does not '\0' terminate when it truncates. + static constexpr char kEllipsis[] = "..."; + int ellipsis_size = std::min(sizeof(kEllipsis) - 1, out_size - 1); + memcpy(out + out_size - ellipsis_size - 1, kEllipsis, ellipsis_size); + out[out_size - 1] = '\0'; + } + + return true; +} + +ABSL_NAMESPACE_END +} // namespace absl diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/symbolize_elf.inc b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/symbolize_elf.inc index 4a4f988a8e..87dbd078b9 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/symbolize_elf.inc +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/symbolize_elf.inc @@ -57,6 +57,7 @@ #include #include +#include #include #include #include @@ -74,6 +75,7 @@ #include "absl/base/port.h" #include "absl/debugging/internal/demangle.h" #include "absl/debugging/internal/vdso_support.h" +#include "absl/strings/string_view.h" namespace absl { ABSL_NAMESPACE_BEGIN @@ -82,6 +84,12 @@ ABSL_NAMESPACE_BEGIN static char *argv0_value = nullptr; void InitializeSymbolizer(const char *argv0) { +#ifdef ABSL_HAVE_VDSO_SUPPORT + // We need to make sure VDSOSupport::Init() is called before any setuid or + // chroot calls, so InitializeSymbolizer() should be called very early in the + // life of a program. + absl::debugging_internal::VDSOSupport::Init(); +#endif if (argv0_value != nullptr) { free(argv0_value); argv0_value = nullptr; @@ -149,13 +157,15 @@ struct FileMappingHint { // Moreover, we are using only TryLock(), if the decorator list // is being modified (is busy), we skip all decorators, and possibly // loose some info. Sorry, that's the best we could do. -base_internal::SpinLock g_decorators_mu(base_internal::kLinkerInitialized); +ABSL_CONST_INIT absl::base_internal::SpinLock g_decorators_mu( + absl::kConstInit, absl::base_internal::SCHEDULE_KERNEL_ONLY); const int kMaxFileMappingHints = 8; int g_num_file_mapping_hints; FileMappingHint g_file_mapping_hints[kMaxFileMappingHints]; // Protects g_file_mapping_hints. -base_internal::SpinLock g_file_mapping_mu(base_internal::kLinkerInitialized); +ABSL_CONST_INIT absl::base_internal::SpinLock g_file_mapping_mu( + absl::kConstInit, absl::base_internal::SCHEDULE_KERNEL_ONLY); // Async-signal-safe function to zero a buffer. // memset() is not guaranteed to be async-signal-safe. @@ -175,6 +185,7 @@ struct ObjFile { fd(-1), elf_type(-1) { SafeMemZero(&elf_header, sizeof(elf_header)); + SafeMemZero(&phdr[0], sizeof(phdr)); } char *filename; @@ -187,6 +198,10 @@ struct ObjFile { int fd; int elf_type; ElfW(Ehdr) elf_header; + + // PT_LOAD program header describing executable code. + // Normally we expect just one, but SWIFT binaries have two. + std::array phdr; }; // Build 4-way associative cache for symbols. Within each cache line, symbols @@ -496,7 +511,7 @@ static ABSL_ATTRIBUTE_NOINLINE bool GetSectionHeaderByType( const int kMaxSectionNameLen = 64; bool ForEachSection(int fd, - const std::function &callback) { ElfW(Ehdr) elf_header; if (!ReadFromOffsetExact(fd, &elf_header, sizeof(elf_header), 0)) { @@ -518,7 +533,7 @@ bool ForEachSection(int fd, return false; } off_t name_offset = shstrtab.sh_offset + out.sh_name; - char header_name[kMaxSectionNameLen + 1]; + char header_name[kMaxSectionNameLen]; ssize_t n_read = ReadFromOffset(fd, &header_name, kMaxSectionNameLen, name_offset); if (n_read == -1) { @@ -527,9 +542,8 @@ bool ForEachSection(int fd, // Long read? return false; } - header_name[n_read] = '\0'; - std::string name(header_name); + absl::string_view name(header_name, strnlen(header_name, n_read)); if (!callback(name, out)) { break; } @@ -687,6 +701,16 @@ static ABSL_ATTRIBUTE_NOINLINE FindSymbolResult FindSymbol( const char *start_address = ComputeOffset(original_start_address, relocation); +#ifdef __arm__ + // ARM functions are always aligned to multiples of two bytes; the + // lowest-order bit in start_address is ignored by the CPU and indicates + // whether the function contains ARM (0) or Thumb (1) code. We don't care + // about what encoding is being used; we just want the real start address + // of the function. + start_address = reinterpret_cast( + reinterpret_cast(start_address) & ~1); +#endif + if (deref_function_descriptor_pointer && InSection(original_start_address, opd)) { // The opd section is mapped into memory. Just dereference @@ -1264,6 +1288,36 @@ static bool MaybeInitializeObjFile(ObjFile *obj) { ABSL_RAW_LOG(WARNING, "%s: failed to read elf header", obj->filename); return false; } + const int phnum = obj->elf_header.e_phnum; + const int phentsize = obj->elf_header.e_phentsize; + size_t phoff = obj->elf_header.e_phoff; + size_t num_executable_load_segments = 0; + for (int j = 0; j < phnum; j++) { + ElfW(Phdr) phdr; + if (!ReadFromOffsetExact(obj->fd, &phdr, sizeof(phdr), phoff)) { + ABSL_RAW_LOG(WARNING, "%s: failed to read program header %d", + obj->filename, j); + return false; + } + phoff += phentsize; + constexpr int rx = PF_X | PF_R; + if (phdr.p_type != PT_LOAD || (phdr.p_flags & rx) != rx) { + // Not a LOAD segment, or not executable code. + continue; + } + if (num_executable_load_segments < obj->phdr.size()) { + memcpy(&obj->phdr[num_executable_load_segments++], &phdr, sizeof(phdr)); + } else { + ABSL_RAW_LOG(WARNING, "%s: too many executable LOAD segments", + obj->filename); + break; + } + } + if (num_executable_load_segments == 0) { + // This object has no "r-x" LOAD segments. That's unexpected. + ABSL_RAW_LOG(WARNING, "%s: no executable LOAD segments", obj->filename); + return false; + } } return true; } @@ -1287,23 +1341,52 @@ const char *Symbolizer::GetSymbol(const void *const pc) { int fd = -1; if (obj != nullptr) { if (MaybeInitializeObjFile(obj)) { - if (obj->elf_type == ET_DYN && - reinterpret_cast(obj->start_addr) >= obj->offset) { + const size_t start_addr = reinterpret_cast(obj->start_addr); + if (obj->elf_type == ET_DYN && start_addr >= obj->offset) { // This object was relocated. // // For obj->offset > 0, adjust the relocation since a mapping at offset // X in the file will have a start address of [true relocation]+X. - relocation = reinterpret_cast(obj->start_addr) - obj->offset; + relocation = start_addr - obj->offset; + + // Note: some binaries have multiple "rx" LOAD segments. We must + // find the right one. + ElfW(Phdr) *phdr = nullptr; + for (size_t j = 0; j < obj->phdr.size(); j++) { + ElfW(Phdr) &p = obj->phdr[j]; + if (p.p_type != PT_LOAD) { + // We only expect PT_LOADs. This must be PT_NULL that we didn't + // write over (i.e. we exhausted all interesting PT_LOADs). + ABSL_RAW_CHECK(p.p_type == PT_NULL, "unexpected p_type"); + break; + } + if (pc < reinterpret_cast(start_addr + p.p_memsz)) { + phdr = &p; + break; + } + } + if (phdr == nullptr) { + // That's unexpected. Hope for the best. + ABSL_RAW_LOG( + WARNING, + "%s: unable to find LOAD segment for pc: %p, start_addr: %zx", + obj->filename, pc, start_addr); + } else { + // Adjust relocation in case phdr.p_vaddr != 0. + // This happens for binaries linked with `lld --rosegment`, and for + // binaries linked with BFD `ld -z separate-code`. + relocation -= phdr->p_vaddr - phdr->p_offset; + } } fd = obj->fd; - } - if (GetSymbolFromObjectFile(*obj, pc, relocation, symbol_buf_, - sizeof(symbol_buf_), tmp_buf_, - sizeof(tmp_buf_)) == SYMBOL_FOUND) { - // Only try to demangle the symbol name if it fit into symbol_buf_. - DemangleInplace(symbol_buf_, sizeof(symbol_buf_), tmp_buf_, - sizeof(tmp_buf_)); + if (GetSymbolFromObjectFile(*obj, pc, relocation, symbol_buf_, + sizeof(symbol_buf_), tmp_buf_, + sizeof(tmp_buf_)) == SYMBOL_FOUND) { + // Only try to demangle the symbol name if it fit into symbol_buf_. + DemangleInplace(symbol_buf_, sizeof(symbol_buf_), tmp_buf_, + sizeof(tmp_buf_)); + } } } else { #if ABSL_HAVE_VDSO_SUPPORT @@ -1374,7 +1457,7 @@ int InstallSymbolDecorator(SymbolDecorator decorator, void *arg) { if (!g_decorators_mu.TryLock()) { // Someone else is using decorators. Get out. - return false; + return -2; } int ret = ticket; if (g_num_decorators >= kMaxDecorators) { @@ -1478,3 +1561,10 @@ bool Symbolize(const void *pc, char *out, int out_size) { ABSL_NAMESPACE_END } // namespace absl + +extern "C" bool AbslInternalGetFileMappingHint(const void **start, + const void **end, uint64_t *offset, + const char **filename) { + return absl::debugging_internal::GetFileMappingHint(start, end, offset, + filename); +} diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/symbolize_emscripten.inc b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/symbolize_emscripten.inc new file mode 100644 index 0000000000..c226c45666 --- /dev/null +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/symbolize_emscripten.inc @@ -0,0 +1,72 @@ +// Copyright 2020 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include + +#include +#include + +#include "absl/base/internal/raw_logging.h" +#include "absl/debugging/internal/demangle.h" +#include "absl/strings/numbers.h" +#include "absl/strings/str_cat.h" +#include "absl/strings/string_view.h" + +extern "C" { +const char* emscripten_pc_get_function(const void* pc); +} + +// clang-format off +EM_JS(bool, HaveOffsetConverter, (), + { return typeof wasmOffsetConverter !== 'undefined'; }); +// clang-format on + +namespace absl { +ABSL_NAMESPACE_BEGIN + +void InitializeSymbolizer(const char*) { + if (!HaveOffsetConverter()) { + ABSL_RAW_LOG(INFO, + "Symbolization unavailable. Rebuild with -sWASM=1 " + "and -sUSE_OFFSET_CONVERTER=1."); + } +} + +bool Symbolize(const void* pc, char* out, int out_size) { + // Check if we have the offset converter necessary for pc_get_function. + // Without it, the program will abort(). + if (!HaveOffsetConverter()) { + return false; + } + const char* func_name = emscripten_pc_get_function(pc); + if (func_name == nullptr) { + return false; + } + + strncpy(out, func_name, out_size); + + if (out[out_size - 1] != '\0') { + // strncpy() does not '\0' terminate when it truncates. + static constexpr char kEllipsis[] = "..."; + int ellipsis_size = std::min(sizeof(kEllipsis) - 1, out_size - 1); + memcpy(out + out_size - ellipsis_size - 1, kEllipsis, ellipsis_size); + out[out_size - 1] = '\0'; + } + + return true; +} + +ABSL_NAMESPACE_END +} // namespace absl diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/symbolize_test.cc b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/symbolize_test.cc index a1d03aab53..c710a3da81 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/symbolize_test.cc +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/debugging/symbolize_test.cc @@ -27,11 +27,13 @@ #include "gtest/gtest.h" #include "absl/base/attributes.h" #include "absl/base/casts.h" +#include "absl/base/config.h" #include "absl/base/internal/per_thread_tls.h" #include "absl/base/internal/raw_logging.h" #include "absl/base/optimization.h" #include "absl/debugging/internal/stack_consumption.h" #include "absl/memory/memory.h" +#include "absl/strings/string_view.h" using testing::Contains; @@ -144,7 +146,22 @@ static const char *TrySymbolize(void *pc) { return TrySymbolizeWithLimit(pc, sizeof(try_symbolize_buffer)); } -#ifdef ABSL_INTERNAL_HAVE_ELF_SYMBOLIZE +#if defined(ABSL_INTERNAL_HAVE_ELF_SYMBOLIZE) || \ + defined(ABSL_INTERNAL_HAVE_DARWIN_SYMBOLIZE) || \ + defined(ABSL_INTERNAL_HAVE_EMSCRIPTEN_SYMBOLIZE) + +// Test with a return address. +void ABSL_ATTRIBUTE_NOINLINE TestWithReturnAddress() { +#if defined(ABSL_HAVE_ATTRIBUTE_NOINLINE) + void *return_address = __builtin_return_address(0); + const char *symbol = TrySymbolize(return_address); + ABSL_RAW_CHECK(symbol != nullptr, "TestWithReturnAddress failed"); + ABSL_RAW_CHECK(strcmp(symbol, "main") == 0, "TestWithReturnAddress failed"); + std::cout << "TestWithReturnAddress passed" << std::endl; +#endif +} + +#ifndef ABSL_INTERNAL_HAVE_EMSCRIPTEN_SYMBOLIZE TEST(Symbolize, Cached) { // Compilers should give us pointers to them. @@ -218,8 +235,8 @@ static const char *SymbolizeStackConsumption(void *pc, int *stack_consumed) { static int GetStackConsumptionUpperLimit() { // Symbolize stack consumption should be within 2kB. int stack_consumption_upper_limit = 2048; -#if defined(ADDRESS_SANITIZER) || defined(MEMORY_SANITIZER) || \ - defined(THREAD_SANITIZER) +#if defined(ABSL_HAVE_ADDRESS_SANITIZER) || \ + defined(ABSL_HAVE_MEMORY_SANITIZER) || defined(ABSL_HAVE_THREAD_SANITIZER) // Account for sanitizer instrumentation requiring additional stack space. stack_consumption_upper_limit *= 5; #endif @@ -258,6 +275,7 @@ TEST(Symbolize, SymbolizeWithDemanglingStackConsumption) { #endif // ABSL_INTERNAL_HAVE_DEBUGGING_STACK_CONSUMPTION +#ifndef ABSL_INTERNAL_HAVE_DARWIN_SYMBOLIZE // Use a 64K page size for PPC. const size_t kPageSize = 64 << 10; // We place a read-only symbols into the .text section and verify that we can @@ -399,8 +417,8 @@ TEST(Symbolize, ForEachSection) { std::vector sections; ASSERT_TRUE(absl::debugging_internal::ForEachSection( - fd, [§ions](const std::string &name, const ElfW(Shdr) &) { - sections.push_back(name); + fd, [§ions](const absl::string_view name, const ElfW(Shdr) &) { + sections.emplace_back(name); return true; })); @@ -413,6 +431,8 @@ TEST(Symbolize, ForEachSection) { close(fd); } +#endif // !ABSL_INTERNAL_HAVE_DARWIN_SYMBOLIZE +#endif // !ABSL_INTERNAL_HAVE_EMSCRIPTEN_SYMBOLIZE // x86 specific tests. Uses some inline assembler. extern "C" { @@ -461,17 +481,46 @@ void ABSL_ATTRIBUTE_NOINLINE TestWithPCInsideInlineFunction() { } } -// Test with a return address. -void ABSL_ATTRIBUTE_NOINLINE TestWithReturnAddress() { +#if defined(__arm__) && ABSL_HAVE_ATTRIBUTE(target) +// Test that we correctly identify bounds of Thumb functions on ARM. +// +// Thumb functions have the lowest-order bit set in their addresses in the ELF +// symbol table. This requires some extra logic to properly compute function +// bounds. To test this logic, nudge a Thumb function right up against an ARM +// function and try to symbolize the ARM function. +// +// A naive implementation will simply use the Thumb function's entry point as +// written in the symbol table and will therefore treat the Thumb function as +// extending one byte further in the instruction stream than it actually does. +// When asked to symbolize the start of the ARM function, it will identify an +// overlap between the Thumb and ARM functions, and it will return the name of +// the Thumb function. +// +// A correct implementation, on the other hand, will null out the lowest-order +// bit in the Thumb function's entry point. It will correctly compute the end of +// the Thumb function, it will find no overlap between the Thumb and ARM +// functions, and it will return the name of the ARM function. + +__attribute__((target("thumb"))) int ArmThumbOverlapThumb(int x) { + return x * x * x; +} + +__attribute__((target("arm"))) int ArmThumbOverlapArm(int x) { + return x * x * x; +} + +void ABSL_ATTRIBUTE_NOINLINE TestArmThumbOverlap() { #if defined(ABSL_HAVE_ATTRIBUTE_NOINLINE) - void *return_address = __builtin_return_address(0); - const char *symbol = TrySymbolize(return_address); - ABSL_RAW_CHECK(symbol != nullptr, "TestWithReturnAddress failed"); - ABSL_RAW_CHECK(strcmp(symbol, "main") == 0, "TestWithReturnAddress failed"); - std::cout << "TestWithReturnAddress passed" << std::endl; + const char *symbol = TrySymbolize((void *)&ArmThumbOverlapArm); + ABSL_RAW_CHECK(symbol != nullptr, "TestArmThumbOverlap failed"); + ABSL_RAW_CHECK(strcmp("ArmThumbOverlapArm()", symbol) == 0, + "TestArmThumbOverlap failed"); + std::cout << "TestArmThumbOverlap passed" << std::endl; #endif } +#endif // defined(__arm__) && ABSL_HAVE_ATTRIBUTE(target) + #elif defined(_WIN32) #if !defined(ABSL_CONSUME_DLL) @@ -514,7 +563,6 @@ TEST(Symbolize, SymbolizeWithDemangling) { #endif // !defined(ABSL_CONSUME_DLL) #else // Symbolizer unimplemented - TEST(Symbolize, Unimplemented) { char buf[64]; EXPECT_FALSE(absl::Symbolize((void *)(&nonstatic_func), buf, sizeof(buf))); @@ -541,10 +589,14 @@ int main(int argc, char **argv) { absl::InitializeSymbolizer(argv[0]); testing::InitGoogleTest(&argc, argv); -#ifdef ABSL_INTERNAL_HAVE_ELF_SYMBOLIZE +#if defined(ABSL_INTERNAL_HAVE_ELF_SYMBOLIZE) || \ + defined(ABSL_INTERNAL_HAVE_DARWIN_SYMBOLIZE) TestWithPCInsideInlineFunction(); TestWithPCInsideNonInlineFunction(); TestWithReturnAddress(); +#if defined(__arm__) && ABSL_HAVE_ATTRIBUTE(target) + TestArmThumbOverlap(); +#endif #endif return RUN_ALL_TESTS(); diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/BUILD.gn b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/BUILD.gn deleted file mode 100644 index bf6481c37a..0000000000 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/BUILD.gn +++ /dev/null @@ -1,205 +0,0 @@ -# Copyright 2019 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -import("//third_party/abseil-cpp/absl.gni") - -# Build targets in this module are marked as "testonly" because it is not clear -# how ABSL_FLAG will interact with //base/command_line.h. -# If this is a problem, feel free to remove "testonly" and use "assert_no_deps" -# on the main Chrome binary. - -absl_source_set("flag_internal") { - testonly = true - sources = [ "internal/flag.cc" ] - public = [ "internal/flag.h" ] - deps = [ - ":config", - ":handle", - ":registry", - "../base", - "../base:config", - "../base:core_headers", - "../memory", - "../meta:type_traits", - "../strings", - "../synchronization", - ] - visibility = [] - visibility += [ - ":*", - "../base/*", - ] -} - -absl_source_set("program_name") { - testonly = true - sources = [ "internal/program_name.cc" ] - public = [ "internal/program_name.h" ] - deps = [ - ":path_util", - "../base:config", - "../base:core_headers", - "../strings", - "../synchronization", - ] - visibility = [] - visibility += [ ":*" ] -} - -absl_source_set("path_util") { - testonly = true - public = [ "internal/path_util.h" ] - deps = [ - "../base:config", - "../strings", - ] - visibility = [] - visibility += [ ":*" ] -} - -absl_source_set("config") { - testonly = true - sources = [ "usage_config.cc" ] - public = [ - "config.h", - "usage_config.h", - ] - deps = [ - ":path_util", - ":program_name", - "../base:config", - "../base:core_headers", - "../strings", - "../synchronization", - ] -} - -absl_source_set("marshalling") { - testonly = true - sources = [ "marshalling.cc" ] - public = [ "marshalling.h" ] - deps = [ - "../base:config", - "../base:core_headers", - "../base:log_severity", - "../strings", - "../strings:str_format", - ] -} - -absl_source_set("handle") { - testonly = true - sources = [ "internal/commandlineflag.cc" ] - public = [ "internal/commandlineflag.h" ] - deps = [ - ":config", - ":marshalling", - "../base:config", - "../base:core_headers", - "../base:fast_type_id", - "../strings", - "../types:optional", - ] - visibility = [] - visibility += [ ":*" ] -} - -absl_source_set("registry") { - testonly = true - sources = [ - "internal/registry.cc", - "internal/type_erased.cc", - ] - public = [ - "internal/registry.h", - "internal/type_erased.h", - ] - deps = [ - ":config", - ":handle", - "../base:config", - "../base:core_headers", - "../base:raw_logging_internal", - "../strings", - "../synchronization", - ] - visibility = [] - visibility += [ ":*" ] -} - -absl_source_set("flag") { - testonly = true - sources = [ "flag.cc" ] - public = [ - "declare.h", - "flag.h", - ] - deps = [ - ":config", - ":flag_internal", - ":handle", - ":marshalling", - ":registry", - "../base", - "../base:config", - "../base:core_headers", - "../strings", - ] -} - -absl_source_set("usage_internal") { - testonly = true - sources = [ "internal/usage.cc" ] - public = [ "internal/usage.h" ] - deps = [ - ":config", - ":flag", - ":flag_internal", - ":handle", - ":path_util", - ":program_name", - ":registry", - "../base:config", - "../base:core_headers", - "../strings", - ] - visibility = [] - visibility += [ ":*" ] -} - -absl_source_set("usage") { - testonly = true - sources = [ "usage.cc" ] - public = [ "usage.h" ] - deps = [ - ":usage_internal", - "../base:config", - "../base:core_headers", - "../strings", - "../synchronization", - ] -} - -absl_source_set("parse") { - testonly = true - sources = [ "parse.cc" ] - public = [ - "internal/parse.h", - "parse.h", - ] - deps = [ - ":config", - ":flag", - ":flag_internal", - ":handle", - ":program_name", - ":registry", - ":usage", - ":usage_internal", - "../base:config", - "../base:core_headers", - "../strings", - "../synchronization", - ] -} diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/CMakeLists.txt b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/CMakeLists.txt index 2204b0ff2d..956f70f868 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/CMakeLists.txt +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/CMakeLists.txt @@ -17,23 +17,16 @@ # Internal-only target, do not depend on directly. absl_cc_library( NAME - flags_internal - SRCS - "internal/flag.cc" + flags_path_util HDRS - "internal/flag.h" + "internal/path_util.h" COPTS ${ABSL_DEFAULT_COPTS} LINKOPTS ${ABSL_DEFAULT_LINKOPTS} DEPS - absl::base absl::config - absl::flags_config - absl::flags_handle - absl::flags_registry - absl::synchronization - absl::meta + absl::strings PUBLIC ) @@ -58,22 +51,6 @@ absl_cc_library( PUBLIC ) -# Internal-only target, do not depend on directly. -absl_cc_library( - NAME - flags_path_util - HDRS - "internal/path_util.h" - COPTS - ${ABSL_DEFAULT_COPTS} - LINKOPTS - ${ABSL_DEFAULT_LINKOPTS} - DEPS - absl::config - absl::strings - PUBLIC -) - absl_cc_library( NAME flags_config @@ -117,7 +94,7 @@ absl_cc_library( # Internal-only target, do not depend on directly. absl_cc_library( NAME - flags_handle + flags_commandlineflag_internal SRCS "internal/commandlineflag.cc" HDRS @@ -129,37 +106,92 @@ absl_cc_library( DEPS absl::config absl::fast_type_id - absl::flags_config - absl::flags_marshalling - absl::core_headers - absl::optional - absl::raw_logging_internal - absl::strings - absl::synchronization ) -# Internal-only target, do not depend on directly. absl_cc_library( NAME - flags_registry + flags_commandlineflag SRCS - "internal/registry.cc" - "internal/type_erased.cc" + "commandlineflag.cc" HDRS - "internal/registry.h" - "internal/type_erased.h" + "commandlineflag.h" COPTS ${ABSL_DEFAULT_COPTS} LINKOPTS ${ABSL_DEFAULT_LINKOPTS} DEPS absl::config + absl::fast_type_id + absl::flags_commandlineflag_internal + absl::optional + absl::strings +) + +# Internal-only target, do not depend on directly. +absl_cc_library( + NAME + flags_private_handle_accessor + SRCS + "internal/private_handle_accessor.cc" + HDRS + "internal/private_handle_accessor.h" + COPTS + ${ABSL_DEFAULT_COPTS} + LINKOPTS + ${ABSL_DEFAULT_LINKOPTS} + DEPS + absl::config + absl::flags_commandlineflag + absl::flags_commandlineflag_internal + absl::strings +) + +absl_cc_library( + NAME + flags_reflection + SRCS + "reflection.cc" + HDRS + "reflection.h" + "internal/registry.h" + COPTS + ${ABSL_DEFAULT_COPTS} + LINKOPTS + ${ABSL_DEFAULT_LINKOPTS} + DEPS + absl::config + absl::flags_commandlineflag + absl::flags_private_handle_accessor absl::flags_config - absl::flags_handle - absl::core_headers - absl::raw_logging_internal absl::strings absl::synchronization + absl::flat_hash_map +) + +# Internal-only target, do not depend on directly. +absl_cc_library( + NAME + flags_internal + SRCS + "internal/flag.cc" + HDRS + "internal/flag.h" + "internal/sequence_lock.h" + COPTS + ${ABSL_DEFAULT_COPTS} + LINKOPTS + ${ABSL_DEFAULT_LINKOPTS} + DEPS + absl::base + absl::config + absl::flags_commandlineflag + absl::flags_commandlineflag_internal + absl::flags_config + absl::flags_marshalling + absl::synchronization + absl::meta + absl::utility + PUBLIC ) absl_cc_library( @@ -176,11 +208,10 @@ absl_cc_library( ${ABSL_DEFAULT_LINKOPTS} DEPS absl::config + absl::flags_commandlineflag absl::flags_config - absl::flags_handle absl::flags_internal - absl::flags_marshalling - absl::flags_registry + absl::flags_reflection absl::base absl::core_headers absl::strings @@ -202,11 +233,13 @@ absl_cc_library( absl::config absl::flags_config absl::flags - absl::flags_handle + absl::flags_commandlineflag absl::flags_internal absl::flags_path_util + absl::flags_private_handle_accessor absl::flags_program_name - absl::flags_registry + absl::flags_reflection + absl::flat_hash_map absl::strings absl::synchronization ) @@ -247,10 +280,12 @@ absl_cc_library( absl::core_headers absl::flags_config absl::flags - absl::flags_handle + absl::flags_commandlineflag + absl::flags_commandlineflag_internal absl::flags_internal + absl::flags_private_handle_accessor absl::flags_program_name - absl::flags_registry + absl::flags_reflection absl::flags_usage absl::strings absl::synchronization @@ -263,17 +298,19 @@ absl_cc_test( NAME flags_commandlineflag_test SRCS - "internal/commandlineflag_test.cc" + "commandlineflag_test.cc" COPTS ${ABSL_TEST_COPTS} DEPS absl::flags + absl::flags_commandlineflag + absl::flags_commandlineflag_internal absl::flags_config - absl::flags_handle - absl::flags_registry + absl::flags_private_handle_accessor + absl::flags_reflection absl::memory absl::strings - gtest_main + GTest::gtest_main ) absl_cc_test( @@ -285,7 +322,7 @@ absl_cc_test( ${ABSL_TEST_COPTS} DEPS absl::flags_config - gtest_main + GTest::gtest_main ) absl_cc_test( @@ -300,11 +337,12 @@ absl_cc_test( absl::core_headers absl::flags absl::flags_config - absl::flags_handle absl::flags_internal - absl::flags_registry + absl::flags_marshalling + absl::flags_reflection absl::strings - gtest_main + absl::time + GTest::gtest_main ) absl_cc_test( @@ -316,7 +354,7 @@ absl_cc_test( ${ABSL_TEST_COPTS} DEPS absl::flags_marshalling - gtest_main + GTest::gtest_main ) absl_cc_test( @@ -329,12 +367,13 @@ absl_cc_test( DEPS absl::flags absl::flags_parse - absl::flags_registry + absl::flags_reflection + absl::flags_usage_internal absl::raw_logging_internal absl::scoped_set_env absl::span absl::strings - gmock_main + GTest::gmock_main ) absl_cc_test( @@ -346,7 +385,7 @@ absl_cc_test( ${ABSL_TEST_COPTS} DEPS absl::flags_path_util - gtest_main + GTest::gtest_main ) absl_cc_test( @@ -359,24 +398,38 @@ absl_cc_test( DEPS absl::flags_program_name absl::strings - gtest_main + GTest::gtest_main ) absl_cc_test( NAME - flags_type_erased_test + flags_reflection_test SRCS - "internal/type_erased_test.cc" + "reflection_test.cc" COPTS ${ABSL_TEST_COPTS} DEPS + absl::flags_commandlineflag_internal absl::flags - absl::flags_handle - absl::flags_marshalling - absl::flags_registry + absl::flags_reflection + absl::flags_usage absl::memory absl::strings - gtest_main + GTest::gmock_main +) + +absl_cc_test( + NAME + flags_sequence_lock_test + SRCS + "internal/sequence_lock_test.cc" + COPTS + ${ABSL_TEST_COPTS} + DEPS + absl::base + absl::flags_internal + absl::time + GTest::gmock_main ) absl_cc_test( @@ -391,7 +444,7 @@ absl_cc_test( absl::flags_path_util absl::flags_program_name absl::strings - gtest_main + GTest::gtest_main ) absl_cc_test( @@ -407,9 +460,8 @@ absl_cc_test( absl::flags_path_util absl::flags_program_name absl::flags_parse - absl::flags_registry + absl::flags_reflection absl::flags_usage - absl::memory absl::strings - gtest + GTest::gtest ) diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/commandlineflag.cc b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/commandlineflag.cc new file mode 100644 index 0000000000..9f3b4a5a28 --- /dev/null +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/commandlineflag.cc @@ -0,0 +1,34 @@ +// +// Copyright 2020 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "absl/flags/commandlineflag.h" + +#include + +#include "absl/base/config.h" +#include "absl/flags/internal/commandlineflag.h" +#include "absl/strings/string_view.h" + +namespace absl { +ABSL_NAMESPACE_BEGIN + +bool CommandLineFlag::IsRetired() const { return false; } +bool CommandLineFlag::ParseFrom(absl::string_view value, std::string* error) { + return ParseFrom(value, flags_internal::SET_FLAGS_VALUE, + flags_internal::kProgrammaticChange, *error); +} + +ABSL_NAMESPACE_END +} // namespace absl diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/commandlineflag.h b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/commandlineflag.h new file mode 100644 index 0000000000..f2fa08977f --- /dev/null +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/commandlineflag.h @@ -0,0 +1,200 @@ +// +// Copyright 2020 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// ----------------------------------------------------------------------------- +// File: commandlineflag.h +// ----------------------------------------------------------------------------- +// +// This header file defines the `CommandLineFlag`, which acts as a type-erased +// handle for accessing metadata about the Abseil Flag in question. +// +// Because an actual Abseil flag is of an unspecified type, you should not +// manipulate or interact directly with objects of that type. Instead, use the +// CommandLineFlag type as an intermediary. +#ifndef ABSL_FLAGS_COMMANDLINEFLAG_H_ +#define ABSL_FLAGS_COMMANDLINEFLAG_H_ + +#include +#include + +#include "absl/base/config.h" +#include "absl/base/internal/fast_type_id.h" +#include "absl/flags/internal/commandlineflag.h" +#include "absl/strings/string_view.h" +#include "absl/types/optional.h" + +namespace absl { +ABSL_NAMESPACE_BEGIN +namespace flags_internal { +class PrivateHandleAccessor; +} // namespace flags_internal + +// CommandLineFlag +// +// This type acts as a type-erased handle for an instance of an Abseil Flag and +// holds reflection information pertaining to that flag. Use CommandLineFlag to +// access a flag's name, location, help string etc. +// +// To obtain an absl::CommandLineFlag, invoke `absl::FindCommandLineFlag()` +// passing it the flag name string. +// +// Example: +// +// // Obtain reflection handle for a flag named "flagname". +// const absl::CommandLineFlag* my_flag_data = +// absl::FindCommandLineFlag("flagname"); +// +// // Now you can get flag info from that reflection handle. +// std::string flag_location = my_flag_data->Filename(); +// ... +class CommandLineFlag { + public: + constexpr CommandLineFlag() = default; + + // Not copyable/assignable. + CommandLineFlag(const CommandLineFlag&) = delete; + CommandLineFlag& operator=(const CommandLineFlag&) = delete; + + // absl::CommandLineFlag::IsOfType() + // + // Return true iff flag has type T. + template + inline bool IsOfType() const { + return TypeId() == base_internal::FastTypeId(); + } + + // absl::CommandLineFlag::TryGet() + // + // Attempts to retrieve the flag value. Returns value on success, + // absl::nullopt otherwise. + template + absl::optional TryGet() const { + if (IsRetired() || !IsOfType()) { + return absl::nullopt; + } + + // Implementation notes: + // + // We are wrapping a union around the value of `T` to serve three purposes: + // + // 1. `U.value` has correct size and alignment for a value of type `T` + // 2. The `U.value` constructor is not invoked since U's constructor does + // not do it explicitly. + // 3. The `U.value` destructor is invoked since U's destructor does it + // explicitly. This makes `U` a kind of RAII wrapper around non default + // constructible value of T, which is destructed when we leave the + // scope. We do need to destroy U.value, which is constructed by + // CommandLineFlag::Read even though we left it in a moved-from state + // after std::move. + // + // All of this serves to avoid requiring `T` being default constructible. + union U { + T value; + U() {} + ~U() { value.~T(); } + }; + U u; + + Read(&u.value); + // allow retired flags to be "read", so we can report invalid access. + if (IsRetired()) { + return absl::nullopt; + } + return std::move(u.value); + } + + // absl::CommandLineFlag::Name() + // + // Returns name of this flag. + virtual absl::string_view Name() const = 0; + + // absl::CommandLineFlag::Filename() + // + // Returns name of the file where this flag is defined. + virtual std::string Filename() const = 0; + + // absl::CommandLineFlag::Help() + // + // Returns help message associated with this flag. + virtual std::string Help() const = 0; + + // absl::CommandLineFlag::IsRetired() + // + // Returns true iff this object corresponds to retired flag. + virtual bool IsRetired() const; + + // absl::CommandLineFlag::DefaultValue() + // + // Returns the default value for this flag. + virtual std::string DefaultValue() const = 0; + + // absl::CommandLineFlag::CurrentValue() + // + // Returns the current value for this flag. + virtual std::string CurrentValue() const = 0; + + // absl::CommandLineFlag::ParseFrom() + // + // Sets the value of the flag based on specified string `value`. If the flag + // was successfully set to new value, it returns true. Otherwise, sets `error` + // to indicate the error, leaves the flag unchanged, and returns false. + bool ParseFrom(absl::string_view value, std::string* error); + + protected: + ~CommandLineFlag() = default; + + private: + friend class flags_internal::PrivateHandleAccessor; + + // Sets the value of the flag based on specified string `value`. If the flag + // was successfully set to new value, it returns true. Otherwise, sets `error` + // to indicate the error, leaves the flag unchanged, and returns false. There + // are three ways to set the flag's value: + // * Update the current flag value + // * Update the flag's default value + // * Update the current flag value if it was never set before + // The mode is selected based on `set_mode` parameter. + virtual bool ParseFrom(absl::string_view value, + flags_internal::FlagSettingMode set_mode, + flags_internal::ValueSource source, + std::string& error) = 0; + + // Returns id of the flag's value type. + virtual flags_internal::FlagFastTypeId TypeId() const = 0; + + // Interface to save flag to some persistent state. Returns current flag state + // or nullptr if flag does not support saving and restoring a state. + virtual std::unique_ptr SaveState() = 0; + + // Copy-construct a new value of the flag's type in a memory referenced by + // the dst based on the current flag's value. + virtual void Read(void* dst) const = 0; + + // To be deleted. Used to return true if flag's current value originated from + // command line. + virtual bool IsSpecifiedOnCommandLine() const = 0; + + // Validates supplied value usign validator or parseflag routine + virtual bool ValidateInputValue(absl::string_view value) const = 0; + + // Checks that flags default value can be converted to string and back to the + // flag's value type. + virtual void CheckDefaultValueParsingRoundtrip() const = 0; +}; + +ABSL_NAMESPACE_END +} // namespace absl + +#endif // ABSL_FLAGS_COMMANDLINEFLAG_H_ diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/internal/commandlineflag_test.cc b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/commandlineflag_test.cc similarity index 50% rename from third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/internal/commandlineflag_test.cc rename to third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/commandlineflag_test.cc index c1142b7c57..585db4ba78 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/internal/commandlineflag_test.cc +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/commandlineflag_test.cc @@ -13,14 +13,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "absl/flags/internal/commandlineflag.h" +#include "absl/flags/commandlineflag.h" #include #include #include "gtest/gtest.h" #include "absl/flags/flag.h" -#include "absl/flags/internal/registry.h" +#include "absl/flags/internal/commandlineflag.h" +#include "absl/flags/internal/private_handle_accessor.h" +#include "absl/flags/reflection.h" #include "absl/flags/usage_config.h" #include "absl/memory/memory.h" #include "absl/strings/match.h" @@ -32,6 +34,10 @@ ABSL_FLAG(std::string, string_flag, "dflt", absl::StrCat("string_flag", " help")); ABSL_RETIRED_FLAG(bool, bool_retired_flag, false, "bool_retired_flag help"); +// These are only used to test default values. +ABSL_FLAG(int, int_flag2, 201, ""); +ABSL_FLAG(std::string, string_flag2, "dflt", ""); + namespace { namespace flags = absl::flags_internal; @@ -45,7 +51,7 @@ class CommandLineFlagTest : public testing::Test { absl::SetFlagsUsageConfig(default_config); } - void SetUp() override { flag_saver_ = absl::make_unique(); } + void SetUp() override { flag_saver_ = absl::make_unique(); } void TearDown() override { flag_saver_.reset(); } private: @@ -58,59 +64,49 @@ class CommandLineFlagTest : public testing::Test { return std::string(fname); } - std::unique_ptr flag_saver_; + std::unique_ptr flag_saver_; }; TEST_F(CommandLineFlagTest, TestAttributesAccessMethods) { - auto* flag_01 = flags::FindCommandLineFlag("int_flag"); + auto* flag_01 = absl::FindCommandLineFlag("int_flag"); ASSERT_TRUE(flag_01); EXPECT_EQ(flag_01->Name(), "int_flag"); EXPECT_EQ(flag_01->Help(), "int_flag help"); - EXPECT_EQ(flag_01->Typename(), ""); EXPECT_TRUE(!flag_01->IsRetired()); EXPECT_TRUE(flag_01->IsOfType()); - EXPECT_TRUE( - absl::EndsWith(flag_01->Filename(), - "absl/flags/internal/commandlineflag_test.cc")) + EXPECT_TRUE(!flag_01->IsOfType()); + EXPECT_TRUE(!flag_01->IsOfType()); + EXPECT_TRUE(absl::EndsWith(flag_01->Filename(), + "absl/flags/commandlineflag_test.cc")) << flag_01->Filename(); - auto* flag_02 = flags::FindCommandLineFlag("string_flag"); + auto* flag_02 = absl::FindCommandLineFlag("string_flag"); ASSERT_TRUE(flag_02); EXPECT_EQ(flag_02->Name(), "string_flag"); EXPECT_EQ(flag_02->Help(), "string_flag help"); - EXPECT_EQ(flag_02->Typename(), ""); EXPECT_TRUE(!flag_02->IsRetired()); EXPECT_TRUE(flag_02->IsOfType()); - EXPECT_TRUE( - absl::EndsWith(flag_02->Filename(), - "absl/flags/internal/commandlineflag_test.cc")) + EXPECT_TRUE(!flag_02->IsOfType()); + EXPECT_TRUE(!flag_02->IsOfType()); + EXPECT_TRUE(absl::EndsWith(flag_02->Filename(), + "absl/flags/commandlineflag_test.cc")) << flag_02->Filename(); - - auto* flag_03 = flags::FindRetiredFlag("bool_retired_flag"); - - ASSERT_TRUE(flag_03); - EXPECT_EQ(flag_03->Name(), "bool_retired_flag"); - EXPECT_EQ(flag_03->Help(), ""); - EXPECT_EQ(flag_03->Typename(), ""); - EXPECT_TRUE(flag_03->IsRetired()); - EXPECT_TRUE(flag_03->IsOfType()); - EXPECT_EQ(flag_03->Filename(), "RETIRED"); } // -------------------------------------------------------------------- TEST_F(CommandLineFlagTest, TestValueAccessMethods) { - absl::SetFlag(&FLAGS_int_flag, 301); - auto* flag_01 = flags::FindCommandLineFlag("int_flag"); + absl::SetFlag(&FLAGS_int_flag2, 301); + auto* flag_01 = absl::FindCommandLineFlag("int_flag2"); ASSERT_TRUE(flag_01); EXPECT_EQ(flag_01->CurrentValue(), "301"); EXPECT_EQ(flag_01->DefaultValue(), "201"); - absl::SetFlag(&FLAGS_string_flag, "new_str_value"); - auto* flag_02 = flags::FindCommandLineFlag("string_flag"); + absl::SetFlag(&FLAGS_string_flag2, "new_str_value"); + auto* flag_02 = absl::FindCommandLineFlag("string_flag2"); ASSERT_TRUE(flag_02); EXPECT_EQ(flag_02->CurrentValue(), "new_str_value"); @@ -122,52 +118,62 @@ TEST_F(CommandLineFlagTest, TestValueAccessMethods) { TEST_F(CommandLineFlagTest, TestParseFromCurrentValue) { std::string err; - auto* flag_01 = flags::FindCommandLineFlag("int_flag"); - EXPECT_FALSE(flag_01->IsSpecifiedOnCommandLine()); + auto* flag_01 = absl::FindCommandLineFlag("int_flag"); + EXPECT_FALSE( + flags::PrivateHandleAccessor::IsSpecifiedOnCommandLine(*flag_01)); - EXPECT_TRUE(flag_01->ParseFrom("11", flags::SET_FLAGS_VALUE, - flags::kProgrammaticChange, &err)); + EXPECT_TRUE(flags::PrivateHandleAccessor::ParseFrom( + *flag_01, "11", flags::SET_FLAGS_VALUE, flags::kProgrammaticChange, err)); EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), 11); - EXPECT_FALSE(flag_01->IsSpecifiedOnCommandLine()); + EXPECT_FALSE( + flags::PrivateHandleAccessor::IsSpecifiedOnCommandLine(*flag_01)); - EXPECT_TRUE(flag_01->ParseFrom("-123", flags::SET_FLAGS_VALUE, - flags::kProgrammaticChange, &err)); + EXPECT_TRUE(flags::PrivateHandleAccessor::ParseFrom( + *flag_01, "-123", flags::SET_FLAGS_VALUE, flags::kProgrammaticChange, + err)); EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), -123); - EXPECT_FALSE(flag_01->IsSpecifiedOnCommandLine()); + EXPECT_FALSE( + flags::PrivateHandleAccessor::IsSpecifiedOnCommandLine(*flag_01)); - EXPECT_TRUE(!flag_01->ParseFrom("xyz", flags::SET_FLAGS_VALUE, - flags::kProgrammaticChange, &err)); + EXPECT_TRUE(!flags::PrivateHandleAccessor::ParseFrom( + *flag_01, "xyz", flags::SET_FLAGS_VALUE, flags::kProgrammaticChange, + err)); EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), -123); EXPECT_EQ(err, "Illegal value 'xyz' specified for flag 'int_flag'"); - EXPECT_FALSE(flag_01->IsSpecifiedOnCommandLine()); + EXPECT_FALSE( + flags::PrivateHandleAccessor::IsSpecifiedOnCommandLine(*flag_01)); - EXPECT_TRUE(!flag_01->ParseFrom("A1", flags::SET_FLAGS_VALUE, - flags::kProgrammaticChange, &err)); + EXPECT_TRUE(!flags::PrivateHandleAccessor::ParseFrom( + *flag_01, "A1", flags::SET_FLAGS_VALUE, flags::kProgrammaticChange, err)); EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), -123); EXPECT_EQ(err, "Illegal value 'A1' specified for flag 'int_flag'"); - EXPECT_FALSE(flag_01->IsSpecifiedOnCommandLine()); + EXPECT_FALSE( + flags::PrivateHandleAccessor::IsSpecifiedOnCommandLine(*flag_01)); - EXPECT_TRUE(flag_01->ParseFrom("0x10", flags::SET_FLAGS_VALUE, - flags::kProgrammaticChange, &err)); + EXPECT_TRUE(flags::PrivateHandleAccessor::ParseFrom( + *flag_01, "0x10", flags::SET_FLAGS_VALUE, flags::kProgrammaticChange, + err)); EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), 16); - EXPECT_FALSE(flag_01->IsSpecifiedOnCommandLine()); + EXPECT_FALSE( + flags::PrivateHandleAccessor::IsSpecifiedOnCommandLine(*flag_01)); - EXPECT_TRUE(flag_01->ParseFrom("011", flags::SET_FLAGS_VALUE, - flags::kCommandLine, &err)); + EXPECT_TRUE(flags::PrivateHandleAccessor::ParseFrom( + *flag_01, "011", flags::SET_FLAGS_VALUE, flags::kCommandLine, err)); EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), 11); - EXPECT_TRUE(flag_01->IsSpecifiedOnCommandLine()); + EXPECT_TRUE(flags::PrivateHandleAccessor::IsSpecifiedOnCommandLine(*flag_01)); - EXPECT_TRUE(!flag_01->ParseFrom("", flags::SET_FLAGS_VALUE, - flags::kProgrammaticChange, &err)); + EXPECT_TRUE(!flags::PrivateHandleAccessor::ParseFrom( + *flag_01, "", flags::SET_FLAGS_VALUE, flags::kProgrammaticChange, err)); EXPECT_EQ(err, "Illegal value '' specified for flag 'int_flag'"); - auto* flag_02 = flags::FindCommandLineFlag("string_flag"); - EXPECT_TRUE(flag_02->ParseFrom("xyz", flags::SET_FLAGS_VALUE, - flags::kProgrammaticChange, &err)); + auto* flag_02 = absl::FindCommandLineFlag("string_flag"); + EXPECT_TRUE(flags::PrivateHandleAccessor::ParseFrom( + *flag_02, "xyz", flags::SET_FLAGS_VALUE, flags::kProgrammaticChange, + err)); EXPECT_EQ(absl::GetFlag(FLAGS_string_flag), "xyz"); - EXPECT_TRUE(flag_02->ParseFrom("", flags::SET_FLAGS_VALUE, - flags::kProgrammaticChange, &err)); + EXPECT_TRUE(flags::PrivateHandleAccessor::ParseFrom( + *flag_02, "", flags::SET_FLAGS_VALUE, flags::kProgrammaticChange, err)); EXPECT_EQ(absl::GetFlag(FLAGS_string_flag), ""); } @@ -176,16 +182,18 @@ TEST_F(CommandLineFlagTest, TestParseFromCurrentValue) { TEST_F(CommandLineFlagTest, TestParseFromDefaultValue) { std::string err; - auto* flag_01 = flags::FindCommandLineFlag("int_flag"); + auto* flag_01 = absl::FindCommandLineFlag("int_flag"); - EXPECT_TRUE(flag_01->ParseFrom("111", flags::SET_FLAGS_DEFAULT, - flags::kProgrammaticChange, &err)); + EXPECT_TRUE(flags::PrivateHandleAccessor::ParseFrom( + *flag_01, "111", flags::SET_FLAGS_DEFAULT, flags::kProgrammaticChange, + err)); EXPECT_EQ(flag_01->DefaultValue(), "111"); - auto* flag_02 = flags::FindCommandLineFlag("string_flag"); + auto* flag_02 = absl::FindCommandLineFlag("string_flag"); - EXPECT_TRUE(flag_02->ParseFrom("abc", flags::SET_FLAGS_DEFAULT, - flags::kProgrammaticChange, &err)); + EXPECT_TRUE(flags::PrivateHandleAccessor::ParseFrom( + *flag_02, "abc", flags::SET_FLAGS_DEFAULT, flags::kProgrammaticChange, + err)); EXPECT_EQ(flag_02->DefaultValue(), "abc"); } @@ -194,24 +202,28 @@ TEST_F(CommandLineFlagTest, TestParseFromDefaultValue) { TEST_F(CommandLineFlagTest, TestParseFromIfDefault) { std::string err; - auto* flag_01 = flags::FindCommandLineFlag("int_flag"); + auto* flag_01 = absl::FindCommandLineFlag("int_flag"); - EXPECT_TRUE(flag_01->ParseFrom("22", flags::SET_FLAG_IF_DEFAULT, - flags::kProgrammaticChange, &err)) + EXPECT_TRUE(flags::PrivateHandleAccessor::ParseFrom( + *flag_01, "22", flags::SET_FLAG_IF_DEFAULT, flags::kProgrammaticChange, + err)) << err; EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), 22); - EXPECT_TRUE(flag_01->ParseFrom("33", flags::SET_FLAG_IF_DEFAULT, - flags::kProgrammaticChange, &err)); + EXPECT_TRUE(flags::PrivateHandleAccessor::ParseFrom( + *flag_01, "33", flags::SET_FLAG_IF_DEFAULT, flags::kProgrammaticChange, + err)); EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), 22); // EXPECT_EQ(err, "ERROR: int_flag is already set to 22"); // Reset back to default value - EXPECT_TRUE(flag_01->ParseFrom("201", flags::SET_FLAGS_VALUE, - flags::kProgrammaticChange, &err)); + EXPECT_TRUE(flags::PrivateHandleAccessor::ParseFrom( + *flag_01, "201", flags::SET_FLAGS_VALUE, flags::kProgrammaticChange, + err)); - EXPECT_TRUE(flag_01->ParseFrom("33", flags::SET_FLAG_IF_DEFAULT, - flags::kProgrammaticChange, &err)); + EXPECT_TRUE(flags::PrivateHandleAccessor::ParseFrom( + *flag_01, "33", flags::SET_FLAG_IF_DEFAULT, flags::kProgrammaticChange, + err)); EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), 201); // EXPECT_EQ(err, "ERROR: int_flag is already set to 201"); } diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/config.h b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/config.h index 001f8feaf6..5ab1f311dc 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/config.h +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/config.h @@ -45,17 +45,6 @@ #define ABSL_FLAGS_STRIP_HELP ABSL_FLAGS_STRIP_NAMES #endif -// ABSL_FLAGS_INTERNAL_ATOMIC_DOUBLE_WORD macro is used for using atomics with -// double words, e.g. absl::Duration. -// For reasons in bug https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80878, modern -// versions of GCC do not support cmpxchg16b instruction in standard atomics. -#ifdef ABSL_FLAGS_INTERNAL_ATOMIC_DOUBLE_WORD -#error "ABSL_FLAGS_INTERNAL_ATOMIC_DOUBLE_WORD should not be defined." -#elif defined(__clang__) && defined(__x86_64__) && \ - defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_16) -#define ABSL_FLAGS_INTERNAL_ATOMIC_DOUBLE_WORD 1 -#endif - // ABSL_FLAGS_INTERNAL_HAS_RTTI macro is used for selecting if we can use RTTI // for flag type identification. #ifdef ABSL_FLAGS_INTERNAL_HAS_RTTI @@ -64,4 +53,24 @@ #define ABSL_FLAGS_INTERNAL_HAS_RTTI 1 #endif // !defined(__GNUC__) || defined(__GXX_RTTI) +// These macros represent the "source of truth" for the list of supported +// built-in types. +#define ABSL_FLAGS_INTERNAL_BUILTIN_TYPES(A) \ + A(bool, bool) \ + A(short, short) \ + A(unsigned short, unsigned_short) \ + A(int, int) \ + A(unsigned int, unsigned_int) \ + A(long, long) \ + A(unsigned long, unsigned_long) \ + A(long long, long_long) \ + A(unsigned long long, unsigned_long_long) \ + A(double, double) \ + A(float, float) + +#define ABSL_FLAGS_INTERNAL_SUPPORTED_TYPES(A) \ + ABSL_FLAGS_INTERNAL_BUILTIN_TYPES(A) \ + A(std::string, std_string) \ + A(std::vector, std_vector_of_string) + #endif // ABSL_FLAGS_CONFIG_H_ diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/declare.h b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/declare.h index 0f8cc6a599..b9794d8b85 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/declare.h +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/declare.h @@ -26,7 +26,6 @@ #define ABSL_FLAGS_DECLARE_H_ #include "absl/base/config.h" -#include "absl/strings/string_view.h" namespace absl { ABSL_NAMESPACE_BEGIN diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/flag.cc b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/flag.cc index f7a457bf0c..531df1287a 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/flag.cc +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/flag.cc @@ -16,8 +16,6 @@ #include "absl/flags/flag.h" #include "absl/base/config.h" -#include "absl/flags/internal/commandlineflag.h" -#include "absl/flags/internal/flag.h" namespace absl { ABSL_NAMESPACE_BEGIN diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/flag.h b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/flag.h index bb917654d5..14209e7ba7 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/flag.h +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/flag.h @@ -33,14 +33,12 @@ #include #include "absl/base/attributes.h" -#include "absl/base/casts.h" #include "absl/base/config.h" +#include "absl/base/optimization.h" #include "absl/flags/config.h" -#include "absl/flags/declare.h" -#include "absl/flags/internal/commandlineflag.h" #include "absl/flags/internal/flag.h" #include "absl/flags/internal/registry.h" -#include "absl/flags/marshalling.h" +#include "absl/strings/string_view.h" namespace absl { ABSL_NAMESPACE_BEGIN @@ -110,49 +108,53 @@ class Flag { impl_(nullptr) {} #endif - flags_internal::Flag* GetImpl() const { + flags_internal::Flag& GetImpl() const { if (!inited_.load(std::memory_order_acquire)) { absl::MutexLock l(flags_internal::GetGlobalConstructionGuard()); if (inited_.load(std::memory_order_acquire)) { - return impl_; + return *impl_; } - impl_ = - new flags_internal::Flag(name_, filename_, - {flags_internal::FlagHelpMsg(help_gen_), - flags_internal::FlagHelpKind::kGenFunc}, - default_value_gen_); + impl_ = new flags_internal::Flag( + name_, filename_, + {flags_internal::FlagHelpMsg(help_gen_), + flags_internal::FlagHelpKind::kGenFunc}, + {flags_internal::FlagDefaultSrc(default_value_gen_), + flags_internal::FlagDefaultKind::kGenFunc}); inited_.store(true, std::memory_order_release); } - return impl_; + return *impl_; } // Public methods of `absl::Flag` are NOT part of the Abseil Flags API. // See https://abseil.io/docs/cpp/guides/flags - bool IsRetired() const { return GetImpl()->IsRetired(); } - bool IsAbseilFlag() const { return GetImpl()->IsAbseilFlag(); } - absl::string_view Name() const { return GetImpl()->Name(); } - std::string Help() const { return GetImpl()->Help(); } - bool IsModified() const { return GetImpl()->IsModified(); } + bool IsRetired() const { return GetImpl().IsRetired(); } + absl::string_view Name() const { return GetImpl().Name(); } + std::string Help() const { return GetImpl().Help(); } + bool IsModified() const { return GetImpl().IsModified(); } bool IsSpecifiedOnCommandLine() const { - return GetImpl()->IsSpecifiedOnCommandLine(); + return GetImpl().IsSpecifiedOnCommandLine(); } - absl::string_view Typename() const { return GetImpl()->Typename(); } - std::string Filename() const { return GetImpl()->Filename(); } - std::string DefaultValue() const { return GetImpl()->DefaultValue(); } - std::string CurrentValue() const { return GetImpl()->CurrentValue(); } + std::string Filename() const { return GetImpl().Filename(); } + std::string DefaultValue() const { return GetImpl().DefaultValue(); } + std::string CurrentValue() const { return GetImpl().CurrentValue(); } template inline bool IsOfType() const { - return GetImpl()->template IsOfType(); + return GetImpl().template IsOfType(); } - T Get() const { return GetImpl()->Get(); } - void Set(const T& v) { GetImpl()->Set(v); } - void SetCallback(const flags_internal::FlagCallbackFunc mutation_callback) { - GetImpl()->SetCallback(mutation_callback); + T Get() const { + return flags_internal::FlagImplPeer::InvokeGet(GetImpl()); + } + void Set(const T& v) { + flags_internal::FlagImplPeer::InvokeSet(GetImpl(), v); + } + void InvokeCallback() { GetImpl().InvokeCallback(); } + + const CommandLineFlag& Reflect() const { + return flags_internal::FlagImplPeer::InvokeReflect(GetImpl()); } - void InvokeCallback() { GetImpl()->InvokeCallback(); } // The data members are logically private, but they need to be public for // this to be an aggregate type. @@ -184,7 +186,7 @@ class Flag { // std::string first_name = absl::GetFlag(FLAGS_firstname); template ABSL_MUST_USE_RESULT T GetFlag(const absl::Flag& flag) { - return flag.Get(); + return flags_internal::FlagImplPeer::InvokeGet(flag); } // SetFlag() @@ -196,7 +198,7 @@ ABSL_MUST_USE_RESULT T GetFlag(const absl::Flag& flag) { // but especially within performance-critical code. template void SetFlag(absl::Flag* flag, const T& v) { - flag->Set(v); + flags_internal::FlagImplPeer::InvokeSet(*flag, v); } // Overload of `SetFlag()` to allow callers to pass in a value that is @@ -205,7 +207,22 @@ void SetFlag(absl::Flag* flag, const T& v) { template void SetFlag(absl::Flag* flag, const V& v) { T value(v); - flag->Set(value); + flags_internal::FlagImplPeer::InvokeSet(*flag, value); +} + +// GetFlagReflectionHandle() +// +// Returns the reflection handle corresponding to specified Abseil Flag +// instance. Use this handle to access flag's reflection information, like name, +// location, default value etc. +// +// Example: +// +// std::string = absl::GetFlagReflectionHandle(FLAGS_count).DefaultValue(); + +template +const CommandLineFlag& GetFlagReflectionHandle(const absl::Flag& f) { + return flags_internal::FlagImplPeer::InvokeReflect(f); } ABSL_NAMESPACE_END @@ -248,6 +265,8 @@ ABSL_NAMESPACE_END // // ABSL_FLAG(T, name, default_value, help).OnUpdate(callback); // +// `callback` should be convertible to `void (*)()`. +// // After any setting of the flag value, the callback will be called at least // once. A rapid sequence of changes may be merged together into the same // callback. No concurrent calls to the callback will be made for the same @@ -262,33 +281,36 @@ ABSL_NAMESPACE_END // Note: ABSL_FLAG.OnUpdate() does not have a public definition. Hence, this // comment serves as its API documentation. - // ----------------------------------------------------------------------------- // Implementation details below this section // ----------------------------------------------------------------------------- // ABSL_FLAG_IMPL macro definition conditional on ABSL_FLAGS_STRIP_NAMES +#if !defined(_MSC_VER) || defined(__clang__) +#define ABSL_FLAG_IMPL_FLAG_PTR(flag) flag +#define ABSL_FLAG_IMPL_HELP_ARG(name) \ + absl::flags_internal::HelpArg( \ + FLAGS_help_storage_##name) +#define ABSL_FLAG_IMPL_DEFAULT_ARG(Type, name) \ + absl::flags_internal::DefaultArg(0) +#else +#define ABSL_FLAG_IMPL_FLAG_PTR(flag) flag.GetImpl() +#define ABSL_FLAG_IMPL_HELP_ARG(name) &AbslFlagHelpGenFor##name::NonConst +#define ABSL_FLAG_IMPL_DEFAULT_ARG(Type, name) &AbslFlagDefaultGenFor##name::Gen +#endif #if ABSL_FLAGS_STRIP_NAMES #define ABSL_FLAG_IMPL_FLAGNAME(txt) "" #define ABSL_FLAG_IMPL_FILENAME() "" -#if !defined(_MSC_VER) || defined(__clang__) -#define ABSL_FLAG_IMPL_REGISTRAR(T, flag) \ - absl::flags_internal::FlagRegistrar(&flag) -#else -#define ABSL_FLAG_IMPL_REGISTRAR(T, flag) \ - absl::flags_internal::FlagRegistrar(flag.GetImpl()) -#endif +#define ABSL_FLAG_IMPL_REGISTRAR(T, flag) \ + absl::flags_internal::FlagRegistrar(ABSL_FLAG_IMPL_FLAG_PTR(flag), \ + nullptr) #else #define ABSL_FLAG_IMPL_FLAGNAME(txt) txt #define ABSL_FLAG_IMPL_FILENAME() __FILE__ -#if !defined(_MSC_VER) || defined(__clang__) -#define ABSL_FLAG_IMPL_REGISTRAR(T, flag) \ - absl::flags_internal::FlagRegistrar(&flag) -#else -#define ABSL_FLAG_IMPL_REGISTRAR(T, flag) \ - absl::flags_internal::FlagRegistrar(flag.GetImpl()) -#endif +#define ABSL_FLAG_IMPL_REGISTRAR(T, flag) \ + absl::flags_internal::FlagRegistrar(ABSL_FLAG_IMPL_FLAG_PTR(flag), \ + __FILE__) #endif // ABSL_FLAG_IMPL macro definition conditional on ABSL_FLAGS_STRIP_HELP @@ -304,50 +326,48 @@ ABSL_NAMESPACE_END // between the two via the call to HelpArg in absl::Flag instantiation below. // If help message expression is constexpr evaluable compiler will optimize // away this whole struct. -#define ABSL_FLAG_IMPL_DECLARE_HELP_WRAPPER(name, txt) \ - struct AbslFlagHelpGenFor##name { \ - template \ - static constexpr const char* Const() { \ - return absl::flags_internal::HelpConstexprWrap( \ - ABSL_FLAG_IMPL_FLAGHELP(txt)); \ - } \ - static std::string NonConst() { return ABSL_FLAG_IMPL_FLAGHELP(txt); } \ - } +// TODO(rogeeff): place these generated structs into local namespace and apply +// ABSL_INTERNAL_UNIQUE_SHORT_NAME. +// TODO(rogeeff): Apply __attribute__((nodebug)) to FLAGS_help_storage_##name +#define ABSL_FLAG_IMPL_DECLARE_HELP_WRAPPER(name, txt) \ + struct AbslFlagHelpGenFor##name { \ + /* The expression is run in the caller as part of the */ \ + /* default value argument. That keeps temporaries alive */ \ + /* long enough for NonConst to work correctly. */ \ + static constexpr absl::string_view Value( \ + absl::string_view v = ABSL_FLAG_IMPL_FLAGHELP(txt)) { \ + return v; \ + } \ + static std::string NonConst() { return std::string(Value()); } \ + }; \ + constexpr auto FLAGS_help_storage_##name ABSL_INTERNAL_UNIQUE_SMALL_NAME() \ + ABSL_ATTRIBUTE_SECTION_VARIABLE(flags_help_cold) = \ + absl::flags_internal::HelpStringAsArray( \ + 0); -#define ABSL_FLAG_IMPL_DECLARE_DEF_VAL_WRAPPER(name, Type, default_value) \ - static void* AbslFlagsInitFlag##name() { \ - return absl::flags_internal::MakeFromDefaultValue(default_value); \ - } +#define ABSL_FLAG_IMPL_DECLARE_DEF_VAL_WRAPPER(name, Type, default_value) \ + struct AbslFlagDefaultGenFor##name { \ + Type value = absl::flags_internal::InitDefaultValue(default_value); \ + static void Gen(void* p) { \ + new (p) Type(AbslFlagDefaultGenFor##name{}.value); \ + } \ + }; // ABSL_FLAG_IMPL // // Note: Name of registrar object is not arbitrary. It is used to "grab" // global name for FLAGS_no symbol, thus preventing the possibility // of defining two flags with names foo and nofoo. -#if !defined(_MSC_VER) || defined(__clang__) -#define ABSL_FLAG_IMPL(Type, name, default_value, help) \ - namespace absl /* block flags in namespaces */ {} \ - ABSL_FLAG_IMPL_DECLARE_DEF_VAL_WRAPPER(name, Type, default_value) \ - ABSL_FLAG_IMPL_DECLARE_HELP_WRAPPER(name, help); \ - ABSL_CONST_INIT absl::Flag FLAGS_##name{ \ - ABSL_FLAG_IMPL_FLAGNAME(#name), ABSL_FLAG_IMPL_FILENAME(), \ - absl::flags_internal::HelpArg(0), \ - &AbslFlagsInitFlag##name}; \ - extern bool FLAGS_no##name; \ - bool FLAGS_no##name = ABSL_FLAG_IMPL_REGISTRAR(Type, FLAGS_##name) -#else -// MSVC version uses aggregate initialization. We also do not try to -// optimize away help wrapper. -#define ABSL_FLAG_IMPL(Type, name, default_value, help) \ - namespace absl /* block flags in namespaces */ {} \ - ABSL_FLAG_IMPL_DECLARE_DEF_VAL_WRAPPER(name, Type, default_value) \ - ABSL_FLAG_IMPL_DECLARE_HELP_WRAPPER(name, help); \ - ABSL_CONST_INIT absl::Flag FLAGS_##name{ \ - ABSL_FLAG_IMPL_FLAGNAME(#name), ABSL_FLAG_IMPL_FILENAME(), \ - &AbslFlagHelpGenFor##name::NonConst, &AbslFlagsInitFlag##name}; \ - extern bool FLAGS_no##name; \ - bool FLAGS_no##name = ABSL_FLAG_IMPL_REGISTRAR(Type, FLAGS_##name) -#endif +#define ABSL_FLAG_IMPL(Type, name, default_value, help) \ + namespace absl /* block flags in namespaces */ {} \ + ABSL_FLAG_IMPL_DECLARE_DEF_VAL_WRAPPER(name, Type, default_value) \ + ABSL_FLAG_IMPL_DECLARE_HELP_WRAPPER(name, help) \ + ABSL_CONST_INIT absl::Flag FLAGS_##name{ \ + ABSL_FLAG_IMPL_FLAGNAME(#name), ABSL_FLAG_IMPL_FILENAME(), \ + ABSL_FLAG_IMPL_HELP_ARG(name), ABSL_FLAG_IMPL_DEFAULT_ARG(Type, name)}; \ + extern absl::flags_internal::FlagRegistrarEmpty FLAGS_no##name; \ + absl::flags_internal::FlagRegistrarEmpty FLAGS_no##name = \ + ABSL_FLAG_IMPL_REGISTRAR(Type, FLAGS_##name) // ABSL_RETIRED_FLAG // @@ -368,11 +388,12 @@ ABSL_NAMESPACE_END // // `default_value` is only used as a double check on the type. `explanation` is // unused. -// TODO(rogeeff): Return an anonymous struct instead of bool, and place it into -// the unnamed namespace. -#define ABSL_RETIRED_FLAG(type, flagname, default_value, explanation) \ - ABSL_ATTRIBUTE_UNUSED static const bool ignored_##flagname = \ - ([] { return type(default_value); }, \ - absl::flags_internal::RetiredFlag(#flagname)) +// TODO(rogeeff): replace RETIRED_FLAGS with FLAGS once forward declarations of +// retired flags are cleaned up. +#define ABSL_RETIRED_FLAG(type, name, default_value, explanation) \ + static absl::flags_internal::RetiredFlag RETIRED_FLAGS_##name; \ + ABSL_ATTRIBUTE_UNUSED static const auto RETIRED_FLAGS_REG_##name = \ + (RETIRED_FLAGS_##name.Retire(#name), \ + ::absl::flags_internal::FlagRegistrarEmpty{}) #endif // ABSL_FLAGS_FLAG_H_ diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/flag_benchmark.cc b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/flag_benchmark.cc index ff95bb5d7b..fc572d9ce3 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/flag_benchmark.cc +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/flag_benchmark.cc @@ -13,7 +13,16 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include + +#include +#include + #include "absl/flags/flag.h" +#include "absl/flags/marshalling.h" +#include "absl/flags/parse.h" +#include "absl/flags/reflection.h" +#include "absl/strings/string_view.h" #include "absl/time/time.h" #include "absl/types/optional.h" #include "benchmark/benchmark.h" @@ -92,26 +101,148 @@ std::string AbslUnparseFlag(const UDT&) { return ""; } A(AbslDuration) \ A(UDT) -#define FLAG_DEF(T) ABSL_FLAG(T, T##_flag, {}, ""); +#define REPLICATE_0(A, T, name, index) A(T, name, index) +#define REPLICATE_1(A, T, name, index) \ + REPLICATE_0(A, T, name, index##0) REPLICATE_0(A, T, name, index##1) +#define REPLICATE_2(A, T, name, index) \ + REPLICATE_1(A, T, name, index##0) REPLICATE_1(A, T, name, index##1) +#define REPLICATE_3(A, T, name, index) \ + REPLICATE_2(A, T, name, index##0) REPLICATE_2(A, T, name, index##1) +#define REPLICATE_4(A, T, name, index) \ + REPLICATE_3(A, T, name, index##0) REPLICATE_3(A, T, name, index##1) +#define REPLICATE_5(A, T, name, index) \ + REPLICATE_4(A, T, name, index##0) REPLICATE_4(A, T, name, index##1) +#define REPLICATE_6(A, T, name, index) \ + REPLICATE_5(A, T, name, index##0) REPLICATE_5(A, T, name, index##1) +#define REPLICATE_7(A, T, name, index) \ + REPLICATE_6(A, T, name, index##0) REPLICATE_6(A, T, name, index##1) +#define REPLICATE_8(A, T, name, index) \ + REPLICATE_7(A, T, name, index##0) REPLICATE_7(A, T, name, index##1) +#define REPLICATE_9(A, T, name, index) \ + REPLICATE_8(A, T, name, index##0) REPLICATE_8(A, T, name, index##1) +#if defined(_MSC_VER) +#define REPLICATE(A, T, name) \ + REPLICATE_7(A, T, name, 0) REPLICATE_7(A, T, name, 1) +#define SINGLE_FLAG(T) FLAGS_##T##_flag_00000000 +#else +#define REPLICATE(A, T, name) \ + REPLICATE_9(A, T, name, 0) REPLICATE_9(A, T, name, 1) +#define SINGLE_FLAG(T) FLAGS_##T##_flag_0000000000 +#endif +#define REPLICATE_ALL(A, T, name) \ + REPLICATE_9(A, T, name, 0) REPLICATE_9(A, T, name, 1) +#define COUNT(T, name, index) +1 +constexpr size_t kNumFlags = 0 REPLICATE(COUNT, _, _); + +#if defined(__clang__) && defined(__linux__) +// Force the flags used for benchmarks into a separate ELF section. +// This ensures that, even when other parts of the code might change size, +// the layout of the flags across cachelines is kept constant. This makes +// benchmark results more reproducible across unrelated code changes. +#pragma clang section data = ".benchmark_flags" +#endif +#define DEFINE_FLAG(T, name, index) ABSL_FLAG(T, name##_##index, {}, ""); +#define FLAG_DEF(T) REPLICATE(DEFINE_FLAG, T, T##_flag); BENCHMARKED_TYPES(FLAG_DEF) +#if defined(__clang__) && defined(__linux__) +#pragma clang section data = "" +#endif +// Register thousands of flags to bloat up the size of the registry. +// This mimics real life production binaries. +#define BLOAT_FLAG(_unused1, _unused2, index) \ + ABSL_FLAG(int, bloat_flag_##index, 0, ""); +REPLICATE_ALL(BLOAT_FLAG, _, _) namespace { -#define BM_GetFlag(T) \ - void BM_GetFlag_##T(benchmark::State& state) { \ - for (auto _ : state) { \ - benchmark::DoNotOptimize(absl::GetFlag(FLAGS_##T##_flag)); \ - } \ - } \ - BENCHMARK(BM_GetFlag_##T); +#define FLAG_PTR(T, name, index) &FLAGS_##name##_##index, +#define FLAG_PTR_ARR(T) \ + static constexpr absl::Flag* FlagPtrs_##T[] = { \ + REPLICATE(FLAG_PTR, T, T##_flag)}; +BENCHMARKED_TYPES(FLAG_PTR_ARR) -BENCHMARKED_TYPES(BM_GetFlag) +#define BM_SingleGetFlag(T) \ + void BM_SingleGetFlag_##T(benchmark::State& state) { \ + for (auto _ : state) { \ + benchmark::DoNotOptimize(absl::GetFlag(SINGLE_FLAG(T))); \ + } \ + } \ + BENCHMARK(BM_SingleGetFlag_##T)->ThreadRange(1, 16); + +BENCHMARKED_TYPES(BM_SingleGetFlag) + +template +struct Accumulator { + using type = T; +}; +template <> +struct Accumulator { + using type = size_t; +}; +template <> +struct Accumulator { + using type = size_t; +}; +template <> +struct Accumulator { + using type = bool; +}; +template <> +struct Accumulator { + using type = bool; +}; +template <> +struct Accumulator { + using type = bool; +}; + +template +void Accumulate(typename Accumulator::type& a, const T& f) { + a += f; +} +void Accumulate(bool& a, bool f) { a = a || f; } +void Accumulate(size_t& a, const std::string& f) { a += f.size(); } +void Accumulate(size_t& a, const std::vector& f) { a += f.size(); } +void Accumulate(bool& a, const OptionalInt& f) { a |= f.has_value(); } +void Accumulate(bool& a, const OptionalString& f) { a |= f.has_value(); } +void Accumulate(bool& a, const UDT& f) { + a |= reinterpret_cast(&f) & 0x1; +} + +#define BM_ManyGetFlag(T) \ + void BM_ManyGetFlag_##T(benchmark::State& state) { \ + Accumulator::type res = {}; \ + while (state.KeepRunningBatch(kNumFlags)) { \ + for (auto* flag_ptr : FlagPtrs_##T) { \ + Accumulate(res, absl::GetFlag(*flag_ptr)); \ + } \ + } \ + benchmark::DoNotOptimize(res); \ + } \ + BENCHMARK(BM_ManyGetFlag_##T)->ThreadRange(1, 8); + +BENCHMARKED_TYPES(BM_ManyGetFlag) + +void BM_ThreadedFindCommandLineFlag(benchmark::State& state) { + char dummy[] = "dummy"; + char* argv[] = {dummy}; + // We need to ensure that flags have been parsed. That is where the registry + // is finalized. + absl::ParseCommandLine(1, argv); + + while (state.KeepRunningBatch(kNumFlags)) { + for (auto* flag_ptr : FlagPtrs_bool) { + benchmark::DoNotOptimize(absl::FindCommandLineFlag(flag_ptr->Name())); + } + } +} +BENCHMARK(BM_ThreadedFindCommandLineFlag)->ThreadRange(1, 16); } // namespace -#define InvokeGetFlag(T) \ - T AbslInvokeGetFlag##T() { return absl::GetFlag(FLAGS_##T##_flag); } \ +#define InvokeGetFlag(T) \ + T AbslInvokeGetFlag##T() { return absl::GetFlag(SINGLE_FLAG(T)); } \ int odr##T = (benchmark::DoNotOptimize(AbslInvokeGetFlag##T), 1); BENCHMARKED_TYPES(InvokeGetFlag) diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/flag_benchmark.lds b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/flag_benchmark.lds new file mode 100644 index 0000000000..af115dfc00 --- /dev/null +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/flag_benchmark.lds @@ -0,0 +1,13 @@ +/* This linker script forces the flags used by flags_benchmark + * into a separate page-aligned section. This isn't necessary for + * correctness but ensures that the benchmark results are more + * reproducible across unrelated code changes. + */ +SECTIONS { + .benchmark_flags : { + . = ALIGN(0x1000); + * (.benchmark_flags); + } +} + +INSERT AFTER .data diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/flag_test.cc b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/flag_test.cc index 377e3b2b89..6e974a5b5e 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/flag_test.cc +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/flag_test.cc @@ -15,25 +15,31 @@ #include "absl/flags/flag.h" +#include #include +#include #include +#include #include +#include // NOLINT #include #include "gtest/gtest.h" #include "absl/base/attributes.h" +#include "absl/base/macros.h" #include "absl/flags/config.h" #include "absl/flags/declare.h" -#include "absl/flags/internal/commandlineflag.h" #include "absl/flags/internal/flag.h" -#include "absl/flags/internal/registry.h" +#include "absl/flags/marshalling.h" +#include "absl/flags/reflection.h" #include "absl/flags/usage_config.h" #include "absl/strings/match.h" #include "absl/strings/numbers.h" #include "absl/strings/str_cat.h" #include "absl/strings/str_split.h" #include "absl/strings/string_view.h" +#include "absl/time/time.h" ABSL_DECLARE_FLAG(int64_t, mistyped_int_flag); ABSL_DECLARE_FLAG(std::vector, mistyped_string_flag); @@ -43,15 +49,19 @@ namespace { namespace flags = absl::flags_internal; std::string TestHelpMsg() { return "dynamic help"; } +#if defined(_MSC_VER) && !defined(__clang__) +std::string TestLiteralHelpMsg() { return "literal help"; } +#endif template -void* TestMakeDflt() { - return new T{}; +void TestMakeDflt(void* dst) { + new (dst) T{}; } void TestCallback() {} struct UDT { UDT() = default; UDT(const UDT&) = default; + UDT& operator=(const UDT&) = default; }; bool AbslParseFlag(absl::string_view, UDT*, std::string*) { return true; } std::string AbslUnparseFlag(const UDT&) { return ""; } @@ -74,6 +84,7 @@ class FlagTest : public testing::Test { #endif return std::string(fname); } + absl::FlagSaver flag_saver_; }; struct S1 { @@ -92,30 +103,30 @@ struct S2 { TEST_F(FlagTest, Traits) { EXPECT_EQ(flags::StorageKind(), - flags::FlagValueStorageKind::kOneWordAtomic); + flags::FlagValueStorageKind::kValueAndInitBit); EXPECT_EQ(flags::StorageKind(), - flags::FlagValueStorageKind::kOneWordAtomic); + flags::FlagValueStorageKind::kValueAndInitBit); EXPECT_EQ(flags::StorageKind(), flags::FlagValueStorageKind::kOneWordAtomic); EXPECT_EQ(flags::StorageKind(), flags::FlagValueStorageKind::kOneWordAtomic); -#if defined(ABSL_FLAGS_INTERNAL_ATOMIC_DOUBLE_WORD) EXPECT_EQ(flags::StorageKind(), - flags::FlagValueStorageKind::kTwoWordsAtomic); + flags::FlagValueStorageKind::kSequenceLocked); EXPECT_EQ(flags::StorageKind(), - flags::FlagValueStorageKind::kTwoWordsAtomic); -#else - EXPECT_EQ(flags::StorageKind(), - flags::FlagValueStorageKind::kHeapAllocated); - EXPECT_EQ(flags::StorageKind(), - flags::FlagValueStorageKind::kHeapAllocated); + flags::FlagValueStorageKind::kSequenceLocked); +// Make sure absl::Duration uses the sequence-locked code path. MSVC 2015 +// doesn't consider absl::Duration to be trivially-copyable so we just +// restrict this to clang as it seems to be a well-behaved compiler. +#ifdef __clang__ + EXPECT_EQ(flags::StorageKind(), + flags::FlagValueStorageKind::kSequenceLocked); #endif EXPECT_EQ(flags::StorageKind(), - flags::FlagValueStorageKind::kHeapAllocated); + flags::FlagValueStorageKind::kAlignedBuffer); EXPECT_EQ(flags::StorageKind>(), - flags::FlagValueStorageKind::kHeapAllocated); + flags::FlagValueStorageKind::kAlignedBuffer); } // -------------------------------------------------------------------- @@ -125,42 +136,60 @@ constexpr flags::FlagHelpArg help_arg{flags::FlagHelpMsg("literal help"), using String = std::string; -#define DEFINE_CONSTRUCTED_FLAG(T) \ - constexpr flags::Flag f1##T("f1", "file", help_arg, &TestMakeDflt); \ - ABSL_CONST_INIT flags::Flag f2##T( \ - "f2", "file", \ - {flags::FlagHelpMsg(&TestHelpMsg), flags::FlagHelpKind::kGenFunc}, \ - &TestMakeDflt) +#if !defined(_MSC_VER) || defined(__clang__) +#define DEFINE_CONSTRUCTED_FLAG(T, dflt, dflt_kind) \ + constexpr flags::FlagDefaultArg f1default##T{ \ + flags::FlagDefaultSrc{dflt}, flags::FlagDefaultKind::dflt_kind}; \ + constexpr absl::Flag f1##T{"f1", "file", help_arg, f1default##T}; \ + ABSL_CONST_INIT absl::Flag f2##T { \ + "f2", "file", \ + {flags::FlagHelpMsg(&TestHelpMsg), flags::FlagHelpKind::kGenFunc}, \ + flags::FlagDefaultArg { \ + flags::FlagDefaultSrc(&TestMakeDflt), \ + flags::FlagDefaultKind::kGenFunc \ + } \ + } +#else +#define DEFINE_CONSTRUCTED_FLAG(T, dflt, dflt_kind) \ + constexpr flags::FlagDefaultArg f1default##T{ \ + flags::FlagDefaultSrc{dflt}, flags::FlagDefaultKind::dflt_kind}; \ + constexpr absl::Flag f1##T{"f1", "file", &TestLiteralHelpMsg, \ + &TestMakeDflt}; \ + ABSL_CONST_INIT absl::Flag f2##T { \ + "f2", "file", &TestHelpMsg, &TestMakeDflt \ + } +#endif -#define TEST_CONSTRUCTED_FLAG(T) TestConstructionFor(f1##T, &f2##T); - -DEFINE_CONSTRUCTED_FLAG(bool); -DEFINE_CONSTRUCTED_FLAG(int16_t); -DEFINE_CONSTRUCTED_FLAG(uint16_t); -DEFINE_CONSTRUCTED_FLAG(int32_t); -DEFINE_CONSTRUCTED_FLAG(uint32_t); -DEFINE_CONSTRUCTED_FLAG(int64_t); -DEFINE_CONSTRUCTED_FLAG(uint64_t); -DEFINE_CONSTRUCTED_FLAG(float); -DEFINE_CONSTRUCTED_FLAG(double); -DEFINE_CONSTRUCTED_FLAG(String); -DEFINE_CONSTRUCTED_FLAG(UDT); +DEFINE_CONSTRUCTED_FLAG(bool, true, kOneWord); +DEFINE_CONSTRUCTED_FLAG(int16_t, 1, kOneWord); +DEFINE_CONSTRUCTED_FLAG(uint16_t, 2, kOneWord); +DEFINE_CONSTRUCTED_FLAG(int32_t, 3, kOneWord); +DEFINE_CONSTRUCTED_FLAG(uint32_t, 4, kOneWord); +DEFINE_CONSTRUCTED_FLAG(int64_t, 5, kOneWord); +DEFINE_CONSTRUCTED_FLAG(uint64_t, 6, kOneWord); +DEFINE_CONSTRUCTED_FLAG(float, 7.8, kOneWord); +DEFINE_CONSTRUCTED_FLAG(double, 9.10, kOneWord); +DEFINE_CONSTRUCTED_FLAG(String, &TestMakeDflt, kGenFunc); +DEFINE_CONSTRUCTED_FLAG(UDT, &TestMakeDflt, kGenFunc); template -bool TestConstructionFor(const flags::Flag& f1, flags::Flag* f2) { - EXPECT_EQ(f1.Name(), "f1"); - EXPECT_EQ(f1.Help(), "literal help"); - EXPECT_EQ(f1.Filename(), "file"); +bool TestConstructionFor(const absl::Flag& f1, absl::Flag& f2) { + EXPECT_EQ(absl::GetFlagReflectionHandle(f1).Name(), "f1"); + EXPECT_EQ(absl::GetFlagReflectionHandle(f1).Help(), "literal help"); + EXPECT_EQ(absl::GetFlagReflectionHandle(f1).Filename(), "file"); - flags::FlagRegistrar(f2).OnUpdate(TestCallback); + flags::FlagRegistrar(ABSL_FLAG_IMPL_FLAG_PTR(f2), nullptr) + .OnUpdate(TestCallback); - EXPECT_EQ(f2->Name(), "f2"); - EXPECT_EQ(f2->Help(), "dynamic help"); - EXPECT_EQ(f2->Filename(), "file"); + EXPECT_EQ(absl::GetFlagReflectionHandle(f2).Name(), "f2"); + EXPECT_EQ(absl::GetFlagReflectionHandle(f2).Help(), "dynamic help"); + EXPECT_EQ(absl::GetFlagReflectionHandle(f2).Filename(), "file"); return true; } +#define TEST_CONSTRUCTED_FLAG(T) TestConstructionFor(f1##T, f2##T); + TEST_F(FlagTest, TestConstruction) { TEST_CONSTRUCTED_FLAG(bool); TEST_CONSTRUCTED_FLAG(int16_t); @@ -190,6 +219,7 @@ ABSL_DECLARE_FLAG(uint64_t, test_flag_08); ABSL_DECLARE_FLAG(double, test_flag_09); ABSL_DECLARE_FLAG(float, test_flag_10); ABSL_DECLARE_FLAG(std::string, test_flag_11); +ABSL_DECLARE_FLAG(absl::Duration, test_flag_12); namespace { @@ -197,17 +227,30 @@ namespace { TEST_F(FlagTest, TestFlagDeclaration) { // test that we can access flag objects. - EXPECT_EQ(FLAGS_test_flag_01.Name(), "test_flag_01"); - EXPECT_EQ(FLAGS_test_flag_02.Name(), "test_flag_02"); - EXPECT_EQ(FLAGS_test_flag_03.Name(), "test_flag_03"); - EXPECT_EQ(FLAGS_test_flag_04.Name(), "test_flag_04"); - EXPECT_EQ(FLAGS_test_flag_05.Name(), "test_flag_05"); - EXPECT_EQ(FLAGS_test_flag_06.Name(), "test_flag_06"); - EXPECT_EQ(FLAGS_test_flag_07.Name(), "test_flag_07"); - EXPECT_EQ(FLAGS_test_flag_08.Name(), "test_flag_08"); - EXPECT_EQ(FLAGS_test_flag_09.Name(), "test_flag_09"); - EXPECT_EQ(FLAGS_test_flag_10.Name(), "test_flag_10"); - EXPECT_EQ(FLAGS_test_flag_11.Name(), "test_flag_11"); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_01).Name(), + "test_flag_01"); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_02).Name(), + "test_flag_02"); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_03).Name(), + "test_flag_03"); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_04).Name(), + "test_flag_04"); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_05).Name(), + "test_flag_05"); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_06).Name(), + "test_flag_06"); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_07).Name(), + "test_flag_07"); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_08).Name(), + "test_flag_08"); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_09).Name(), + "test_flag_09"); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_10).Name(), + "test_flag_10"); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_11).Name(), + "test_flag_11"); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_12).Name(), + "test_flag_12"); } #endif // !ABSL_FLAGS_STRIP_NAMES @@ -226,6 +269,7 @@ ABSL_FLAG(uint64_t, test_flag_08, 9876543, "test flag 08"); ABSL_FLAG(double, test_flag_09, -9.876e-50, "test flag 09"); ABSL_FLAG(float, test_flag_10, 1.234e12f, "test flag 10"); ABSL_FLAG(std::string, test_flag_11, "", "test flag 11"); +ABSL_FLAG(absl::Duration, test_flag_12, absl::Minutes(10), "test flag 12"); namespace { @@ -233,77 +277,168 @@ namespace { TEST_F(FlagTest, TestFlagDefinition) { absl::string_view expected_file_name = "absl/flags/flag_test.cc"; - EXPECT_EQ(FLAGS_test_flag_01.Name(), "test_flag_01"); - EXPECT_EQ(FLAGS_test_flag_01.Help(), "test flag 01"); - EXPECT_TRUE(absl::EndsWith(FLAGS_test_flag_01.Filename(), expected_file_name)) - << FLAGS_test_flag_01.Filename(); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_01).Name(), + "test_flag_01"); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_01).Help(), + "test flag 01"); + EXPECT_TRUE(absl::EndsWith( + absl::GetFlagReflectionHandle(FLAGS_test_flag_01).Filename(), + expected_file_name)) + << absl::GetFlagReflectionHandle(FLAGS_test_flag_01).Filename(); - EXPECT_EQ(FLAGS_test_flag_02.Name(), "test_flag_02"); - EXPECT_EQ(FLAGS_test_flag_02.Help(), "test flag 02"); - EXPECT_TRUE(absl::EndsWith(FLAGS_test_flag_02.Filename(), expected_file_name)) - << FLAGS_test_flag_02.Filename(); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_02).Name(), + "test_flag_02"); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_02).Help(), + "test flag 02"); + EXPECT_TRUE(absl::EndsWith( + absl::GetFlagReflectionHandle(FLAGS_test_flag_02).Filename(), + expected_file_name)) + << absl::GetFlagReflectionHandle(FLAGS_test_flag_02).Filename(); - EXPECT_EQ(FLAGS_test_flag_03.Name(), "test_flag_03"); - EXPECT_EQ(FLAGS_test_flag_03.Help(), "test flag 03"); - EXPECT_TRUE(absl::EndsWith(FLAGS_test_flag_03.Filename(), expected_file_name)) - << FLAGS_test_flag_03.Filename(); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_03).Name(), + "test_flag_03"); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_03).Help(), + "test flag 03"); + EXPECT_TRUE(absl::EndsWith( + absl::GetFlagReflectionHandle(FLAGS_test_flag_03).Filename(), + expected_file_name)) + << absl::GetFlagReflectionHandle(FLAGS_test_flag_03).Filename(); - EXPECT_EQ(FLAGS_test_flag_04.Name(), "test_flag_04"); - EXPECT_EQ(FLAGS_test_flag_04.Help(), "test flag 04"); - EXPECT_TRUE(absl::EndsWith(FLAGS_test_flag_04.Filename(), expected_file_name)) - << FLAGS_test_flag_04.Filename(); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_04).Name(), + "test_flag_04"); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_04).Help(), + "test flag 04"); + EXPECT_TRUE(absl::EndsWith( + absl::GetFlagReflectionHandle(FLAGS_test_flag_04).Filename(), + expected_file_name)) + << absl::GetFlagReflectionHandle(FLAGS_test_flag_04).Filename(); - EXPECT_EQ(FLAGS_test_flag_05.Name(), "test_flag_05"); - EXPECT_EQ(FLAGS_test_flag_05.Help(), "test flag 05"); - EXPECT_TRUE(absl::EndsWith(FLAGS_test_flag_05.Filename(), expected_file_name)) - << FLAGS_test_flag_05.Filename(); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_05).Name(), + "test_flag_05"); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_05).Help(), + "test flag 05"); + EXPECT_TRUE(absl::EndsWith( + absl::GetFlagReflectionHandle(FLAGS_test_flag_05).Filename(), + expected_file_name)) + << absl::GetFlagReflectionHandle(FLAGS_test_flag_05).Filename(); - EXPECT_EQ(FLAGS_test_flag_06.Name(), "test_flag_06"); - EXPECT_EQ(FLAGS_test_flag_06.Help(), "test flag 06"); - EXPECT_TRUE(absl::EndsWith(FLAGS_test_flag_06.Filename(), expected_file_name)) - << FLAGS_test_flag_06.Filename(); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_06).Name(), + "test_flag_06"); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_06).Help(), + "test flag 06"); + EXPECT_TRUE(absl::EndsWith( + absl::GetFlagReflectionHandle(FLAGS_test_flag_06).Filename(), + expected_file_name)) + << absl::GetFlagReflectionHandle(FLAGS_test_flag_06).Filename(); - EXPECT_EQ(FLAGS_test_flag_07.Name(), "test_flag_07"); - EXPECT_EQ(FLAGS_test_flag_07.Help(), "test flag 07"); - EXPECT_TRUE(absl::EndsWith(FLAGS_test_flag_07.Filename(), expected_file_name)) - << FLAGS_test_flag_07.Filename(); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_07).Name(), + "test_flag_07"); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_07).Help(), + "test flag 07"); + EXPECT_TRUE(absl::EndsWith( + absl::GetFlagReflectionHandle(FLAGS_test_flag_07).Filename(), + expected_file_name)) + << absl::GetFlagReflectionHandle(FLAGS_test_flag_07).Filename(); - EXPECT_EQ(FLAGS_test_flag_08.Name(), "test_flag_08"); - EXPECT_EQ(FLAGS_test_flag_08.Help(), "test flag 08"); - EXPECT_TRUE(absl::EndsWith(FLAGS_test_flag_08.Filename(), expected_file_name)) - << FLAGS_test_flag_08.Filename(); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_08).Name(), + "test_flag_08"); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_08).Help(), + "test flag 08"); + EXPECT_TRUE(absl::EndsWith( + absl::GetFlagReflectionHandle(FLAGS_test_flag_08).Filename(), + expected_file_name)) + << absl::GetFlagReflectionHandle(FLAGS_test_flag_08).Filename(); - EXPECT_EQ(FLAGS_test_flag_09.Name(), "test_flag_09"); - EXPECT_EQ(FLAGS_test_flag_09.Help(), "test flag 09"); - EXPECT_TRUE(absl::EndsWith(FLAGS_test_flag_09.Filename(), expected_file_name)) - << FLAGS_test_flag_09.Filename(); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_09).Name(), + "test_flag_09"); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_09).Help(), + "test flag 09"); + EXPECT_TRUE(absl::EndsWith( + absl::GetFlagReflectionHandle(FLAGS_test_flag_09).Filename(), + expected_file_name)) + << absl::GetFlagReflectionHandle(FLAGS_test_flag_09).Filename(); - EXPECT_EQ(FLAGS_test_flag_10.Name(), "test_flag_10"); - EXPECT_EQ(FLAGS_test_flag_10.Help(), "test flag 10"); - EXPECT_TRUE(absl::EndsWith(FLAGS_test_flag_10.Filename(), expected_file_name)) - << FLAGS_test_flag_10.Filename(); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_10).Name(), + "test_flag_10"); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_10).Help(), + "test flag 10"); + EXPECT_TRUE(absl::EndsWith( + absl::GetFlagReflectionHandle(FLAGS_test_flag_10).Filename(), + expected_file_name)) + << absl::GetFlagReflectionHandle(FLAGS_test_flag_10).Filename(); - EXPECT_EQ(FLAGS_test_flag_11.Name(), "test_flag_11"); - EXPECT_EQ(FLAGS_test_flag_11.Help(), "test flag 11"); - EXPECT_TRUE(absl::EndsWith(FLAGS_test_flag_11.Filename(), expected_file_name)) - << FLAGS_test_flag_11.Filename(); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_11).Name(), + "test_flag_11"); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_11).Help(), + "test flag 11"); + EXPECT_TRUE(absl::EndsWith( + absl::GetFlagReflectionHandle(FLAGS_test_flag_11).Filename(), + expected_file_name)) + << absl::GetFlagReflectionHandle(FLAGS_test_flag_11).Filename(); + + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_12).Name(), + "test_flag_12"); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_12).Help(), + "test flag 12"); + EXPECT_TRUE(absl::EndsWith( + absl::GetFlagReflectionHandle(FLAGS_test_flag_12).Filename(), + expected_file_name)) + << absl::GetFlagReflectionHandle(FLAGS_test_flag_12).Filename(); } #endif // !ABSL_FLAGS_STRIP_NAMES // -------------------------------------------------------------------- TEST_F(FlagTest, TestDefault) { - EXPECT_EQ(FLAGS_test_flag_01.DefaultValue(), "true"); - EXPECT_EQ(FLAGS_test_flag_02.DefaultValue(), "1234"); - EXPECT_EQ(FLAGS_test_flag_03.DefaultValue(), "-34"); - EXPECT_EQ(FLAGS_test_flag_04.DefaultValue(), "189"); - EXPECT_EQ(FLAGS_test_flag_05.DefaultValue(), "10765"); - EXPECT_EQ(FLAGS_test_flag_06.DefaultValue(), "40000"); - EXPECT_EQ(FLAGS_test_flag_07.DefaultValue(), "-1234567"); - EXPECT_EQ(FLAGS_test_flag_08.DefaultValue(), "9876543"); - EXPECT_EQ(FLAGS_test_flag_09.DefaultValue(), "-9.876e-50"); - EXPECT_EQ(FLAGS_test_flag_10.DefaultValue(), "1.234e+12"); - EXPECT_EQ(FLAGS_test_flag_11.DefaultValue(), ""); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_01).DefaultValue(), + "true"); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_02).DefaultValue(), + "1234"); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_03).DefaultValue(), + "-34"); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_04).DefaultValue(), + "189"); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_05).DefaultValue(), + "10765"); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_06).DefaultValue(), + "40000"); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_07).DefaultValue(), + "-1234567"); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_08).DefaultValue(), + "9876543"); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_09).DefaultValue(), + "-9.876e-50"); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_10).DefaultValue(), + "1.234e+12"); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_11).DefaultValue(), + ""); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_12).DefaultValue(), + "10m"); + + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_01).CurrentValue(), + "true"); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_02).CurrentValue(), + "1234"); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_03).CurrentValue(), + "-34"); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_04).CurrentValue(), + "189"); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_05).CurrentValue(), + "10765"); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_06).CurrentValue(), + "40000"); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_07).CurrentValue(), + "-1234567"); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_08).CurrentValue(), + "9876543"); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_09).CurrentValue(), + "-9.876e-50"); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_10).CurrentValue(), + "1.234e+12"); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_11).CurrentValue(), + ""); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_12).CurrentValue(), + "10m"); EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_01), true); EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_02), 1234); @@ -316,6 +451,7 @@ TEST_F(FlagTest, TestDefault) { EXPECT_NEAR(absl::GetFlag(FLAGS_test_flag_09), -9.876e-50, 1e-55); EXPECT_NEAR(absl::GetFlag(FLAGS_test_flag_10), 1.234e12f, 1e5f); EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_11), ""); + EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_12), absl::Minutes(10)); } // -------------------------------------------------------------------- @@ -357,12 +493,18 @@ ABSL_FLAG(NonTriviallyCopyableAggregate, test_flag_eb_06, {}, ""); namespace { TEST_F(FlagTest, TestEmptyBracesDefault) { - EXPECT_EQ(FLAGS_test_flag_eb_01.DefaultValue(), "false"); - EXPECT_EQ(FLAGS_test_flag_eb_02.DefaultValue(), "0"); - EXPECT_EQ(FLAGS_test_flag_eb_03.DefaultValue(), "0"); - EXPECT_EQ(FLAGS_test_flag_eb_04.DefaultValue(), "0"); - EXPECT_EQ(FLAGS_test_flag_eb_05.DefaultValue(), ""); - EXPECT_EQ(FLAGS_test_flag_eb_06.DefaultValue(), "0"); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_eb_01).DefaultValue(), + "false"); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_eb_02).DefaultValue(), + "0"); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_eb_03).DefaultValue(), + "0"); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_eb_04).DefaultValue(), + "0"); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_eb_05).DefaultValue(), + ""); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_eb_06).DefaultValue(), + "0"); EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_eb_01), false); EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_eb_02), 0); @@ -408,6 +550,75 @@ TEST_F(FlagTest, TestGetSet) { absl::SetFlag(&FLAGS_test_flag_11, "asdf"); EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_11), "asdf"); + + absl::SetFlag(&FLAGS_test_flag_12, absl::Seconds(110)); + EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_12), absl::Seconds(110)); +} + +// -------------------------------------------------------------------- + +TEST_F(FlagTest, TestGetViaReflection) { + auto* handle = absl::FindCommandLineFlag("test_flag_01"); + EXPECT_EQ(*handle->TryGet(), true); + handle = absl::FindCommandLineFlag("test_flag_02"); + EXPECT_EQ(*handle->TryGet(), 1234); + handle = absl::FindCommandLineFlag("test_flag_03"); + EXPECT_EQ(*handle->TryGet(), -34); + handle = absl::FindCommandLineFlag("test_flag_04"); + EXPECT_EQ(*handle->TryGet(), 189); + handle = absl::FindCommandLineFlag("test_flag_05"); + EXPECT_EQ(*handle->TryGet(), 10765); + handle = absl::FindCommandLineFlag("test_flag_06"); + EXPECT_EQ(*handle->TryGet(), 40000); + handle = absl::FindCommandLineFlag("test_flag_07"); + EXPECT_EQ(*handle->TryGet(), -1234567); + handle = absl::FindCommandLineFlag("test_flag_08"); + EXPECT_EQ(*handle->TryGet(), 9876543); + handle = absl::FindCommandLineFlag("test_flag_09"); + EXPECT_NEAR(*handle->TryGet(), -9.876e-50, 1e-55); + handle = absl::FindCommandLineFlag("test_flag_10"); + EXPECT_NEAR(*handle->TryGet(), 1.234e12f, 1e5f); + handle = absl::FindCommandLineFlag("test_flag_11"); + EXPECT_EQ(*handle->TryGet(), ""); + handle = absl::FindCommandLineFlag("test_flag_12"); + EXPECT_EQ(*handle->TryGet(), absl::Minutes(10)); +} + +// -------------------------------------------------------------------- + +TEST_F(FlagTest, ConcurrentSetAndGet) { + static constexpr int kNumThreads = 8; + // Two arbitrary durations. One thread will concurrently flip the flag + // between these two values, while the other threads read it and verify + // that no other value is seen. + static const absl::Duration kValidDurations[] = { + absl::Seconds(int64_t{0x6cebf47a9b68c802}) + absl::Nanoseconds(229702057), + absl::Seconds(int64_t{0x23fec0307e4e9d3}) + absl::Nanoseconds(44555374)}; + absl::SetFlag(&FLAGS_test_flag_12, kValidDurations[0]); + + std::atomic stop{false}; + std::vector threads; + auto* handle = absl::FindCommandLineFlag("test_flag_12"); + for (int i = 0; i < kNumThreads; i++) { + threads.emplace_back([&]() { + while (!stop.load(std::memory_order_relaxed)) { + // Try loading the flag both directly and via a reflection + // handle. + absl::Duration v = absl::GetFlag(FLAGS_test_flag_12); + EXPECT_TRUE(v == kValidDurations[0] || v == kValidDurations[1]); + v = *handle->TryGet(); + EXPECT_TRUE(v == kValidDurations[0] || v == kValidDurations[1]); + } + }); + } + absl::Time end_time = absl::Now() + absl::Seconds(1); + int i = 0; + while (absl::Now() < end_time) { + absl::SetFlag(&FLAGS_test_flag_12, + kValidDurations[i++ % ABSL_ARRAYSIZE(kValidDurations)]); + } + stop.store(true, std::memory_order_relaxed); + for (auto& t : threads) t.join(); } // -------------------------------------------------------------------- @@ -416,28 +627,33 @@ int GetDflt1() { return 1; } } // namespace -ABSL_FLAG(int, test_flag_12, GetDflt1(), "test flag 12"); -ABSL_FLAG(std::string, test_flag_13, absl::StrCat("AAA", "BBB"), - "test flag 13"); +ABSL_FLAG(int, test_int_flag_with_non_const_default, GetDflt1(), + "test int flag non const default"); +ABSL_FLAG(std::string, test_string_flag_with_non_const_default, + absl::StrCat("AAA", "BBB"), "test string flag non const default"); namespace { TEST_F(FlagTest, TestNonConstexprDefault) { - EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_12), 1); - EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_13), "AAABBB"); + EXPECT_EQ(absl::GetFlag(FLAGS_test_int_flag_with_non_const_default), 1); + EXPECT_EQ(absl::GetFlag(FLAGS_test_string_flag_with_non_const_default), + "AAABBB"); } // -------------------------------------------------------------------- } // namespace -ABSL_FLAG(bool, test_flag_14, true, absl::StrCat("test ", "flag ", "14")); +ABSL_FLAG(bool, test_flag_with_non_const_help, true, + absl::StrCat("test ", "flag ", "non const help")); namespace { #if !ABSL_FLAGS_STRIP_HELP TEST_F(FlagTest, TestNonConstexprHelp) { - EXPECT_EQ(FLAGS_test_flag_14.Help(), "test flag 14"); + EXPECT_EQ( + absl::GetFlagReflectionHandle(FLAGS_test_flag_with_non_const_help).Help(), + "test flag non const help"); } #endif //! ABSL_FLAGS_STRIP_HELP @@ -503,14 +719,16 @@ std::string AbslUnparseFlag(const CustomUDT& f) { } // namespace -ABSL_FLAG(CustomUDT, test_flag_15, CustomUDT(), "test flag 15"); +ABSL_FLAG(CustomUDT, test_flag_custom_udt, CustomUDT(), "test flag custom UDT"); namespace { TEST_F(FlagTest, TestCustomUDT) { - EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_15), CustomUDT(1, 1)); - absl::SetFlag(&FLAGS_test_flag_15, CustomUDT(2, 3)); - EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_15), CustomUDT(2, 3)); + EXPECT_EQ(flags::StorageKind(), + flags::FlagValueStorageKind::kOneWordAtomic); + EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_custom_udt), CustomUDT(1, 1)); + absl::SetFlag(&FLAGS_test_flag_custom_udt, CustomUDT(2, 3)); + EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_custom_udt), CustomUDT(2, 3)); } // MSVC produces link error on the type mismatch. @@ -521,18 +739,21 @@ using FlagDeathTest = FlagTest; TEST_F(FlagDeathTest, TestTypeMismatchValidations) { #if !defined(NDEBUG) - EXPECT_DEATH(static_cast(absl::GetFlag(FLAGS_mistyped_int_flag)), - "Flag 'mistyped_int_flag' is defined as one type and declared " - "as another"); - EXPECT_DEATH(static_cast(absl::GetFlag(FLAGS_mistyped_string_flag)), - "Flag 'mistyped_string_flag' is defined as one type and " - "declared as another"); + EXPECT_DEATH_IF_SUPPORTED( + static_cast(absl::GetFlag(FLAGS_mistyped_int_flag)), + "Flag 'mistyped_int_flag' is defined as one type and declared " + "as another"); + EXPECT_DEATH_IF_SUPPORTED( + static_cast(absl::GetFlag(FLAGS_mistyped_string_flag)), + "Flag 'mistyped_string_flag' is defined as one type and " + "declared as another"); #endif - EXPECT_DEATH(absl::SetFlag(&FLAGS_mistyped_int_flag, 1), - "Flag 'mistyped_int_flag' is defined as one type and declared " - "as another"); - EXPECT_DEATH( + EXPECT_DEATH_IF_SUPPORTED( + absl::SetFlag(&FLAGS_mistyped_int_flag, 1), + "Flag 'mistyped_int_flag' is defined as one type and declared " + "as another"); + EXPECT_DEATH_IF_SUPPORTED( absl::SetFlag(&FLAGS_mistyped_string_flag, std::vector{}), "Flag 'mistyped_string_flag' is defined as one type and declared as " "another"); @@ -570,16 +791,17 @@ std::string AbslUnparseFlag(const ConversionTestVal& val) { // Flag default values can be specified with a value that converts to the flag // value type implicitly. -ABSL_FLAG(ConversionTestVal, test_flag_16, - ConversionTestVal::ViaImplicitConv::kTen, "test flag 16"); +ABSL_FLAG(ConversionTestVal, test_flag_implicit_conv, + ConversionTestVal::ViaImplicitConv::kTen, + "test flag init via implicit conversion"); namespace { TEST_F(FlagTest, CanSetViaImplicitConversion) { - EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_16).a, 10); - absl::SetFlag(&FLAGS_test_flag_16, + EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_implicit_conv).a, 10); + absl::SetFlag(&FLAGS_test_flag_implicit_conv, ConversionTestVal::ViaImplicitConv::kEleven); - EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_16).a, 11); + EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_implicit_conv).a, 11); } // -------------------------------------------------------------------- @@ -632,17 +854,126 @@ ABSL_RETIRED_FLAG(bool, old_bool_flag, true, "old descr"); ABSL_RETIRED_FLAG(int, old_int_flag, (int)std::sqrt(10), "old descr"); ABSL_RETIRED_FLAG(std::string, old_str_flag, "", absl::StrCat("old ", "descr")); +bool initializaion_order_fiasco_test = [] { + // Iterate over all the flags during static initialization. + // This should not trigger ASan's initialization-order-fiasco. + auto* handle1 = absl::FindCommandLineFlag("flag_on_separate_file"); + auto* handle2 = absl::FindCommandLineFlag("retired_flag_on_separate_file"); + if (handle1 != nullptr && handle2 != nullptr) { + return handle1->Name() == handle2->Name(); + } + return true; +}(); + namespace { TEST_F(FlagTest, TestRetiredFlagRegistration) { - bool is_bool = false; - EXPECT_TRUE(flags::IsRetiredFlag("old_bool_flag", &is_bool)); - EXPECT_TRUE(is_bool); - EXPECT_TRUE(flags::IsRetiredFlag("old_int_flag", &is_bool)); - EXPECT_FALSE(is_bool); - EXPECT_TRUE(flags::IsRetiredFlag("old_str_flag", &is_bool)); - EXPECT_FALSE(is_bool); - EXPECT_FALSE(flags::IsRetiredFlag("some_other_flag", &is_bool)); + auto* handle = absl::FindCommandLineFlag("old_bool_flag"); + EXPECT_TRUE(handle->IsOfType()); + EXPECT_TRUE(handle->IsRetired()); + handle = absl::FindCommandLineFlag("old_int_flag"); + EXPECT_TRUE(handle->IsOfType()); + EXPECT_TRUE(handle->IsRetired()); + handle = absl::FindCommandLineFlag("old_str_flag"); + EXPECT_TRUE(handle->IsOfType()); + EXPECT_TRUE(handle->IsRetired()); } } // namespace + +// -------------------------------------------------------------------- + +namespace { + +// User-defined type with small alignment, but size exceeding 16. +struct SmallAlignUDT { + SmallAlignUDT() : c('A'), s(12) {} + char c; + int16_t s; + char bytes[14]; +}; + +bool AbslParseFlag(absl::string_view, SmallAlignUDT*, std::string*) { + return true; +} +std::string AbslUnparseFlag(const SmallAlignUDT&) { return ""; } + +// User-defined type with small size, but not trivially copyable. +struct NonTriviallyCopyableUDT { + NonTriviallyCopyableUDT() : c('A') {} + NonTriviallyCopyableUDT(const NonTriviallyCopyableUDT& rhs) : c(rhs.c) {} + NonTriviallyCopyableUDT& operator=(const NonTriviallyCopyableUDT& rhs) { + c = rhs.c; + return *this; + } + + char c; +}; + +bool AbslParseFlag(absl::string_view, NonTriviallyCopyableUDT*, std::string*) { + return true; +} +std::string AbslUnparseFlag(const NonTriviallyCopyableUDT&) { return ""; } + +} // namespace + +ABSL_FLAG(SmallAlignUDT, test_flag_sa_udt, {}, "help"); +ABSL_FLAG(NonTriviallyCopyableUDT, test_flag_ntc_udt, {}, "help"); + +namespace { + +TEST_F(FlagTest, TestSmallAlignUDT) { + SmallAlignUDT value = absl::GetFlag(FLAGS_test_flag_sa_udt); + EXPECT_EQ(value.c, 'A'); + EXPECT_EQ(value.s, 12); + + value.c = 'B'; + value.s = 45; + absl::SetFlag(&FLAGS_test_flag_sa_udt, value); + value = absl::GetFlag(FLAGS_test_flag_sa_udt); + EXPECT_EQ(value.c, 'B'); + EXPECT_EQ(value.s, 45); +} + +TEST_F(FlagTest, TestNonTriviallyCopyableUDT) { + NonTriviallyCopyableUDT value = absl::GetFlag(FLAGS_test_flag_ntc_udt); + EXPECT_EQ(value.c, 'A'); + + value.c = 'B'; + absl::SetFlag(&FLAGS_test_flag_ntc_udt, value); + value = absl::GetFlag(FLAGS_test_flag_ntc_udt); + EXPECT_EQ(value.c, 'B'); +} + +} // namespace + +// -------------------------------------------------------------------- + +namespace { + +enum TestE { A = 1, B = 2, C = 3 }; + +struct EnumWrapper { + EnumWrapper() : e(A) {} + + TestE e; +}; + +bool AbslParseFlag(absl::string_view, EnumWrapper*, std::string*) { + return true; +} +std::string AbslUnparseFlag(const EnumWrapper&) { return ""; } + +} // namespace + +ABSL_FLAG(EnumWrapper, test_enum_wrapper_flag, {}, "help"); + +TEST_F(FlagTest, TesTypeWrappingEnum) { + EnumWrapper value = absl::GetFlag(FLAGS_test_enum_wrapper_flag); + EXPECT_EQ(value.e, A); + + value.e = B; + absl::SetFlag(&FLAGS_test_enum_wrapper_flag, value); + value = absl::GetFlag(FLAGS_test_enum_wrapper_flag); + EXPECT_EQ(value.e, B); +} diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/flag_test_defs.cc b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/flag_test_defs.cc index 49f91dee39..4e1693cdb9 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/flag_test_defs.cc +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/flag_test_defs.cc @@ -20,5 +20,5 @@ ABSL_FLAG(int, mistyped_int_flag, 0, ""); ABSL_FLAG(std::string, mistyped_string_flag, "", ""); -ABSL_RETIRED_FLAG(bool, old_bool_flag, true, - "repetition of retired flag definition"); +ABSL_FLAG(bool, flag_on_separate_file, false, ""); +ABSL_RETIRED_FLAG(bool, retired_flag_on_separate_file, false, ""); diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/internal/commandlineflag.cc b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/internal/commandlineflag.cc index 90765a3eb6..4482955c4c 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/internal/commandlineflag.cc +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/internal/commandlineflag.cc @@ -21,10 +21,6 @@ namespace flags_internal { FlagStateInterface::~FlagStateInterface() {} -bool CommandLineFlag::IsRetired() const { return false; } -bool CommandLineFlag::IsAbseilFlag() const { return true; } - } // namespace flags_internal ABSL_NAMESPACE_END } // namespace absl - diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/internal/commandlineflag.h b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/internal/commandlineflag.h index ef992f7f47..ebfe81ba1e 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/internal/commandlineflag.h +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/internal/commandlineflag.h @@ -16,31 +16,19 @@ #ifndef ABSL_FLAGS_INTERNAL_COMMANDLINEFLAG_H_ #define ABSL_FLAGS_INTERNAL_COMMANDLINEFLAG_H_ -#include -#include - -#include -#include -#include - #include "absl/base/config.h" #include "absl/base/internal/fast_type_id.h" -#include "absl/base/macros.h" -#include "absl/flags/config.h" -#include "absl/flags/marshalling.h" -#include "absl/strings/string_view.h" -#include "absl/types/optional.h" namespace absl { ABSL_NAMESPACE_BEGIN namespace flags_internal { // An alias for flag fast type id. This value identifies the flag value type -// simialarly to typeid(T), without relying on RTTI being available. In most +// similarly to typeid(T), without relying on RTTI being available. In most // cases this id is enough to uniquely identify the flag's value type. In a few // cases we'll have to resort to using actual RTTI implementation if it is // available. -using FlagFastTypeId = base_internal::FastTypeIdType; +using FlagFastTypeId = absl::base_internal::FastTypeIdType; // Options that control SetCommandLineOptionWithMode. enum FlagSettingMode { @@ -73,129 +61,6 @@ class FlagStateInterface { virtual void Restore() const = 0; }; -// Holds all information for a flag. -class CommandLineFlag { - public: - constexpr CommandLineFlag() = default; - - // Not copyable/assignable. - CommandLineFlag(const CommandLineFlag&) = delete; - CommandLineFlag& operator=(const CommandLineFlag&) = delete; - - // Non-polymorphic access methods. - - // Return true iff flag has type T. - template - inline bool IsOfType() const { - return TypeId() == base_internal::FastTypeId(); - } - - // Attempts to retrieve the flag value. Returns value on success, - // absl::nullopt otherwise. - template - absl::optional Get() const { - if (IsRetired() || !IsOfType()) { - return absl::nullopt; - } - - // Implementation notes: - // - // We are wrapping a union around the value of `T` to serve three purposes: - // - // 1. `U.value` has correct size and alignment for a value of type `T` - // 2. The `U.value` constructor is not invoked since U's constructor does - // not do it explicitly. - // 3. The `U.value` destructor is invoked since U's destructor does it - // explicitly. This makes `U` a kind of RAII wrapper around non default - // constructible value of T, which is destructed when we leave the - // scope. We do need to destroy U.value, which is constructed by - // CommandLineFlag::Read even though we left it in a moved-from state - // after std::move. - // - // All of this serves to avoid requiring `T` being default constructible. - union U { - T value; - U() {} - ~U() { value.~T(); } - }; - U u; - - Read(&u.value); - return std::move(u.value); - } - - // Polymorphic access methods - - // Returns name of this flag. - virtual absl::string_view Name() const = 0; - // Returns name of the file where this flag is defined. - virtual std::string Filename() const = 0; - // Returns name of the flag's value type for some built-in types or empty - // string. - virtual absl::string_view Typename() const = 0; - // Returns help message associated with this flag. - virtual std::string Help() const = 0; - // Returns true iff this object corresponds to retired flag. - virtual bool IsRetired() const; - // Returns true iff this is a handle to an Abseil Flag. - virtual bool IsAbseilFlag() const; - // Returns id of the flag's value type. - virtual FlagFastTypeId TypeId() const = 0; - virtual bool IsModified() const = 0; - virtual bool IsSpecifiedOnCommandLine() const = 0; - virtual std::string DefaultValue() const = 0; - virtual std::string CurrentValue() const = 0; - - // Interfaces to operate on validators. - virtual bool ValidateInputValue(absl::string_view value) const = 0; - - // Interface to save flag to some persistent state. Returns current flag state - // or nullptr if flag does not support saving and restoring a state. - virtual std::unique_ptr SaveState() = 0; - - // Sets the value of the flag based on specified string `value`. If the flag - // was successfully set to new value, it returns true. Otherwise, sets `error` - // to indicate the error, leaves the flag unchanged, and returns false. There - // are three ways to set the flag's value: - // * Update the current flag value - // * Update the flag's default value - // * Update the current flag value if it was never set before - // The mode is selected based on `set_mode` parameter. - virtual bool ParseFrom(absl::string_view value, - flags_internal::FlagSettingMode set_mode, - flags_internal::ValueSource source, - std::string* error) = 0; - - // Checks that flags default value can be converted to string and back to the - // flag's value type. - virtual void CheckDefaultValueParsingRoundtrip() const = 0; - - protected: - ~CommandLineFlag() = default; - - private: - // Copy-construct a new value of the flag's type in a memory referenced by - // the dst based on the current flag's value. - virtual void Read(void* dst) const = 0; -}; - -// This macro is the "source of truth" for the list of supported flag built-in -// types. -#define ABSL_FLAGS_INTERNAL_BUILTIN_TYPES(A) \ - A(bool) \ - A(short) \ - A(unsigned short) \ - A(int) \ - A(unsigned int) \ - A(long) \ - A(unsigned long) \ - A(long long) \ - A(unsigned long long) \ - A(double) \ - A(float) \ - A(std::string) \ - A(std::vector) - } // namespace flags_internal ABSL_NAMESPACE_END } // namespace absl diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/internal/flag.cc b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/internal/flag.cc index f3c424ad83..1515022d11 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/internal/flag.cc +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/internal/flag.cc @@ -15,22 +15,26 @@ #include "absl/flags/internal/flag.h" +#include #include #include #include +#include #include #include +#include #include -#include +#include -#include "absl/base/attributes.h" +#include "absl/base/call_once.h" #include "absl/base/casts.h" #include "absl/base/config.h" -#include "absl/base/const_init.h" #include "absl/base/optimization.h" +#include "absl/flags/config.h" #include "absl/flags/internal/commandlineflag.h" #include "absl/flags/usage_config.h" +#include "absl/memory/memory.h" #include "absl/strings/str_cat.h" #include "absl/strings/string_view.h" #include "absl/synchronization/mutex.h" @@ -49,9 +53,9 @@ namespace { // Currently we only validate flag values for user-defined flag types. bool ShouldValidateFlagValue(FlagFastTypeId flag_type_id) { -#define DONT_VALIDATE(T) \ +#define DONT_VALIDATE(T, _) \ if (flag_type_id == base_internal::FastTypeId()) return false; - ABSL_FLAGS_INTERNAL_BUILTIN_TYPES(DONT_VALIDATE) + ABSL_FLAGS_INTERNAL_SUPPORTED_TYPES(DONT_VALIDATE) #undef DONT_VALIDATE return true; @@ -63,14 +67,14 @@ bool ShouldValidateFlagValue(FlagFastTypeId flag_type_id) { // need to acquire these locks themselves. class MutexRelock { public: - explicit MutexRelock(absl::Mutex* mu) : mu_(mu) { mu_->Unlock(); } - ~MutexRelock() { mu_->Lock(); } + explicit MutexRelock(absl::Mutex& mu) : mu_(mu) { mu_.Unlock(); } + ~MutexRelock() { mu_.Lock(); } MutexRelock(const MutexRelock&) = delete; MutexRelock& operator=(const MutexRelock&) = delete; private: - absl::Mutex* mu_; + absl::Mutex& mu_; }; } // namespace @@ -83,7 +87,7 @@ class FlagImpl; class FlagState : public flags_internal::FlagStateInterface { public: template - FlagState(FlagImpl* flag_impl, const V& v, bool modified, + FlagState(FlagImpl& flag_impl, const V& v, bool modified, bool on_command_line, int64_t counter) : flag_impl_(flag_impl), value_(v), @@ -92,9 +96,10 @@ class FlagState : public flags_internal::FlagStateInterface { counter_(counter) {} ~FlagState() override { - if (flag_impl_->ValueStorageKind() != FlagValueStorageKind::kHeapAllocated) + if (flag_impl_.ValueStorageKind() != FlagValueStorageKind::kAlignedBuffer && + flag_impl_.ValueStorageKind() != FlagValueStorageKind::kSequenceLocked) return; - flags_internal::Delete(flag_impl_->op_, value_.dynamic); + flags_internal::Delete(flag_impl_.op_, value_.heap_allocated); } private: @@ -102,23 +107,21 @@ class FlagState : public flags_internal::FlagStateInterface { // Restores the flag to the saved state. void Restore() const override { - if (!flag_impl_->RestoreState(*this)) return; + if (!flag_impl_.RestoreState(*this)) return; - ABSL_INTERNAL_LOG( - INFO, absl::StrCat("Restore saved value of ", flag_impl_->Name(), - " to: ", flag_impl_->CurrentValue())); + ABSL_INTERNAL_LOG(INFO, + absl::StrCat("Restore saved value of ", flag_impl_.Name(), + " to: ", flag_impl_.CurrentValue())); } // Flag and saved flag data. - FlagImpl* flag_impl_; + FlagImpl& flag_impl_; union SavedValue { - explicit SavedValue(void* v) : dynamic(v) {} + explicit SavedValue(void* v) : heap_allocated(v) {} explicit SavedValue(int64_t v) : one_word(v) {} - explicit SavedValue(flags_internal::AlignedTwoWords v) : two_words(v) {} - void* dynamic; + void* heap_allocated; int64_t one_word; - flags_internal::AlignedTwoWords two_words; } value_; bool modified_; bool on_command_line_; @@ -128,29 +131,54 @@ class FlagState : public flags_internal::FlagStateInterface { /////////////////////////////////////////////////////////////////////////////// // Flag implementation, which does not depend on flag value type. +DynValueDeleter::DynValueDeleter(FlagOpFn op_arg) : op(op_arg) {} + +void DynValueDeleter::operator()(void* ptr) const { + if (op == nullptr) return; + + Delete(op, ptr); +} + void FlagImpl::Init() { new (&data_guard_) absl::Mutex; - // At this point the default_value_ always points to gen_func. - std::unique_ptr init_value( - (*default_value_.gen_func)(), DynValueDeleter{op_}); + auto def_kind = static_cast(def_kind_); + switch (ValueStorageKind()) { - case FlagValueStorageKind::kHeapAllocated: - HeapAllocatedValue() = init_value.release(); - break; + case FlagValueStorageKind::kValueAndInitBit: case FlagValueStorageKind::kOneWordAtomic: { - int64_t atomic_value; - std::memcpy(&atomic_value, init_value.get(), Sizeof(op_)); - OneWordValue().store(atomic_value, std::memory_order_release); + alignas(int64_t) std::array buf{}; + if (def_kind == FlagDefaultKind::kGenFunc) { + (*default_value_.gen_func)(buf.data()); + } else { + assert(def_kind != FlagDefaultKind::kDynamicValue); + std::memcpy(buf.data(), &default_value_, Sizeof(op_)); + } + if (ValueStorageKind() == FlagValueStorageKind::kValueAndInitBit) { + // We presume here the memory layout of FlagValueAndInitBit struct. + uint8_t initialized = 1; + std::memcpy(buf.data() + Sizeof(op_), &initialized, + sizeof(initialized)); + } + OneWordValue().store(absl::bit_cast(buf), + std::memory_order_release); break; } - case FlagValueStorageKind::kTwoWordsAtomic: { - AlignedTwoWords atomic_value{0, 0}; - std::memcpy(&atomic_value, init_value.get(), Sizeof(op_)); - TwoWordsValue().store(atomic_value, std::memory_order_release); + case FlagValueStorageKind::kSequenceLocked: { + // For this storage kind the default_value_ always points to gen_func + // during initialization. + assert(def_kind == FlagDefaultKind::kGenFunc); + (*default_value_.gen_func)(AtomicBufferValue()); break; } + case FlagValueStorageKind::kAlignedBuffer: + // For this storage kind the default_value_ always points to gen_func + // during initialization. + assert(def_kind == FlagDefaultKind::kGenFunc); + (*default_value_.gen_func)(AlignedBufferValue()); + break; } + seq_lock_.MarkInitialized(); } absl::Mutex* FlagImpl::DataGuard() const { @@ -188,35 +216,42 @@ void FlagImpl::AssertValidType(FlagFastTypeId rhs_type_id, std::unique_ptr FlagImpl::MakeInitValue() const { void* res = nullptr; - if (DefaultKind() == FlagDefaultKind::kDynamicValue) { - res = flags_internal::Clone(op_, default_value_.dynamic_value); - } else { - res = (*default_value_.gen_func)(); + switch (DefaultKind()) { + case FlagDefaultKind::kDynamicValue: + res = flags_internal::Clone(op_, default_value_.dynamic_value); + break; + case FlagDefaultKind::kGenFunc: + res = flags_internal::Alloc(op_); + (*default_value_.gen_func)(res); + break; + default: + res = flags_internal::Clone(op_, &default_value_); + break; } return {res, DynValueDeleter{op_}}; } void FlagImpl::StoreValue(const void* src) { switch (ValueStorageKind()) { - case FlagValueStorageKind::kHeapAllocated: - Copy(op_, src, HeapAllocatedValue()); - break; + case FlagValueStorageKind::kValueAndInitBit: case FlagValueStorageKind::kOneWordAtomic: { - int64_t one_word_val = 0; + // Load the current value to avoid setting 'init' bit manualy. + int64_t one_word_val = OneWordValue().load(std::memory_order_acquire); std::memcpy(&one_word_val, src, Sizeof(op_)); OneWordValue().store(one_word_val, std::memory_order_release); + seq_lock_.IncrementModificationCount(); break; } - case FlagValueStorageKind::kTwoWordsAtomic: { - AlignedTwoWords two_words_val{0, 0}; - std::memcpy(&two_words_val, src, Sizeof(op_)); - TwoWordsValue().store(two_words_val, std::memory_order_release); + case FlagValueStorageKind::kSequenceLocked: { + seq_lock_.Write(AtomicBufferValue(), src, Sizeof(op_)); break; } + case FlagValueStorageKind::kAlignedBuffer: + Copy(op_, src, AlignedBufferValue()); + seq_lock_.IncrementModificationCount(); + break; } - modified_ = true; - ++counter_; InvokeCallback(); } @@ -226,8 +261,6 @@ std::string FlagImpl::Filename() const { return flags_internal::GetUsageConfig().normalize_filename(filename_); } -absl::string_view FlagImpl::Typename() const { return ""; } - std::string FlagImpl::Help() const { return HelpSourceKind() == FlagHelpKind::kLiteral ? help_.literal : help_.gen_func(); @@ -237,9 +270,8 @@ FlagFastTypeId FlagImpl::TypeId() const { return flags_internal::FastTypeId(op_); } -bool FlagImpl::IsModified() const { - absl::MutexLock l(DataGuard()); - return modified_; +int64_t FlagImpl::ModificationCount() const { + return seq_lock_.ModificationCount(); } bool FlagImpl::IsSpecifiedOnCommandLine() const { @@ -257,21 +289,22 @@ std::string FlagImpl::DefaultValue() const { std::string FlagImpl::CurrentValue() const { auto* guard = DataGuard(); // Make sure flag initialized switch (ValueStorageKind()) { - case FlagValueStorageKind::kHeapAllocated: { - absl::MutexLock l(guard); - return flags_internal::Unparse(op_, HeapAllocatedValue()); - } + case FlagValueStorageKind::kValueAndInitBit: case FlagValueStorageKind::kOneWordAtomic: { const auto one_word_val = absl::bit_cast>( OneWordValue().load(std::memory_order_acquire)); return flags_internal::Unparse(op_, one_word_val.data()); } - case FlagValueStorageKind::kTwoWordsAtomic: { - const auto two_words_val = - absl::bit_cast>( - TwoWordsValue().load(std::memory_order_acquire)); - return flags_internal::Unparse(op_, two_words_val.data()); + case FlagValueStorageKind::kSequenceLocked: { + std::unique_ptr cloned(flags_internal::Alloc(op_), + DynValueDeleter{op_}); + ReadSequenceLockedData(cloned.get()); + return flags_internal::Unparse(op_, cloned.get()); + } + case FlagValueStorageKind::kAlignedBuffer: { + absl::MutexLock l(guard); + return flags_internal::Unparse(op_, AlignedBufferValue()); } } @@ -307,7 +340,7 @@ void FlagImpl::InvokeCallback() const { // and it also can be different by the time the callback invocation is // completed. Requires that *primary_lock be held in exclusive mode; it may be // released and reacquired by the implementation. - MutexRelock relock(DataGuard()); + MutexRelock relock(*DataGuard()); absl::MutexLock lock(&callback_->guard); cb(); } @@ -318,20 +351,26 @@ std::unique_ptr FlagImpl::SaveState() { bool modified = modified_; bool on_command_line = on_command_line_; switch (ValueStorageKind()) { - case FlagValueStorageKind::kHeapAllocated: { - return absl::make_unique( - this, flags_internal::Clone(op_, HeapAllocatedValue()), modified, - on_command_line, counter_); - } + case FlagValueStorageKind::kValueAndInitBit: case FlagValueStorageKind::kOneWordAtomic: { return absl::make_unique( - this, OneWordValue().load(std::memory_order_acquire), modified, - on_command_line, counter_); + *this, OneWordValue().load(std::memory_order_acquire), modified, + on_command_line, ModificationCount()); } - case FlagValueStorageKind::kTwoWordsAtomic: { + case FlagValueStorageKind::kSequenceLocked: { + void* cloned = flags_internal::Alloc(op_); + // Read is guaranteed to be successful because we hold the lock. + bool success = + seq_lock_.TryRead(cloned, AtomicBufferValue(), Sizeof(op_)); + assert(success); + static_cast(success); + return absl::make_unique(*this, cloned, modified, + on_command_line, ModificationCount()); + } + case FlagValueStorageKind::kAlignedBuffer: { return absl::make_unique( - this, TwoWordsValue().load(std::memory_order_acquire), modified, - on_command_line, counter_); + *this, flags_internal::Clone(op_, AlignedBufferValue()), modified, + on_command_line, ModificationCount()); } } return nullptr; @@ -339,20 +378,18 @@ std::unique_ptr FlagImpl::SaveState() { bool FlagImpl::RestoreState(const FlagState& flag_state) { absl::MutexLock l(DataGuard()); - - if (flag_state.counter_ == counter_) { + if (flag_state.counter_ == ModificationCount()) { return false; } switch (ValueStorageKind()) { - case FlagValueStorageKind::kHeapAllocated: - StoreValue(flag_state.value_.dynamic); - break; + case FlagValueStorageKind::kValueAndInitBit: case FlagValueStorageKind::kOneWordAtomic: StoreValue(&flag_state.value_.one_word); break; - case FlagValueStorageKind::kTwoWordsAtomic: - StoreValue(&flag_state.value_.two_words); + case FlagValueStorageKind::kSequenceLocked: + case FlagValueStorageKind::kAlignedBuffer: + StoreValue(flag_state.value_.heap_allocated); break; } @@ -363,25 +400,28 @@ bool FlagImpl::RestoreState(const FlagState& flag_state) { } template -typename StorageT::value_type& FlagImpl::OffsetValue() const { +StorageT* FlagImpl::OffsetValue() const { char* p = reinterpret_cast(const_cast(this)); // The offset is deduced via Flag value type specific op_. size_t offset = flags_internal::ValueOffset(op_); - return reinterpret_cast(p + offset)->value; + return reinterpret_cast(p + offset); } -void*& FlagImpl::HeapAllocatedValue() const { - assert(ValueStorageKind() == FlagValueStorageKind::kHeapAllocated); - return OffsetValue(); +void* FlagImpl::AlignedBufferValue() const { + assert(ValueStorageKind() == FlagValueStorageKind::kAlignedBuffer); + return OffsetValue(); } + +std::atomic* FlagImpl::AtomicBufferValue() const { + assert(ValueStorageKind() == FlagValueStorageKind::kSequenceLocked); + return OffsetValue>(); +} + std::atomic& FlagImpl::OneWordValue() const { - assert(ValueStorageKind() == FlagValueStorageKind::kOneWordAtomic); - return OffsetValue(); -} -std::atomic& FlagImpl::TwoWordsValue() const { - assert(ValueStorageKind() == FlagValueStorageKind::kTwoWordsAtomic); - return OffsetValue(); + assert(ValueStorageKind() == FlagValueStorageKind::kOneWordAtomic || + ValueStorageKind() == FlagValueStorageKind::kValueAndInitBit); + return OffsetValue()->value; } // Attempts to parse supplied `value` string using parsing routine in the `flag` @@ -389,14 +429,14 @@ std::atomic& FlagImpl::TwoWordsValue() const { // parsed value. In case if any error is encountered in either step, the error // message is stored in 'err' std::unique_ptr FlagImpl::TryParse( - absl::string_view value, std::string* err) const { + absl::string_view value, std::string& err) const { std::unique_ptr tentative_value = MakeInitValue(); std::string parse_err; if (!flags_internal::Parse(op_, value, tentative_value.get(), &parse_err)) { absl::string_view err_sep = parse_err.empty() ? "" : "; "; - *err = absl::StrCat("Illegal value '", value, "' specified for flag '", - Name(), "'", err_sep, parse_err); + err = absl::StrCat("Illegal value '", value, "' specified for flag '", + Name(), "'", err_sep, parse_err); return nullptr; } @@ -406,26 +446,56 @@ std::unique_ptr FlagImpl::TryParse( void FlagImpl::Read(void* dst) const { auto* guard = DataGuard(); // Make sure flag initialized switch (ValueStorageKind()) { - case FlagValueStorageKind::kHeapAllocated: { - absl::MutexLock l(guard); - flags_internal::CopyConstruct(op_, HeapAllocatedValue(), dst); - break; - } + case FlagValueStorageKind::kValueAndInitBit: case FlagValueStorageKind::kOneWordAtomic: { const int64_t one_word_val = OneWordValue().load(std::memory_order_acquire); std::memcpy(dst, &one_word_val, Sizeof(op_)); break; } - case FlagValueStorageKind::kTwoWordsAtomic: { - const AlignedTwoWords two_words_val = - TwoWordsValue().load(std::memory_order_acquire); - std::memcpy(dst, &two_words_val, Sizeof(op_)); + case FlagValueStorageKind::kSequenceLocked: { + ReadSequenceLockedData(dst); + break; + } + case FlagValueStorageKind::kAlignedBuffer: { + absl::MutexLock l(guard); + flags_internal::CopyConstruct(op_, AlignedBufferValue(), dst); break; } } } +int64_t FlagImpl::ReadOneWord() const { + assert(ValueStorageKind() == FlagValueStorageKind::kOneWordAtomic || + ValueStorageKind() == FlagValueStorageKind::kValueAndInitBit); + auto* guard = DataGuard(); // Make sure flag initialized + (void)guard; + return OneWordValue().load(std::memory_order_acquire); +} + +bool FlagImpl::ReadOneBool() const { + assert(ValueStorageKind() == FlagValueStorageKind::kValueAndInitBit); + auto* guard = DataGuard(); // Make sure flag initialized + (void)guard; + return absl::bit_cast>( + OneWordValue().load(std::memory_order_acquire)) + .value; +} + +void FlagImpl::ReadSequenceLockedData(void* dst) const { + int size = Sizeof(op_); + // Attempt to read using the sequence lock. + if (ABSL_PREDICT_TRUE(seq_lock_.TryRead(dst, AtomicBufferValue(), size))) { + return; + } + // We failed due to contention. Acquire the lock to prevent contention + // and try again. + absl::ReaderMutexLock l(DataGuard()); + bool success = seq_lock_.TryRead(dst, AtomicBufferValue(), size); + assert(success); + static_cast(success); +} + void FlagImpl::Write(const void* src) { absl::MutexLock l(DataGuard()); @@ -452,7 +522,7 @@ void FlagImpl::Write(const void* src) { // * Update the current flag value if it was never set before // The mode is selected based on 'set_mode' parameter. bool FlagImpl::ParseFrom(absl::string_view value, FlagSettingMode set_mode, - ValueSource source, std::string* err) { + ValueSource source, std::string& err) { absl::MutexLock l(DataGuard()); switch (set_mode) { diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/internal/flag.h b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/internal/flag.h index c1bf865281..8636fadcdb 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/internal/flag.h +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/internal/flag.h @@ -16,38 +16,73 @@ #ifndef ABSL_FLAGS_INTERNAL_FLAG_H_ #define ABSL_FLAGS_INTERNAL_FLAG_H_ +#include #include #include #include #include +#include #include #include #include +#include "absl/base/attributes.h" #include "absl/base/call_once.h" +#include "absl/base/casts.h" #include "absl/base/config.h" +#include "absl/base/optimization.h" #include "absl/base/thread_annotations.h" +#include "absl/flags/commandlineflag.h" #include "absl/flags/config.h" #include "absl/flags/internal/commandlineflag.h" #include "absl/flags/internal/registry.h" -#include "absl/memory/memory.h" +#include "absl/flags/internal/sequence_lock.h" +#include "absl/flags/marshalling.h" #include "absl/meta/type_traits.h" -#include "absl/strings/str_cat.h" #include "absl/strings/string_view.h" #include "absl/synchronization/mutex.h" +#include "absl/utility/utility.h" namespace absl { ABSL_NAMESPACE_BEGIN + +/////////////////////////////////////////////////////////////////////////////// +// Forward declaration of absl::Flag public API. namespace flags_internal { +template +class Flag; +} // namespace flags_internal + +#if defined(_MSC_VER) && !defined(__clang__) +template +class Flag; +#else +template +using Flag = flags_internal::Flag; +#endif + +template +ABSL_MUST_USE_RESULT T GetFlag(const absl::Flag& flag); + +template +void SetFlag(absl::Flag* flag, const T& v); + +template +void SetFlag(absl::Flag* flag, const V& v); + +template +const CommandLineFlag& GetFlagReflectionHandle(const absl::Flag& f); /////////////////////////////////////////////////////////////////////////////// // Flag value type operations, eg., parsing, copying, etc. are provided // by function specific to that type with a signature matching FlagOpFn. +namespace flags_internal { + enum class FlagOp { + kAlloc, kDelete, - kClone, kCopy, kCopyConstruct, kSizeof, @@ -63,13 +98,13 @@ using FlagOpFn = void* (*)(FlagOp, const void*, void*, void*); template void* FlagOps(FlagOp op, const void* v1, void* v2, void* v3); -// Deletes memory interpreting obj as flag value type pointer. -inline void Delete(FlagOpFn op, const void* obj) { - op(FlagOp::kDelete, obj, nullptr, nullptr); +// Allocate aligned memory for a flag value. +inline void* Alloc(FlagOpFn op) { + return op(FlagOp::kAlloc, nullptr, nullptr, nullptr); } -// Makes a copy of flag value pointed by obj. -inline void* Clone(FlagOpFn op, const void* obj) { - return op(FlagOp::kClone, obj, nullptr, nullptr); +// Deletes memory interpreting obj as flag value type pointer. +inline void Delete(FlagOpFn op, void* obj) { + op(FlagOp::kDelete, nullptr, obj, nullptr); } // Copies src to dst interpreting as flag value type pointers. inline void Copy(FlagOpFn op, const void* src, void* dst) { @@ -80,6 +115,12 @@ inline void Copy(FlagOpFn op, const void* src, void* dst) { inline void CopyConstruct(FlagOpFn op, const void* src, void* dst) { op(FlagOp::kCopyConstruct, src, dst, nullptr); } +// Makes a copy of flag value pointed by obj. +inline void* Clone(FlagOpFn op, const void* obj) { + void* res = flags_internal::Alloc(op); + flags_internal::CopyConstruct(op, obj, res); + return res; +} // Returns true if parsing of input text is successfull. inline bool Parse(FlagOpFn op, absl::string_view text, void* dst, std::string* error) { @@ -137,6 +178,28 @@ inline const std::type_info* GenRuntimeTypeId() { // cases. using HelpGenFunc = std::string (*)(); +template +struct FixedCharArray { + char value[N]; + + template + static constexpr FixedCharArray FromLiteralString( + absl::string_view str, absl::index_sequence) { + return (void)str, FixedCharArray({{str[I]..., '\0'}}); + } +}; + +template +constexpr FixedCharArray HelpStringAsArray(int) { + return FixedCharArray::FromLiteralString( + Gen::Value(), absl::make_index_sequence{}); +} + +template +constexpr std::false_type HelpStringAsArray(char) { + return std::false_type{}; +} + union FlagHelpMsg { constexpr explicit FlagHelpMsg(const char* help_msg) : literal(help_msg) {} constexpr explicit FlagHelpMsg(HelpGenFunc help_gen) : gen_func(help_gen) {} @@ -154,40 +217,28 @@ struct FlagHelpArg { extern const char kStrippedFlagHelp[]; -// HelpConstexprWrap is used by struct AbslFlagHelpGenFor##name generated by -// ABSL_FLAG macro. It is only used to silence the compiler in the case where -// help message expression is not constexpr and does not have type const char*. -// If help message expression is indeed constexpr const char* HelpConstexprWrap -// is just a trivial identity function. -template -const char* HelpConstexprWrap(const T&) { - return nullptr; -} -constexpr const char* HelpConstexprWrap(const char* p) { return p; } -constexpr const char* HelpConstexprWrap(char* p) { return p; } - // These two HelpArg overloads allows us to select at compile time one of two // way to pass Help argument to absl::Flag. We'll be passing -// AbslFlagHelpGenFor##name as T and integer 0 as a single argument to prefer -// first overload if possible. If T::Const is evaluatable on constexpr -// context (see non template int parameter below) we'll choose first overload. -// In this case the help message expression is immediately evaluated and is used -// to construct the absl::Flag. No additionl code is generated by ABSL_FLAG. -// Otherwise SFINAE kicks in and first overload is dropped from the +// AbslFlagHelpGenFor##name as Gen and integer 0 as a single argument to prefer +// first overload if possible. If help message is evaluatable on constexpr +// context We'll be able to make FixedCharArray out of it and we'll choose first +// overload. In this case the help message expression is immediately evaluated +// and is used to construct the absl::Flag. No additionl code is generated by +// ABSL_FLAG Otherwise SFINAE kicks in and first overload is dropped from the // consideration, in which case the second overload will be used. The second // overload does not attempt to evaluate the help message expression // immediately and instead delays the evaluation by returing the function // pointer (&T::NonConst) genering the help message when necessary. This is // evaluatable in constexpr context, but the cost is an extra function being // generated in the ABSL_FLAG code. -template -constexpr FlagHelpArg HelpArg(int) { - return {FlagHelpMsg(T::Const()), FlagHelpKind::kLiteral}; +template +constexpr FlagHelpArg HelpArg(const FixedCharArray& value) { + return {FlagHelpMsg(value.value), FlagHelpKind::kLiteral}; } -template -constexpr FlagHelpArg HelpArg(char) { - return {FlagHelpMsg(&T::NonConst), FlagHelpKind::kGenFunc}; +template +constexpr FlagHelpArg HelpArg(std::false_type) { + return {FlagHelpMsg(&Gen::NonConst), FlagHelpKind::kGenFunc}; } /////////////////////////////////////////////////////////////////////////////// @@ -195,104 +246,109 @@ constexpr FlagHelpArg HelpArg(char) { // Signature for the function generating the initial flag value (usually // based on default value supplied in flag's definition) -using FlagDfltGenFunc = void* (*)(); +using FlagDfltGenFunc = void (*)(void*); union FlagDefaultSrc { constexpr explicit FlagDefaultSrc(FlagDfltGenFunc gen_func_arg) : gen_func(gen_func_arg) {} +#define ABSL_FLAGS_INTERNAL_DFLT_FOR_TYPE(T, name) \ + T name##_value; \ + constexpr explicit FlagDefaultSrc(T value) : name##_value(value) {} // NOLINT + ABSL_FLAGS_INTERNAL_BUILTIN_TYPES(ABSL_FLAGS_INTERNAL_DFLT_FOR_TYPE) +#undef ABSL_FLAGS_INTERNAL_DFLT_FOR_TYPE + void* dynamic_value; FlagDfltGenFunc gen_func; }; -enum class FlagDefaultKind : uint8_t { kDynamicValue = 0, kGenFunc = 1 }; +enum class FlagDefaultKind : uint8_t { + kDynamicValue = 0, + kGenFunc = 1, + kOneWord = 2 // for default values UP to one word in size +}; + +struct FlagDefaultArg { + FlagDefaultSrc source; + FlagDefaultKind kind; +}; + +// This struct and corresponding overload to InitDefaultValue are used to +// facilitate usage of {} as default value in ABSL_FLAG macro. +// TODO(rogeeff): Fix handling types with explicit constructors. +struct EmptyBraces {}; + +template +constexpr T InitDefaultValue(T t) { + return t; +} + +template +constexpr T InitDefaultValue(EmptyBraces) { + return T{}; +} + +template ::value, int>::type = + (GenT{}, 0)> +constexpr FlagDefaultArg DefaultArg(int) { + return {FlagDefaultSrc(GenT{}.value), FlagDefaultKind::kOneWord}; +} + +template +constexpr FlagDefaultArg DefaultArg(char) { + return {FlagDefaultSrc(&GenT::Gen), FlagDefaultKind::kGenFunc}; +} /////////////////////////////////////////////////////////////////////////////// // Flag current value auxiliary structs. constexpr int64_t UninitializedFlagValue() { return 0xababababababababll; } +template +using FlagUseValueAndInitBitStorage = std::integral_constant< + bool, absl::type_traits_internal::is_trivially_copyable::value && + std::is_default_constructible::value && (sizeof(T) < 8)>; + template using FlagUseOneWordStorage = std::integral_constant< bool, absl::type_traits_internal::is_trivially_copyable::value && (sizeof(T) <= 8)>; -#if defined(ABSL_FLAGS_INTERNAL_ATOMIC_DOUBLE_WORD) -// Clang does not always produce cmpxchg16b instruction when alignment of a 16 -// bytes type is not 16. -struct alignas(16) AlignedTwoWords { - int64_t first; - int64_t second; - - bool IsInitialized() const { - return first != flags_internal::UninitializedFlagValue(); - } -}; - -template -using FlagUseTwoWordsStorage = std::integral_constant< +template +using FlagUseSequenceLockStorage = std::integral_constant< bool, absl::type_traits_internal::is_trivially_copyable::value && - (sizeof(T) > 8) && (sizeof(T) <= 16)>; -#else -// This is actually unused and only here to avoid ifdefs in other palces. -struct AlignedTwoWords { - constexpr AlignedTwoWords() noexcept : dummy() {} - constexpr AlignedTwoWords(int64_t, int64_t) noexcept : dummy() {} - char dummy; - - bool IsInitialized() const { - std::abort(); - return true; - } -}; - -// This trait should be type dependent, otherwise SFINAE below will fail -template -using FlagUseTwoWordsStorage = - std::integral_constant; -#endif - -template -using FlagUseHeapStorage = - std::integral_constant::value && - !FlagUseTwoWordsStorage::value>; + (sizeof(T) > 8)>; enum class FlagValueStorageKind : uint8_t { - kHeapAllocated = 0, + kValueAndInitBit = 0, kOneWordAtomic = 1, - kTwoWordsAtomic = 2 + kSequenceLocked = 2, + kAlignedBuffer = 3, }; template static constexpr FlagValueStorageKind StorageKind() { - return FlagUseHeapStorage::value - ? FlagValueStorageKind::kHeapAllocated - : FlagUseOneWordStorage::value - ? FlagValueStorageKind::kOneWordAtomic - : FlagUseTwoWordsStorage::value - ? FlagValueStorageKind::kTwoWordsAtomic - : FlagValueStorageKind::kHeapAllocated; + return FlagUseValueAndInitBitStorage::value + ? FlagValueStorageKind::kValueAndInitBit + : FlagUseOneWordStorage::value + ? FlagValueStorageKind::kOneWordAtomic + : FlagUseSequenceLockStorage::value + ? FlagValueStorageKind::kSequenceLocked + : FlagValueStorageKind::kAlignedBuffer; } -struct FlagHeapAllocatedValue { - using value_type = void*; - - value_type value; -}; - struct FlagOneWordValue { - using value_type = std::atomic; - constexpr FlagOneWordValue() : value(UninitializedFlagValue()) {} - - value_type value; + constexpr explicit FlagOneWordValue(int64_t v) : value(v) {} + std::atomic value; }; -struct FlagTwoWordsValue { - using value_type = std::atomic; - constexpr FlagTwoWordsValue() - : value(AlignedTwoWords{UninitializedFlagValue(), 0}) {} - - value_type value; +template +struct alignas(8) FlagValueAndInitBit { + T value; + // Use an int instead of a bool to guarantee that a non-zero value has + // a bit set. + uint8_t init; }; template -struct FlagValue - : FlagHeapAllocatedValue { - bool Get(T*) const { return false; } +struct FlagValue : FlagOneWordValue { + constexpr FlagValue() : FlagOneWordValue(0) {} + bool Get(const SequenceLock&, T& dst) const { + int64_t storage = value.load(std::memory_order_acquire); + if (ABSL_PREDICT_FALSE(storage == 0)) { + return false; + } + dst = absl::bit_cast>(storage).value; + return true; + } }; template struct FlagValue : FlagOneWordValue { - bool Get(T* dst) const { + constexpr FlagValue() : FlagOneWordValue(UninitializedFlagValue()) {} + bool Get(const SequenceLock&, T& dst) const { int64_t one_word_val = value.load(std::memory_order_acquire); if (ABSL_PREDICT_FALSE(one_word_val == UninitializedFlagValue())) { return false; } - std::memcpy(dst, static_cast(&one_word_val), sizeof(T)); + std::memcpy(&dst, static_cast(&one_word_val), sizeof(T)); return true; } }; template -struct FlagValue : FlagTwoWordsValue { - bool Get(T* dst) const { - AlignedTwoWords two_words_val = value.load(std::memory_order_acquire); - if (ABSL_PREDICT_FALSE(!two_words_val.IsInitialized())) { - return false; - } - std::memcpy(dst, static_cast(&two_words_val), sizeof(T)); - return true; +struct FlagValue { + bool Get(const SequenceLock& lock, T& dst) const { + return lock.TryRead(&dst, value_words, sizeof(T)); } + + static constexpr int kNumWords = + flags_internal::AlignUp(sizeof(T), sizeof(uint64_t)) / sizeof(uint64_t); + + alignas(T) alignas( + std::atomic) std::atomic value_words[kNumWords]; +}; + +template +struct FlagValue { + bool Get(const SequenceLock&, T&) const { return false; } + + alignas(T) char value[sizeof(T)]; }; /////////////////////////////////////////////////////////////////////////////// @@ -347,37 +419,54 @@ struct FlagCallback { // The class encapsulates the Flag's data and access to it. struct DynValueDeleter { - explicit DynValueDeleter(FlagOpFn op_arg = nullptr) : op(op_arg) {} - void operator()(void* ptr) const { - if (op != nullptr) flags_internal::Delete(op, ptr); - } + explicit DynValueDeleter(FlagOpFn op_arg = nullptr); + void operator()(void* ptr) const; FlagOpFn op; }; class FlagState; -class FlagImpl final : public flags_internal::CommandLineFlag { +class FlagImpl final : public CommandLineFlag { public: constexpr FlagImpl(const char* name, const char* filename, FlagOpFn op, FlagHelpArg help, FlagValueStorageKind value_kind, - FlagDfltGenFunc default_value_gen) + FlagDefaultArg default_arg) : name_(name), filename_(filename), op_(op), help_(help.source), help_source_kind_(static_cast(help.kind)), value_storage_kind_(static_cast(value_kind)), - def_kind_(static_cast(FlagDefaultKind::kGenFunc)), + def_kind_(static_cast(default_arg.kind)), modified_(false), on_command_line_(false), - counter_(0), callback_(nullptr), - default_value_(default_value_gen), + default_value_(default_arg.source), data_guard_{} {} // Constant access methods + int64_t ReadOneWord() const ABSL_LOCKS_EXCLUDED(*DataGuard()); + bool ReadOneBool() const ABSL_LOCKS_EXCLUDED(*DataGuard()); void Read(void* dst) const override ABSL_LOCKS_EXCLUDED(*DataGuard()); + void Read(bool* value) const ABSL_LOCKS_EXCLUDED(*DataGuard()) { + *value = ReadOneBool(); + } + template () == + FlagValueStorageKind::kOneWordAtomic, + int> = 0> + void Read(T* value) const ABSL_LOCKS_EXCLUDED(*DataGuard()) { + int64_t v = ReadOneWord(); + std::memcpy(value, static_cast(&v), sizeof(T)); + } + template () == + FlagValueStorageKind::kValueAndInitBit, + int>::type = 0> + void Read(T* value) const ABSL_LOCKS_EXCLUDED(*DataGuard()) { + *value = absl::bit_cast>(ReadOneWord()).value; + } // Mutating access methods void Write(const void* src) ABSL_LOCKS_EXCLUDED(*DataGuard()); @@ -402,7 +491,8 @@ class FlagImpl final : public flags_internal::CommandLineFlag { friend class FlagState; // Ensures that `data_guard_` is initialized and returns it. - absl::Mutex* DataGuard() const ABSL_LOCK_RETURNED((absl::Mutex*)&data_guard_); + absl::Mutex* DataGuard() const + ABSL_LOCK_RETURNED(reinterpret_cast(data_guard_)); // Returns heap allocated value of type T initialized with default value. std::unique_ptr MakeInitValue() const ABSL_EXCLUSIVE_LOCKS_REQUIRED(*DataGuard()); @@ -416,25 +506,33 @@ class FlagImpl final : public flags_internal::CommandLineFlag { // it is only used inside the three routines below, which are defined in // flag.cc, we can define it in that file as well. template - typename StorageT::value_type& OffsetValue() const; - // This is an accessor for a value stored in heap allocated storage. - // Returns a mutable reference to a pointer to allow vlaue mutation. - void*& HeapAllocatedValue() const; + StorageT* OffsetValue() const; + // This is an accessor for a value stored in an aligned buffer storage + // used for non-trivially-copyable data types. + // Returns a mutable pointer to the start of a buffer. + void* AlignedBufferValue() const; + + // The same as above, but used for sequencelock-protected storage. + std::atomic* AtomicBufferValue() const; + // This is an accessor for a value stored as one word atomic. Returns a // mutable reference to an atomic value. std::atomic& OneWordValue() const; - // This is an accessor for a value stored as two words atomic. Returns a - // mutable reference to an atomic value. - std::atomic& TwoWordsValue() const; // Attempts to parse supplied `value` string. If parsing is successful, // returns new value. Otherwise returns nullptr. std::unique_ptr TryParse(absl::string_view value, - std::string* err) const + std::string& err) const ABSL_EXCLUSIVE_LOCKS_REQUIRED(*DataGuard()); // Stores the flag value based on the pointer to the source. void StoreValue(const void* src) ABSL_EXCLUSIVE_LOCKS_REQUIRED(*DataGuard()); + // Copy the flag data, protected by `seq_lock_` into `dst`. + // + // REQUIRES: ValueStorageKind() == kSequenceLocked. + void ReadSequenceLockedData(void* dst) const + ABSL_LOCKS_EXCLUDED(*DataGuard()); + FlagHelpKind HelpSourceKind() const { return static_cast(help_source_kind_); } @@ -449,10 +547,8 @@ class FlagImpl final : public flags_internal::CommandLineFlag { // CommandLineFlag interface implementation absl::string_view Name() const override; std::string Filename() const override; - absl::string_view Typename() const override; std::string Help() const override; FlagFastTypeId TypeId() const override; - bool IsModified() const override ABSL_LOCKS_EXCLUDED(*DataGuard()); bool IsSpecifiedOnCommandLine() const override ABSL_LOCKS_EXCLUDED(*DataGuard()); std::string DefaultValue() const override ABSL_LOCKS_EXCLUDED(*DataGuard()); @@ -462,6 +558,8 @@ class FlagImpl final : public flags_internal::CommandLineFlag { void CheckDefaultValueParsingRoundtrip() const override ABSL_LOCKS_EXCLUDED(*DataGuard()); + int64_t ModificationCount() const ABSL_EXCLUSIVE_LOCKS_REQUIRED(*DataGuard()); + // Interfaces to save and restore flags to/from persistent state. // Returns current flag state or nullptr if flag does not support // saving and restoring a state. @@ -474,7 +572,7 @@ class FlagImpl final : public flags_internal::CommandLineFlag { ABSL_LOCKS_EXCLUDED(*DataGuard()); bool ParseFrom(absl::string_view value, FlagSettingMode set_mode, - ValueSource source, std::string* error) override + ValueSource source, std::string& error) override ABSL_LOCKS_EXCLUDED(*DataGuard()); // Immutable flag's state. @@ -492,30 +590,25 @@ class FlagImpl final : public flags_internal::CommandLineFlag { // Kind of storage this flag is using for the flag's value. const uint8_t value_storage_kind_ : 2; - // ------------------------------------------------------------------------ - // The bytes containing the const bitfields must not be shared with bytes - // containing the mutable bitfields. - // ------------------------------------------------------------------------ - - // Unique tag for absl::call_once call to initialize this flag. - // - // The placement of this variable between the immutable and mutable bitfields - // is important as prevents them from occupying the same byte. If you remove - // this variable, make sure to maintain this property. - absl::once_flag init_control_; + uint8_t : 0; // The bytes containing the const bitfields must not be + // shared with bytes containing the mutable bitfields. // Mutable flag's state (guarded by `data_guard_`). - // If def_kind_ == kDynamicValue, default_value_ holds a dynamically allocated - // value. - uint8_t def_kind_ : 1 ABSL_GUARDED_BY(*DataGuard()); + // def_kind_ is not guard by DataGuard() since it is accessed in Init without + // locks. + uint8_t def_kind_ : 2; // Has this flag's value been modified? bool modified_ : 1 ABSL_GUARDED_BY(*DataGuard()); // Has this flag been specified on command line. bool on_command_line_ : 1 ABSL_GUARDED_BY(*DataGuard()); - // Mutation counter - int64_t counter_ ABSL_GUARDED_BY(*DataGuard()); + // Unique tag for absl::call_once call to initialize this flag. + absl::once_flag init_control_; + + // Sequence lock / mutation counter. + flags_internal::SequenceLock seq_lock_; + // Optional flag's callback and absl::Mutex to guard the invocations. FlagCallback* callback_ ABSL_GUARDED_BY(*DataGuard()); // Either a pointer to the function generating the default value based on the @@ -541,12 +634,28 @@ class FlagImpl final : public flags_internal::CommandLineFlag { template class Flag { public: - constexpr Flag(const char* name, const char* filename, const FlagHelpArg help, - const FlagDfltGenFunc default_value_gen) + constexpr Flag(const char* name, const char* filename, FlagHelpArg help, + const FlagDefaultArg default_arg) : impl_(name, filename, &FlagOps, help, - flags_internal::StorageKind(), default_value_gen), + flags_internal::StorageKind(), default_arg), value_() {} + // CommandLineFlag interface + absl::string_view Name() const { return impl_.Name(); } + std::string Filename() const { return impl_.Filename(); } + std::string Help() const { return impl_.Help(); } + // Do not use. To be removed. + bool IsSpecifiedOnCommandLine() const { + return impl_.IsSpecifiedOnCommandLine(); + } + std::string DefaultValue() const { return impl_.DefaultValue(); } + std::string CurrentValue() const { return impl_.CurrentValue(); } + + private: + template + friend class FlagRegistrar; + friend class FlagImplPeer; + T Get() const { // See implementation notes in CommandLineFlag::Get(). union U { @@ -560,32 +669,18 @@ class Flag { impl_.AssertValidType(base_internal::FastTypeId(), &GenRuntimeTypeId); #endif - if (!value_.Get(&u.value)) impl_.Read(&u.value); + if (ABSL_PREDICT_FALSE(!value_.Get(impl_.seq_lock_, u.value))) { + impl_.Read(&u.value); + } return std::move(u.value); } void Set(const T& v) { impl_.AssertValidType(base_internal::FastTypeId(), &GenRuntimeTypeId); impl_.Write(&v); } - void SetCallback(const FlagCallbackFunc mutation_callback) { - impl_.SetCallback(mutation_callback); - } - // CommandLineFlag interface - absl::string_view Name() const { return impl_.Name(); } - std::string Filename() const { return impl_.Filename(); } - absl::string_view Typename() const { return ""; } - std::string Help() const { return impl_.Help(); } - bool IsModified() const { return impl_.IsModified(); } - bool IsSpecifiedOnCommandLine() const { - return impl_.IsSpecifiedOnCommandLine(); - } - std::string DefaultValue() const { return impl_.DefaultValue(); } - std::string CurrentValue() const { return impl_.CurrentValue(); } - - private: - template - friend class FlagRegistrar; + // Access to the reflection. + const CommandLineFlag& Reflect() const { return impl_; } // Flag's data // The implementation depends on value_ field to be placed exactly after the @@ -595,16 +690,41 @@ class Flag { FlagValue value_; }; +/////////////////////////////////////////////////////////////////////////////// +// Trampoline for friend access + +class FlagImplPeer { + public: + template + static T InvokeGet(const FlagType& flag) { + return flag.Get(); + } + template + static void InvokeSet(FlagType& flag, const T& v) { + flag.Set(v); + } + template + static const CommandLineFlag& InvokeReflect(const FlagType& f) { + return f.Reflect(); + } +}; + /////////////////////////////////////////////////////////////////////////////// // Implementation of Flag value specific operations routine. template void* FlagOps(FlagOp op, const void* v1, void* v2, void* v3) { switch (op) { - case FlagOp::kDelete: - delete static_cast(v1); + case FlagOp::kAlloc: { + std::allocator alloc; + return std::allocator_traits>::allocate(alloc, 1); + } + case FlagOp::kDelete: { + T* p = static_cast(v2); + p->~T(); + std::allocator alloc; + std::allocator_traits>::deallocate(alloc, p, 1); return nullptr; - case FlagOp::kClone: - return new T(*static_cast(v1)); + } case FlagOp::kCopy: *static_cast(v2) = *static_cast(v1); return nullptr; @@ -648,40 +768,29 @@ void* FlagOps(FlagOp op, const void* v1, void* v2, void* v3) { // This class facilitates Flag object registration and tail expression-based // flag definition, for example: // ABSL_FLAG(int, foo, 42, "Foo help").OnUpdate(NotifyFooWatcher); +struct FlagRegistrarEmpty {}; template class FlagRegistrar { public: - explicit FlagRegistrar(Flag* flag) : flag_(flag) { - if (do_register) flags_internal::RegisterCommandLineFlag(&flag_->impl_); + explicit FlagRegistrar(Flag& flag, const char* filename) : flag_(flag) { + if (do_register) + flags_internal::RegisterCommandLineFlag(flag_.impl_, filename); } - FlagRegistrar& OnUpdate(FlagCallbackFunc cb) && { - flag_->SetCallback(cb); + FlagRegistrar OnUpdate(FlagCallbackFunc cb) && { + flag_.impl_.SetCallback(cb); return *this; } - // Make the registrar "die" gracefully as a bool on a line where registration - // happens. Registrar objects are intended to live only as temporary. - operator bool() const { return true; } // NOLINT + // Make the registrar "die" gracefully as an empty struct on a line where + // registration happens. Registrar objects are intended to live only as + // temporary. + operator FlagRegistrarEmpty() const { return {}; } // NOLINT private: - Flag* flag_; // Flag being registered (not owned). + Flag& flag_; // Flag being registered (not owned). }; -// This struct and corresponding overload to MakeDefaultValue are used to -// facilitate usage of {} as default value in ABSL_FLAG macro. -struct EmptyBraces {}; - -template -T* MakeFromDefaultValue(T t) { - return new T(std::move(t)); -} - -template -T* MakeFromDefaultValue(EmptyBraces) { - return new T{}; -} - } // namespace flags_internal ABSL_NAMESPACE_END } // namespace absl diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/internal/parse.h b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/internal/parse.h index 03e8a07bf3..de706c8984 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/internal/parse.h +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/internal/parse.h @@ -21,6 +21,7 @@ #include "absl/base/config.h" #include "absl/flags/declare.h" +#include "absl/strings/string_view.h" ABSL_DECLARE_FLAG(std::vector, flagfile); ABSL_DECLARE_FLAG(std::vector, fromenv); @@ -44,6 +45,13 @@ std::vector ParseCommandLineImpl(int argc, char* argv[], UsageFlagsAction usage_flag_act, OnUndefinedFlag on_undef_flag); +// -------------------------------------------------------------------- +// Inspect original command line + +// Returns true if flag with specified name was either present on the original +// command line or specified in flag file present on the original command line. +bool WasPresentOnCommandLine(absl::string_view flag_name); + } // namespace flags_internal ABSL_NAMESPACE_END } // namespace absl diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/internal/path_util.h b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/internal/path_util.h index 365c830522..a6594d3347 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/internal/path_util.h +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/internal/path_util.h @@ -17,7 +17,6 @@ #define ABSL_FLAGS_INTERNAL_PATH_UTIL_H_ #include "absl/base/config.h" -#include "absl/strings/match.h" #include "absl/strings/string_view.h" namespace absl { diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/internal/private_handle_accessor.cc b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/internal/private_handle_accessor.cc new file mode 100644 index 0000000000..a7eb58b6d4 --- /dev/null +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/internal/private_handle_accessor.cc @@ -0,0 +1,65 @@ +// +// Copyright 2020 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "absl/flags/internal/private_handle_accessor.h" + +#include +#include + +#include "absl/base/config.h" +#include "absl/flags/commandlineflag.h" +#include "absl/flags/internal/commandlineflag.h" +#include "absl/strings/string_view.h" + +namespace absl { +ABSL_NAMESPACE_BEGIN +namespace flags_internal { + +FlagFastTypeId PrivateHandleAccessor::TypeId(const CommandLineFlag& flag) { + return flag.TypeId(); +} + +std::unique_ptr PrivateHandleAccessor::SaveState( + CommandLineFlag& flag) { + return flag.SaveState(); +} + +bool PrivateHandleAccessor::IsSpecifiedOnCommandLine( + const CommandLineFlag& flag) { + return flag.IsSpecifiedOnCommandLine(); +} + +bool PrivateHandleAccessor::ValidateInputValue(const CommandLineFlag& flag, + absl::string_view value) { + return flag.ValidateInputValue(value); +} + +void PrivateHandleAccessor::CheckDefaultValueParsingRoundtrip( + const CommandLineFlag& flag) { + flag.CheckDefaultValueParsingRoundtrip(); +} + +bool PrivateHandleAccessor::ParseFrom(CommandLineFlag& flag, + absl::string_view value, + flags_internal::FlagSettingMode set_mode, + flags_internal::ValueSource source, + std::string& error) { + return flag.ParseFrom(value, set_mode, source, error); +} + +} // namespace flags_internal +ABSL_NAMESPACE_END +} // namespace absl + diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/internal/private_handle_accessor.h b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/internal/private_handle_accessor.h new file mode 100644 index 0000000000..c64435cd61 --- /dev/null +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/internal/private_handle_accessor.h @@ -0,0 +1,61 @@ +// +// Copyright 2020 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef ABSL_FLAGS_INTERNAL_PRIVATE_HANDLE_ACCESSOR_H_ +#define ABSL_FLAGS_INTERNAL_PRIVATE_HANDLE_ACCESSOR_H_ + +#include +#include + +#include "absl/base/config.h" +#include "absl/flags/commandlineflag.h" +#include "absl/flags/internal/commandlineflag.h" +#include "absl/strings/string_view.h" + +namespace absl { +ABSL_NAMESPACE_BEGIN +namespace flags_internal { + +// This class serves as a trampoline to access private methods of +// CommandLineFlag. This class is intended for use exclusively internally inside +// of the Abseil Flags implementation. +class PrivateHandleAccessor { + public: + // Access to CommandLineFlag::TypeId. + static FlagFastTypeId TypeId(const CommandLineFlag& flag); + + // Access to CommandLineFlag::SaveState. + static std::unique_ptr SaveState(CommandLineFlag& flag); + + // Access to CommandLineFlag::IsSpecifiedOnCommandLine. + static bool IsSpecifiedOnCommandLine(const CommandLineFlag& flag); + + // Access to CommandLineFlag::ValidateInputValue. + static bool ValidateInputValue(const CommandLineFlag& flag, + absl::string_view value); + + // Access to CommandLineFlag::CheckDefaultValueParsingRoundtrip. + static void CheckDefaultValueParsingRoundtrip(const CommandLineFlag& flag); + + static bool ParseFrom(CommandLineFlag& flag, absl::string_view value, + flags_internal::FlagSettingMode set_mode, + flags_internal::ValueSource source, std::string& error); +}; + +} // namespace flags_internal +ABSL_NAMESPACE_END +} // namespace absl + +#endif // ABSL_FLAGS_INTERNAL_PRIVATE_HANDLE_ACCESSOR_H_ diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/internal/program_name_test.cc b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/internal/program_name_test.cc index 269142f225..aff9f6315e 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/internal/program_name_test.cc +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/internal/program_name_test.cc @@ -25,7 +25,7 @@ namespace { namespace flags = absl::flags_internal; -TEST(FlagsPathUtilTest, TestInitialProgamName) { +TEST(FlagsPathUtilTest, TestProgamNameInterfaces) { flags::SetProgramInvocationName("absl/flags/program_name_test"); std::string program_name = flags::ProgramInvocationName(); for (char& c : program_name) @@ -43,9 +43,7 @@ TEST(FlagsPathUtilTest, TestInitialProgamName) { EXPECT_TRUE(absl::EndsWith(program_name, expect_name)) << program_name; EXPECT_EQ(flags::ShortProgramInvocationName(), expect_basename); -} -TEST(FlagsPathUtilTest, TestProgamNameInterfaces) { flags::SetProgramInvocationName("a/my_test"); EXPECT_EQ(flags::ProgramInvocationName(), "a/my_test"); diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/internal/registry.cc b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/internal/registry.cc deleted file mode 100644 index eb619c7086..0000000000 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/internal/registry.cc +++ /dev/null @@ -1,351 +0,0 @@ -// -// Copyright 2019 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "absl/flags/internal/registry.h" - -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "absl/base/config.h" -#include "absl/base/internal/raw_logging.h" -#include "absl/base/thread_annotations.h" -#include "absl/flags/internal/commandlineflag.h" -#include "absl/flags/usage_config.h" -#include "absl/strings/str_cat.h" -#include "absl/strings/string_view.h" -#include "absl/synchronization/mutex.h" - -// -------------------------------------------------------------------- -// FlagRegistry implementation -// A FlagRegistry holds all flag objects indexed -// by their names so that if you know a flag's name you can access or -// set it. - -namespace absl { -ABSL_NAMESPACE_BEGIN -namespace flags_internal { - -// -------------------------------------------------------------------- -// FlagRegistry -// A FlagRegistry singleton object holds all flag objects indexed -// by their names so that if you know a flag's name (as a C -// string), you can access or set it. If the function is named -// FooLocked(), you must own the registry lock before calling -// the function; otherwise, you should *not* hold the lock, and -// the function will acquire it itself if needed. -// -------------------------------------------------------------------- - -class FlagRegistry { - public: - FlagRegistry() = default; - ~FlagRegistry() = default; - - // Store a flag in this registry. Takes ownership of *flag. - void RegisterFlag(CommandLineFlag* flag); - - void Lock() ABSL_EXCLUSIVE_LOCK_FUNCTION(lock_) { lock_.Lock(); } - void Unlock() ABSL_UNLOCK_FUNCTION(lock_) { lock_.Unlock(); } - - // Returns the flag object for the specified name, or nullptr if not found. - // Will emit a warning if a 'retired' flag is specified. - CommandLineFlag* FindFlagLocked(absl::string_view name); - - // Returns the retired flag object for the specified name, or nullptr if not - // found or not retired. Does not emit a warning. - CommandLineFlag* FindRetiredFlagLocked(absl::string_view name); - - static FlagRegistry* GlobalRegistry(); // returns a singleton registry - - private: - friend class FlagSaverImpl; // reads all the flags in order to copy them - friend void ForEachFlagUnlocked( - std::function visitor); - - // The map from name to flag, for FindFlagLocked(). - using FlagMap = std::map; - using FlagIterator = FlagMap::iterator; - using FlagConstIterator = FlagMap::const_iterator; - FlagMap flags_; - - absl::Mutex lock_; - - // Disallow - FlagRegistry(const FlagRegistry&); - FlagRegistry& operator=(const FlagRegistry&); -}; - -FlagRegistry* FlagRegistry::GlobalRegistry() { - static FlagRegistry* global_registry = new FlagRegistry; - return global_registry; -} - -namespace { - -class FlagRegistryLock { - public: - explicit FlagRegistryLock(FlagRegistry* fr) : fr_(fr) { fr_->Lock(); } - ~FlagRegistryLock() { fr_->Unlock(); } - - private: - FlagRegistry* const fr_; -}; - -void DestroyRetiredFlag(CommandLineFlag* flag); -} // namespace - -void FlagRegistry::RegisterFlag(CommandLineFlag* flag) { - FlagRegistryLock registry_lock(this); - std::pair ins = - flags_.insert(FlagMap::value_type(flag->Name(), flag)); - if (ins.second == false) { // means the name was already in the map - CommandLineFlag* old_flag = ins.first->second; - if (flag->IsRetired() != old_flag->IsRetired()) { - // All registrations must agree on the 'retired' flag. - flags_internal::ReportUsageError( - absl::StrCat( - "Retired flag '", flag->Name(), - "' was defined normally in file '", - (flag->IsRetired() ? old_flag->Filename() : flag->Filename()), - "'."), - true); - } else if (flag->TypeId() != old_flag->TypeId()) { - flags_internal::ReportUsageError( - absl::StrCat("Flag '", flag->Name(), - "' was defined more than once but with " - "differing types. Defined in files '", - old_flag->Filename(), "' and '", flag->Filename(), - "' with types '", old_flag->Typename(), "' and '", - flag->Typename(), "', respectively."), - true); - } else if (old_flag->IsRetired()) { - // Retired flag can just be deleted. - DestroyRetiredFlag(flag); - return; - } else if (old_flag->Filename() != flag->Filename()) { - flags_internal::ReportUsageError( - absl::StrCat("Flag '", flag->Name(), - "' was defined more than once (in files '", - old_flag->Filename(), "' and '", flag->Filename(), - "')."), - true); - } else { - flags_internal::ReportUsageError( - absl::StrCat( - "Something wrong with flag '", flag->Name(), "' in file '", - flag->Filename(), "'. One possibility: file '", flag->Filename(), - "' is being linked both statically and dynamically into this " - "executable. e.g. some files listed as srcs to a test and also " - "listed as srcs of some shared lib deps of the same test."), - true); - } - // All cases above are fatal, except for the retired flags. - std::exit(1); - } -} - -CommandLineFlag* FlagRegistry::FindFlagLocked(absl::string_view name) { - FlagConstIterator i = flags_.find(name); - if (i == flags_.end()) { - return nullptr; - } - - if (i->second->IsRetired()) { - flags_internal::ReportUsageError( - absl::StrCat("Accessing retired flag '", name, "'"), false); - } - - return i->second; -} - -CommandLineFlag* FlagRegistry::FindRetiredFlagLocked(absl::string_view name) { - FlagConstIterator i = flags_.find(name); - if (i == flags_.end() || !i->second->IsRetired()) { - return nullptr; - } - - return i->second; -} - -// -------------------------------------------------------------------- -// FlagSaver -// FlagSaverImpl -// This class stores the states of all flags at construct time, -// and restores all flags to that state at destruct time. -// Its major implementation challenge is that it never modifies -// pointers in the 'main' registry, so global FLAG_* vars always -// point to the right place. -// -------------------------------------------------------------------- - -class FlagSaverImpl { - public: - FlagSaverImpl() = default; - FlagSaverImpl(const FlagSaverImpl&) = delete; - void operator=(const FlagSaverImpl&) = delete; - - // Saves the flag states from the flag registry into this object. - // It's an error to call this more than once. - void SaveFromRegistry() { - assert(backup_registry_.empty()); // call only once! - flags_internal::ForEachFlag([&](flags_internal::CommandLineFlag* flag) { - if (auto flag_state = flag->SaveState()) { - backup_registry_.emplace_back(std::move(flag_state)); - } - }); - } - - // Restores the saved flag states into the flag registry. - void RestoreToRegistry() { - for (const auto& flag_state : backup_registry_) { - flag_state->Restore(); - } - } - - private: - std::vector> - backup_registry_; -}; - -FlagSaver::FlagSaver() : impl_(new FlagSaverImpl) { impl_->SaveFromRegistry(); } - -void FlagSaver::Ignore() { - delete impl_; - impl_ = nullptr; -} - -FlagSaver::~FlagSaver() { - if (!impl_) return; - - impl_->RestoreToRegistry(); - delete impl_; -} - -// -------------------------------------------------------------------- - -CommandLineFlag* FindCommandLineFlag(absl::string_view name) { - if (name.empty()) return nullptr; - FlagRegistry* const registry = FlagRegistry::GlobalRegistry(); - FlagRegistryLock frl(registry); - - return registry->FindFlagLocked(name); -} - -CommandLineFlag* FindRetiredFlag(absl::string_view name) { - FlagRegistry* const registry = FlagRegistry::GlobalRegistry(); - FlagRegistryLock frl(registry); - - return registry->FindRetiredFlagLocked(name); -} - -// -------------------------------------------------------------------- - -void ForEachFlagUnlocked(std::function visitor) { - FlagRegistry* const registry = FlagRegistry::GlobalRegistry(); - for (FlagRegistry::FlagConstIterator i = registry->flags_.begin(); - i != registry->flags_.end(); ++i) { - visitor(i->second); - } -} - -void ForEachFlag(std::function visitor) { - FlagRegistry* const registry = FlagRegistry::GlobalRegistry(); - FlagRegistryLock frl(registry); - ForEachFlagUnlocked(visitor); -} - -// -------------------------------------------------------------------- - -bool RegisterCommandLineFlag(CommandLineFlag* flag) { - FlagRegistry::GlobalRegistry()->RegisterFlag(flag); - return true; -} - -// -------------------------------------------------------------------- - -namespace { - -class RetiredFlagObj final : public flags_internal::CommandLineFlag { - public: - constexpr RetiredFlagObj(const char* name, FlagFastTypeId type_id) - : name_(name), type_id_(type_id) {} - - private: - absl::string_view Name() const override { return name_; } - std::string Filename() const override { return "RETIRED"; } - absl::string_view Typename() const override { return ""; } - FlagFastTypeId TypeId() const override { return type_id_; } - std::string Help() const override { return ""; } - bool IsRetired() const override { return true; } - bool IsModified() const override { return false; } - bool IsSpecifiedOnCommandLine() const override { return false; } - std::string DefaultValue() const override { return ""; } - std::string CurrentValue() const override { return ""; } - - // Any input is valid - bool ValidateInputValue(absl::string_view) const override { return true; } - - std::unique_ptr SaveState() override { - return nullptr; - } - - bool ParseFrom(absl::string_view, flags_internal::FlagSettingMode, - flags_internal::ValueSource, std::string*) override { - return false; - } - - void CheckDefaultValueParsingRoundtrip() const override {} - - void Read(void*) const override {} - - // Data members - const char* const name_; - const FlagFastTypeId type_id_; -}; - -void DestroyRetiredFlag(flags_internal::CommandLineFlag* flag) { - assert(flag->IsRetired()); - delete static_cast(flag); -} - -} // namespace - -bool Retire(const char* name, FlagFastTypeId type_id) { - auto* flag = new flags_internal::RetiredFlagObj(name, type_id); - FlagRegistry::GlobalRegistry()->RegisterFlag(flag); - return true; -} - -// -------------------------------------------------------------------- - -bool IsRetiredFlag(absl::string_view name, bool* type_is_bool) { - assert(!name.empty()); - CommandLineFlag* flag = flags_internal::FindRetiredFlag(name); - if (flag == nullptr) { - return false; - } - assert(type_is_bool); - *type_is_bool = flag->IsOfType(); - return true; -} - -} // namespace flags_internal -ABSL_NAMESPACE_END -} // namespace absl diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/internal/registry.h b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/internal/registry.h index af8ed6b99b..4b68c85f5c 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/internal/registry.h +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/internal/registry.h @@ -17,11 +17,9 @@ #define ABSL_FLAGS_INTERNAL_REGISTRY_H_ #include -#include -#include #include "absl/base/config.h" -#include "absl/base/macros.h" +#include "absl/flags/commandlineflag.h" #include "absl/flags/internal/commandlineflag.h" #include "absl/strings/string_view.h" @@ -32,19 +30,15 @@ namespace absl { ABSL_NAMESPACE_BEGIN namespace flags_internal { -CommandLineFlag* FindCommandLineFlag(absl::string_view name); -CommandLineFlag* FindRetiredFlag(absl::string_view name); - -// Executes specified visitor for each non-retired flag in the registry. -// Requires the caller hold the registry lock. -void ForEachFlagUnlocked(std::function visitor); // Executes specified visitor for each non-retired flag in the registry. While // callback are executed, the registry is locked and can't be changed. -void ForEachFlag(std::function visitor); +void ForEachFlag(std::function visitor); //----------------------------------------------------------------------------- -bool RegisterCommandLineFlag(CommandLineFlag*); +bool RegisterCommandLineFlag(CommandLineFlag&, const char* filename); + +void FinalizeRegistry(); //----------------------------------------------------------------------------- // Retired registrations: @@ -79,42 +73,21 @@ bool RegisterCommandLineFlag(CommandLineFlag*); // // Retire flag with name "name" and type indicated by ops. -bool Retire(const char* name, FlagFastTypeId type_id); +void Retire(const char* name, FlagFastTypeId type_id, char* buf); + +constexpr size_t kRetiredFlagObjSize = 3 * sizeof(void*); +constexpr size_t kRetiredFlagObjAlignment = alignof(void*); // Registered a retired flag with name 'flag_name' and type 'T'. template -inline bool RetiredFlag(const char* flag_name) { - return flags_internal::Retire(flag_name, base_internal::FastTypeId()); -} - -// If the flag is retired, returns true and indicates in |*type_is_bool| -// whether the type of the retired flag is a bool. -// Only to be called by code that needs to explicitly ignore retired flags. -bool IsRetiredFlag(absl::string_view name, bool* type_is_bool); - -//----------------------------------------------------------------------------- -// Saves the states (value, default value, whether the user has set -// the flag, registered validators, etc) of all flags, and restores -// them when the FlagSaver is destroyed. -// -// This class is thread-safe. However, its destructor writes to -// exactly the set of flags that have changed value during its -// lifetime, so concurrent _direct_ access to those flags -// (i.e. FLAGS_foo instead of {Get,Set}CommandLineOption()) is unsafe. - -class FlagSaver { +class RetiredFlag { public: - FlagSaver(); - ~FlagSaver(); - - FlagSaver(const FlagSaver&) = delete; - void operator=(const FlagSaver&) = delete; - - // Prevents saver from restoring the saved state of flags. - void Ignore(); + void Retire(const char* flag_name) { + flags_internal::Retire(flag_name, base_internal::FastTypeId(), buf_); + } private: - class FlagSaverImpl* impl_; // we use pimpl here to keep API steady + alignas(kRetiredFlagObjAlignment) char buf_[kRetiredFlagObjSize]; }; } // namespace flags_internal diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/internal/sequence_lock.h b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/internal/sequence_lock.h new file mode 100644 index 0000000000..36318ab9d3 --- /dev/null +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/internal/sequence_lock.h @@ -0,0 +1,187 @@ +// +// Copyright 2020 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef ABSL_FLAGS_INTERNAL_SEQUENCE_LOCK_H_ +#define ABSL_FLAGS_INTERNAL_SEQUENCE_LOCK_H_ + +#include +#include + +#include +#include +#include + +#include "absl/base/optimization.h" + +namespace absl { +ABSL_NAMESPACE_BEGIN +namespace flags_internal { + +// Align 'x' up to the nearest 'align' bytes. +inline constexpr size_t AlignUp(size_t x, size_t align) { + return align * ((x + align - 1) / align); +} + +// A SequenceLock implements lock-free reads. A sequence counter is incremented +// before and after each write, and readers access the counter before and after +// accessing the protected data. If the counter is verified to not change during +// the access, and the sequence counter value was even, then the reader knows +// that the read was race-free and valid. Otherwise, the reader must fall back +// to a Mutex-based code path. +// +// This particular SequenceLock starts in an "uninitialized" state in which +// TryRead() returns false. It must be enabled by calling MarkInitialized(). +// This serves as a marker that the associated flag value has not yet been +// initialized and a slow path needs to be taken. +// +// The memory reads and writes protected by this lock must use the provided +// `TryRead()` and `Write()` functions. These functions behave similarly to +// `memcpy()`, with one oddity: the protected data must be an array of +// `std::atomic`. This is to comply with the C++ standard, which +// considers data races on non-atomic objects to be undefined behavior. See "Can +// Seqlocks Get Along With Programming Language Memory Models?"[1] by Hans J. +// Boehm for more details. +// +// [1] https://www.hpl.hp.com/techreports/2012/HPL-2012-68.pdf +class SequenceLock { + public: + constexpr SequenceLock() : lock_(kUninitialized) {} + + // Mark that this lock is ready for use. + void MarkInitialized() { + assert(lock_.load(std::memory_order_relaxed) == kUninitialized); + lock_.store(0, std::memory_order_release); + } + + // Copy "size" bytes of data from "src" to "dst", protected as a read-side + // critical section of the sequence lock. + // + // Unlike traditional sequence lock implementations which loop until getting a + // clean read, this implementation returns false in the case of concurrent + // calls to `Write`. In such a case, the caller should fall back to a + // locking-based slow path. + // + // Returns false if the sequence lock was not yet marked as initialized. + // + // NOTE: If this returns false, "dst" may be overwritten with undefined + // (potentially uninitialized) data. + bool TryRead(void* dst, const std::atomic* src, size_t size) const { + // Acquire barrier ensures that no loads done by f() are reordered + // above the first load of the sequence counter. + int64_t seq_before = lock_.load(std::memory_order_acquire); + if (ABSL_PREDICT_FALSE(seq_before & 1) == 1) return false; + RelaxedCopyFromAtomic(dst, src, size); + // Another acquire fence ensures that the load of 'lock_' below is + // strictly ordered after the RelaxedCopyToAtomic call above. + std::atomic_thread_fence(std::memory_order_acquire); + int64_t seq_after = lock_.load(std::memory_order_relaxed); + return ABSL_PREDICT_TRUE(seq_before == seq_after); + } + + // Copy "size" bytes from "src" to "dst" as a write-side critical section + // of the sequence lock. Any concurrent readers will be forced to retry + // until they get a read that does not conflict with this write. + // + // This call must be externally synchronized against other calls to Write, + // but may proceed concurrently with reads. + void Write(std::atomic* dst, const void* src, size_t size) { + // We can use relaxed instructions to increment the counter since we + // are extenally synchronized. The std::atomic_thread_fence below + // ensures that the counter updates don't get interleaved with the + // copy to the data. + int64_t orig_seq = lock_.load(std::memory_order_relaxed); + assert((orig_seq & 1) == 0); // Must be initially unlocked. + lock_.store(orig_seq + 1, std::memory_order_relaxed); + + // We put a release fence between update to lock_ and writes to shared data. + // Thus all stores to shared data are effectively release operations and + // update to lock_ above cannot be re-ordered past any of them. Note that + // this barrier is not for the fetch_add above. A release barrier for the + // fetch_add would be before it, not after. + std::atomic_thread_fence(std::memory_order_release); + RelaxedCopyToAtomic(dst, src, size); + // "Release" semantics ensure that none of the writes done by + // RelaxedCopyToAtomic() can be reordered after the following modification. + lock_.store(orig_seq + 2, std::memory_order_release); + } + + // Return the number of times that Write() has been called. + // + // REQUIRES: This must be externally synchronized against concurrent calls to + // `Write()` or `IncrementModificationCount()`. + // REQUIRES: `MarkInitialized()` must have been previously called. + int64_t ModificationCount() const { + int64_t val = lock_.load(std::memory_order_relaxed); + assert(val != kUninitialized && (val & 1) == 0); + return val / 2; + } + + // REQUIRES: This must be externally synchronized against concurrent calls to + // `Write()` or `ModificationCount()`. + // REQUIRES: `MarkInitialized()` must have been previously called. + void IncrementModificationCount() { + int64_t val = lock_.load(std::memory_order_relaxed); + assert(val != kUninitialized); + lock_.store(val + 2, std::memory_order_relaxed); + } + + private: + // Perform the equivalent of "memcpy(dst, src, size)", but using relaxed + // atomics. + static void RelaxedCopyFromAtomic(void* dst, const std::atomic* src, + size_t size) { + char* dst_byte = static_cast(dst); + while (size >= sizeof(uint64_t)) { + uint64_t word = src->load(std::memory_order_relaxed); + std::memcpy(dst_byte, &word, sizeof(word)); + dst_byte += sizeof(word); + src++; + size -= sizeof(word); + } + if (size > 0) { + uint64_t word = src->load(std::memory_order_relaxed); + std::memcpy(dst_byte, &word, size); + } + } + + // Perform the equivalent of "memcpy(dst, src, size)", but using relaxed + // atomics. + static void RelaxedCopyToAtomic(std::atomic* dst, const void* src, + size_t size) { + const char* src_byte = static_cast(src); + while (size >= sizeof(uint64_t)) { + uint64_t word; + std::memcpy(&word, src_byte, sizeof(word)); + dst->store(word, std::memory_order_relaxed); + src_byte += sizeof(word); + dst++; + size -= sizeof(word); + } + if (size > 0) { + uint64_t word = 0; + std::memcpy(&word, src_byte, size); + dst->store(word, std::memory_order_relaxed); + } + } + + static constexpr int64_t kUninitialized = -1; + std::atomic lock_; +}; + +} // namespace flags_internal +ABSL_NAMESPACE_END +} // namespace absl + +#endif // ABSL_FLAGS_INTERNAL_SEQUENCE_LOCK_H_ diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/internal/sequence_lock_test.cc b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/internal/sequence_lock_test.cc new file mode 100644 index 0000000000..c3ec372ed8 --- /dev/null +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/internal/sequence_lock_test.cc @@ -0,0 +1,169 @@ +// Copyright 2020 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#include "absl/flags/internal/sequence_lock.h" + +#include +#include +#include // NOLINT(build/c++11) +#include +#include + +#include "gtest/gtest.h" +#include "absl/base/internal/sysinfo.h" +#include "absl/container/fixed_array.h" +#include "absl/time/clock.h" + +namespace { + +namespace flags = absl::flags_internal; + +class ConcurrentSequenceLockTest + : public testing::TestWithParam> { + public: + ConcurrentSequenceLockTest() + : buf_bytes_(std::get<0>(GetParam())), + num_threads_(std::get<1>(GetParam())) {} + + protected: + const int buf_bytes_; + const int num_threads_; +}; + +TEST_P(ConcurrentSequenceLockTest, ReadAndWrite) { + const int buf_words = + flags::AlignUp(buf_bytes_, sizeof(uint64_t)) / sizeof(uint64_t); + + // The buffer that will be protected by the SequenceLock. + absl::FixedArray> protected_buf(buf_words); + for (auto& v : protected_buf) v = -1; + + flags::SequenceLock seq_lock; + std::atomic stop{false}; + std::atomic bad_reads{0}; + std::atomic good_reads{0}; + std::atomic unsuccessful_reads{0}; + + // Start a bunch of threads which read 'protected_buf' under the sequence + // lock. The main thread will concurrently update 'protected_buf'. The updates + // always consist of an array of identical integers. The reader ensures that + // any data it reads matches that pattern (i.e. the reads are not "torn"). + std::vector threads; + for (int i = 0; i < num_threads_; i++) { + threads.emplace_back([&]() { + absl::FixedArray local_buf(buf_bytes_); + while (!stop.load(std::memory_order_relaxed)) { + if (seq_lock.TryRead(local_buf.data(), protected_buf.data(), + buf_bytes_)) { + bool good = true; + for (const auto& v : local_buf) { + if (v != local_buf[0]) good = false; + } + if (good) { + good_reads.fetch_add(1, std::memory_order_relaxed); + } else { + bad_reads.fetch_add(1, std::memory_order_relaxed); + } + } else { + unsuccessful_reads.fetch_add(1, std::memory_order_relaxed); + } + } + }); + } + while (unsuccessful_reads.load(std::memory_order_relaxed) < num_threads_) { + absl::SleepFor(absl::Milliseconds(1)); + } + seq_lock.MarkInitialized(); + + // Run a maximum of 5 seconds. On Windows, the scheduler behavior seems + // somewhat unfair and without an explicit timeout for this loop, the tests + // can run a long time. + absl::Time deadline = absl::Now() + absl::Seconds(5); + for (int i = 0; i < 100 && absl::Now() < deadline; i++) { + absl::FixedArray writer_buf(buf_bytes_); + for (auto& v : writer_buf) v = i; + seq_lock.Write(protected_buf.data(), writer_buf.data(), buf_bytes_); + absl::SleepFor(absl::Microseconds(10)); + } + stop.store(true, std::memory_order_relaxed); + for (auto& t : threads) t.join(); + ASSERT_GE(good_reads, 0); + ASSERT_EQ(bad_reads, 0); +} + +// Simple helper for generating a range of thread counts. +// Generates [low, low*scale, low*scale^2, ...high) +// (even if high is between low*scale^k and low*scale^(k+1)). +std::vector MultiplicativeRange(int low, int high, int scale) { + std::vector result; + for (int current = low; current < high; current *= scale) { + result.push_back(current); + } + result.push_back(high); + return result; +} + +#ifndef ABSL_HAVE_THREAD_SANITIZER +const int kMaxThreads = absl::base_internal::NumCPUs(); +#else +// With TSAN, a lot of threads contending for atomic access on the sequence +// lock make this test run too slowly. +const int kMaxThreads = std::min(absl::base_internal::NumCPUs(), 4); +#endif + +// Return all of the interesting buffer sizes worth testing: +// powers of two and adjacent values. +std::vector InterestingBufferSizes() { + std::vector ret; + for (int v : MultiplicativeRange(1, 128, 2)) { + ret.push_back(v); + if (v > 1) { + ret.push_back(v - 1); + } + ret.push_back(v + 1); + } + return ret; +} + +INSTANTIATE_TEST_SUITE_P( + TestManyByteSizes, ConcurrentSequenceLockTest, + testing::Combine( + // Buffer size (bytes). + testing::ValuesIn(InterestingBufferSizes()), + // Number of reader threads. + testing::ValuesIn(MultiplicativeRange(1, kMaxThreads, 2)))); + +// Simple single-threaded test, parameterized by the size of the buffer to be +// protected. +class SequenceLockTest : public testing::TestWithParam {}; + +TEST_P(SequenceLockTest, SingleThreaded) { + const int size = GetParam(); + absl::FixedArray> protected_buf( + flags::AlignUp(size, sizeof(uint64_t)) / sizeof(uint64_t)); + + flags::SequenceLock seq_lock; + seq_lock.MarkInitialized(); + + std::vector src_buf(size, 'x'); + seq_lock.Write(protected_buf.data(), src_buf.data(), size); + + std::vector dst_buf(size, '0'); + ASSERT_TRUE(seq_lock.TryRead(dst_buf.data(), protected_buf.data(), size)); + ASSERT_EQ(src_buf, dst_buf); +} +INSTANTIATE_TEST_SUITE_P(TestManyByteSizes, SequenceLockTest, + // Buffer size (bytes). + testing::Range(1, 128)); + +} // namespace diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/internal/type_erased.cc b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/internal/type_erased.cc deleted file mode 100644 index 75b4cdf891..0000000000 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/internal/type_erased.cc +++ /dev/null @@ -1,90 +0,0 @@ -// -// Copyright 2019 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "absl/flags/internal/type_erased.h" - -#include - -#include - -#include "absl/base/config.h" -#include "absl/base/internal/raw_logging.h" -#include "absl/flags/internal/commandlineflag.h" -#include "absl/flags/internal/registry.h" -#include "absl/flags/usage_config.h" -#include "absl/strings/string_view.h" - -namespace absl { -ABSL_NAMESPACE_BEGIN -namespace flags_internal { - -bool GetCommandLineOption(absl::string_view name, std::string* value) { - if (name.empty()) return false; - assert(value); - - CommandLineFlag* flag = flags_internal::FindCommandLineFlag(name); - if (flag == nullptr || flag->IsRetired()) { - return false; - } - - *value = flag->CurrentValue(); - return true; -} - -bool SetCommandLineOption(absl::string_view name, absl::string_view value) { - return SetCommandLineOptionWithMode(name, value, - flags_internal::SET_FLAGS_VALUE); -} - -bool SetCommandLineOptionWithMode(absl::string_view name, - absl::string_view value, - FlagSettingMode set_mode) { - CommandLineFlag* flag = flags_internal::FindCommandLineFlag(name); - - if (!flag || flag->IsRetired()) return false; - - std::string error; - if (!flag->ParseFrom(value, set_mode, kProgrammaticChange, &error)) { - // Errors here are all of the form: the provided name was a recognized - // flag, but the value was invalid (bad type, or validation failed). - flags_internal::ReportUsageError(error, false); - return false; - } - - return true; -} - -// -------------------------------------------------------------------- - -bool IsValidFlagValue(absl::string_view name, absl::string_view value) { - CommandLineFlag* flag = flags_internal::FindCommandLineFlag(name); - - return flag != nullptr && - (flag->IsRetired() || flag->ValidateInputValue(value)); -} - -// -------------------------------------------------------------------- - -bool SpecifiedOnCommandLine(absl::string_view name) { - CommandLineFlag* flag = flags_internal::FindCommandLineFlag(name); - if (flag != nullptr && !flag->IsRetired()) { - return flag->IsSpecifiedOnCommandLine(); - } - return false; -} - -} // namespace flags_internal -ABSL_NAMESPACE_END -} // namespace absl diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/internal/type_erased.h b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/internal/type_erased.h deleted file mode 100644 index 188429c771..0000000000 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/internal/type_erased.h +++ /dev/null @@ -1,90 +0,0 @@ -// -// Copyright 2019 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef ABSL_FLAGS_INTERNAL_TYPE_ERASED_H_ -#define ABSL_FLAGS_INTERNAL_TYPE_ERASED_H_ - -#include - -#include "absl/base/config.h" -#include "absl/flags/internal/commandlineflag.h" -#include "absl/flags/internal/registry.h" -#include "absl/strings/string_view.h" - -// -------------------------------------------------------------------- -// Registry interfaces operating on type erased handles. - -namespace absl { -ABSL_NAMESPACE_BEGIN -namespace flags_internal { - -// If a flag named "name" exists, store its current value in *OUTPUT -// and return true. Else return false without changing *OUTPUT. -// Thread-safe. -bool GetCommandLineOption(absl::string_view name, std::string* value); - -// Set the value of the flag named "name" to value. If successful, -// returns true. If not successful (e.g., the flag was not found or -// the value is not a valid value), returns false. -// Thread-safe. -bool SetCommandLineOption(absl::string_view name, absl::string_view value); - -bool SetCommandLineOptionWithMode(absl::string_view name, - absl::string_view value, - FlagSettingMode set_mode); - -//----------------------------------------------------------------------------- - -// Returns true iff all of the following conditions are true: -// (a) "name" names a registered flag -// (b) "value" can be parsed succesfully according to the type of the flag -// (c) parsed value passes any validator associated with the flag -bool IsValidFlagValue(absl::string_view name, absl::string_view value); - -//----------------------------------------------------------------------------- - -// Returns true iff a flag named "name" was specified on the command line -// (either directly, or via one of --flagfile or --fromenv or --tryfromenv). -// -// Any non-command-line modification of the flag does not affect the -// result of this function. So for example, if a flag was passed on -// the command line but then reset via SET_FLAGS_DEFAULT, this -// function will still return true. -bool SpecifiedOnCommandLine(absl::string_view name); - -//----------------------------------------------------------------------------- - -// If a flag with specified "name" exists and has type T, store -// its current value in *dst and return true. Else return false -// without touching *dst. T must obey all of the requirements for -// types passed to DEFINE_FLAG. -template -inline bool GetByName(absl::string_view name, T* dst) { - CommandLineFlag* flag = flags_internal::FindCommandLineFlag(name); - if (!flag) return false; - - if (auto val = flag->Get()) { - *dst = *val; - return true; - } - - return false; -} - -} // namespace flags_internal -ABSL_NAMESPACE_END -} // namespace absl - -#endif // ABSL_FLAGS_INTERNAL_TYPE_ERASED_H_ diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/internal/type_erased_test.cc b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/internal/type_erased_test.cc deleted file mode 100644 index 4ce5981047..0000000000 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/internal/type_erased_test.cc +++ /dev/null @@ -1,157 +0,0 @@ -// -// Copyright 2019 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "absl/flags/internal/type_erased.h" - -#include -#include - -#include "gtest/gtest.h" -#include "absl/flags/flag.h" -#include "absl/flags/internal/commandlineflag.h" -#include "absl/flags/internal/registry.h" -#include "absl/flags/marshalling.h" -#include "absl/memory/memory.h" - -ABSL_FLAG(int, int_flag, 1, "int_flag help"); -ABSL_FLAG(std::string, string_flag, "dflt", "string_flag help"); -ABSL_RETIRED_FLAG(bool, bool_retired_flag, false, "bool_retired_flag help"); - -namespace { - -namespace flags = absl::flags_internal; - -class TypeErasedTest : public testing::Test { - protected: - void SetUp() override { flag_saver_ = absl::make_unique(); } - void TearDown() override { flag_saver_.reset(); } - - private: - std::unique_ptr flag_saver_; -}; - -// -------------------------------------------------------------------- - -TEST_F(TypeErasedTest, TestGetCommandLineOption) { - std::string value; - EXPECT_TRUE(flags::GetCommandLineOption("int_flag", &value)); - EXPECT_EQ(value, "1"); - - EXPECT_TRUE(flags::GetCommandLineOption("string_flag", &value)); - EXPECT_EQ(value, "dflt"); - - EXPECT_FALSE(flags::GetCommandLineOption("bool_retired_flag", &value)); - - EXPECT_FALSE(flags::GetCommandLineOption("unknown_flag", &value)); -} - -// -------------------------------------------------------------------- - -TEST_F(TypeErasedTest, TestSetCommandLineOption) { - EXPECT_TRUE(flags::SetCommandLineOption("int_flag", "101")); - EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), 101); - - EXPECT_TRUE(flags::SetCommandLineOption("string_flag", "asdfgh")); - EXPECT_EQ(absl::GetFlag(FLAGS_string_flag), "asdfgh"); - - EXPECT_FALSE(flags::SetCommandLineOption("bool_retired_flag", "true")); - - EXPECT_FALSE(flags::SetCommandLineOption("unknown_flag", "true")); -} - -// -------------------------------------------------------------------- - -TEST_F(TypeErasedTest, TestSetCommandLineOptionWithMode_SET_FLAGS_VALUE) { - EXPECT_TRUE(flags::SetCommandLineOptionWithMode("int_flag", "101", - flags::SET_FLAGS_VALUE)); - EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), 101); - - EXPECT_TRUE(flags::SetCommandLineOptionWithMode("string_flag", "asdfgh", - flags::SET_FLAGS_VALUE)); - EXPECT_EQ(absl::GetFlag(FLAGS_string_flag), "asdfgh"); - - EXPECT_FALSE(flags::SetCommandLineOptionWithMode("bool_retired_flag", "true", - flags::SET_FLAGS_VALUE)); - - EXPECT_FALSE(flags::SetCommandLineOptionWithMode("unknown_flag", "true", - flags::SET_FLAGS_VALUE)); -} - -// -------------------------------------------------------------------- - -TEST_F(TypeErasedTest, TestSetCommandLineOptionWithMode_SET_FLAG_IF_DEFAULT) { - EXPECT_TRUE(flags::SetCommandLineOptionWithMode("int_flag", "101", - flags::SET_FLAG_IF_DEFAULT)); - EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), 101); - - // This semantic is broken. We return true instead of false. Value is not - // updated. - EXPECT_TRUE(flags::SetCommandLineOptionWithMode("int_flag", "202", - flags::SET_FLAG_IF_DEFAULT)); - EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), 101); - - EXPECT_TRUE(flags::SetCommandLineOptionWithMode("string_flag", "asdfgh", - flags::SET_FLAG_IF_DEFAULT)); - EXPECT_EQ(absl::GetFlag(FLAGS_string_flag), "asdfgh"); - - EXPECT_FALSE(flags::SetCommandLineOptionWithMode("bool_retired_flag", "true", - flags::SET_FLAG_IF_DEFAULT)); - - EXPECT_FALSE(flags::SetCommandLineOptionWithMode("unknown_flag", "true", - flags::SET_FLAG_IF_DEFAULT)); -} - -// -------------------------------------------------------------------- - -TEST_F(TypeErasedTest, TestSetCommandLineOptionWithMode_SET_FLAGS_DEFAULT) { - EXPECT_TRUE(flags::SetCommandLineOptionWithMode("int_flag", "101", - flags::SET_FLAGS_DEFAULT)); - - // Set it again to ensure that resetting logic is covered. - EXPECT_TRUE(flags::SetCommandLineOptionWithMode("int_flag", "102", - flags::SET_FLAGS_DEFAULT)); - - EXPECT_TRUE(flags::SetCommandLineOptionWithMode("int_flag", "103", - flags::SET_FLAGS_DEFAULT)); - - EXPECT_TRUE(flags::SetCommandLineOptionWithMode("string_flag", "asdfgh", - flags::SET_FLAGS_DEFAULT)); - EXPECT_EQ(absl::GetFlag(FLAGS_string_flag), "asdfgh"); - - EXPECT_FALSE(flags::SetCommandLineOptionWithMode("bool_retired_flag", "true", - flags::SET_FLAGS_DEFAULT)); - - EXPECT_FALSE(flags::SetCommandLineOptionWithMode("unknown_flag", "true", - flags::SET_FLAGS_DEFAULT)); - - // This should be successfull, since flag is still is not set - EXPECT_TRUE(flags::SetCommandLineOptionWithMode("int_flag", "202", - flags::SET_FLAG_IF_DEFAULT)); - EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), 202); -} - -// -------------------------------------------------------------------- - -TEST_F(TypeErasedTest, TestIsValidFlagValue) { - EXPECT_TRUE(flags::IsValidFlagValue("int_flag", "57")); - EXPECT_TRUE(flags::IsValidFlagValue("int_flag", "-101")); - EXPECT_FALSE(flags::IsValidFlagValue("int_flag", "1.1")); - - EXPECT_TRUE(flags::IsValidFlagValue("string_flag", "#%^#%^$%DGHDG$W%adsf")); - - EXPECT_TRUE(flags::IsValidFlagValue("bool_retired_flag", "true")); -} - -} // namespace diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/internal/usage.cc b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/internal/usage.cc index a9a5cba94d..949709e883 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/internal/usage.cc +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/internal/usage.cc @@ -15,6 +15,8 @@ #include "absl/flags/internal/usage.h" +#include + #include #include #include @@ -23,10 +25,11 @@ #include #include "absl/base/config.h" +#include "absl/flags/commandlineflag.h" #include "absl/flags/flag.h" -#include "absl/flags/internal/commandlineflag.h" #include "absl/flags/internal/flag.h" #include "absl/flags/internal/path_util.h" +#include "absl/flags/internal/private_handle_accessor.h" #include "absl/flags/internal/program_name.h" #include "absl/flags/internal/registry.h" #include "absl/flags/usage_config.h" @@ -34,46 +37,25 @@ #include "absl/strings/str_split.h" #include "absl/strings/string_view.h" -ABSL_FLAG(bool, help, false, - "show help on important flags for this binary [tip: all flags can " - "have two dashes]"); -ABSL_FLAG(bool, helpfull, false, "show help on all flags"); -ABSL_FLAG(bool, helpshort, false, - "show help on only the main module for this program"); -ABSL_FLAG(bool, helppackage, false, - "show help on all modules in the main package"); -ABSL_FLAG(bool, version, false, "show version and build info and exit"); -ABSL_FLAG(bool, only_check_args, false, "exit after checking all flags"); -ABSL_FLAG(std::string, helpon, "", - "show help on the modules named by this flag value"); -ABSL_FLAG(std::string, helpmatch, "", - "show help on modules whose name contains the specified substr"); +// Dummy global variables to prevent anyone else defining these. +bool FLAGS_help = false; +bool FLAGS_helpfull = false; +bool FLAGS_helpshort = false; +bool FLAGS_helppackage = false; +bool FLAGS_version = false; +bool FLAGS_only_check_args = false; +bool FLAGS_helpon = false; +bool FLAGS_helpmatch = false; namespace absl { ABSL_NAMESPACE_BEGIN namespace flags_internal { namespace { -absl::string_view TypenameForHelp(const flags_internal::CommandLineFlag& flag) { - // Only report names of v1 built-in types -#define HANDLE_V1_BUILTIN_TYPE(t) \ - if (flag.IsOfType()) { \ - return #t; \ - } +using PerFlagFilter = std::function; - HANDLE_V1_BUILTIN_TYPE(bool); - HANDLE_V1_BUILTIN_TYPE(int32_t); - HANDLE_V1_BUILTIN_TYPE(int64_t); - HANDLE_V1_BUILTIN_TYPE(uint64_t); - HANDLE_V1_BUILTIN_TYPE(double); -#undef HANDLE_V1_BUILTIN_TYPE - - if (flag.IsOfType()) { - return "string"; - } - - return ""; -} +// Maximum length size in a human readable format. +constexpr size_t kHrfMaxLineLength = 80; // This class is used to emit an XML element with `tag` and `text`. // It adds opening and closing tags and escapes special characters in the text. @@ -127,9 +109,12 @@ class FlagHelpPrettyPrinter { public: // Pretty printer holds on to the std::ostream& reference to direct an output // to that stream. - FlagHelpPrettyPrinter(int max_line_len, std::ostream* out) - : out_(*out), + FlagHelpPrettyPrinter(size_t max_line_len, size_t min_line_len, + size_t wrapped_line_indent, std::ostream& out) + : out_(out), max_line_len_(max_line_len), + min_line_len_(min_line_len), + wrapped_line_indent_(wrapped_line_indent), line_len_(0), first_line_(true) {} @@ -163,7 +148,8 @@ class FlagHelpPrettyPrinter { } // Write the token, ending the string first if necessary/possible. - if (!new_line && (line_len_ + token.size() >= max_line_len_)) { + if (!new_line && + (line_len_ + static_cast(token.size()) >= max_line_len_)) { EndLine(); new_line = true; } @@ -182,13 +168,12 @@ class FlagHelpPrettyPrinter { void StartLine() { if (first_line_) { - out_ << " "; - line_len_ = 4; + line_len_ = min_line_len_; first_line_ = false; } else { - out_ << " "; - line_len_ = 6; + line_len_ = min_line_len_ + wrapped_line_indent_; } + out_ << std::string(line_len_, ' '); } void EndLine() { out_ << '\n'; @@ -197,14 +182,15 @@ class FlagHelpPrettyPrinter { private: std::ostream& out_; - const int max_line_len_; - int line_len_; + const size_t max_line_len_; + const size_t min_line_len_; + const size_t wrapped_line_indent_; + size_t line_len_; bool first_line_; }; -void FlagHelpHumanReadable(const flags_internal::CommandLineFlag& flag, - std::ostream* out) { - FlagHelpPrettyPrinter printer(80, out); // Max line length is 80. +void FlagHelpHumanReadable(const CommandLineFlag& flag, std::ostream& out) { + FlagHelpPrettyPrinter printer(kHrfMaxLineLength, 4, 2, out); // Flag name. printer.Write(absl::StrCat("--", flag.Name())); @@ -212,23 +198,20 @@ void FlagHelpHumanReadable(const flags_internal::CommandLineFlag& flag, // Flag help. printer.Write(absl::StrCat("(", flag.Help(), ");"), /*wrap_line=*/true); - // Flag data type (for V1 flags only). - if (!flag.IsAbseilFlag() && !flag.IsRetired()) { - printer.Write(absl::StrCat("type: ", TypenameForHelp(flag), ";")); - } - // The listed default value will be the actual default from the flag // definition in the originating source file, unless the value has // subsequently been modified using SetCommandLineOption() with mode // SET_FLAGS_DEFAULT. std::string dflt_val = flag.DefaultValue(); + std::string curr_val = flag.CurrentValue(); + bool is_modified = curr_val != dflt_val; + if (flag.IsOfType()) { dflt_val = absl::StrCat("\"", dflt_val, "\""); } printer.Write(absl::StrCat("default: ", dflt_val, ";")); - if (flag.IsModified()) { - std::string curr_val = flag.CurrentValue(); + if (is_modified) { if (flag.IsOfType()) { curr_val = absl::StrCat("\"", curr_val, "\""); } @@ -243,7 +226,7 @@ void FlagHelpHumanReadable(const flags_internal::CommandLineFlag& flag, // If a flag's help message has been stripped (e.g. by adding '#define // STRIP_FLAG_HELP 1' then this flag will not be displayed by '--help' // and its variants. -void FlagsHelpImpl(std::ostream& out, flags_internal::FlagKindFilter filter_cb, +void FlagsHelpImpl(std::ostream& out, PerFlagFilter filter_cb, HelpFormat format, absl::string_view program_usage_message) { if (format == HelpFormat::kHumanReadable) { out << flags_internal::ShortProgramInvocationName() << ": " @@ -262,50 +245,54 @@ void FlagsHelpImpl(std::ostream& out, flags_internal::FlagKindFilter filter_cb, << XMLElement("usage", program_usage_message) << '\n'; } - // Map of package name to + // Ordered map of package name to // map of file name to // vector of flags in the file. // This map is used to output matching flags grouped by package and file // name. std::map>> + std::map>> matching_flags; - flags_internal::ForEachFlag([&](flags_internal::CommandLineFlag* flag) { - std::string flag_filename = flag->Filename(); - + flags_internal::ForEachFlag([&](absl::CommandLineFlag& flag) { // Ignore retired flags. - if (flag->IsRetired()) return; + if (flag.IsRetired()) return; // If the flag has been stripped, pretend that it doesn't exist. - if (flag->Help() == flags_internal::kStrippedFlagHelp) return; + if (flag.Help() == flags_internal::kStrippedFlagHelp) return; // Make sure flag satisfies the filter - if (!filter_cb || !filter_cb(flag_filename)) return; + if (!filter_cb(flag)) return; + + std::string flag_filename = flag.Filename(); matching_flags[std::string(flags_internal::Package(flag_filename))] [flag_filename] - .push_back(flag); + .push_back(&flag); }); - absl::string_view - package_separator; // controls blank lines between packages. - absl::string_view file_separator; // controls blank lines between files. - for (const auto& package : matching_flags) { + absl::string_view package_separator; // controls blank lines between packages + absl::string_view file_separator; // controls blank lines between files + for (auto& package : matching_flags) { if (format == HelpFormat::kHumanReadable) { out << package_separator; package_separator = "\n\n"; } file_separator = ""; - for (const auto& flags_in_file : package.second) { + for (auto& flags_in_file : package.second) { if (format == HelpFormat::kHumanReadable) { out << file_separator << " Flags from " << flags_in_file.first << ":\n"; file_separator = "\n"; } + std::sort(std::begin(flags_in_file.second), + std::end(flags_in_file.second), + [](const CommandLineFlag* lhs, const CommandLineFlag* rhs) { + return lhs->Name() < rhs->Name(); + }); + for (const auto* flag : flags_in_file.second) { flags_internal::FlagHelp(out, *flag, format); } @@ -313,27 +300,46 @@ void FlagsHelpImpl(std::ostream& out, flags_internal::FlagKindFilter filter_cb, } if (format == HelpFormat::kHumanReadable) { + FlagHelpPrettyPrinter printer(kHrfMaxLineLength, 0, 0, out); + if (filter_cb && matching_flags.empty()) { - out << " No modules matched: use -helpfull\n"; + printer.Write("No flags matched.\n", true); } + printer.EndLine(); + printer.Write( + "Try --helpfull to get a list of all flags or --help=substring " + "shows help for flags which include specified substring in either " + "in the name, or description or path.\n", + true); } else { // The end of the document. out << "\n"; } } +void FlagsHelpImpl(std::ostream& out, + flags_internal::FlagKindFilter filename_filter_cb, + HelpFormat format, absl::string_view program_usage_message) { + FlagsHelpImpl( + out, + [&](const absl::CommandLineFlag& flag) { + return filename_filter_cb && filename_filter_cb(flag.Filename()); + }, + format, program_usage_message); +} + } // namespace // -------------------------------------------------------------------- // Produces the help message describing specific flag. -void FlagHelp(std::ostream& out, const flags_internal::CommandLineFlag& flag, +void FlagHelp(std::ostream& out, const CommandLineFlag& flag, HelpFormat format) { if (format == HelpFormat::kHumanReadable) - flags_internal::FlagHelpHumanReadable(flag, &out); + flags_internal::FlagHelpHumanReadable(flag, out); } // -------------------------------------------------------------------- -// Produces the help messages for all flags matching the filter. +// Produces the help messages for all flags matching the filename filter. // If filter is empty produces help messages for all flags. void FlagsHelp(std::ostream& out, absl::string_view filter, HelpFormat format, absl::string_view program_usage_message) { @@ -348,68 +354,171 @@ void FlagsHelp(std::ostream& out, absl::string_view filter, HelpFormat format, // If so, handles them appropriately. int HandleUsageFlags(std::ostream& out, absl::string_view program_usage_message) { - if (absl::GetFlag(FLAGS_helpshort)) { - flags_internal::FlagsHelpImpl( - out, flags_internal::GetUsageConfig().contains_helpshort_flags, - HelpFormat::kHumanReadable, program_usage_message); - return 1; - } + switch (GetFlagsHelpMode()) { + case HelpMode::kNone: + break; + case HelpMode::kImportant: + flags_internal::FlagsHelpImpl( + out, flags_internal::GetUsageConfig().contains_help_flags, + GetFlagsHelpFormat(), program_usage_message); + return 1; - if (absl::GetFlag(FLAGS_helpfull)) { - // show all options - flags_internal::FlagsHelp(out, "", HelpFormat::kHumanReadable, - program_usage_message); - return 1; - } + case HelpMode::kShort: + flags_internal::FlagsHelpImpl( + out, flags_internal::GetUsageConfig().contains_helpshort_flags, + GetFlagsHelpFormat(), program_usage_message); + return 1; - if (!absl::GetFlag(FLAGS_helpon).empty()) { - flags_internal::FlagsHelp( - out, absl::StrCat("/", absl::GetFlag(FLAGS_helpon), "."), - HelpFormat::kHumanReadable, program_usage_message); - return 1; - } + case HelpMode::kFull: + flags_internal::FlagsHelp(out, "", GetFlagsHelpFormat(), + program_usage_message); + return 1; - if (!absl::GetFlag(FLAGS_helpmatch).empty()) { - flags_internal::FlagsHelp(out, absl::GetFlag(FLAGS_helpmatch), - HelpFormat::kHumanReadable, - program_usage_message); - return 1; - } + case HelpMode::kPackage: + flags_internal::FlagsHelpImpl( + out, flags_internal::GetUsageConfig().contains_helppackage_flags, + GetFlagsHelpFormat(), program_usage_message); - if (absl::GetFlag(FLAGS_help)) { - flags_internal::FlagsHelpImpl( - out, flags_internal::GetUsageConfig().contains_help_flags, - HelpFormat::kHumanReadable, program_usage_message); + return 1; - out << "\nTry --helpfull to get a list of all flags.\n"; + case HelpMode::kMatch: { + std::string substr = GetFlagsHelpMatchSubstr(); + if (substr.empty()) { + // show all options + flags_internal::FlagsHelp(out, substr, GetFlagsHelpFormat(), + program_usage_message); + } else { + auto filter_cb = [&substr](const absl::CommandLineFlag& flag) { + if (absl::StrContains(flag.Name(), substr)) return true; + if (absl::StrContains(flag.Filename(), substr)) return true; + if (absl::StrContains(flag.Help(), substr)) return true; - return 1; - } + return false; + }; + flags_internal::FlagsHelpImpl( + out, filter_cb, HelpFormat::kHumanReadable, program_usage_message); + } - if (absl::GetFlag(FLAGS_helppackage)) { - flags_internal::FlagsHelpImpl( - out, flags_internal::GetUsageConfig().contains_helppackage_flags, - HelpFormat::kHumanReadable, program_usage_message); + return 1; + } + case HelpMode::kVersion: + if (flags_internal::GetUsageConfig().version_string) + out << flags_internal::GetUsageConfig().version_string(); + // Unlike help, we may be asking for version in a script, so return 0 + return 0; - out << "\nTry --helpfull to get a list of all flags.\n"; - - return 1; - } - - if (absl::GetFlag(FLAGS_version)) { - if (flags_internal::GetUsageConfig().version_string) - out << flags_internal::GetUsageConfig().version_string(); - // Unlike help, we may be asking for version in a script, so return 0 - return 0; - } - - if (absl::GetFlag(FLAGS_only_check_args)) { - return 0; + case HelpMode::kOnlyCheckArgs: + return 0; } return -1; } +// -------------------------------------------------------------------- +// Globals representing usage reporting flags + +namespace { + +ABSL_CONST_INIT absl::Mutex help_attributes_guard(absl::kConstInit); +ABSL_CONST_INIT std::string* match_substr + ABSL_GUARDED_BY(help_attributes_guard) = nullptr; +ABSL_CONST_INIT HelpMode help_mode ABSL_GUARDED_BY(help_attributes_guard) = + HelpMode::kNone; +ABSL_CONST_INIT HelpFormat help_format ABSL_GUARDED_BY(help_attributes_guard) = + HelpFormat::kHumanReadable; + +} // namespace + +std::string GetFlagsHelpMatchSubstr() { + absl::MutexLock l(&help_attributes_guard); + if (match_substr == nullptr) return ""; + return *match_substr; +} + +void SetFlagsHelpMatchSubstr(absl::string_view substr) { + absl::MutexLock l(&help_attributes_guard); + if (match_substr == nullptr) match_substr = new std::string; + match_substr->assign(substr.data(), substr.size()); +} + +HelpMode GetFlagsHelpMode() { + absl::MutexLock l(&help_attributes_guard); + return help_mode; +} + +void SetFlagsHelpMode(HelpMode mode) { + absl::MutexLock l(&help_attributes_guard); + help_mode = mode; +} + +HelpFormat GetFlagsHelpFormat() { + absl::MutexLock l(&help_attributes_guard); + return help_format; +} + +void SetFlagsHelpFormat(HelpFormat format) { + absl::MutexLock l(&help_attributes_guard); + help_format = format; +} + +// Deduces usage flags from the input argument in a form --name=value or +// --name. argument is already split into name and value before we call this +// function. +bool DeduceUsageFlags(absl::string_view name, absl::string_view value) { + if (absl::ConsumePrefix(&name, "help")) { + if (name == "") { + if (value.empty()) { + SetFlagsHelpMode(HelpMode::kImportant); + } else { + SetFlagsHelpMode(HelpMode::kMatch); + SetFlagsHelpMatchSubstr(value); + } + return true; + } + + if (name == "match") { + SetFlagsHelpMode(HelpMode::kMatch); + SetFlagsHelpMatchSubstr(value); + return true; + } + + if (name == "on") { + SetFlagsHelpMode(HelpMode::kMatch); + SetFlagsHelpMatchSubstr(absl::StrCat("/", value, ".")); + return true; + } + + if (name == "full") { + SetFlagsHelpMode(HelpMode::kFull); + return true; + } + + if (name == "short") { + SetFlagsHelpMode(HelpMode::kShort); + return true; + } + + if (name == "package") { + SetFlagsHelpMode(HelpMode::kPackage); + return true; + } + + return false; + } + + if (name == "version") { + SetFlagsHelpMode(HelpMode::kVersion); + return true; + } + + if (name == "only_check_args") { + SetFlagsHelpMode(HelpMode::kOnlyCheckArgs); + return true; + } + + return false; +} + } // namespace flags_internal ABSL_NAMESPACE_END } // namespace absl diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/internal/usage.h b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/internal/usage.h index 6b080fd1ee..c0bcac5762 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/internal/usage.h +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/internal/usage.h @@ -20,8 +20,8 @@ #include #include "absl/base/config.h" +#include "absl/flags/commandlineflag.h" #include "absl/flags/declare.h" -#include "absl/flags/internal/commandlineflag.h" #include "absl/strings/string_view.h" // -------------------------------------------------------------------- @@ -36,8 +36,9 @@ enum class HelpFormat { kHumanReadable, }; -// Outputs the help message describing specific flag. -void FlagHelp(std::ostream& out, const flags_internal::CommandLineFlag& flag, +// Streams the help message describing `flag` to `out`. +// The default value for `flag` is included in the output. +void FlagHelp(std::ostream& out, const CommandLineFlag& flag, HelpFormat format = HelpFormat::kHumanReadable); // Produces the help messages for all flags matching the filter. A flag matches @@ -65,17 +66,39 @@ void FlagsHelp(std::ostream& out, absl::string_view filter, int HandleUsageFlags(std::ostream& out, absl::string_view program_usage_message); +// -------------------------------------------------------------------- +// Globals representing usage reporting flags + +enum class HelpMode { + kNone, + kImportant, + kShort, + kFull, + kPackage, + kMatch, + kVersion, + kOnlyCheckArgs +}; + +// Returns substring to filter help output (--help=substr argument) +std::string GetFlagsHelpMatchSubstr(); +// Returns the requested help mode. +HelpMode GetFlagsHelpMode(); +// Returns the requested help format. +HelpFormat GetFlagsHelpFormat(); + +// These are corresponding setters to the attributes above. +void SetFlagsHelpMatchSubstr(absl::string_view); +void SetFlagsHelpMode(HelpMode); +void SetFlagsHelpFormat(HelpFormat); + +// Deduces usage flags from the input argument in a form --name=value or +// --name. argument is already split into name and value before we call this +// function. +bool DeduceUsageFlags(absl::string_view name, absl::string_view value); + } // namespace flags_internal ABSL_NAMESPACE_END } // namespace absl -ABSL_DECLARE_FLAG(bool, help); -ABSL_DECLARE_FLAG(bool, helpfull); -ABSL_DECLARE_FLAG(bool, helpshort); -ABSL_DECLARE_FLAG(bool, helppackage); -ABSL_DECLARE_FLAG(bool, version); -ABSL_DECLARE_FLAG(bool, only_check_args); -ABSL_DECLARE_FLAG(std::string, helpon); -ABSL_DECLARE_FLAG(std::string, helpmatch); - #endif // ABSL_FLAGS_INTERNAL_USAGE_H_ diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/internal/usage_test.cc b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/internal/usage_test.cc index e1e57e5570..044d71c87d 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/internal/usage_test.cc +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/internal/usage_test.cc @@ -21,15 +21,13 @@ #include #include "gtest/gtest.h" -#include "absl/flags/declare.h" #include "absl/flags/flag.h" #include "absl/flags/internal/parse.h" #include "absl/flags/internal/path_util.h" #include "absl/flags/internal/program_name.h" -#include "absl/flags/internal/registry.h" +#include "absl/flags/reflection.h" #include "absl/flags/usage.h" #include "absl/flags/usage_config.h" -#include "absl/memory/memory.h" #include "absl/strings/match.h" #include "absl/strings/string_view.h" @@ -47,6 +45,7 @@ static const char kTestUsageMessage[] = "Custom usage message"; struct UDT { UDT() = default; UDT(const UDT&) = default; + UDT& operator=(const UDT&) = default; }; bool AbslParseFlag(absl::string_view, UDT*, std::string*) { return true; } std::string AbslUnparseFlag(const UDT&) { return "UDT{}"; } @@ -89,9 +88,14 @@ class UsageReportingTest : public testing::Test { default_config.normalize_filename = &NormalizeFileName; absl::SetFlagsUsageConfig(default_config); } + ~UsageReportingTest() override { + flags::SetFlagsHelpMode(flags::HelpMode::kNone); + flags::SetFlagsHelpMatchSubstr(""); + flags::SetFlagsHelpFormat(flags::HelpFormat::kHumanReadable); + } private: - flags::FlagSaver flag_saver_; + absl::FlagSaver flag_saver_; }; // -------------------------------------------------------------------- @@ -103,15 +107,16 @@ TEST_F(UsageReportingDeathTest, TestSetProgramUsageMessage) { #ifndef _WIN32 // TODO(rogeeff): figure out why this does not work on Windows. - EXPECT_DEATH(absl::SetProgramUsageMessage("custom usage message"), - ".*SetProgramUsageMessage\\(\\) called twice.*"); + EXPECT_DEATH_IF_SUPPORTED( + absl::SetProgramUsageMessage("custom usage message"), + ".*SetProgramUsageMessage\\(\\) called twice.*"); #endif } // -------------------------------------------------------------------- TEST_F(UsageReportingTest, TestFlagHelpHRF_on_flag_01) { - const auto* flag = flags::FindCommandLineFlag("usage_reporting_test_flag_01"); + const auto* flag = absl::FindCommandLineFlag("usage_reporting_test_flag_01"); std::stringstream test_buf; flags::FlagHelp(test_buf, *flag, flags::HelpFormat::kHumanReadable); @@ -123,7 +128,7 @@ TEST_F(UsageReportingTest, TestFlagHelpHRF_on_flag_01) { } TEST_F(UsageReportingTest, TestFlagHelpHRF_on_flag_02) { - const auto* flag = flags::FindCommandLineFlag("usage_reporting_test_flag_02"); + const auto* flag = absl::FindCommandLineFlag("usage_reporting_test_flag_02"); std::stringstream test_buf; flags::FlagHelp(test_buf, *flag, flags::HelpFormat::kHumanReadable); @@ -135,7 +140,7 @@ TEST_F(UsageReportingTest, TestFlagHelpHRF_on_flag_02) { } TEST_F(UsageReportingTest, TestFlagHelpHRF_on_flag_03) { - const auto* flag = flags::FindCommandLineFlag("usage_reporting_test_flag_03"); + const auto* flag = absl::FindCommandLineFlag("usage_reporting_test_flag_03"); std::stringstream test_buf; flags::FlagHelp(test_buf, *flag, flags::HelpFormat::kHumanReadable); @@ -147,7 +152,7 @@ TEST_F(UsageReportingTest, TestFlagHelpHRF_on_flag_03) { } TEST_F(UsageReportingTest, TestFlagHelpHRF_on_flag_04) { - const auto* flag = flags::FindCommandLineFlag("usage_reporting_test_flag_04"); + const auto* flag = absl::FindCommandLineFlag("usage_reporting_test_flag_04"); std::stringstream test_buf; flags::FlagHelp(test_buf, *flag, flags::HelpFormat::kHumanReadable); @@ -159,7 +164,7 @@ TEST_F(UsageReportingTest, TestFlagHelpHRF_on_flag_04) { } TEST_F(UsageReportingTest, TestFlagHelpHRF_on_flag_05) { - const auto* flag = flags::FindCommandLineFlag("usage_reporting_test_flag_05"); + const auto* flag = absl::FindCommandLineFlag("usage_reporting_test_flag_05"); std::stringstream test_buf; flags::FlagHelp(test_buf, *flag, flags::HelpFormat::kHumanReadable); @@ -192,6 +197,10 @@ TEST_F(UsageReportingTest, TestFlagsHelpHRF) { Some more help. Even more long long long long long long long long long long long long help message.); default: ""; + +Try --helpfull to get a list of all flags or --help=substring shows help for +flags which include specified substring in either in the name, or description or +path. )"; std::stringstream test_buf_01; @@ -215,7 +224,11 @@ TEST_F(UsageReportingTest, TestFlagsHelpHRF) { EXPECT_EQ(test_buf_04.str(), R"(usage_test: Custom usage message - No modules matched: use -helpfull +No flags matched. + +Try --helpfull to get a list of all flags or --help=substring shows help for +flags which include specified substring in either in the name, or description or +path. )"); std::stringstream test_buf_05; @@ -227,12 +240,8 @@ TEST_F(UsageReportingTest, TestFlagsHelpHRF) { absl::StartsWith(test_out_str, "usage_test: Custom usage message")); EXPECT_TRUE(absl::StrContains( test_out_str, "Flags from absl/flags/internal/usage_test.cc:")); - EXPECT_TRUE(absl::StrContains(test_out_str, - "Flags from absl/flags/internal/usage.cc:")); EXPECT_TRUE( absl::StrContains(test_out_str, "-usage_reporting_test_flag_01 ")); - EXPECT_TRUE(absl::StrContains(test_out_str, "-help (show help")) - << test_out_str; } // -------------------------------------------------------------------- @@ -245,7 +254,7 @@ TEST_F(UsageReportingTest, TestNoUsageFlags) { // -------------------------------------------------------------------- TEST_F(UsageReportingTest, TestUsageFlag_helpshort) { - absl::SetFlag(&FLAGS_helpshort, true); + flags::SetFlagsHelpMode(flags::HelpMode::kShort); std::stringstream test_buf; EXPECT_EQ(flags::HandleUsageFlags(test_buf, kTestUsageMessage), 1); @@ -268,13 +277,17 @@ TEST_F(UsageReportingTest, TestUsageFlag_helpshort) { Some more help. Even more long long long long long long long long long long long long help message.); default: ""; + +Try --helpfull to get a list of all flags or --help=substring shows help for +flags which include specified substring in either in the name, or description or +path. )"); } // -------------------------------------------------------------------- -TEST_F(UsageReportingTest, TestUsageFlag_help) { - absl::SetFlag(&FLAGS_help, true); +TEST_F(UsageReportingTest, TestUsageFlag_help_simple) { + flags::SetFlagsHelpMode(flags::HelpMode::kImportant); std::stringstream test_buf; EXPECT_EQ(flags::HandleUsageFlags(test_buf, kTestUsageMessage), 1); @@ -298,14 +311,74 @@ TEST_F(UsageReportingTest, TestUsageFlag_help) { Even more long long long long long long long long long long long long help message.); default: ""; -Try --helpfull to get a list of all flags. +Try --helpfull to get a list of all flags or --help=substring shows help for +flags which include specified substring in either in the name, or description or +path. +)"); +} + +// -------------------------------------------------------------------- + +TEST_F(UsageReportingTest, TestUsageFlag_help_one_flag) { + flags::SetFlagsHelpMode(flags::HelpMode::kMatch); + flags::SetFlagsHelpMatchSubstr("usage_reporting_test_flag_06"); + + std::stringstream test_buf; + EXPECT_EQ(flags::HandleUsageFlags(test_buf, kTestUsageMessage), 1); + EXPECT_EQ(test_buf.str(), + R"(usage_test: Custom usage message + + Flags from absl/flags/internal/usage_test.cc: + --usage_reporting_test_flag_06 (usage_reporting_test_flag_06 help message. + + Some more help. + Even more long long long long long long long long long long long long help + message.); default: ""; + +Try --helpfull to get a list of all flags or --help=substring shows help for +flags which include specified substring in either in the name, or description or +path. +)"); +} + +// -------------------------------------------------------------------- + +TEST_F(UsageReportingTest, TestUsageFlag_help_multiple_flag) { + flags::SetFlagsHelpMode(flags::HelpMode::kMatch); + flags::SetFlagsHelpMatchSubstr("test_flag"); + + std::stringstream test_buf; + EXPECT_EQ(flags::HandleUsageFlags(test_buf, kTestUsageMessage), 1); + EXPECT_EQ(test_buf.str(), + R"(usage_test: Custom usage message + + Flags from absl/flags/internal/usage_test.cc: + --usage_reporting_test_flag_01 (usage_reporting_test_flag_01 help message); + default: 101; + --usage_reporting_test_flag_02 (usage_reporting_test_flag_02 help message); + default: false; + --usage_reporting_test_flag_03 (usage_reporting_test_flag_03 help message); + default: 1.03; + --usage_reporting_test_flag_04 (usage_reporting_test_flag_04 help message); + default: 1000000000000004; + --usage_reporting_test_flag_05 (usage_reporting_test_flag_05 help message); + default: UDT{}; + --usage_reporting_test_flag_06 (usage_reporting_test_flag_06 help message. + + Some more help. + Even more long long long long long long long long long long long long help + message.); default: ""; + +Try --helpfull to get a list of all flags or --help=substring shows help for +flags which include specified substring in either in the name, or description or +path. )"); } // -------------------------------------------------------------------- TEST_F(UsageReportingTest, TestUsageFlag_helppackage) { - absl::SetFlag(&FLAGS_helppackage, true); + flags::SetFlagsHelpMode(flags::HelpMode::kPackage); std::stringstream test_buf; EXPECT_EQ(flags::HandleUsageFlags(test_buf, kTestUsageMessage), 1); @@ -329,14 +402,16 @@ TEST_F(UsageReportingTest, TestUsageFlag_helppackage) { Even more long long long long long long long long long long long long help message.); default: ""; -Try --helpfull to get a list of all flags. +Try --helpfull to get a list of all flags or --help=substring shows help for +flags which include specified substring in either in the name, or description or +path. )"); } // -------------------------------------------------------------------- TEST_F(UsageReportingTest, TestUsageFlag_version) { - absl::SetFlag(&FLAGS_version, true); + flags::SetFlagsHelpMode(flags::HelpMode::kVersion); std::stringstream test_buf; EXPECT_EQ(flags::HandleUsageFlags(test_buf, kTestUsageMessage), 0); @@ -350,7 +425,7 @@ TEST_F(UsageReportingTest, TestUsageFlag_version) { // -------------------------------------------------------------------- TEST_F(UsageReportingTest, TestUsageFlag_only_check_args) { - absl::SetFlag(&FLAGS_only_check_args, true); + flags::SetFlagsHelpMode(flags::HelpMode::kOnlyCheckArgs); std::stringstream test_buf; EXPECT_EQ(flags::HandleUsageFlags(test_buf, kTestUsageMessage), 0); @@ -360,17 +435,22 @@ TEST_F(UsageReportingTest, TestUsageFlag_only_check_args) { // -------------------------------------------------------------------- TEST_F(UsageReportingTest, TestUsageFlag_helpon) { - absl::SetFlag(&FLAGS_helpon, "bla-bla"); + flags::SetFlagsHelpMode(flags::HelpMode::kMatch); + flags::SetFlagsHelpMatchSubstr("/bla-bla."); std::stringstream test_buf_01; EXPECT_EQ(flags::HandleUsageFlags(test_buf_01, kTestUsageMessage), 1); EXPECT_EQ(test_buf_01.str(), R"(usage_test: Custom usage message - No modules matched: use -helpfull +No flags matched. + +Try --helpfull to get a list of all flags or --help=substring shows help for +flags which include specified substring in either in the name, or description or +path. )"); - absl::SetFlag(&FLAGS_helpon, "usage_test"); + flags::SetFlagsHelpMatchSubstr("/usage_test."); std::stringstream test_buf_02; EXPECT_EQ(flags::HandleUsageFlags(test_buf_02, kTestUsageMessage), 1); @@ -393,6 +473,10 @@ TEST_F(UsageReportingTest, TestUsageFlag_helpon) { Some more help. Even more long long long long long long long long long long long long help message.); default: ""; + +Try --helpfull to get a list of all flags or --help=substring shows help for +flags which include specified substring in either in the name, or description or +path. )"); } diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/marshalling.cc b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/marshalling.cc index 09baae88cd..81f9cebd6f 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/marshalling.cc +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/marshalling.cc @@ -74,15 +74,16 @@ static int NumericBase(absl::string_view text) { } template -inline bool ParseFlagImpl(absl::string_view text, IntType* dst) { +inline bool ParseFlagImpl(absl::string_view text, IntType& dst) { text = absl::StripAsciiWhitespace(text); - return absl::numbers_internal::safe_strtoi_base(text, dst, NumericBase(text)); + return absl::numbers_internal::safe_strtoi_base(text, &dst, + NumericBase(text)); } bool AbslParseFlag(absl::string_view text, short* dst, std::string*) { int val; - if (!ParseFlagImpl(text, &val)) return false; + if (!ParseFlagImpl(text, val)) return false; if (static_cast(val) != val) // worked, but number out of range return false; *dst = static_cast(val); @@ -91,7 +92,7 @@ bool AbslParseFlag(absl::string_view text, short* dst, std::string*) { bool AbslParseFlag(absl::string_view text, unsigned short* dst, std::string*) { unsigned int val; - if (!ParseFlagImpl(text, &val)) return false; + if (!ParseFlagImpl(text, val)) return false; if (static_cast(val) != val) // worked, but number out of range return false; @@ -100,28 +101,28 @@ bool AbslParseFlag(absl::string_view text, unsigned short* dst, std::string*) { } bool AbslParseFlag(absl::string_view text, int* dst, std::string*) { - return ParseFlagImpl(text, dst); + return ParseFlagImpl(text, *dst); } bool AbslParseFlag(absl::string_view text, unsigned int* dst, std::string*) { - return ParseFlagImpl(text, dst); + return ParseFlagImpl(text, *dst); } bool AbslParseFlag(absl::string_view text, long* dst, std::string*) { - return ParseFlagImpl(text, dst); + return ParseFlagImpl(text, *dst); } bool AbslParseFlag(absl::string_view text, unsigned long* dst, std::string*) { - return ParseFlagImpl(text, dst); + return ParseFlagImpl(text, *dst); } bool AbslParseFlag(absl::string_view text, long long* dst, std::string*) { - return ParseFlagImpl(text, dst); + return ParseFlagImpl(text, *dst); } bool AbslParseFlag(absl::string_view text, unsigned long long* dst, std::string*) { - return ParseFlagImpl(text, dst); + return ParseFlagImpl(text, *dst); } // -------------------------------------------------------------------- diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/marshalling.h b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/marshalling.h index 0b5033547e..7cbc136d57 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/marshalling.h +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/marshalling.h @@ -83,7 +83,7 @@ // // AbslParseFlag converts from a string to OutputMode. // // Must be in same namespace as OutputMode. // -// // Parses an OutputMode from the command line flag value `text. Returns +// // Parses an OutputMode from the command line flag value `text`. Returns // // `true` and sets `*mode` on success; returns `false` and sets `*error` // // on failure. // bool AbslParseFlag(absl::string_view text, @@ -139,7 +139,7 @@ // // // Within the implementation, `AbslParseFlag()` will, in turn invoke // // `absl::ParseFlag()` on its constituent `int` and `std::string` types -// // (which have built-in Abseil flag support. +// // (which have built-in Abseil flag support). // // bool AbslParseFlag(absl::string_view text, MyFlagType* flag, // std::string* err) { diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/parse.cc b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/parse.cc index b60b36f608..dd1a6796ca 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/parse.cc +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/parse.cc @@ -34,14 +34,16 @@ #include "absl/base/config.h" #include "absl/base/const_init.h" #include "absl/base/thread_annotations.h" +#include "absl/flags/commandlineflag.h" #include "absl/flags/config.h" #include "absl/flags/flag.h" #include "absl/flags/internal/commandlineflag.h" #include "absl/flags/internal/flag.h" #include "absl/flags/internal/parse.h" +#include "absl/flags/internal/private_handle_accessor.h" #include "absl/flags/internal/program_name.h" -#include "absl/flags/internal/registry.h" #include "absl/flags/internal/usage.h" +#include "absl/flags/reflection.h" #include "absl/flags/usage.h" #include "absl/flags/usage_config.h" #include "absl/strings/ascii.h" @@ -66,6 +68,22 @@ ABSL_CONST_INIT bool fromenv_needs_processing ABSL_CONST_INIT bool tryfromenv_needs_processing ABSL_GUARDED_BY(processing_checks_guard) = false; +ABSL_CONST_INIT absl::Mutex specified_flags_guard(absl::kConstInit); +ABSL_CONST_INIT std::vector* specified_flags + ABSL_GUARDED_BY(specified_flags_guard) = nullptr; + +struct SpecifiedFlagsCompare { + bool operator()(const CommandLineFlag* a, const CommandLineFlag* b) const { + return a->Name() < b->Name(); + } + bool operator()(const CommandLineFlag* a, absl::string_view b) const { + return a->Name() < b; + } + bool operator()(absl::string_view a, const CommandLineFlag* b) const { + return a < b->Name(); + } +}; + } // namespace } // namespace flags_internal ABSL_NAMESPACE_END @@ -205,7 +223,7 @@ bool ArgsList::ReadFromFlagfile(const std::string& flag_file_name) { // Reads the environment variable with name `name` and stores results in // `value`. If variable is not present in environment returns false, otherwise // returns true. -bool GetEnvVar(const char* var_name, std::string* var_value) { +bool GetEnvVar(const char* var_name, std::string& var_value) { #ifdef _WIN32 char buf[1024]; auto get_res = GetEnvironmentVariableA(var_name, buf, sizeof(buf)); @@ -217,14 +235,14 @@ bool GetEnvVar(const char* var_name, std::string* var_value) { return false; } - *var_value = std::string(buf, get_res); + var_value = std::string(buf, get_res); #else const char* val = ::getenv(var_name); if (val == nullptr) { return false; } - *var_value = val; + var_value = val; #endif return true; @@ -272,11 +290,11 @@ std::tuple SplitNameAndValue( // found flag or nullptr // is negative in case of --nofoo std::tuple LocateFlag(absl::string_view flag_name) { - CommandLineFlag* flag = flags_internal::FindCommandLineFlag(flag_name); + CommandLineFlag* flag = absl::FindCommandLineFlag(flag_name); bool is_negative = false; if (!flag && absl::ConsumePrefix(&flag_name, "no")) { - flag = flags_internal::FindCommandLineFlag(flag_name); + flag = absl::FindCommandLineFlag(flag_name); is_negative = true; } @@ -289,16 +307,17 @@ std::tuple LocateFlag(absl::string_view flag_name) { // back. void CheckDefaultValuesParsingRoundtrip() { #ifndef NDEBUG - flags_internal::ForEachFlag([&](CommandLineFlag* flag) { - if (flag->IsRetired()) return; + flags_internal::ForEachFlag([&](CommandLineFlag& flag) { + if (flag.IsRetired()) return; -#define IGNORE_TYPE(T) \ - if (flag->IsOfType()) return; +#define ABSL_FLAGS_INTERNAL_IGNORE_TYPE(T, _) \ + if (flag.IsOfType()) return; - ABSL_FLAGS_INTERNAL_BUILTIN_TYPES(IGNORE_TYPE) -#undef IGNORE_TYPE + ABSL_FLAGS_INTERNAL_SUPPORTED_TYPES(ABSL_FLAGS_INTERNAL_IGNORE_TYPE) +#undef ABSL_FLAGS_INTERNAL_IGNORE_TYPE - flag->CheckDefaultValueParsingRoundtrip(); + flags_internal::PrivateHandleAccessor::CheckDefaultValueParsingRoundtrip( + flag); }); #endif } @@ -311,13 +330,13 @@ void CheckDefaultValuesParsingRoundtrip() { // the first flagfile in the input list are processed before the second flagfile // etc. bool ReadFlagfiles(const std::vector& flagfiles, - std::vector* input_args) { + std::vector& input_args) { bool success = true; for (auto it = flagfiles.rbegin(); it != flagfiles.rend(); ++it) { ArgsList al; if (al.ReadFromFlagfile(*it)) { - input_args->push_back(al); + input_args.push_back(al); } else { success = false; } @@ -332,7 +351,7 @@ bool ReadFlagfiles(const std::vector& flagfiles, // `flag_name` is a string from the input flag_names list. If successful we // append a single ArgList at the end of the input_args. bool ReadFlagsFromEnv(const std::vector& flag_names, - std::vector* input_args, + std::vector& input_args, bool fail_on_absent_in_env) { bool success = true; std::vector args; @@ -353,7 +372,7 @@ bool ReadFlagsFromEnv(const std::vector& flag_names, const std::string envname = absl::StrCat("FLAGS_", flag_name); std::string envval; - if (!GetEnvVar(envname.c_str(), &envval)) { + if (!GetEnvVar(envname.c_str(), envval)) { if (fail_on_absent_in_env) { flags_internal::ReportUsageError( absl::StrCat(envname, " not found in environment"), true); @@ -368,7 +387,7 @@ bool ReadFlagsFromEnv(const std::vector& flag_names, } if (success) { - input_args->emplace_back(args); + input_args.emplace_back(args); } return success; @@ -378,8 +397,8 @@ bool ReadFlagsFromEnv(const std::vector& flag_names, // Returns success status, which is true if were able to handle all generator // flags (flagfile, fromenv, tryfromemv) successfully. -bool HandleGeneratorFlags(std::vector* input_args, - std::vector* flagfile_value) { +bool HandleGeneratorFlags(std::vector& input_args, + std::vector& flagfile_value) { bool success = true; absl::MutexLock l(&flags_internal::processing_checks_guard); @@ -404,9 +423,9 @@ bool HandleGeneratorFlags(std::vector* input_args, if (flags_internal::flagfile_needs_processing) { auto flagfiles = absl::GetFlag(FLAGS_flagfile); - if (input_args->size() == 1) { - flagfile_value->insert(flagfile_value->end(), flagfiles.begin(), - flagfiles.end()); + if (input_args.size() == 1) { + flagfile_value.insert(flagfile_value.end(), flagfiles.begin(), + flagfiles.end()); } success &= ReadFlagfiles(flagfiles, input_args); @@ -575,12 +594,28 @@ bool CanIgnoreUndefinedFlag(absl::string_view flag_name) { // -------------------------------------------------------------------- +bool WasPresentOnCommandLine(absl::string_view flag_name) { + absl::MutexLock l(&specified_flags_guard); + ABSL_INTERNAL_CHECK(specified_flags != nullptr, + "ParseCommandLine is not invoked yet"); + + return std::binary_search(specified_flags->begin(), specified_flags->end(), + flag_name, SpecifiedFlagsCompare{}); +} + +// -------------------------------------------------------------------- + std::vector ParseCommandLineImpl(int argc, char* argv[], ArgvListAction arg_list_act, UsageFlagsAction usage_flag_act, OnUndefinedFlag on_undef_flag) { ABSL_INTERNAL_CHECK(argc > 0, "Missing argv[0]"); + // Once parsing has started we will not have more flag registrations. + // If we did, they would be missing during parsing, which is a problem on + // itself. + flags_internal::FinalizeRegistry(); + // This routine does not return anything since we abort on failure. CheckDefaultValuesParsingRoundtrip(); @@ -605,13 +640,20 @@ std::vector ParseCommandLineImpl(int argc, char* argv[], } output_args.push_back(argv[0]); + absl::MutexLock l(&specified_flags_guard); + if (specified_flags == nullptr) { + specified_flags = new std::vector; + } else { + specified_flags->clear(); + } + // Iterate through the list of the input arguments. First level are arguments // originated from argc/argv. Following levels are arguments originated from // recursive parsing of flagfile(s). bool success = true; while (!input_args.empty()) { // 10. First we process the built-in generator flags. - success &= HandleGeneratorFlags(&input_args, &flagfile_value); + success &= HandleGeneratorFlags(input_args, flagfile_value); // 30. Select top-most (most recent) arguments list. If it is empty drop it // and re-try. @@ -671,6 +713,11 @@ std::vector ParseCommandLineImpl(int argc, char* argv[], std::tie(flag, is_negative) = LocateFlag(flag_name); if (flag == nullptr) { + // Usage flags are not modeled as Abseil flags. Locate them separately. + if (flags_internal::DeduceUsageFlags(flag_name, value)) { + continue; + } + if (on_undef_flag != OnUndefinedFlag::kIgnoreUndefined) { undefined_flag_names.emplace_back(arg_from_argv, std::string(flag_name)); @@ -692,13 +739,17 @@ std::vector ParseCommandLineImpl(int argc, char* argv[], } // 100. Set the located flag to a new new value, unless it is retired. - // Setting retired flag fails, but we ignoring it here. - if (flag->IsRetired()) continue; - + // Setting retired flag fails, but we ignoring it here while also reporting + // access to retired flag. std::string error; - if (!flag->ParseFrom(value, SET_FLAGS_VALUE, kCommandLine, &error)) { + if (!flags_internal::PrivateHandleAccessor::ParseFrom( + *flag, value, SET_FLAGS_VALUE, kCommandLine, error)) { + if (flag->IsRetired()) continue; + flags_internal::ReportUsageError(error, true); success = false; + } else { + specified_flags->push_back(flag); } } @@ -750,6 +801,10 @@ std::vector ParseCommandLineImpl(int argc, char* argv[], } } + // Trim and sort the vector. + specified_flags->shrink_to_fit(); + std::sort(specified_flags->begin(), specified_flags->end(), + SpecifiedFlagsCompare{}); return output_args; } diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/parse.h b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/parse.h index f37b0602e6..929de2cb40 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/parse.h +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/parse.h @@ -23,7 +23,6 @@ #ifndef ABSL_FLAGS_PARSE_H_ #define ABSL_FLAGS_PARSE_H_ -#include #include #include "absl/base/config.h" diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/parse_test.cc b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/parse_test.cc index 6f49377a93..8dc91db2b3 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/parse_test.cc +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/parse_test.cc @@ -28,7 +28,8 @@ #include "absl/flags/declare.h" #include "absl/flags/flag.h" #include "absl/flags/internal/parse.h" -#include "absl/flags/internal/registry.h" +#include "absl/flags/internal/usage.h" +#include "absl/flags/reflection.h" #include "absl/strings/str_cat.h" #include "absl/strings/string_view.h" #include "absl/strings/substitute.h" @@ -45,6 +46,7 @@ using absl::base_internal::ScopedSetEnv; struct UDT { UDT() = default; UDT(const UDT&) = default; + UDT& operator=(const UDT&) = default; UDT(int v) : value(v) {} // NOLINT int value; @@ -171,8 +173,8 @@ constexpr const char* const ff2_data[] = { // temporary directory location. This way we can test inclusion of one flagfile // from another flagfile. const char* GetFlagfileFlag(const std::vector& ffd, - std::string* flagfile_flag) { - *flagfile_flag = "--flagfile="; + std::string& flagfile_flag) { + flagfile_flag = "--flagfile="; absl::string_view separator; for (const auto& flagfile_data : ffd) { std::string flagfile_name = @@ -183,11 +185,11 @@ const char* GetFlagfileFlag(const std::vector& ffd, flagfile_out << absl::Substitute(line, GetTestTempDir()) << "\n"; } - absl::StrAppend(flagfile_flag, separator, flagfile_name); + absl::StrAppend(&flagfile_flag, separator, flagfile_name); separator = ","; } - return flagfile_flag->c_str(); + return flagfile_flag.c_str(); } } // namespace @@ -207,8 +209,11 @@ namespace flags = absl::flags_internal; using testing::ElementsAreArray; class ParseTest : public testing::Test { + public: + ~ParseTest() override { flags::SetFlagsHelpMode(flags::HelpMode::kNone); } + private: - flags::FlagSaver flag_saver_; + absl::FlagSaver flag_saver_; }; // -------------------------------------------------------------------- @@ -481,21 +486,22 @@ TEST_F(ParseDeathTest, TestUndefinedArg) { "testbin", "--undefined_flag", }; - EXPECT_DEATH(InvokeParse(in_args1), - "Unknown command line flag 'undefined_flag'"); + EXPECT_DEATH_IF_SUPPORTED(InvokeParse(in_args1), + "Unknown command line flag 'undefined_flag'"); const char* in_args2[] = { "testbin", "--noprefixed_flag", }; - EXPECT_DEATH(InvokeParse(in_args2), - "Unknown command line flag 'noprefixed_flag'"); + EXPECT_DEATH_IF_SUPPORTED(InvokeParse(in_args2), + "Unknown command line flag 'noprefixed_flag'"); const char* in_args3[] = { "testbin", "--Int_flag=1", }; - EXPECT_DEATH(InvokeParse(in_args3), "Unknown command line flag 'Int_flag'"); + EXPECT_DEATH_IF_SUPPORTED(InvokeParse(in_args3), + "Unknown command line flag 'Int_flag'"); } // -------------------------------------------------------------------- @@ -505,7 +511,7 @@ TEST_F(ParseDeathTest, TestInvalidBoolFlagFormat) { "testbin", "--bool_flag=", }; - EXPECT_DEATH( + EXPECT_DEATH_IF_SUPPORTED( InvokeParse(in_args1), "Missing the value after assignment for the boolean flag 'bool_flag'"); @@ -513,7 +519,7 @@ TEST_F(ParseDeathTest, TestInvalidBoolFlagFormat) { "testbin", "--nobool_flag=true", }; - EXPECT_DEATH(InvokeParse(in_args2), + EXPECT_DEATH_IF_SUPPORTED(InvokeParse(in_args2), "Negative form with assignment is not valid for the boolean " "flag 'bool_flag'"); } @@ -525,14 +531,14 @@ TEST_F(ParseDeathTest, TestInvalidNonBoolFlagFormat) { "testbin", "--nostring_flag", }; - EXPECT_DEATH(InvokeParse(in_args1), + EXPECT_DEATH_IF_SUPPORTED(InvokeParse(in_args1), "Negative form is not valid for the flag 'string_flag'"); const char* in_args2[] = { "testbin", "--int_flag", }; - EXPECT_DEATH(InvokeParse(in_args2), + EXPECT_DEATH_IF_SUPPORTED(InvokeParse(in_args2), "Missing the value for the flag 'int_flag'"); } @@ -543,7 +549,7 @@ TEST_F(ParseDeathTest, TestInvalidUDTFlagFormat) { "testbin", "--udt_flag=1", }; - EXPECT_DEATH(InvokeParse(in_args1), + EXPECT_DEATH_IF_SUPPORTED(InvokeParse(in_args1), "Illegal value '1' specified for flag 'udt_flag'; Use values A, " "AAA instead"); @@ -552,7 +558,7 @@ TEST_F(ParseDeathTest, TestInvalidUDTFlagFormat) { "--udt_flag", "AA", }; - EXPECT_DEATH(InvokeParse(in_args2), + EXPECT_DEATH_IF_SUPPORTED(InvokeParse(in_args2), "Illegal value 'AA' specified for flag 'udt_flag'; Use values " "A, AAA instead"); } @@ -587,14 +593,14 @@ TEST_F(ParseTest, TestSimpleValidFlagfile) { const char* in_args1[] = { "testbin", GetFlagfileFlag({{"parse_test.ff1", absl::MakeConstSpan(ff1_data)}}, - &flagfile_flag), + flagfile_flag), }; TestParse(in_args1, -1, 0.1, "q2w2 ", true); const char* in_args2[] = { "testbin", GetFlagfileFlag({{"parse_test.ff2", absl::MakeConstSpan(ff2_data)}}, - &flagfile_flag), + flagfile_flag), }; TestParse(in_args2, 100, 0.1, "q2w2 ", false); } @@ -608,7 +614,7 @@ TEST_F(ParseTest, TestValidMultiFlagfile) { "testbin", GetFlagfileFlag({{"parse_test.ff2", absl::MakeConstSpan(ff2_data)}, {"parse_test.ff1", absl::MakeConstSpan(ff1_data)}}, - &flagfile_flag), + flagfile_flag), }; TestParse(in_args1, -1, 0.1, "q2w2 ", true); } @@ -621,7 +627,7 @@ TEST_F(ParseTest, TestFlagfileMixedWithRegularFlags) { const char* in_args1[] = { "testbin", "--int_flag=3", GetFlagfileFlag({{"parse_test.ff1", absl::MakeConstSpan(ff1_data)}}, - &flagfile_flag), + flagfile_flag), "-double_flag=0.2"}; TestParse(in_args1, -1, 0.2, "q2w2 ", true); } @@ -636,10 +642,14 @@ TEST_F(ParseTest, TestFlagfileInFlagfile) { "--flagfile=$0/parse_test.ff2", }; + GetFlagfileFlag({{"parse_test.ff2", absl::MakeConstSpan(ff2_data)}, + {"parse_test.ff1", absl::MakeConstSpan(ff1_data)}}, + flagfile_flag); + const char* in_args1[] = { "testbin", GetFlagfileFlag({{"parse_test.ff3", absl::MakeConstSpan(ff3_data)}}, - &flagfile_flag), + flagfile_flag), }; TestParse(in_args1, 100, 0.1, "q2w2 ", false); } @@ -656,9 +666,9 @@ TEST_F(ParseDeathTest, TestInvalidFlagfiles) { const char* in_args1[] = { "testbin", GetFlagfileFlag({{"parse_test.ff4", - absl::MakeConstSpan(ff4_data)}}, &flagfile_flag), + absl::MakeConstSpan(ff4_data)}}, flagfile_flag), }; - EXPECT_DEATH(InvokeParse(in_args1), + EXPECT_DEATH_IF_SUPPORTED(InvokeParse(in_args1), "Unknown command line flag 'unknown_flag'"); constexpr const char* const ff5_data[] = { @@ -668,9 +678,9 @@ TEST_F(ParseDeathTest, TestInvalidFlagfiles) { const char* in_args2[] = { "testbin", GetFlagfileFlag({{"parse_test.ff5", - absl::MakeConstSpan(ff5_data)}}, &flagfile_flag), + absl::MakeConstSpan(ff5_data)}}, flagfile_flag), }; - EXPECT_DEATH(InvokeParse(in_args2), + EXPECT_DEATH_IF_SUPPORTED(InvokeParse(in_args2), "Unknown command line flag 'int_flag 10'"); constexpr const char* const ff6_data[] = { @@ -680,16 +690,17 @@ TEST_F(ParseDeathTest, TestInvalidFlagfiles) { const char* in_args3[] = { "testbin", GetFlagfileFlag({{"parse_test.ff6", absl::MakeConstSpan(ff6_data)}}, - &flagfile_flag), + flagfile_flag), }; - EXPECT_DEATH(InvokeParse(in_args3), + EXPECT_DEATH_IF_SUPPORTED(InvokeParse(in_args3), "Flagfile can't contain position arguments or --"); const char* in_args4[] = { "testbin", "--flagfile=invalid_flag_file", }; - EXPECT_DEATH(InvokeParse(in_args4), "Can't open flagfile invalid_flag_file"); + EXPECT_DEATH_IF_SUPPORTED(InvokeParse(in_args4), + "Can't open flagfile invalid_flag_file"); constexpr const char* const ff7_data[] = { "--int_flag=10", @@ -700,9 +711,9 @@ TEST_F(ParseDeathTest, TestInvalidFlagfiles) { const char* in_args5[] = { "testbin", GetFlagfileFlag({{"parse_test.ff7", absl::MakeConstSpan(ff7_data)}}, - &flagfile_flag), + flagfile_flag), }; - EXPECT_DEATH(InvokeParse(in_args5), + EXPECT_DEATH_IF_SUPPORTED(InvokeParse(in_args5), "Unexpected line in the flagfile .*: \\*bin\\*"); } @@ -724,7 +735,7 @@ TEST_F(ParseTest, TestReadingRequiredFlagsFromEnv) { TEST_F(ParseDeathTest, TestReadingUnsetRequiredFlagsFromEnv) { const char* in_args1[] = {"testbin", "--fromenv=int_flag"}; - EXPECT_DEATH(InvokeParse(in_args1), + EXPECT_DEATH_IF_SUPPORTED(InvokeParse(in_args1), "FLAGS_int_flag not found in environment"); } @@ -735,7 +746,8 @@ TEST_F(ParseDeathTest, TestRecursiveFlagsFromEnv) { ScopedSetEnv set_tryfromenv("FLAGS_tryfromenv", "int_flag"); - EXPECT_DEATH(InvokeParse(in_args1), "Infinite recursion on flag tryfromenv"); + EXPECT_DEATH_IF_SUPPORTED(InvokeParse(in_args1), + "Infinite recursion on flag tryfromenv"); } // -------------------------------------------------------------------- @@ -844,7 +856,7 @@ TEST_F(ParseTest, TestIgnoreUndefinedFlags) { // -------------------------------------------------------------------- -TEST_F(ParseDeathTest, TestHelpFlagHandling) { +TEST_F(ParseDeathTest, TestSimpleHelpFlagHandling) { const char* in_args1[] = { "testbin", "--help", @@ -863,7 +875,56 @@ TEST_F(ParseDeathTest, TestHelpFlagHandling) { flags::UsageFlagsAction::kIgnoreUsage, flags::OnUndefinedFlag::kAbortIfUndefined); + EXPECT_EQ(flags::GetFlagsHelpMode(), flags::HelpMode::kImportant); EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), 3); } +// -------------------------------------------------------------------- + +TEST_F(ParseDeathTest, TestSubstringHelpFlagHandling) { + const char* in_args1[] = { + "testbin", + "--help=abcd", + }; + + auto out_args1 = flags::ParseCommandLineImpl( + 2, const_cast(in_args1), flags::ArgvListAction::kRemoveParsedArgs, + flags::UsageFlagsAction::kIgnoreUsage, + flags::OnUndefinedFlag::kAbortIfUndefined); + + EXPECT_EQ(flags::GetFlagsHelpMode(), flags::HelpMode::kMatch); + EXPECT_EQ(flags::GetFlagsHelpMatchSubstr(), "abcd"); + + const char* in_args2[] = {"testbin", "--help", "some_positional_arg"}; + + auto out_args2 = flags::ParseCommandLineImpl( + 3, const_cast(in_args2), flags::ArgvListAction::kRemoveParsedArgs, + flags::UsageFlagsAction::kIgnoreUsage, + flags::OnUndefinedFlag::kAbortIfUndefined); + + EXPECT_EQ(flags::GetFlagsHelpMode(), flags::HelpMode::kImportant); +} + +// -------------------------------------------------------------------- + +TEST_F(ParseTest, WasPresentOnCommandLine) { + const char* in_args1[] = { + "testbin", "arg1", "--bool_flag", + "--int_flag=211", "arg2", "--double_flag=1.1", + "--string_flag", "asd", "--", + "--some_flag", "arg4", + }; + + InvokeParse(in_args1); + + EXPECT_TRUE(flags::WasPresentOnCommandLine("bool_flag")); + EXPECT_TRUE(flags::WasPresentOnCommandLine("int_flag")); + EXPECT_TRUE(flags::WasPresentOnCommandLine("double_flag")); + EXPECT_TRUE(flags::WasPresentOnCommandLine("string_flag")); + EXPECT_FALSE(flags::WasPresentOnCommandLine("some_flag")); + EXPECT_FALSE(flags::WasPresentOnCommandLine("another_flag")); +} + +// -------------------------------------------------------------------- + } // namespace diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/reflection.cc b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/reflection.cc new file mode 100644 index 0000000000..dbce4032ab --- /dev/null +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/reflection.cc @@ -0,0 +1,354 @@ +// +// Copyright 2020 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "absl/flags/reflection.h" + +#include + +#include +#include + +#include "absl/base/config.h" +#include "absl/base/thread_annotations.h" +#include "absl/container/flat_hash_map.h" +#include "absl/flags/commandlineflag.h" +#include "absl/flags/internal/private_handle_accessor.h" +#include "absl/flags/internal/registry.h" +#include "absl/flags/usage_config.h" +#include "absl/strings/str_cat.h" +#include "absl/strings/string_view.h" +#include "absl/synchronization/mutex.h" + +namespace absl { +ABSL_NAMESPACE_BEGIN +namespace flags_internal { + +// -------------------------------------------------------------------- +// FlagRegistry +// A FlagRegistry singleton object holds all flag objects indexed by their +// names so that if you know a flag's name, you can access or set it. If the +// function is named FooLocked(), you must own the registry lock before +// calling the function; otherwise, you should *not* hold the lock, and the +// function will acquire it itself if needed. +// -------------------------------------------------------------------- + +class FlagRegistry { + public: + FlagRegistry() = default; + ~FlagRegistry() = default; + + // Store a flag in this registry. Takes ownership of *flag. + void RegisterFlag(CommandLineFlag& flag, const char* filename); + + void Lock() ABSL_EXCLUSIVE_LOCK_FUNCTION(lock_) { lock_.Lock(); } + void Unlock() ABSL_UNLOCK_FUNCTION(lock_) { lock_.Unlock(); } + + // Returns the flag object for the specified name, or nullptr if not found. + // Will emit a warning if a 'retired' flag is specified. + CommandLineFlag* FindFlag(absl::string_view name); + + static FlagRegistry& GlobalRegistry(); // returns a singleton registry + + private: + friend class flags_internal::FlagSaverImpl; // reads all the flags in order + // to copy them + friend void ForEachFlag(std::function visitor); + friend void FinalizeRegistry(); + + // The map from name to flag, for FindFlag(). + using FlagMap = absl::flat_hash_map; + using FlagIterator = FlagMap::iterator; + using FlagConstIterator = FlagMap::const_iterator; + FlagMap flags_; + std::vector flat_flags_; + std::atomic finalized_flags_{false}; + + absl::Mutex lock_; + + // Disallow + FlagRegistry(const FlagRegistry&); + FlagRegistry& operator=(const FlagRegistry&); +}; + +namespace { + +class FlagRegistryLock { + public: + explicit FlagRegistryLock(FlagRegistry& fr) : fr_(fr) { fr_.Lock(); } + ~FlagRegistryLock() { fr_.Unlock(); } + + private: + FlagRegistry& fr_; +}; + +} // namespace + +CommandLineFlag* FlagRegistry::FindFlag(absl::string_view name) { + if (finalized_flags_.load(std::memory_order_acquire)) { + // We could save some gcus here if we make `Name()` be non-virtual. + // We could move the `const char*` name to the base class. + auto it = std::partition_point( + flat_flags_.begin(), flat_flags_.end(), + [=](CommandLineFlag* f) { return f->Name() < name; }); + if (it != flat_flags_.end() && (*it)->Name() == name) return *it; + } + + FlagRegistryLock frl(*this); + auto it = flags_.find(name); + return it != flags_.end() ? it->second : nullptr; +} + +void FlagRegistry::RegisterFlag(CommandLineFlag& flag, const char* filename) { + if (filename != nullptr && + flag.Filename() != GetUsageConfig().normalize_filename(filename)) { + flags_internal::ReportUsageError( + absl::StrCat( + "Inconsistency between flag object and registration for flag '", + flag.Name(), + "', likely due to duplicate flags or an ODR violation. Relevant " + "files: ", + flag.Filename(), " and ", filename), + true); + std::exit(1); + } + + FlagRegistryLock registry_lock(*this); + + std::pair ins = + flags_.insert(FlagMap::value_type(flag.Name(), &flag)); + if (ins.second == false) { // means the name was already in the map + CommandLineFlag& old_flag = *ins.first->second; + if (flag.IsRetired() != old_flag.IsRetired()) { + // All registrations must agree on the 'retired' flag. + flags_internal::ReportUsageError( + absl::StrCat( + "Retired flag '", flag.Name(), "' was defined normally in file '", + (flag.IsRetired() ? old_flag.Filename() : flag.Filename()), "'."), + true); + } else if (flags_internal::PrivateHandleAccessor::TypeId(flag) != + flags_internal::PrivateHandleAccessor::TypeId(old_flag)) { + flags_internal::ReportUsageError( + absl::StrCat("Flag '", flag.Name(), + "' was defined more than once but with " + "differing types. Defined in files '", + old_flag.Filename(), "' and '", flag.Filename(), "'."), + true); + } else if (old_flag.IsRetired()) { + return; + } else if (old_flag.Filename() != flag.Filename()) { + flags_internal::ReportUsageError( + absl::StrCat("Flag '", flag.Name(), + "' was defined more than once (in files '", + old_flag.Filename(), "' and '", flag.Filename(), "')."), + true); + } else { + flags_internal::ReportUsageError( + absl::StrCat( + "Something is wrong with flag '", flag.Name(), "' in file '", + flag.Filename(), "'. One possibility: file '", flag.Filename(), + "' is being linked both statically and dynamically into this " + "executable. e.g. some files listed as srcs to a test and also " + "listed as srcs of some shared lib deps of the same test."), + true); + } + // All cases above are fatal, except for the retired flags. + std::exit(1); + } +} + +FlagRegistry& FlagRegistry::GlobalRegistry() { + static FlagRegistry* global_registry = new FlagRegistry; + return *global_registry; +} + +// -------------------------------------------------------------------- + +void ForEachFlag(std::function visitor) { + FlagRegistry& registry = FlagRegistry::GlobalRegistry(); + + if (registry.finalized_flags_.load(std::memory_order_acquire)) { + for (const auto& i : registry.flat_flags_) visitor(*i); + } + + FlagRegistryLock frl(registry); + for (const auto& i : registry.flags_) visitor(*i.second); +} + +// -------------------------------------------------------------------- + +bool RegisterCommandLineFlag(CommandLineFlag& flag, const char* filename) { + FlagRegistry::GlobalRegistry().RegisterFlag(flag, filename); + return true; +} + +void FinalizeRegistry() { + auto& registry = FlagRegistry::GlobalRegistry(); + FlagRegistryLock frl(registry); + if (registry.finalized_flags_.load(std::memory_order_relaxed)) { + // Was already finalized. Ignore the second time. + return; + } + registry.flat_flags_.reserve(registry.flags_.size()); + for (const auto& f : registry.flags_) { + registry.flat_flags_.push_back(f.second); + } + std::sort(std::begin(registry.flat_flags_), std::end(registry.flat_flags_), + [](const CommandLineFlag* lhs, const CommandLineFlag* rhs) { + return lhs->Name() < rhs->Name(); + }); + registry.flags_.clear(); + registry.finalized_flags_.store(true, std::memory_order_release); +} + +// -------------------------------------------------------------------- + +namespace { + +class RetiredFlagObj final : public CommandLineFlag { + public: + constexpr RetiredFlagObj(const char* name, FlagFastTypeId type_id) + : name_(name), type_id_(type_id) {} + + private: + absl::string_view Name() const override { return name_; } + std::string Filename() const override { + OnAccess(); + return "RETIRED"; + } + FlagFastTypeId TypeId() const override { return type_id_; } + std::string Help() const override { + OnAccess(); + return ""; + } + bool IsRetired() const override { return true; } + bool IsSpecifiedOnCommandLine() const override { + OnAccess(); + return false; + } + std::string DefaultValue() const override { + OnAccess(); + return ""; + } + std::string CurrentValue() const override { + OnAccess(); + return ""; + } + + // Any input is valid + bool ValidateInputValue(absl::string_view) const override { + OnAccess(); + return true; + } + + std::unique_ptr SaveState() override { + return nullptr; + } + + bool ParseFrom(absl::string_view, flags_internal::FlagSettingMode, + flags_internal::ValueSource, std::string&) override { + OnAccess(); + return false; + } + + void CheckDefaultValueParsingRoundtrip() const override { OnAccess(); } + + void Read(void*) const override { OnAccess(); } + + void OnAccess() const { + flags_internal::ReportUsageError( + absl::StrCat("Accessing retired flag '", name_, "'"), false); + } + + // Data members + const char* const name_; + const FlagFastTypeId type_id_; +}; + +} // namespace + +void Retire(const char* name, FlagFastTypeId type_id, char* buf) { + static_assert(sizeof(RetiredFlagObj) == kRetiredFlagObjSize, ""); + static_assert(alignof(RetiredFlagObj) == kRetiredFlagObjAlignment, ""); + auto* flag = ::new (static_cast(buf)) + flags_internal::RetiredFlagObj(name, type_id); + FlagRegistry::GlobalRegistry().RegisterFlag(*flag, nullptr); +} + +// -------------------------------------------------------------------- + +class FlagSaverImpl { + public: + FlagSaverImpl() = default; + FlagSaverImpl(const FlagSaverImpl&) = delete; + void operator=(const FlagSaverImpl&) = delete; + + // Saves the flag states from the flag registry into this object. + // It's an error to call this more than once. + void SaveFromRegistry() { + assert(backup_registry_.empty()); // call only once! + flags_internal::ForEachFlag([&](CommandLineFlag& flag) { + if (auto flag_state = + flags_internal::PrivateHandleAccessor::SaveState(flag)) { + backup_registry_.emplace_back(std::move(flag_state)); + } + }); + } + + // Restores the saved flag states into the flag registry. + void RestoreToRegistry() { + for (const auto& flag_state : backup_registry_) { + flag_state->Restore(); + } + } + + private: + std::vector> + backup_registry_; +}; + +} // namespace flags_internal + +FlagSaver::FlagSaver() : impl_(new flags_internal::FlagSaverImpl) { + impl_->SaveFromRegistry(); +} + +FlagSaver::~FlagSaver() { + if (!impl_) return; + + impl_->RestoreToRegistry(); + delete impl_; +} + +// -------------------------------------------------------------------- + +CommandLineFlag* FindCommandLineFlag(absl::string_view name) { + if (name.empty()) return nullptr; + flags_internal::FlagRegistry& registry = + flags_internal::FlagRegistry::GlobalRegistry(); + return registry.FindFlag(name); +} + +// -------------------------------------------------------------------- + +absl::flat_hash_map GetAllFlags() { + absl::flat_hash_map res; + flags_internal::ForEachFlag([&](CommandLineFlag& flag) { + if (!flag.IsRetired()) res.insert({flag.Name(), &flag}); + }); + return res; +} + +ABSL_NAMESPACE_END +} // namespace absl diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/reflection.h b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/reflection.h new file mode 100644 index 0000000000..e6baf5de4b --- /dev/null +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/reflection.h @@ -0,0 +1,90 @@ +// +// Copyright 2020 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// ----------------------------------------------------------------------------- +// File: reflection.h +// ----------------------------------------------------------------------------- +// +// This file defines the routines to access and operate on an Abseil Flag's +// reflection handle. + +#ifndef ABSL_FLAGS_REFLECTION_H_ +#define ABSL_FLAGS_REFLECTION_H_ + +#include + +#include "absl/base/config.h" +#include "absl/container/flat_hash_map.h" +#include "absl/flags/commandlineflag.h" +#include "absl/flags/internal/commandlineflag.h" + +namespace absl { +ABSL_NAMESPACE_BEGIN +namespace flags_internal { +class FlagSaverImpl; +} // namespace flags_internal + +// FindCommandLineFlag() +// +// Returns the reflection handle of an Abseil flag of the specified name, or +// `nullptr` if not found. This function will emit a warning if the name of a +// 'retired' flag is specified. +absl::CommandLineFlag* FindCommandLineFlag(absl::string_view name); + +// Returns current state of the Flags registry in a form of mapping from flag +// name to a flag reflection handle. +absl::flat_hash_map GetAllFlags(); + +//------------------------------------------------------------------------------ +// FlagSaver +//------------------------------------------------------------------------------ +// +// A FlagSaver object stores the state of flags in the scope where the FlagSaver +// is defined, allowing modification of those flags within that scope and +// automatic restoration of the flags to their previous state upon leaving the +// scope. +// +// A FlagSaver can be used within tests to temporarily change the test +// environment and restore the test case to its previous state. +// +// Example: +// +// void MyFunc() { +// absl::FlagSaver fs; +// ... +// absl::SetFlag(&FLAGS_myFlag, otherValue); +// ... +// } // scope of FlagSaver left, flags return to previous state +// +// This class is thread-safe. + +class FlagSaver { + public: + FlagSaver(); + ~FlagSaver(); + + FlagSaver(const FlagSaver&) = delete; + void operator=(const FlagSaver&) = delete; + + private: + flags_internal::FlagSaverImpl* impl_; +}; + +//----------------------------------------------------------------------------- + +ABSL_NAMESPACE_END +} // namespace absl + +#endif // ABSL_FLAGS_REFLECTION_H_ diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/reflection_test.cc b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/reflection_test.cc new file mode 100644 index 0000000000..79cfa90c3a --- /dev/null +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/reflection_test.cc @@ -0,0 +1,265 @@ +// +// Copyright 2019 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "absl/flags/reflection.h" + +#include +#include + +#include "gmock/gmock.h" +#include "gtest/gtest.h" +#include "absl/flags/declare.h" +#include "absl/flags/flag.h" +#include "absl/flags/internal/commandlineflag.h" +#include "absl/flags/marshalling.h" +#include "absl/memory/memory.h" +#include "absl/strings/str_cat.h" +#include "absl/strings/str_split.h" + +ABSL_FLAG(int, int_flag, 1, "int_flag help"); +ABSL_FLAG(std::string, string_flag, "dflt", "string_flag help"); +ABSL_RETIRED_FLAG(bool, bool_retired_flag, false, "bool_retired_flag help"); + +namespace { + +class ReflectionTest : public testing::Test { + protected: + void SetUp() override { flag_saver_ = absl::make_unique(); } + void TearDown() override { flag_saver_.reset(); } + + private: + std::unique_ptr flag_saver_; +}; + +// -------------------------------------------------------------------- + +TEST_F(ReflectionTest, TestFindCommandLineFlag) { + auto* handle = absl::FindCommandLineFlag("some_flag"); + EXPECT_EQ(handle, nullptr); + + handle = absl::FindCommandLineFlag("int_flag"); + EXPECT_NE(handle, nullptr); + + handle = absl::FindCommandLineFlag("string_flag"); + EXPECT_NE(handle, nullptr); + + handle = absl::FindCommandLineFlag("bool_retired_flag"); + EXPECT_NE(handle, nullptr); +} + +// -------------------------------------------------------------------- + +TEST_F(ReflectionTest, TestGetAllFlags) { + auto all_flags = absl::GetAllFlags(); + EXPECT_NE(all_flags.find("int_flag"), all_flags.end()); + EXPECT_EQ(all_flags.find("bool_retired_flag"), all_flags.end()); + EXPECT_EQ(all_flags.find("some_undefined_flag"), all_flags.end()); + + std::vector flag_names_first_attempt; + auto all_flags_1 = absl::GetAllFlags(); + for (auto f : all_flags_1) { + flag_names_first_attempt.push_back(f.first); + } + + std::vector flag_names_second_attempt; + auto all_flags_2 = absl::GetAllFlags(); + for (auto f : all_flags_2) { + flag_names_second_attempt.push_back(f.first); + } + + EXPECT_THAT(flag_names_first_attempt, + ::testing::UnorderedElementsAreArray(flag_names_second_attempt)); +} + +// -------------------------------------------------------------------- + +struct CustomUDT { + CustomUDT() : a(1), b(1) {} + CustomUDT(int a_, int b_) : a(a_), b(b_) {} + + friend bool operator==(const CustomUDT& f1, const CustomUDT& f2) { + return f1.a == f2.a && f1.b == f2.b; + } + + int a; + int b; +}; +bool AbslParseFlag(absl::string_view in, CustomUDT* f, std::string*) { + std::vector parts = + absl::StrSplit(in, ':', absl::SkipWhitespace()); + + if (parts.size() != 2) return false; + + if (!absl::SimpleAtoi(parts[0], &f->a)) return false; + + if (!absl::SimpleAtoi(parts[1], &f->b)) return false; + + return true; +} +std::string AbslUnparseFlag(const CustomUDT& f) { + return absl::StrCat(f.a, ":", f.b); +} + +} // namespace + +// -------------------------------------------------------------------- + +ABSL_FLAG(bool, test_flag_01, true, ""); +ABSL_FLAG(int, test_flag_02, 1234, ""); +ABSL_FLAG(int16_t, test_flag_03, -34, ""); +ABSL_FLAG(uint16_t, test_flag_04, 189, ""); +ABSL_FLAG(int32_t, test_flag_05, 10765, ""); +ABSL_FLAG(uint32_t, test_flag_06, 40000, ""); +ABSL_FLAG(int64_t, test_flag_07, -1234567, ""); +ABSL_FLAG(uint64_t, test_flag_08, 9876543, ""); +ABSL_FLAG(double, test_flag_09, -9.876e-50, ""); +ABSL_FLAG(float, test_flag_10, 1.234e12f, ""); +ABSL_FLAG(std::string, test_flag_11, "", ""); +ABSL_FLAG(absl::Duration, test_flag_12, absl::Minutes(10), ""); +static int counter = 0; +ABSL_FLAG(int, test_flag_13, 200, "").OnUpdate([]() { counter++; }); +ABSL_FLAG(CustomUDT, test_flag_14, {}, ""); + +namespace { + +TEST_F(ReflectionTest, TestFlagSaverInScope) { + { + absl::FlagSaver s; + counter = 0; + absl::SetFlag(&FLAGS_test_flag_01, false); + absl::SetFlag(&FLAGS_test_flag_02, -1021); + absl::SetFlag(&FLAGS_test_flag_03, 6009); + absl::SetFlag(&FLAGS_test_flag_04, 44); + absl::SetFlag(&FLAGS_test_flag_05, +800); + absl::SetFlag(&FLAGS_test_flag_06, -40978756); + absl::SetFlag(&FLAGS_test_flag_07, 23405); + absl::SetFlag(&FLAGS_test_flag_08, 975310); + absl::SetFlag(&FLAGS_test_flag_09, 1.00001); + absl::SetFlag(&FLAGS_test_flag_10, -3.54f); + absl::SetFlag(&FLAGS_test_flag_11, "asdf"); + absl::SetFlag(&FLAGS_test_flag_12, absl::Hours(20)); + absl::SetFlag(&FLAGS_test_flag_13, 4); + absl::SetFlag(&FLAGS_test_flag_14, CustomUDT{-1, -2}); + } + + EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_01), true); + EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_02), 1234); + EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_03), -34); + EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_04), 189); + EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_05), 10765); + EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_06), 40000); + EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_07), -1234567); + EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_08), 9876543); + EXPECT_NEAR(absl::GetFlag(FLAGS_test_flag_09), -9.876e-50, 1e-55); + EXPECT_NEAR(absl::GetFlag(FLAGS_test_flag_10), 1.234e12f, 1e5f); + EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_11), ""); + EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_12), absl::Minutes(10)); + EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_13), 200); + EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_14), CustomUDT{}); + EXPECT_EQ(counter, 2); +} + +// -------------------------------------------------------------------- + +TEST_F(ReflectionTest, TestFlagSaverVsUpdateViaReflection) { + { + absl::FlagSaver s; + counter = 0; + std::string error; + EXPECT_TRUE( + absl::FindCommandLineFlag("test_flag_01")->ParseFrom("false", &error)) + << error; + EXPECT_TRUE( + absl::FindCommandLineFlag("test_flag_02")->ParseFrom("-4536", &error)) + << error; + EXPECT_TRUE( + absl::FindCommandLineFlag("test_flag_03")->ParseFrom("111", &error)) + << error; + EXPECT_TRUE( + absl::FindCommandLineFlag("test_flag_04")->ParseFrom("909", &error)) + << error; + EXPECT_TRUE( + absl::FindCommandLineFlag("test_flag_05")->ParseFrom("-2004", &error)) + << error; + EXPECT_TRUE( + absl::FindCommandLineFlag("test_flag_06")->ParseFrom("1000023", &error)) + << error; + EXPECT_TRUE( + absl::FindCommandLineFlag("test_flag_07")->ParseFrom("69305", &error)) + << error; + EXPECT_TRUE(absl::FindCommandLineFlag("test_flag_08") + ->ParseFrom("1000000001", &error)) + << error; + EXPECT_TRUE( + absl::FindCommandLineFlag("test_flag_09")->ParseFrom("2.09021", &error)) + << error; + EXPECT_TRUE( + absl::FindCommandLineFlag("test_flag_10")->ParseFrom("-33.1", &error)) + << error; + EXPECT_TRUE( + absl::FindCommandLineFlag("test_flag_11")->ParseFrom("ADD_FOO", &error)) + << error; + EXPECT_TRUE(absl::FindCommandLineFlag("test_flag_12") + ->ParseFrom("3h11m16s", &error)) + << error; + EXPECT_TRUE( + absl::FindCommandLineFlag("test_flag_13")->ParseFrom("0", &error)) + << error; + EXPECT_TRUE( + absl::FindCommandLineFlag("test_flag_14")->ParseFrom("10:1", &error)) + << error; + } + + EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_01), true); + EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_02), 1234); + EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_03), -34); + EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_04), 189); + EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_05), 10765); + EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_06), 40000); + EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_07), -1234567); + EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_08), 9876543); + EXPECT_NEAR(absl::GetFlag(FLAGS_test_flag_09), -9.876e-50, 1e-55); + EXPECT_NEAR(absl::GetFlag(FLAGS_test_flag_10), 1.234e12f, 1e5f); + EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_11), ""); + EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_12), absl::Minutes(10)); + EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_13), 200); + EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_14), CustomUDT{}); + EXPECT_EQ(counter, 2); +} + +// -------------------------------------------------------------------- + +TEST_F(ReflectionTest, TestMultipleFlagSaversInEnclosedScopes) { + { + absl::FlagSaver s; + absl::SetFlag(&FLAGS_test_flag_08, 10); + EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_08), 10); + { + absl::FlagSaver s; + absl::SetFlag(&FLAGS_test_flag_08, 20); + EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_08), 20); + { + absl::FlagSaver s; + absl::SetFlag(&FLAGS_test_flag_08, -200); + EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_08), -200); + } + EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_08), 20); + } + EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_08), 10); + } + EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_08), 9876543); +} + +} // namespace diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/usage_config.cc b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/usage_config.cc index 0d21bce6a9..5d7426db31 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/usage_config.cc +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/usage_config.cc @@ -15,6 +15,7 @@ #include "absl/flags/usage_config.h" +#include #include #include @@ -33,7 +34,8 @@ extern "C" { // Additional report of fatal usage error message before we std::exit. Error is // fatal if is_fatal argument to ReportUsageError is true. -ABSL_ATTRIBUTE_WEAK void AbslInternalReportFatalUsageError(absl::string_view) {} +ABSL_ATTRIBUTE_WEAK void ABSL_INTERNAL_C_SYMBOL( + AbslInternalReportFatalUsageError)(absl::string_view) {} } // extern "C" @@ -127,7 +129,7 @@ void ReportUsageError(absl::string_view msg, bool is_fatal) { std::cerr << "ERROR: " << msg << std::endl; if (is_fatal) { - AbslInternalReportFatalUsageError(msg); + ABSL_INTERNAL_C_SYMBOL(AbslInternalReportFatalUsageError)(msg); } } diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/usage_config.h b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/usage_config.h index 96eecea231..ded70300f0 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/usage_config.h +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/flags/usage_config.h @@ -127,7 +127,8 @@ extern "C" { // Additional report of fatal usage error message before we std::exit. Error is // fatal if is_fatal argument to ReportUsageError is true. -void AbslInternalReportFatalUsageError(absl::string_view); +void ABSL_INTERNAL_C_SYMBOL(AbslInternalReportFatalUsageError)( + absl::string_view); } // extern "C" diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/functional/BUILD.gn b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/functional/BUILD.gn deleted file mode 100644 index 59bdb5795a..0000000000 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/functional/BUILD.gn +++ /dev/null @@ -1,25 +0,0 @@ -# Copyright 2020 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -import("//third_party/abseil-cpp/absl.gni") - -absl_source_set("bind_front") { - sources = [ "internal/front_binder.h" ] - public = [ "bind_front.h" ] - deps = [ - "../base:base_internal", - "../container:compressed_tuple", - "../meta:type_traits", - "../utility", - ] -} - -absl_source_set("function_ref") { - sources = [ "internal/function_ref.h" ] - public = [ "function_ref.h" ] - deps = [ - "../base:base_internal", - "../meta:type_traits", - ] -} diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/functional/CMakeLists.txt b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/functional/CMakeLists.txt index cda914f2cd..338ddc6c6c 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/functional/CMakeLists.txt +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/functional/CMakeLists.txt @@ -39,7 +39,7 @@ absl_cc_test( DEPS absl::bind_front absl::memory - gmock_main + GTest::gmock_main ) absl_cc_library( @@ -53,6 +53,7 @@ absl_cc_library( ${ABSL_DEFAULT_COPTS} DEPS absl::base_internal + absl::core_headers absl::meta PUBLIC ) @@ -68,5 +69,5 @@ absl_cc_test( absl::function_ref absl::memory absl::test_instance_tracker - gmock_main + GTest::gmock_main ) diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/functional/function_ref.h b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/functional/function_ref.h index 370acc55b0..824e3cea9d 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/functional/function_ref.h +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/functional/function_ref.h @@ -50,6 +50,7 @@ #include #include +#include "absl/base/attributes.h" #include "absl/functional/internal/function_ref.h" #include "absl/meta/type_traits.h" @@ -90,7 +91,7 @@ class FunctionRef { // Used to disable constructors for objects that are not compatible with the // signature of this FunctionRef. template > + typename FR = absl::base_internal::invoke_result_t> using EnableIfCompatible = typename std::enable_if::value || std::is_convertible::value>::type; @@ -98,7 +99,8 @@ class FunctionRef { public: // Constructs a FunctionRef from any invokable type. template > - FunctionRef(const F& f) // NOLINT(runtime/explicit) + // NOLINTNEXTLINE(runtime/explicit) + FunctionRef(const F& f ABSL_ATTRIBUTE_LIFETIME_BOUND) : invoker_(&absl::functional_internal::InvokeObject) { absl::functional_internal::AssertNonNull(f); ptr_.obj = &f; @@ -122,6 +124,7 @@ class FunctionRef { // To help prevent subtle lifetime bugs, FunctionRef is not assignable. // Typically, it should only be used as an argument type. FunctionRef& operator=(const FunctionRef& rhs) = delete; + FunctionRef(const FunctionRef& rhs) = default; // Call the underlying object. R operator()(Args... args) const { diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/functional/internal/front_binder.h b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/functional/internal/front_binder.h index a4d95da44a..45f52de73d 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/functional/internal/front_binder.h +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/functional/internal/front_binder.h @@ -33,7 +33,7 @@ namespace functional_internal { // Invoke the method, expanding the tuple of bound arguments. template R Apply(Tuple&& bound, absl::index_sequence, Args&&... free) { - return base_internal::Invoke( + return base_internal::invoke( absl::forward(bound).template get()..., absl::forward(free)...); } @@ -50,22 +50,22 @@ class FrontBinder { constexpr explicit FrontBinder(absl::in_place_t, Ts&&... ts) : bound_args_(absl::forward(ts)...) {} - template > + template > R operator()(FreeArgs&&... free_args) & { return functional_internal::Apply(bound_args_, Idx(), absl::forward(free_args)...); } template > + class R = base_internal::invoke_result_t< + const F&, const BoundArgs&..., FreeArgs&&...>> R operator()(FreeArgs&&... free_args) const& { return functional_internal::Apply(bound_args_, Idx(), absl::forward(free_args)...); } - template > R operator()(FreeArgs&&... free_args) && { // This overload is called when *this is an rvalue. If some of the bound @@ -75,8 +75,8 @@ class FrontBinder { } template > + class R = base_internal::invoke_result_t< + const F&&, const BoundArgs&&..., FreeArgs&&...>> R operator()(FreeArgs&&... free_args) const&& { // This overload is called when *this is an rvalue. If some of the bound // arguments are stored by value or rvalue reference, we move them. diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/functional/internal/function_ref.h b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/functional/internal/function_ref.h index d1575054ea..b5bb8b430a 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/functional/internal/function_ref.h +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/functional/internal/function_ref.h @@ -71,14 +71,14 @@ template R InvokeObject(VoidPtr ptr, typename ForwardT::type... args) { auto o = static_cast(ptr.obj); return static_cast( - absl::base_internal::Invoke(*o, std::forward(args)...)); + absl::base_internal::invoke(*o, std::forward(args)...)); } template R InvokeFunction(VoidPtr ptr, typename ForwardT::type... args) { auto f = reinterpret_cast(ptr.fun); return static_cast( - absl::base_internal::Invoke(f, std::forward(args)...)); + absl::base_internal::invoke(f, std::forward(args)...)); } template diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/hash/BUILD.gn b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/hash/BUILD.gn deleted file mode 100644 index de413b4132..0000000000 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/hash/BUILD.gn +++ /dev/null @@ -1,75 +0,0 @@ -# Copyright 2018 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -import("//build_overrides/build.gni") -import("//third_party/abseil-cpp/absl.gni") - -# Usage of Abseil in Chromium is guarded by an explicit opt-in list, before -# adding projects to this list please reach out to cxx@chromium.org and CC: -# - https://cs.chromium.org/chromium/src/third_party/abseil-cpp/OWNERS -# -# More information can be found at: -# https://docs.google.com/document/d/1DgS1-A3rzboTLjpf4m1sqkJgWjnY_Ru2dokk1X1vBDU -if (build_with_chromium) { - default_visibility = absl_visibility - default_visibility += [ "//third_party/openscreen/*" ] -} else { - default_visibility = [ "*" ] -} - -absl_source_set("hash") { - sources = [ - "internal/hash.cc", - "internal/hash.h", - ] - public = [ "hash.h" ] - deps = [ - ":city", - "../base:core_headers", - "../base:endian", - "../container:fixed_array", - "../meta:type_traits", - "../numeric:int128", - "../strings", - "../strings:cord", - "../types:optional", - "../types:variant", - "../utility", - ] - visibility = default_visibility -} - -absl_source_set("hash_testing") { - testonly = true - public = [ "hash_testing.h" ] - deps = [ - ":spy_hash_state", - "../meta:type_traits", - "../strings", - "../types:variant", - "//testing/gtest", - ] -} - -absl_source_set("spy_hash_state") { - testonly = true - public = [ "internal/spy_hash_state.h" ] - deps = [ - ":hash", - "../strings", - "../strings:str_format", - ] - visibility = [] - visibility += [ "../*" ] -} - -absl_source_set("city") { - public = [ "internal/city.h" ] - sources = [ "internal/city.cc" ] - deps = [ - "../base:config", - "../base:core_headers", - "../base:endian", - ] -} diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/hash/CMakeLists.txt b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/hash/CMakeLists.txt index 4e55514743..5916ae3cf0 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/hash/CMakeLists.txt +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/hash/CMakeLists.txt @@ -24,8 +24,9 @@ absl_cc_library( "internal/hash.h" COPTS ${ABSL_DEFAULT_COPTS} - DEPS - absl::cord + DEPS + absl::city + absl::config absl::core_headers absl::endian absl::fixed_array @@ -35,7 +36,7 @@ absl_cc_library( absl::optional absl::variant absl::utility - absl::city + absl::low_level_hash PUBLIC ) @@ -51,7 +52,7 @@ absl_cc_library( absl::meta absl::strings absl::variant - gmock + GTest::gmock TESTONLY ) @@ -71,7 +72,7 @@ absl_cc_test( absl::spy_hash_state absl::meta absl::int128 - gmock_main + GTest::gmock_main ) absl_cc_library( @@ -112,6 +113,34 @@ absl_cc_test( ${ABSL_TEST_COPTS} DEPS absl::city - gmock_main + GTest::gmock_main ) +absl_cc_library( + NAME + low_level_hash + HDRS + "internal/low_level_hash.h" + SRCS + "internal/low_level_hash.cc" + COPTS + ${ABSL_DEFAULT_COPTS} + DEPS + absl::bits + absl::config + absl::endian + absl::int128 +) + +absl_cc_test( + NAME + low_level_hash_test + SRCS + "internal/low_level_hash_test.cc" + COPTS + ${ABSL_TEST_COPTS} + DEPS + absl::low_level_hash + absl::strings + GTest::gmock_main +) diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/hash/hash.h b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/hash/hash.h index 3dbeab6977..8282ea53c6 100644 --- a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/hash/hash.h +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/hash/hash.h @@ -37,8 +37,11 @@ // types. Hashing of that combined state is separately done by `absl::Hash`. // // One should assume that a hash algorithm is chosen randomly at the start of -// each process. E.g., absl::Hash()(9) in one process and -// absl::Hash()(9) in another process are likely to differ. +// each process. E.g., `absl::Hash{}(9)` in one process and +// `absl::Hash{}(9)` in another process are likely to differ. +// +// `absl::Hash` is intended to strongly mix input bits with a target of passing +// an [Avalanche Test](https://en.wikipedia.org/wiki/Avalanche_effect). // // Example: // @@ -70,6 +73,8 @@ #ifndef ABSL_HASH_HASH_H_ #define ABSL_HASH_HASH_H_ +#include + #include "absl/hash/internal/hash.h" namespace absl { @@ -85,7 +90,6 @@ ABSL_NAMESPACE_BEGIN // * T is an arithmetic or pointer type // * T defines an overload for `AbslHashValue(H, const T&)` for an arbitrary // hash state `H`. -// - T defines a specialization of `HASH_NAMESPACE::hash` // - T defines a specialization of `std::hash` // // `absl::Hash` intrinsically supports the following types: @@ -125,8 +129,6 @@ ABSL_NAMESPACE_BEGIN // * Natively supported types out of the box (see above) // * Types for which an `AbslHashValue()` overload is provided (such as // user-defined types). See "Adding Type Support to `absl::Hash`" below. -// * Types which define a `HASH_NAMESPACE::hash` specialization (aka -// `__gnu_cxx::hash` for gcc/Clang or `stdext::hash` for MSVC) // * Types which define a `std::hash` specialization // // The fallback to legacy hash functions exists mainly for backwards @@ -214,6 +216,26 @@ ABSL_NAMESPACE_BEGIN template using Hash = absl::hash_internal::Hash; +// HashOf +// +// absl::HashOf() is a helper that generates a hash from the values of its +// arguments. It dispatches to absl::Hash directly, as follows: +// * HashOf(t) == absl::Hash{}(t) +// * HashOf(a, b, c) == HashOf(std::make_tuple(a, b, c)) +// +// HashOf(a1, a2, ...) == HashOf(b1, b2, ...) is guaranteed when +// * The argument lists have pairwise identical C++ types +// * a1 == b1 && a2 == b2 && ... +// +// The requirement that the arguments match in both type and value is critical. +// It means that `a == b` does not necessarily imply `HashOf(a) == HashOf(b)` if +// `a` and `b` have different types. For example, `HashOf(2) != HashOf(2.0)`. +template +size_t HashOf(const Types&... values) { + auto tuple = std::tie(values...); + return absl::Hash{}(tuple); +} + // HashState // // A type erased version of the hash state concept, for use in user-defined diff --git a/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/hash/hash_benchmark.cc b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/hash/hash_benchmark.cc new file mode 100644 index 0000000000..d498ac29c0 --- /dev/null +++ b/third-party/webrtc/dependencies/third_party/abseil-cpp/absl/hash/hash_benchmark.cc @@ -0,0 +1,254 @@ +// Copyright 2018 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include +#include +#include + +#include "absl/base/attributes.h" +#include "absl/hash/hash.h" +#include "absl/random/random.h" +#include "absl/strings/cord.h" +#include "absl/strings/cord_test_helpers.h" +#include "absl/strings/string_view.h" +#include "benchmark/benchmark.h" + +namespace { + +using absl::Hash; + +template