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 namespace Data { 11 12 enum class LoadDirection : char { 13 Around, 14 Before, 15 After, 16 }; 17 18 struct MessagePosition { 19 FullMsgId fullId; 20 TimeId date = 0; 21 22 explicit operator bool() const { 23 return (fullId.msg != 0); 24 } 25 26 inline constexpr bool operator<(const MessagePosition &other) const { 27 if (date < other.date) { 28 return true; 29 } else if (other.date < date) { 30 return false; 31 } 32 return (fullId < other.fullId); 33 } 34 inline constexpr bool operator>(const MessagePosition &other) const { 35 return other < *this; 36 } 37 inline constexpr bool operator<=(const MessagePosition &other) const { 38 return !(other < *this); 39 } 40 inline constexpr bool operator>=(const MessagePosition &other) const { 41 return !(*this < other); 42 } 43 inline constexpr bool operator==(const MessagePosition &other) const { 44 return (date == other.date) 45 && (fullId == other.fullId); 46 } 47 inline constexpr bool operator!=(const MessagePosition &other) const { 48 return !(*this == other); 49 } 50 }; 51 52 struct MessagesRange { 53 MessagePosition from; 54 MessagePosition till; 55 56 inline constexpr bool operator==(const MessagesRange &other) const { 57 return (from == other.from) 58 && (till == other.till); 59 } 60 inline constexpr bool operator!=(const MessagesRange &other) const { 61 return !(*this == other); 62 } 63 }; 64 65 constexpr auto MinDate = TimeId(0); 66 constexpr auto MaxDate = std::numeric_limits<TimeId>::max(); 67 constexpr auto MinMessagePosition = MessagePosition{ 68 .fullId = FullMsgId(NoChannel, 1), 69 .date = MinDate, 70 }; 71 constexpr auto MaxMessagePosition = MessagePosition{ 72 .fullId = FullMsgId(NoChannel, ServerMaxMsgId - 1), 73 .date = MaxDate, 74 }; 75 constexpr auto FullMessagesRange = MessagesRange{ 76 .from = MinMessagePosition, 77 .till = MaxMessagePosition, 78 }; 79 constexpr auto UnreadMessagePosition = MessagePosition{ 80 .fullId = FullMsgId(NoChannel, ShowAtUnreadMsgId), 81 .date = MinDate, 82 }; 83 84 struct MessagesSlice { 85 std::vector<FullMsgId> ids; 86 FullMsgId nearestToAround; 87 std::optional<int> skippedBefore; 88 std::optional<int> skippedAfter; 89 std::optional<int> fullCount; 90 }; 91 92 struct MessagesQuery { 93 MessagePosition aroundId; 94 int limitBefore = 0; 95 int limitAfter = 0; 96 }; 97 98 struct MessagesResult { 99 std::optional<int> count; 100 std::optional<int> skippedBefore; 101 std::optional<int> skippedAfter; 102 base::flat_set<MessagePosition> messageIds; 103 }; 104 105 struct MessagesSliceUpdate { 106 const base::flat_set<MessagePosition> *messages = nullptr; 107 MessagesRange range; 108 std::optional<int> count; 109 }; 110 111 class MessagesList { 112 public: 113 void addOne(MessagePosition messageId); 114 void addNew(MessagePosition messageId); 115 void addSlice( 116 std::vector<MessagePosition> &&messageIds, 117 MessagesRange noSkipRange, 118 std::optional<int> count); 119 void removeOne(MessagePosition messageId); 120 void removeAll(ChannelId channelId); 121 void removeLessThan(MessagePosition messageId); 122 void invalidate(); 123 void invalidateBottom(); 124 [[nodiscard]] rpl::producer<MessagesResult> query( 125 MessagesQuery &&query) const; 126 [[nodiscard]] rpl::producer<MessagesSliceUpdate> sliceUpdated() const; 127 128 [[nodiscard]] MessagesResult snapshot(MessagesQuery &&query) const; 129 [[nodiscard]] rpl::producer<MessagesResult> viewer( 130 MessagesQuery &&query) const; 131 132 [[nodiscard]] bool empty() const; 133 134 private: 135 struct Slice { 136 Slice( 137 base::flat_set<MessagePosition> &&messages, 138 MessagesRange range); 139 140 template <typename Range> 141 void merge( 142 const Range &moreMessages, 143 MessagesRange moreNoSkipRange); 144 145 base::flat_set<MessagePosition> messages; 146 MessagesRange range; 147 148 inline bool operator<(const Slice &other) const { 149 return range.from < other.range.from; 150 } 151 152 }; 153 154 template <typename Range> 155 int uniteAndAdd( 156 MessagesSliceUpdate &update, 157 base::flat_set<Slice>::iterator uniteFrom, 158 base::flat_set<Slice>::iterator uniteTill, 159 const Range &messages, 160 MessagesRange noSkipRange); 161 template <typename Range> 162 int addRangeItemsAndCountNew( 163 MessagesSliceUpdate &update, 164 const Range &messages, 165 MessagesRange noSkipRange); 166 template <typename Range> 167 void addRange( 168 const Range &messages, 169 MessagesRange noSkipRange, 170 std::optional<int> count, 171 bool incrementCount = false); 172 173 MessagesResult queryFromSlice( 174 const MessagesQuery &query, 175 const Slice &slice) const; 176 MessagesResult queryCurrent(const MessagesQuery &query) const; 177 178 std::optional<int> _count; 179 base::flat_set<Slice> _slices; 180 181 rpl::event_stream<MessagesSliceUpdate> _sliceUpdated; 182 183 }; 184 185 class MessagesSliceBuilder { 186 public: 187 using Key = MessagePosition; 188 189 MessagesSliceBuilder(Key key, int limitBefore, int limitAfter); 190 191 bool applyInitial(const MessagesResult &result); 192 bool applyUpdate(const MessagesSliceUpdate &update); 193 bool removeOne(MessagePosition messageId); 194 bool removeFromChannel(ChannelId channelId); 195 bool removeAll(); 196 bool invalidated(); 197 bool bottomInvalidated(); 198 199 void checkInsufficient(); 200 struct AroundData { 201 MessagePosition aroundId; 202 LoadDirection direction = LoadDirection::Around; 203 204 inline bool operator<(const AroundData &other) const { 205 return (aroundId < other.aroundId) 206 || ((aroundId == other.aroundId) 207 && (direction < other.direction)); 208 } 209 }; insufficientAround()210 auto insufficientAround() const { 211 return _insufficientAround.events(); 212 } 213 214 MessagesSlice snapshot() const; 215 216 private: 217 enum class RequestDirection { 218 Before, 219 After, 220 }; 221 void requestMessages(RequestDirection direction); 222 void requestMessagesCount(); 223 void fillSkippedAndSliceToLimits(); 224 void sliceToLimits(); 225 226 void mergeSliceData( 227 std::optional<int> count, 228 const base::flat_set<MessagePosition> &messageIds, 229 std::optional<int> skippedBefore = std::nullopt, 230 std::optional<int> skippedAfter = std::nullopt); 231 232 MessagePosition _key; 233 base::flat_set<MessagePosition> _ids; 234 MessagesRange _range; 235 std::optional<int> _fullCount; 236 std::optional<int> _skippedBefore; 237 std::optional<int> _skippedAfter; 238 int _limitBefore = 0; 239 int _limitAfter = 0; 240 241 rpl::event_stream<AroundData> _insufficientAround; 242 243 }; 244 245 } // namespace Data 246