| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243 |
- /*
- This file is part of Telegram Desktop,
- the official desktop application for the Telegram messaging service.
- For license and copyright information please follow this link:
- https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
- */
- #pragma once
- namespace Data {
- enum class LoadDirection : char {
- Around,
- Before,
- After,
- };
- struct MessagePosition {
- FullMsgId fullId;
- TimeId date = 0;
- explicit operator bool() const {
- return (fullId.msg != 0);
- }
- inline constexpr bool operator<(const MessagePosition &other) const {
- if (date < other.date) {
- return true;
- } else if (other.date < date) {
- return false;
- }
- return (fullId < other.fullId);
- }
- inline constexpr bool operator>(const MessagePosition &other) const {
- return other < *this;
- }
- inline constexpr bool operator<=(const MessagePosition &other) const {
- return !(other < *this);
- }
- inline constexpr bool operator>=(const MessagePosition &other) const {
- return !(*this < other);
- }
- inline constexpr bool operator==(const MessagePosition &other) const {
- return (date == other.date)
- && (fullId == other.fullId);
- }
- inline constexpr bool operator!=(const MessagePosition &other) const {
- return !(*this == other);
- }
- };
- struct MessagesRange {
- MessagePosition from;
- MessagePosition till;
- inline constexpr bool operator==(const MessagesRange &other) const {
- return (from == other.from)
- && (till == other.till);
- }
- inline constexpr bool operator!=(const MessagesRange &other) const {
- return !(*this == other);
- }
- };
- constexpr auto MinDate = TimeId(0);
- constexpr auto MaxDate = std::numeric_limits<TimeId>::max();
- constexpr auto MinMessagePosition = MessagePosition{
- .fullId = FullMsgId(PeerId(), 1),
- .date = MinDate,
- };
- constexpr auto MaxMessagePosition = MessagePosition{
- .fullId = FullMsgId(PeerId(), ServerMaxMsgId - 1),
- .date = MaxDate,
- };
- constexpr auto FullMessagesRange = MessagesRange{
- .from = MinMessagePosition,
- .till = MaxMessagePosition,
- };
- constexpr auto UnreadMessagePosition = MessagePosition{
- .fullId = FullMsgId(PeerId(), ShowAtUnreadMsgId),
- .date = MinDate,
- };
- struct MessagesSlice {
- std::vector<FullMsgId> ids;
- FullMsgId nearestToAround;
- std::optional<int> skippedBefore;
- std::optional<int> skippedAfter;
- std::optional<int> fullCount;
- };
- struct MessagesQuery {
- MessagePosition aroundId;
- int limitBefore = 0;
- int limitAfter = 0;
- };
- struct MessagesResult {
- std::optional<int> count;
- std::optional<int> skippedBefore;
- std::optional<int> skippedAfter;
- base::flat_set<MessagePosition> messageIds;
- };
- struct MessagesSliceUpdate {
- const base::flat_set<MessagePosition> *messages = nullptr;
- MessagesRange range;
- std::optional<int> count;
- };
- class MessagesList {
- public:
- void addOne(MessagePosition messageId);
- void addNew(MessagePosition messageId);
- void addSlice(
- std::vector<MessagePosition> &&messageIds,
- MessagesRange noSkipRange,
- std::optional<int> count);
- void removeOne(MessagePosition messageId);
- void removeLessThan(MessagePosition messageId);
- void invalidate();
- void invalidateBottom();
- [[nodiscard]] rpl::producer<MessagesResult> query(
- MessagesQuery &&query) const;
- [[nodiscard]] rpl::producer<MessagesSliceUpdate> sliceUpdated() const;
- [[nodiscard]] MessagesResult snapshot(MessagesQuery &&query) const;
- [[nodiscard]] rpl::producer<MessagesResult> viewer(
- MessagesQuery &&query) const;
- [[nodiscard]] bool empty() const;
- private:
- struct Slice {
- Slice(
- base::flat_set<MessagePosition> &&messages,
- MessagesRange range);
- template <typename Range>
- void merge(
- const Range &moreMessages,
- MessagesRange moreNoSkipRange);
- base::flat_set<MessagePosition> messages;
- MessagesRange range;
- inline bool operator<(const Slice &other) const {
- return range.from < other.range.from;
- }
- };
- template <typename Range>
- int uniteAndAdd(
- MessagesSliceUpdate &update,
- base::flat_set<Slice>::iterator uniteFrom,
- base::flat_set<Slice>::iterator uniteTill,
- const Range &messages,
- MessagesRange noSkipRange);
- template <typename Range>
- int addRangeItemsAndCountNew(
- MessagesSliceUpdate &update,
- const Range &messages,
- MessagesRange noSkipRange);
- template <typename Range>
- void addRange(
- const Range &messages,
- MessagesRange noSkipRange,
- std::optional<int> count,
- bool incrementCount = false);
- MessagesResult queryFromSlice(
- const MessagesQuery &query,
- const Slice &slice) const;
- MessagesResult queryCurrent(const MessagesQuery &query) const;
- std::optional<int> _count;
- base::flat_set<Slice> _slices;
- rpl::event_stream<MessagesSliceUpdate> _sliceUpdated;
- };
- class MessagesSliceBuilder {
- public:
- using Key = MessagePosition;
- MessagesSliceBuilder(Key key, int limitBefore, int limitAfter);
- bool applyInitial(const MessagesResult &result);
- bool applyUpdate(const MessagesSliceUpdate &update);
- bool removeOne(MessagePosition messageId);
- bool removeAll();
- bool invalidated();
- bool bottomInvalidated();
- void checkInsufficient();
- struct AroundData {
- MessagePosition aroundId;
- LoadDirection direction = LoadDirection::Around;
- inline bool operator<(const AroundData &other) const {
- return (aroundId < other.aroundId)
- || ((aroundId == other.aroundId)
- && (direction < other.direction));
- }
- };
- auto insufficientAround() const {
- return _insufficientAround.events();
- }
- MessagesSlice snapshot() const;
- private:
- enum class RequestDirection {
- Before,
- After,
- };
- void requestMessages(RequestDirection direction);
- void requestMessagesCount();
- void fillSkippedAndSliceToLimits();
- void sliceToLimits();
- void mergeSliceData(
- std::optional<int> count,
- const base::flat_set<MessagePosition> &messageIds,
- std::optional<int> skippedBefore = std::nullopt,
- std::optional<int> skippedAfter = std::nullopt);
- MessagePosition _key;
- base::flat_set<MessagePosition> _ids;
- MessagesRange _range;
- std::optional<int> _fullCount;
- std::optional<int> _skippedBefore;
- std::optional<int> _skippedAfter;
- int _limitBefore = 0;
- int _limitAfter = 0;
- rpl::event_stream<AroundData> _insufficientAround;
- };
- } // namespace Data
|