2018-12-31 20:04:05 +01:00
|
|
|
//
|
2021-01-01 13:57:46 +01:00
|
|
|
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021
|
2018-12-31 20:04:05 +01:00
|
|
|
//
|
|
|
|
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
|
|
|
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|
|
|
//
|
|
|
|
#pragma once
|
|
|
|
|
2019-12-01 17:03:51 +01:00
|
|
|
#include "td/telegram/ScheduledServerMessageId.h"
|
2019-11-26 17:33:18 +01:00
|
|
|
#include "td/telegram/ServerMessageId.h"
|
2018-12-31 20:04:05 +01:00
|
|
|
|
|
|
|
#include "td/utils/common.h"
|
|
|
|
#include "td/utils/StringBuilder.h"
|
|
|
|
|
|
|
|
#include <functional>
|
|
|
|
#include <limits>
|
|
|
|
#include <type_traits>
|
|
|
|
|
|
|
|
namespace td {
|
|
|
|
|
2019-12-02 21:29:08 +01:00
|
|
|
enum class MessageType : int32 { None, Server, YetUnsent, Local };
|
2018-05-01 19:13:36 +02:00
|
|
|
|
2018-12-31 20:04:05 +01:00
|
|
|
class MessageId {
|
|
|
|
int64 id = 0;
|
|
|
|
|
|
|
|
static constexpr int32 SERVER_ID_SHIFT = 20;
|
2019-11-26 16:52:59 +01:00
|
|
|
static constexpr int32 SHORT_TYPE_MASK = (1 << 2) - 1;
|
2018-12-31 20:04:05 +01:00
|
|
|
static constexpr int32 TYPE_MASK = (1 << 3) - 1;
|
|
|
|
static constexpr int32 FULL_TYPE_MASK = (1 << SERVER_ID_SHIFT) - 1;
|
2019-11-26 16:52:59 +01:00
|
|
|
static constexpr int32 SCHEDULED_MASK = 4;
|
2018-12-31 20:04:05 +01:00
|
|
|
static constexpr int32 TYPE_YET_UNSENT = 1;
|
|
|
|
static constexpr int32 TYPE_LOCAL = 2;
|
|
|
|
|
2019-11-26 01:32:05 +01:00
|
|
|
friend StringBuilder &operator<<(StringBuilder &string_builder, MessageId message_id);
|
|
|
|
|
2019-11-26 16:52:59 +01:00
|
|
|
// ordinary message ID layout
|
|
|
|
// |-------31--------|---17---|1|--2-|
|
|
|
|
// |server_message_id|local_id|0|type|
|
|
|
|
|
|
|
|
// scheduled message ID layout
|
|
|
|
// |-------30-------|----18---|1|--2-|
|
|
|
|
// |send_date-2**30 |server_id|1|type|
|
|
|
|
|
2019-11-26 20:35:16 +01:00
|
|
|
ServerMessageId get_server_message_id_force() const;
|
|
|
|
|
2019-12-01 17:03:51 +01:00
|
|
|
ScheduledServerMessageId get_scheduled_server_message_id_force() const {
|
2019-11-26 21:47:13 +01:00
|
|
|
CHECK(is_scheduled());
|
2019-12-01 17:03:51 +01:00
|
|
|
return ScheduledServerMessageId(static_cast<int32>((id >> 3) & ((1 << 18) - 1)));
|
2019-11-26 20:35:16 +01:00
|
|
|
}
|
|
|
|
|
2019-11-26 01:32:05 +01:00
|
|
|
public:
|
2018-12-31 20:04:05 +01:00
|
|
|
MessageId() = default;
|
|
|
|
|
|
|
|
explicit MessageId(ServerMessageId server_message_id)
|
|
|
|
: id(static_cast<int64>(server_message_id.get()) << SERVER_ID_SHIFT) {
|
|
|
|
}
|
|
|
|
|
2019-12-02 21:29:08 +01:00
|
|
|
MessageId(ScheduledServerMessageId server_message_id, int32 send_date, bool force = false);
|
2019-11-26 16:52:59 +01:00
|
|
|
|
2018-12-31 20:04:05 +01:00
|
|
|
explicit constexpr MessageId(int64 message_id) : id(message_id) {
|
|
|
|
}
|
|
|
|
template <class T, typename = std::enable_if_t<std::is_convertible<T, int64>::value>>
|
|
|
|
MessageId(T message_id) = delete;
|
|
|
|
|
|
|
|
static constexpr MessageId min() {
|
2019-11-29 13:03:03 +01:00
|
|
|
return MessageId(static_cast<int64>(MessageId::TYPE_YET_UNSENT));
|
2018-12-31 20:04:05 +01:00
|
|
|
}
|
|
|
|
static constexpr MessageId max() {
|
|
|
|
return MessageId(static_cast<int64>(std::numeric_limits<int32>::max()) << SERVER_ID_SHIFT);
|
|
|
|
}
|
|
|
|
|
2019-11-26 17:18:57 +01:00
|
|
|
bool is_valid() const;
|
2018-12-31 20:04:05 +01:00
|
|
|
|
2019-11-26 17:18:57 +01:00
|
|
|
bool is_valid_scheduled() const;
|
2019-11-26 16:52:59 +01:00
|
|
|
|
2018-12-31 20:04:05 +01:00
|
|
|
int64 get() const {
|
|
|
|
return id;
|
|
|
|
}
|
|
|
|
|
2019-11-26 17:18:57 +01:00
|
|
|
MessageType get_type() const;
|
2018-05-01 19:13:36 +02:00
|
|
|
|
2019-11-26 16:52:59 +01:00
|
|
|
bool is_scheduled() const {
|
|
|
|
return (id & SCHEDULED_MASK) != 0;
|
|
|
|
}
|
|
|
|
|
2018-12-31 20:04:05 +01:00
|
|
|
bool is_yet_unsent() const {
|
2019-11-26 16:52:59 +01:00
|
|
|
CHECK(is_valid() || is_scheduled());
|
|
|
|
return (id & SHORT_TYPE_MASK) == TYPE_YET_UNSENT;
|
2018-12-31 20:04:05 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
bool is_local() const {
|
2019-11-26 16:52:59 +01:00
|
|
|
CHECK(is_valid() || is_scheduled());
|
|
|
|
return (id & SHORT_TYPE_MASK) == TYPE_LOCAL;
|
2018-12-31 20:04:05 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
bool is_server() const {
|
|
|
|
CHECK(is_valid());
|
|
|
|
return (id & FULL_TYPE_MASK) == 0;
|
|
|
|
}
|
|
|
|
|
2019-11-26 16:52:59 +01:00
|
|
|
bool is_scheduled_server() const {
|
|
|
|
CHECK(is_valid_scheduled());
|
|
|
|
return (id & SHORT_TYPE_MASK) == 0;
|
|
|
|
}
|
|
|
|
|
2019-11-29 13:03:03 +01:00
|
|
|
bool is_any_server() const {
|
|
|
|
return is_scheduled() ? is_scheduled_server() : is_server();
|
|
|
|
}
|
|
|
|
|
2019-11-26 20:35:16 +01:00
|
|
|
ServerMessageId get_server_message_id() const {
|
|
|
|
CHECK(id == 0 || is_server());
|
|
|
|
return get_server_message_id_force();
|
|
|
|
}
|
2018-12-31 20:04:05 +01:00
|
|
|
|
2019-11-29 17:24:45 +01:00
|
|
|
// returns greatest server message identifier not bigger than this message identifier
|
2018-05-03 10:57:19 +02:00
|
|
|
MessageId get_prev_server_message_id() const {
|
2019-11-26 21:47:13 +01:00
|
|
|
CHECK(!is_scheduled());
|
2018-05-03 10:57:19 +02:00
|
|
|
return MessageId(id & ~FULL_TYPE_MASK);
|
|
|
|
}
|
|
|
|
|
2019-11-29 17:24:45 +01:00
|
|
|
// returns smallest server message identifier not less than this message identifier
|
2018-12-31 20:04:05 +01:00
|
|
|
MessageId get_next_server_message_id() const {
|
2019-11-26 21:47:13 +01:00
|
|
|
CHECK(!is_scheduled());
|
2018-12-31 20:04:05 +01:00
|
|
|
return MessageId((id + FULL_TYPE_MASK) & ~FULL_TYPE_MASK);
|
|
|
|
}
|
|
|
|
|
2019-11-26 17:18:57 +01:00
|
|
|
MessageId get_next_message_id(MessageType type) const;
|
2019-11-26 01:32:05 +01:00
|
|
|
|
2019-12-01 17:03:51 +01:00
|
|
|
ScheduledServerMessageId get_scheduled_server_message_id() const {
|
2019-11-26 16:52:59 +01:00
|
|
|
CHECK(is_scheduled_server());
|
2019-11-26 20:35:16 +01:00
|
|
|
return get_scheduled_server_message_id_force();
|
2019-11-26 16:52:59 +01:00
|
|
|
}
|
|
|
|
|
2019-12-02 21:29:08 +01:00
|
|
|
int32 get_scheduled_message_date() const {
|
|
|
|
CHECK(is_valid_scheduled());
|
|
|
|
return static_cast<int32>(id >> 21) + (1 << 30);
|
|
|
|
}
|
|
|
|
|
2018-12-31 20:04:05 +01:00
|
|
|
bool operator==(const MessageId &other) const {
|
|
|
|
return id == other.id;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool operator!=(const MessageId &other) const {
|
|
|
|
return id != other.id;
|
|
|
|
}
|
|
|
|
|
2019-11-29 17:11:06 +01:00
|
|
|
friend bool operator<(const MessageId &lhs, const MessageId &rhs) {
|
|
|
|
CHECK(lhs.is_scheduled() == rhs.is_scheduled());
|
|
|
|
return lhs.id < rhs.id;
|
|
|
|
}
|
|
|
|
|
|
|
|
friend bool operator>(const MessageId &lhs, const MessageId &rhs) {
|
2020-03-12 16:36:47 +01:00
|
|
|
CHECK(lhs.is_scheduled() == rhs.is_scheduled());
|
|
|
|
return lhs.id > rhs.id;
|
2019-11-29 17:11:06 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
friend bool operator<=(const MessageId &lhs, const MessageId &rhs) {
|
2020-03-12 16:36:47 +01:00
|
|
|
CHECK(lhs.is_scheduled() == rhs.is_scheduled());
|
|
|
|
return lhs.id <= rhs.id;
|
2019-11-29 17:11:06 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
friend bool operator>=(const MessageId &lhs, const MessageId &rhs) {
|
2020-03-12 16:36:47 +01:00
|
|
|
CHECK(lhs.is_scheduled() == rhs.is_scheduled());
|
|
|
|
return lhs.id >= rhs.id;
|
2019-11-29 17:11:06 +01:00
|
|
|
}
|
|
|
|
|
2018-12-31 20:04:05 +01:00
|
|
|
template <class StorerT>
|
|
|
|
void store(StorerT &storer) const {
|
|
|
|
storer.store_long(id);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class ParserT>
|
|
|
|
void parse(ParserT &parser) {
|
|
|
|
id = parser.fetch_long();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
struct MessageIdHash {
|
|
|
|
std::size_t operator()(MessageId message_id) const {
|
|
|
|
return std::hash<int64>()(message_id.get());
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
} // namespace td
|