1 /*
2 This file is part of Telegram Desktop,
3 the official desktop application for the Telegram messaging service.
4 
5 For license and copyright information please follow this link:
6 https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
7 */
8 #pragma once
9 
10 using BareId = uint64;
11 
12 struct PeerIdZeroHelper {
13 };
14 using PeerIdZero = void(PeerIdZeroHelper::*)();
15 
16 template <uint8 Shift>
17 struct ChatIdType {
18 	BareId bare = 0;
19 	static constexpr BareId kShift = Shift;
20 	static constexpr BareId kReservedBit = BareId(0x80);
21 	static_assert((Shift & kReservedBit) == 0, "Last bit is reserved.");
22 
23 	constexpr ChatIdType() noexcept = default;
24 	//constexpr ChatIdType(PeerIdZero) noexcept { // UserId id = 0;
25 	//}
ChatIdTypeChatIdType26 	constexpr ChatIdType(BareId value) noexcept : bare(value) {
27 	}
ChatIdTypeChatIdType28 	constexpr ChatIdType(MTPlong value) noexcept : bare(value.v) {
29 	}
30 
31 	[[nodiscard]] constexpr explicit operator bool() const noexcept {
32 		return (bare != 0);
33 	}
34 	[[nodiscard]] constexpr bool operator!() const noexcept {
35 		return !bare;
36 	}
37 
38 };
39 
40 template <uchar Shift>
41 [[nodiscard]] inline constexpr bool operator==(
42 		ChatIdType<Shift> a,
43 		ChatIdType<Shift> b) noexcept {
44 	return (a.bare == b.bare);
45 }
46 
47 template <uchar Shift>
48 [[nodiscard]] inline constexpr bool operator!=(
49 		ChatIdType<Shift> a,
50 		ChatIdType<Shift> b) noexcept {
51 	return (a.bare != b.bare);
52 }
53 
54 template <uchar Shift>
55 [[nodiscard]] inline constexpr bool operator<(
56 		ChatIdType<Shift> a,
57 		ChatIdType<Shift> b) noexcept {
58 	return (a.bare < b.bare);
59 }
60 
61 template <uchar Shift>
62 [[nodiscard]] inline constexpr bool operator>(
63 		ChatIdType<Shift> a,
64 		ChatIdType<Shift> b) noexcept {
65 	return (a.bare > b.bare);
66 }
67 
68 template <uchar Shift>
69 [[nodiscard]] inline constexpr bool operator<=(
70 		ChatIdType<Shift> a,
71 		ChatIdType<Shift> b) noexcept {
72 	return (a.bare <= b.bare);
73 }
74 
75 template <uchar Shift>
76 [[nodiscard]] inline constexpr bool operator>=(
77 		ChatIdType<Shift> a,
78 		ChatIdType<Shift> b) noexcept {
79 	return (a.bare >= b.bare);
80 }
81 
82 template <uchar Shift>
83 [[nodiscard]] inline constexpr bool operator==(
84 		ChatIdType<Shift> a,
85 		PeerIdZero) noexcept {
86 	return (a.bare == 0);
87 }
88 
89 template <uchar Shift>
90 [[nodiscard]] inline constexpr bool operator==(
91 		PeerIdZero,
92 		ChatIdType<Shift> a) noexcept {
93 	return (0 == a.bare);
94 }
95 
96 template <uchar Shift>
97 [[nodiscard]] inline constexpr bool operator!=(
98 		ChatIdType<Shift> a,
99 		PeerIdZero) noexcept {
100 	return (a.bare != 0);
101 }
102 
103 template <uchar Shift>
104 [[nodiscard]] inline constexpr bool operator!=(
105 		PeerIdZero,
106 		ChatIdType<Shift> a) noexcept {
107 	return (0 != a.bare);
108 }
109 
110 template <uchar Shift>
111 bool operator<(ChatIdType<Shift>, PeerIdZero) = delete;
112 
113 template <uchar Shift>
114 bool operator<(PeerIdZero, ChatIdType<Shift>) = delete;
115 
116 template <uchar Shift>
117 bool operator>(ChatIdType<Shift>, PeerIdZero) = delete;
118 
119 template <uchar Shift>
120 bool operator>(PeerIdZero, ChatIdType<Shift>) = delete;
121 
122 template <uchar Shift>
123 bool operator<=(ChatIdType<Shift>, PeerIdZero) = delete;
124 
125 template <uchar Shift>
126 bool operator<=(PeerIdZero, ChatIdType<Shift>) = delete;
127 
128 template <uchar Shift>
129 bool operator>=(ChatIdType<Shift>, PeerIdZero) = delete;
130 
131 template <uchar Shift>
132 bool operator>=(PeerIdZero, ChatIdType<Shift>) = delete;
133 
134 using UserId = ChatIdType<0>;
135 using ChatId = ChatIdType<1>;
136 using ChannelId = ChatIdType<2>;
137 using FakeChatId = ChatIdType<0x7F>;
138 
139 inline constexpr auto NoChannel = ChannelId(0);
140 
141 struct PeerIdHelper {
142 	BareId value = 0;
PeerIdHelperPeerIdHelper143 	constexpr PeerIdHelper(BareId value) noexcept : value(value) {
144 	}
145 };
146 
147 struct PeerId {
148 	BareId value = 0;
149 	static constexpr BareId kChatTypeMask = BareId(0xFFFFFFFFFFFFULL);
150 
151 	constexpr PeerId() noexcept = default;
PeerIdPeerId152 	constexpr PeerId(PeerIdZero) noexcept { // PeerId id = 0;
153 	}
154 	template <uchar Shift>
PeerIdPeerId155 	constexpr PeerId(ChatIdType<Shift> id) noexcept
156 	: value(id.bare | (BareId(Shift) << 48)) {
157 	}
158 	// This instead of explicit PeerId(BareId) allows to use both
159 	// PeerId(uint64(..)) and PeerId(0).
PeerIdPeerId160 	constexpr PeerId(PeerIdHelper value) noexcept : value(value.value) {
161 	}
162 
163 	template <typename SomeChatIdType, BareId = SomeChatIdType::kShift>
isPeerId164 	[[nodiscard]] constexpr bool is() const noexcept {
165 		return ((value >> 48) & BareId(0xFF)) == SomeChatIdType::kShift;
166 	}
167 
168 	template <typename SomeChatIdType, BareId = SomeChatIdType::kShift>
toPeerId169 	[[nodiscard]] constexpr SomeChatIdType to() const noexcept {
170 		return is<SomeChatIdType>() ? (value & kChatTypeMask) : 0;
171 	}
172 
173 	[[nodiscard]] constexpr explicit operator bool() const noexcept {
174 		return (value != 0);
175 	}
176 	[[nodiscard]] constexpr bool operator!() const noexcept {
177 		return !value;
178 	}
179 
180 };
181 
182 [[nodiscard]] inline constexpr bool operator==(PeerId a, PeerId b) noexcept {
183 	return (a.value == b.value);
184 }
185 
186 [[nodiscard]] inline constexpr bool operator!=(PeerId a, PeerId b) noexcept {
187 	return (a.value != b.value);
188 }
189 
190 [[nodiscard]] inline constexpr bool operator<(PeerId a, PeerId b) noexcept {
191 	return (a.value < b.value);
192 }
193 
194 [[nodiscard]] inline constexpr bool operator>(PeerId a, PeerId b) noexcept {
195 	return (a.value > b.value);
196 }
197 
198 [[nodiscard]] inline constexpr bool operator<=(PeerId a, PeerId b) noexcept {
199 	return (a.value <= b.value);
200 }
201 
202 [[nodiscard]] inline constexpr bool operator>=(PeerId a, PeerId b) noexcept {
203 	return (a.value >= b.value);
204 }
205 
206 [[nodiscard]] inline constexpr bool operator==(
207 		PeerId a,
208 		PeerIdZero) noexcept {
209 	return (a.value == 0);
210 }
211 
212 [[nodiscard]] inline constexpr bool operator==(
213 		PeerIdZero,
214 		PeerId a) noexcept {
215 	return (0 == a.value);
216 }
217 
218 [[nodiscard]] inline constexpr bool operator!=(
219 		PeerId a,
220 		PeerIdZero) noexcept {
221 	return (a.value != 0);
222 }
223 
224 [[nodiscard]] inline constexpr bool operator!=(
225 		PeerIdZero,
226 		PeerId a) noexcept {
227 	return (0 != a.value);
228 }
229 
230 bool operator<(PeerId, PeerIdZero) = delete;
231 bool operator<(PeerIdZero, PeerId) = delete;
232 bool operator>(PeerId, PeerIdZero) = delete;
233 bool operator>(PeerIdZero, PeerId) = delete;
234 bool operator<=(PeerId, PeerIdZero) = delete;
235 bool operator<=(PeerIdZero, PeerId) = delete;
236 bool operator>=(PeerId, PeerIdZero) = delete;
237 bool operator>=(PeerIdZero, PeerId) = delete;
238 
peerIsUser(PeerId id)239 [[nodiscard]] inline constexpr bool peerIsUser(PeerId id) noexcept {
240 	return id.is<UserId>();
241 }
242 
peerIsChat(PeerId id)243 [[nodiscard]] inline constexpr bool peerIsChat(PeerId id) noexcept {
244 	return id.is<ChatId>();
245 }
246 
peerIsChannel(PeerId id)247 [[nodiscard]] inline constexpr bool peerIsChannel(PeerId id) noexcept {
248 	return id.is<ChannelId>();
249 }
250 
peerFromUser(UserId userId)251 [[nodiscard]] inline constexpr PeerId peerFromUser(UserId userId) noexcept {
252 	return userId;
253 }
254 
peerFromChat(ChatId chatId)255 [[nodiscard]] inline constexpr PeerId peerFromChat(ChatId chatId) noexcept {
256 	return chatId;
257 }
258 
peerFromChannel(ChannelId channelId)259 [[nodiscard]] inline constexpr PeerId peerFromChannel(
260 		ChannelId channelId) noexcept {
261 	return channelId;
262 }
263 
peerFromUser(MTPlong userId)264 [[nodiscard]] inline constexpr PeerId peerFromUser(MTPlong userId) noexcept {
265 	return peerFromUser(userId.v);
266 }
267 
peerFromChat(MTPint chatId)268 [[nodiscard]] inline constexpr PeerId peerFromChat(MTPint chatId) noexcept {
269 	return peerFromChat(chatId.v);
270 }
271 
peerFromChannel(MTPint channelId)272 [[nodiscard]] inline constexpr PeerId peerFromChannel(
273 		MTPint channelId) noexcept {
274 	return peerFromChannel(channelId.v);
275 }
276 
peerToUser(PeerId id)277 [[nodiscard]] inline constexpr UserId peerToUser(PeerId id) noexcept {
278 	return id.to<UserId>();
279 }
280 
peerToChat(PeerId id)281 [[nodiscard]] inline constexpr ChatId peerToChat(PeerId id) noexcept {
282 	return id.to<ChatId>();
283 }
284 
peerToChannel(PeerId id)285 [[nodiscard]] inline constexpr ChannelId peerToChannel(PeerId id) noexcept {
286 	return id.to<ChannelId>();
287 }
288 
peerToBareMTPInt(PeerId id)289 [[nodiscard]] inline MTPlong peerToBareMTPInt(PeerId id) {
290 	return MTP_long(id.value & PeerId::kChatTypeMask);
291 }
292 
293 [[nodiscard]] PeerId peerFromMTP(const MTPPeer &peer);
294 [[nodiscard]] MTPpeer peerToMTP(PeerId id);
295 
296 // Supports both modern and legacy serializations.
297 [[nodiscard]] PeerId DeserializePeerId(quint64 serialized);
298 [[nodiscard]] quint64 SerializePeerId(PeerId id);
299 
300 namespace std {
301 
302 template <uchar Shift>
303 struct hash<ChatIdType<Shift>> : private hash<BareId> {
304 	size_t operator()(ChatIdType<Shift> value) const noexcept {
305 		return hash<BareId>::operator()(value.bare);
306 	}
307 };
308 
309 template <>
310 struct hash<PeerId> : private hash<BareId> {
311 	size_t operator()(PeerId value) const noexcept {
312 		return hash<BareId>::operator()(value.value);
313 	}
314 };
315 
316 } // namespace std
317