tdesktop/Telegram/SourceFiles/data/data_messages.h

256 lines
6.0 KiB
C
Raw Normal View History

2018-01-09 17:08:31 +00:00
/*
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 {
constexpr MessagePosition() = default;
constexpr MessagePosition(TimeId date, FullMsgId fullId)
: fullId(fullId)
, date(date) {
}
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);
}
FullMsgId fullId;
TimeId date = 0;
};
struct MessagesRange {
constexpr MessagesRange() = default;
constexpr MessagesRange(MessagePosition from, MessagePosition till)
: from(from)
, till(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);
}
MessagePosition from;
MessagePosition till;
};
constexpr auto MinDate = TimeId(0);
2018-01-09 17:08:31 +00:00
constexpr auto MaxDate = std::numeric_limits<TimeId>::max();
2018-02-04 19:57:03 +00:00
constexpr auto MinMessagePosition = MessagePosition(
MinDate,
FullMsgId(NoChannel, 1));
2018-02-04 19:57:03 +00:00
constexpr auto MaxMessagePosition = MessagePosition(
MaxDate,
FullMsgId(NoChannel, ServerMaxMsgId - 1));
2018-01-09 17:08:31 +00:00
constexpr auto FullMessagesRange = MessagesRange(
MinMessagePosition,
MaxMessagePosition);
2018-02-04 19:57:03 +00:00
constexpr auto UnreadMessagePosition = MessagePosition(
MinDate,
FullMsgId(NoChannel, ShowAtUnreadMsgId));
2018-01-09 17:08:31 +00:00
struct MessagesSlice {
std::vector<FullMsgId> ids;
2018-09-21 16:28:46 +00:00
std::optional<int> skippedBefore;
std::optional<int> skippedAfter;
std::optional<int> fullCount;
2018-01-09 17:08:31 +00:00
};
struct MessagesQuery {
MessagesQuery(
MessagePosition aroundId,
int limitBefore,
int limitAfter)
: aroundId(aroundId)
, limitBefore(limitBefore)
, limitAfter(limitAfter) {
}
MessagePosition aroundId;
int limitBefore = 0;
int limitAfter = 0;
};
struct MessagesResult {
2018-09-21 16:28:46 +00:00
std::optional<int> count;
std::optional<int> skippedBefore;
std::optional<int> skippedAfter;
2018-01-09 17:08:31 +00:00
base::flat_set<MessagePosition> messageIds;
};
struct MessagesSliceUpdate {
const base::flat_set<MessagePosition> *messages = nullptr;
MessagesRange range;
2018-09-21 16:28:46 +00:00
std::optional<int> count;
2018-01-09 17:08:31 +00:00
};
class MessagesList {
public:
void addNew(MessagePosition messageId);
void addSlice(
std::vector<MessagePosition> &&messageIds,
MessagesRange noSkipRange,
2018-09-21 16:28:46 +00:00
std::optional<int> count);
2018-01-09 17:08:31 +00:00
void removeOne(MessagePosition messageId);
void removeAll(ChannelId channelId);
void invalidate();
void invalidateBottom();
2018-01-09 17:08:31 +00:00
rpl::producer<MessagesResult> query(MessagesQuery &&query) const;
rpl::producer<MessagesSliceUpdate> sliceUpdated() 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,
2018-09-21 16:28:46 +00:00
std::optional<int> count,
2018-01-09 17:08:31 +00:00
bool incrementCount = false);
MessagesResult queryFromSlice(
const MessagesQuery &query,
const Slice &slice) const;
2018-09-21 16:28:46 +00:00
std::optional<int> _count;
2018-01-09 17:08:31 +00:00
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 removeFromChannel(ChannelId channelId);
bool removeAll();
bool invalidated();
bool bottomInvalidated();
2018-01-09 17:08:31 +00:00
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(
2018-09-21 16:28:46 +00:00
std::optional<int> count,
2018-01-09 17:08:31 +00:00
const base::flat_set<MessagePosition> &messageIds,
2018-09-21 16:28:46 +00:00
std::optional<int> skippedBefore = std::nullopt,
std::optional<int> skippedAfter = std::nullopt);
2018-01-09 17:08:31 +00:00
MessagePosition _key;
base::flat_set<MessagePosition> _ids;
MessagesRange _range;
2018-09-21 16:28:46 +00:00
std::optional<int> _fullCount;
std::optional<int> _skippedBefore;
std::optional<int> _skippedAfter;
2018-01-09 17:08:31 +00:00
int _limitBefore = 0;
int _limitAfter = 0;
rpl::event_stream<AroundData> _insufficientAround;
};
} // namespace Data