init
Some checks failed
Docker. / Ubuntu (push) Has been cancelled
User-agent updater. / User-agent (push) Failing after 15s
Lock Threads / lock (push) Failing after 10s
Waiting for answer. / waiting-for-answer (push) Failing after 22s
Needs user action. / needs-user-action (push) Failing after 8s
Can't reproduce. / cant-reproduce (push) Failing after 8s
Close stale issues and PRs / stale (push) Has been cancelled
Some checks failed
Docker. / Ubuntu (push) Has been cancelled
User-agent updater. / User-agent (push) Failing after 15s
Lock Threads / lock (push) Failing after 10s
Waiting for answer. / waiting-for-answer (push) Failing after 22s
Needs user action. / needs-user-action (push) Failing after 8s
Can't reproduce. / cant-reproduce (push) Failing after 8s
Close stale issues and PRs / stale (push) Has been cancelled
This commit is contained in:
243
Telegram/SourceFiles/data/data_messages.h
Normal file
243
Telegram/SourceFiles/data/data_messages.h
Normal file
@@ -0,0 +1,243 @@
|
||||
/*
|
||||
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
|
||||
Reference in New Issue
Block a user