1 /* 2 This file is part of Telegram Desktop, 3 the official desktop application for the Telegram messaging service. 4 5 For license and copyright information please follow this link: 6 https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL 7 */ 8 #pragma once 9 10 #include "data/data_abstract_sparse_ids.h" 11 #include "data/data_messages.h" 12 13 namespace Storage { 14 struct SparseIdsListResult; 15 struct SparseIdsSliceUpdate; 16 } // namespace Storage 17 18 class SparseIdsSlice final : public AbstractSparseIds<base::flat_set<MsgId>> { 19 public: 20 using Key = MsgId; 21 using AbstractSparseIds<base::flat_set<MsgId>>::AbstractSparseIds; 22 23 }; 24 25 using SparseUnsortedIdsSlice = AbstractSparseIds<std::vector<MsgId>>; 26 27 class SparseIdsMergedSlice { 28 public: 29 using UniversalMsgId = MsgId; 30 struct Key { 31 Key( 32 PeerId peerId, 33 PeerId migratedPeerId, 34 UniversalMsgId universalId, 35 bool scheduled = false) peerIdKey36 : peerId(peerId) 37 , scheduled(scheduled) 38 , migratedPeerId(scheduled ? 0 : migratedPeerId) 39 , universalId(universalId) { 40 } 41 42 bool operator==(const Key &other) const { 43 return (peerId == other.peerId) 44 && (migratedPeerId == other.migratedPeerId) 45 && (universalId == other.universalId); 46 } 47 bool operator!=(const Key &other) const { 48 return !(*this == other); 49 } 50 51 PeerId peerId = 0; 52 bool scheduled = false; 53 PeerId migratedPeerId = 0; 54 UniversalMsgId universalId = 0; 55 56 }; 57 58 SparseIdsMergedSlice(Key key); 59 SparseIdsMergedSlice( 60 Key key, 61 SparseIdsSlice part, 62 std::optional<SparseIdsSlice> migrated); 63 SparseIdsMergedSlice( 64 Key key, 65 SparseUnsortedIdsSlice scheduled); 66 67 std::optional<int> fullCount() const; 68 std::optional<int> skippedBefore() const; 69 std::optional<int> skippedAfter() const; 70 std::optional<int> indexOf(FullMsgId fullId) const; 71 int size() const; 72 FullMsgId operator[](int index) const; 73 std::optional<int> distance(const Key &a, const Key &b) const; 74 std::optional<FullMsgId> nearest(UniversalMsgId id) const; 75 76 using SimpleViewerFunction = rpl::producer<SparseIdsSlice>( 77 PeerId peerId, 78 SparseIdsSlice::Key simpleKey, 79 int limitBefore, 80 int limitAfter); 81 static rpl::producer<SparseIdsMergedSlice> CreateViewer( 82 SparseIdsMergedSlice::Key key, 83 int limitBefore, 84 int limitAfter, 85 Fn<SimpleViewerFunction> simpleViewer); 86 87 private: PartKey(const Key & key)88 static SparseIdsSlice::Key PartKey(const Key &key) { 89 return (key.universalId < 0) ? 1 : key.universalId; 90 } MigratedKey(const Key & key)91 static SparseIdsSlice::Key MigratedKey(const Key &key) { 92 return (key.universalId < 0) 93 ? (ServerMaxMsgId + key.universalId) 94 : (key.universalId > 0) ? (ServerMaxMsgId - 1) : 0; 95 } MigratedSlice(const Key & key)96 static std::optional<SparseIdsSlice> MigratedSlice(const Key &key) { 97 return key.migratedPeerId 98 ? base::make_optional(SparseIdsSlice()) 99 : std::nullopt; 100 } 101 IsFromSlice(PeerId peerId,FullMsgId fullId)102 static bool IsFromSlice(PeerId peerId, FullMsgId fullId) { 103 return peerIsChannel(peerId) 104 ? (peerId == peerFromChannel(fullId.channel)) 105 : !fullId.channel; 106 } ComputeId(PeerId peerId,MsgId msgId)107 static FullMsgId ComputeId(PeerId peerId, MsgId msgId) { 108 return FullMsgId(peerToChannel(peerId), msgId); 109 } ComputeId(const Key & key)110 static FullMsgId ComputeId(const Key &key) { 111 return (key.universalId >= 0) 112 ? ComputeId(key.peerId, key.universalId) 113 : ComputeId(key.migratedPeerId, ServerMaxMsgId + key.universalId); 114 } Add(const std::optional<int> & a,const std::optional<int> & b)115 static std::optional<int> Add( 116 const std::optional<int> &a, 117 const std::optional<int> &b) { 118 return (a && b) ? base::make_optional(*a + *b) : std::nullopt; 119 } 120 isFromPart(FullMsgId fullId)121 bool isFromPart(FullMsgId fullId) const { 122 return IsFromSlice(_key.peerId, fullId); 123 } isFromMigrated(FullMsgId fullId)124 bool isFromMigrated(FullMsgId fullId) const { 125 return _migrated 126 ? IsFromSlice(_key.migratedPeerId, fullId) 127 : false; 128 } migratedSize()129 int migratedSize() const { 130 return isolatedInPart() ? 0 : _migrated->size(); 131 } isolatedInPart()132 bool isolatedInPart() const { 133 return IsServerMsgId(_key.universalId) 134 && (!_migrated || _part.skippedBefore() != 0); 135 } isolatedInMigrated()136 bool isolatedInMigrated() const { 137 return IsServerMsgId(ServerMaxMsgId + _key.universalId) 138 && (_migrated->skippedAfter() != 0); 139 } 140 141 Key _key; 142 SparseIdsSlice _part; 143 std::optional<SparseIdsSlice> _migrated; 144 std::optional<SparseUnsortedIdsSlice> _scheduled; 145 146 }; 147 148 class SparseIdsSliceBuilder { 149 public: 150 using Key = SparseIdsSlice::Key; 151 152 SparseIdsSliceBuilder(Key key, int limitBefore, int limitAfter); 153 154 bool applyInitial(const Storage::SparseIdsListResult &result); 155 bool applyUpdate(const Storage::SparseIdsSliceUpdate &update); 156 bool removeOne(MsgId messageId); 157 bool removeAll(); 158 bool invalidateBottom(); 159 160 void checkInsufficient(); 161 struct AroundData { 162 MsgId aroundId = 0; 163 Data::LoadDirection direction = Data::LoadDirection::Around; 164 165 inline bool operator<(const AroundData &other) const { 166 return (aroundId < other.aroundId) 167 || ((aroundId == other.aroundId) 168 && (direction < other.direction)); 169 } 170 }; insufficientAround()171 auto insufficientAround() const { 172 return _insufficientAround.events(); 173 } 174 175 SparseIdsSlice snapshot() const; 176 177 private: 178 enum class RequestDirection { 179 Before, 180 After, 181 }; 182 void requestMessages(RequestDirection direction); 183 void requestMessagesCount(); 184 void fillSkippedAndSliceToLimits(); 185 void sliceToLimits(); 186 187 void mergeSliceData( 188 std::optional<int> count, 189 const base::flat_set<MsgId> &messageIds, 190 std::optional<int> skippedBefore = std::nullopt, 191 std::optional<int> skippedAfter = std::nullopt); 192 193 Key _key; 194 base::flat_set<MsgId> _ids; 195 std::optional<int> _fullCount; 196 std::optional<int> _skippedBefore; 197 std::optional<int> _skippedAfter; 198 int _limitBefore = 0; 199 int _limitAfter = 0; 200 201 rpl::event_stream<AroundData> _insufficientAround; 202 203 }; 204