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:
203
Telegram/SourceFiles/data/data_sparse_ids.h
Normal file
203
Telegram/SourceFiles/data/data_sparse_ids.h
Normal file
@@ -0,0 +1,203 @@
|
||||
/*
|
||||
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
|
||||
|
||||
#include "data/data_abstract_sparse_ids.h"
|
||||
#include "data/data_messages.h"
|
||||
|
||||
namespace Storage {
|
||||
struct SparseIdsListResult;
|
||||
struct SparseIdsSliceUpdate;
|
||||
} // namespace Storage
|
||||
|
||||
class SparseIdsSlice final : public AbstractSparseIds<base::flat_set<MsgId>> {
|
||||
public:
|
||||
using Key = MsgId;
|
||||
using AbstractSparseIds<base::flat_set<MsgId>>::AbstractSparseIds;
|
||||
|
||||
};
|
||||
|
||||
using SparseUnsortedIdsSlice = AbstractSparseIds<std::vector<MsgId>>;
|
||||
|
||||
class SparseIdsMergedSlice {
|
||||
public:
|
||||
using UniversalMsgId = MsgId;
|
||||
static constexpr MsgId kScheduledTopicId = ScheduledMaxMsgId;
|
||||
static constexpr MsgId kSavedMusicTopicId = ScheduledMaxMsgId + 1;
|
||||
|
||||
struct Key {
|
||||
Key(
|
||||
PeerId peerId,
|
||||
MsgId topicRootId,
|
||||
PeerId monoforumPeerId,
|
||||
PeerId migratedPeerId,
|
||||
UniversalMsgId universalId)
|
||||
: peerId(peerId)
|
||||
, topicRootId(topicRootId)
|
||||
, monoforumPeerId(monoforumPeerId)
|
||||
, migratedPeerId((topicRootId || monoforumPeerId) ? 0 : migratedPeerId)
|
||||
, universalId(universalId) {
|
||||
}
|
||||
|
||||
friend inline constexpr bool operator==(
|
||||
const Key &,
|
||||
const Key &) = default;
|
||||
|
||||
PeerId peerId = 0;
|
||||
MsgId topicRootId = 0;
|
||||
PeerId monoforumPeerId = 0;
|
||||
PeerId migratedPeerId = 0;
|
||||
UniversalMsgId universalId = 0;
|
||||
};
|
||||
|
||||
SparseIdsMergedSlice(Key key);
|
||||
SparseIdsMergedSlice(
|
||||
Key key,
|
||||
SparseIdsSlice part,
|
||||
std::optional<SparseIdsSlice> migrated);
|
||||
SparseIdsMergedSlice(
|
||||
Key key,
|
||||
SparseUnsortedIdsSlice unsorted);
|
||||
|
||||
std::optional<int> fullCount() const;
|
||||
std::optional<int> skippedBefore() const;
|
||||
std::optional<int> skippedAfter() const;
|
||||
std::optional<int> indexOf(FullMsgId fullId) const;
|
||||
int size() const;
|
||||
FullMsgId operator[](int index) const;
|
||||
std::optional<int> distance(const Key &a, const Key &b) const;
|
||||
std::optional<FullMsgId> nearest(UniversalMsgId id) const;
|
||||
|
||||
using SimpleViewerFunction = rpl::producer<SparseIdsSlice>(
|
||||
PeerId peerId,
|
||||
MsgId topicRootId,
|
||||
PeerId monoforumPeerId,
|
||||
SparseIdsSlice::Key simpleKey,
|
||||
int limitBefore,
|
||||
int limitAfter);
|
||||
static rpl::producer<SparseIdsMergedSlice> CreateViewer(
|
||||
SparseIdsMergedSlice::Key key,
|
||||
int limitBefore,
|
||||
int limitAfter,
|
||||
Fn<SimpleViewerFunction> simpleViewer);
|
||||
|
||||
private:
|
||||
static SparseIdsSlice::Key PartKey(const Key &key) {
|
||||
return (key.universalId < 0) ? 1 : key.universalId;
|
||||
}
|
||||
static SparseIdsSlice::Key MigratedKey(const Key &key) {
|
||||
return (key.universalId < 0)
|
||||
? (ServerMaxMsgId + key.universalId)
|
||||
: (key.universalId > 0) ? (ServerMaxMsgId - 1) : 0;
|
||||
}
|
||||
static std::optional<SparseIdsSlice> MigratedSlice(const Key &key) {
|
||||
return key.migratedPeerId
|
||||
? base::make_optional(SparseIdsSlice())
|
||||
: std::nullopt;
|
||||
}
|
||||
|
||||
static bool IsFromSlice(PeerId peerId, FullMsgId fullId) {
|
||||
return (peerId == fullId.peer);
|
||||
}
|
||||
static FullMsgId ComputeId(PeerId peerId, MsgId msgId) {
|
||||
return FullMsgId(peerId, msgId);
|
||||
}
|
||||
static FullMsgId ComputeId(const Key &key) {
|
||||
return (key.universalId >= 0)
|
||||
? ComputeId(key.peerId, key.universalId)
|
||||
: ComputeId(key.migratedPeerId, ServerMaxMsgId + key.universalId);
|
||||
}
|
||||
static std::optional<int> Add(
|
||||
const std::optional<int> &a,
|
||||
const std::optional<int> &b) {
|
||||
return (a && b) ? base::make_optional(*a + *b) : std::nullopt;
|
||||
}
|
||||
|
||||
bool isFromPart(FullMsgId fullId) const {
|
||||
return IsFromSlice(_key.peerId, fullId);
|
||||
}
|
||||
bool isFromMigrated(FullMsgId fullId) const {
|
||||
return _migrated
|
||||
? IsFromSlice(_key.migratedPeerId, fullId)
|
||||
: false;
|
||||
}
|
||||
int migratedSize() const {
|
||||
return isolatedInPart() ? 0 : _migrated->size();
|
||||
}
|
||||
bool isolatedInPart() const {
|
||||
return IsServerMsgId(_key.universalId)
|
||||
&& (!_migrated || _part.skippedBefore() != 0);
|
||||
}
|
||||
bool isolatedInMigrated() const {
|
||||
return IsServerMsgId(ServerMaxMsgId + _key.universalId)
|
||||
&& (_migrated->skippedAfter() != 0);
|
||||
}
|
||||
|
||||
Key _key;
|
||||
SparseIdsSlice _part;
|
||||
std::optional<SparseIdsSlice> _migrated;
|
||||
std::optional<SparseUnsortedIdsSlice> _unsorted;
|
||||
|
||||
};
|
||||
|
||||
class SparseIdsSliceBuilder {
|
||||
public:
|
||||
using Key = SparseIdsSlice::Key;
|
||||
|
||||
SparseIdsSliceBuilder(Key key, int limitBefore, int limitAfter);
|
||||
|
||||
bool applyInitial(const Storage::SparseIdsListResult &result);
|
||||
bool applyUpdate(const Storage::SparseIdsSliceUpdate &update);
|
||||
bool removeOne(MsgId messageId);
|
||||
bool removeAll();
|
||||
bool invalidateBottom();
|
||||
|
||||
void checkInsufficient();
|
||||
struct AroundData {
|
||||
MsgId aroundId = 0;
|
||||
Data::LoadDirection direction = Data::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();
|
||||
}
|
||||
|
||||
SparseIdsSlice 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<MsgId> &messageIds,
|
||||
std::optional<int> skippedBefore = std::nullopt,
|
||||
std::optional<int> skippedAfter = std::nullopt);
|
||||
|
||||
Key _key;
|
||||
base::flat_set<MsgId> _ids;
|
||||
std::optional<int> _fullCount;
|
||||
std::optional<int> _skippedBefore;
|
||||
std::optional<int> _skippedAfter;
|
||||
int _limitBefore = 0;
|
||||
int _limitAfter = 0;
|
||||
|
||||
rpl::event_stream<AroundData> _insufficientAround;
|
||||
|
||||
};
|
||||
Reference in New Issue
Block a user