data_messages.h 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. /*
  2. This file is part of Telegram Desktop,
  3. the official desktop application for the Telegram messaging service.
  4. For license and copyright information please follow this link:
  5. https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
  6. */
  7. #pragma once
  8. namespace Data {
  9. enum class LoadDirection : char {
  10. Around,
  11. Before,
  12. After,
  13. };
  14. struct MessagePosition {
  15. FullMsgId fullId;
  16. TimeId date = 0;
  17. explicit operator bool() const {
  18. return (fullId.msg != 0);
  19. }
  20. inline constexpr bool operator<(const MessagePosition &other) const {
  21. if (date < other.date) {
  22. return true;
  23. } else if (other.date < date) {
  24. return false;
  25. }
  26. return (fullId < other.fullId);
  27. }
  28. inline constexpr bool operator>(const MessagePosition &other) const {
  29. return other < *this;
  30. }
  31. inline constexpr bool operator<=(const MessagePosition &other) const {
  32. return !(other < *this);
  33. }
  34. inline constexpr bool operator>=(const MessagePosition &other) const {
  35. return !(*this < other);
  36. }
  37. inline constexpr bool operator==(const MessagePosition &other) const {
  38. return (date == other.date)
  39. && (fullId == other.fullId);
  40. }
  41. inline constexpr bool operator!=(const MessagePosition &other) const {
  42. return !(*this == other);
  43. }
  44. };
  45. struct MessagesRange {
  46. MessagePosition from;
  47. MessagePosition till;
  48. inline constexpr bool operator==(const MessagesRange &other) const {
  49. return (from == other.from)
  50. && (till == other.till);
  51. }
  52. inline constexpr bool operator!=(const MessagesRange &other) const {
  53. return !(*this == other);
  54. }
  55. };
  56. constexpr auto MinDate = TimeId(0);
  57. constexpr auto MaxDate = std::numeric_limits<TimeId>::max();
  58. constexpr auto MinMessagePosition = MessagePosition{
  59. .fullId = FullMsgId(PeerId(), 1),
  60. .date = MinDate,
  61. };
  62. constexpr auto MaxMessagePosition = MessagePosition{
  63. .fullId = FullMsgId(PeerId(), ServerMaxMsgId - 1),
  64. .date = MaxDate,
  65. };
  66. constexpr auto FullMessagesRange = MessagesRange{
  67. .from = MinMessagePosition,
  68. .till = MaxMessagePosition,
  69. };
  70. constexpr auto UnreadMessagePosition = MessagePosition{
  71. .fullId = FullMsgId(PeerId(), ShowAtUnreadMsgId),
  72. .date = MinDate,
  73. };
  74. struct MessagesSlice {
  75. std::vector<FullMsgId> ids;
  76. FullMsgId nearestToAround;
  77. std::optional<int> skippedBefore;
  78. std::optional<int> skippedAfter;
  79. std::optional<int> fullCount;
  80. };
  81. struct MessagesQuery {
  82. MessagePosition aroundId;
  83. int limitBefore = 0;
  84. int limitAfter = 0;
  85. };
  86. struct MessagesResult {
  87. std::optional<int> count;
  88. std::optional<int> skippedBefore;
  89. std::optional<int> skippedAfter;
  90. base::flat_set<MessagePosition> messageIds;
  91. };
  92. struct MessagesSliceUpdate {
  93. const base::flat_set<MessagePosition> *messages = nullptr;
  94. MessagesRange range;
  95. std::optional<int> count;
  96. };
  97. class MessagesList {
  98. public:
  99. void addOne(MessagePosition messageId);
  100. void addNew(MessagePosition messageId);
  101. void addSlice(
  102. std::vector<MessagePosition> &&messageIds,
  103. MessagesRange noSkipRange,
  104. std::optional<int> count);
  105. void removeOne(MessagePosition messageId);
  106. void removeLessThan(MessagePosition messageId);
  107. void invalidate();
  108. void invalidateBottom();
  109. [[nodiscard]] rpl::producer<MessagesResult> query(
  110. MessagesQuery &&query) const;
  111. [[nodiscard]] rpl::producer<MessagesSliceUpdate> sliceUpdated() const;
  112. [[nodiscard]] MessagesResult snapshot(MessagesQuery &&query) const;
  113. [[nodiscard]] rpl::producer<MessagesResult> viewer(
  114. MessagesQuery &&query) const;
  115. [[nodiscard]] bool empty() const;
  116. private:
  117. struct Slice {
  118. Slice(
  119. base::flat_set<MessagePosition> &&messages,
  120. MessagesRange range);
  121. template <typename Range>
  122. void merge(
  123. const Range &moreMessages,
  124. MessagesRange moreNoSkipRange);
  125. base::flat_set<MessagePosition> messages;
  126. MessagesRange range;
  127. inline bool operator<(const Slice &other) const {
  128. return range.from < other.range.from;
  129. }
  130. };
  131. template <typename Range>
  132. int uniteAndAdd(
  133. MessagesSliceUpdate &update,
  134. base::flat_set<Slice>::iterator uniteFrom,
  135. base::flat_set<Slice>::iterator uniteTill,
  136. const Range &messages,
  137. MessagesRange noSkipRange);
  138. template <typename Range>
  139. int addRangeItemsAndCountNew(
  140. MessagesSliceUpdate &update,
  141. const Range &messages,
  142. MessagesRange noSkipRange);
  143. template <typename Range>
  144. void addRange(
  145. const Range &messages,
  146. MessagesRange noSkipRange,
  147. std::optional<int> count,
  148. bool incrementCount = false);
  149. MessagesResult queryFromSlice(
  150. const MessagesQuery &query,
  151. const Slice &slice) const;
  152. MessagesResult queryCurrent(const MessagesQuery &query) const;
  153. std::optional<int> _count;
  154. base::flat_set<Slice> _slices;
  155. rpl::event_stream<MessagesSliceUpdate> _sliceUpdated;
  156. };
  157. class MessagesSliceBuilder {
  158. public:
  159. using Key = MessagePosition;
  160. MessagesSliceBuilder(Key key, int limitBefore, int limitAfter);
  161. bool applyInitial(const MessagesResult &result);
  162. bool applyUpdate(const MessagesSliceUpdate &update);
  163. bool removeOne(MessagePosition messageId);
  164. bool removeAll();
  165. bool invalidated();
  166. bool bottomInvalidated();
  167. void checkInsufficient();
  168. struct AroundData {
  169. MessagePosition aroundId;
  170. LoadDirection direction = LoadDirection::Around;
  171. inline bool operator<(const AroundData &other) const {
  172. return (aroundId < other.aroundId)
  173. || ((aroundId == other.aroundId)
  174. && (direction < other.direction));
  175. }
  176. };
  177. auto insufficientAround() const {
  178. return _insufficientAround.events();
  179. }
  180. MessagesSlice snapshot() const;
  181. private:
  182. enum class RequestDirection {
  183. Before,
  184. After,
  185. };
  186. void requestMessages(RequestDirection direction);
  187. void requestMessagesCount();
  188. void fillSkippedAndSliceToLimits();
  189. void sliceToLimits();
  190. void mergeSliceData(
  191. std::optional<int> count,
  192. const base::flat_set<MessagePosition> &messageIds,
  193. std::optional<int> skippedBefore = std::nullopt,
  194. std::optional<int> skippedAfter = std::nullopt);
  195. MessagePosition _key;
  196. base::flat_set<MessagePosition> _ids;
  197. MessagesRange _range;
  198. std::optional<int> _fullCount;
  199. std::optional<int> _skippedBefore;
  200. std::optional<int> _skippedAfter;
  201. int _limitBefore = 0;
  202. int _limitAfter = 0;
  203. rpl::event_stream<AroundData> _insufficientAround;
  204. };
  205. } // namespace Data