// // Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2022 // // 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) // #include "td/telegram/Usernames.h" #include "td/utils/algorithm.h" #include "td/utils/FlatHashSet.h" #include "td/utils/logging.h" #include "td/utils/misc.h" #include "td/utils/utf8.h" namespace td { Usernames::Usernames(string &&first_username, vector> &&usernames) { if (usernames.empty()) { if (!first_username.empty()) { active_usernames_.push_back(std::move(first_username)); editable_username_pos_ = 0; } return; } if (!first_username.empty()) { LOG(ERROR) << "Receive first username " << first_username << " with " << to_string(usernames); return; } bool was_editable = false; for (auto &username : usernames) { if (username->username_.empty()) { LOG(ERROR) << "Receive empty username in " << to_string(usernames); return; } if (username->editable_) { if (was_editable) { LOG(ERROR) << "Receive two editable usernames in " << to_string(usernames); return; } if (!username->active_) { LOG(ERROR) << "Receive disabled editable usernames in " << to_string(usernames); return; } was_editable = true; } } for (size_t i = 0; i < usernames.size(); i++) { if (usernames[i]->active_) { active_usernames_.push_back(std::move(usernames[i]->username_)); if (usernames[i]->editable_) { editable_username_pos_ = narrow_cast(i); } } else { disabled_usernames_.push_back(std::move(usernames[i]->username_)); } } CHECK(has_editable_username() == was_editable); } tl_object_ptr Usernames::get_usernames_object() const { if (is_empty()) { return nullptr; } return make_tl_object( vector(active_usernames_), vector(disabled_usernames_), has_editable_username() ? active_usernames_[editable_username_pos_] : string()); } Usernames Usernames::change_editable_username(string &&new_username) const { Usernames result = *this; if (has_editable_username()) { if (new_username.empty()) { result.active_usernames_.erase(result.active_usernames_.begin() + editable_username_pos_); result.editable_username_pos_ = -1; } else { // keep position result.active_usernames_[editable_username_pos_] = std::move(new_username); } } else if (!new_username.empty()) { // add to the beginning result.active_usernames_.insert(result.active_usernames_.begin(), std::move(new_username)); result.editable_username_pos_ = 0; } return result; } bool Usernames::can_toggle(const string &username) const { if (td::contains(active_usernames_, username)) { return !has_editable_username() || active_usernames_[editable_username_pos_] != username; } if (td::contains(disabled_usernames_, username)) { return true; } return false; } Usernames Usernames::toggle(const string &username, bool is_active) const { Usernames result = *this; for (size_t i = 0; i < disabled_usernames_.size(); i++) { if (disabled_usernames_[i] == username) { if (is_active) { // activate the username result.disabled_usernames_.erase(result.disabled_usernames_.begin() + i); result.active_usernames_.push_back(username); // editable username position wasn't changed } return result; } } for (size_t i = 0; i < active_usernames_.size(); i++) { if (active_usernames_[i] == username) { if (!is_active) { // disable the username result.active_usernames_.erase(result.active_usernames_.begin() + i); result.disabled_usernames_.insert(result.disabled_usernames_.begin(), username); if (result.has_editable_username() && i <= static_cast(result.editable_username_pos_)) { CHECK(i != static_cast(result.editable_username_pos_)); CHECK(result.editable_username_pos_ > 0); result.editable_username_pos_--; } } return result; } } UNREACHABLE(); return result; } Usernames Usernames::deactivate_all() const { Usernames result; for (size_t i = 0; i < active_usernames_.size(); i++) { if (i == static_cast(editable_username_pos_)) { result.active_usernames_.push_back(active_usernames_[i]); result.editable_username_pos_ = 0; } else { result.disabled_usernames_.push_back(active_usernames_[i]); } } append(result.disabled_usernames_, disabled_usernames_); CHECK(result.has_editable_username() == has_editable_username()); return result; } bool Usernames::can_reorder_to(const vector &new_username_order) const { if (new_username_order.size() != active_usernames_.size()) { return false; } FlatHashSet active_usernames; for (auto &username : active_usernames_) { active_usernames.insert(username); } for (auto &username : new_username_order) { auto it = active_usernames.find(username); if (it == active_usernames.end()) { return false; } active_usernames.erase(it); } CHECK(active_usernames.empty()); return true; } Usernames Usernames::reorder_to(vector &&new_username_order) const { Usernames result; result.active_usernames_ = std::move(new_username_order); result.disabled_usernames_ = disabled_usernames_; if (has_editable_username()) { const string &editable_username = active_usernames_[editable_username_pos_]; for (size_t i = 0; i < result.active_usernames_.size(); i++) { if (result.active_usernames_[i] == editable_username) { result.editable_username_pos_ = narrow_cast(i); break; } } CHECK(result.has_editable_username()); } return result; } void Usernames::check_utf8_validness() { for (auto &username : active_usernames_) { if (!check_utf8(username)) { LOG(ERROR) << "Have invalid active username \"" << username << '"'; *this = Usernames(); return; } } for (auto &username : disabled_usernames_) { if (!check_utf8(username)) { LOG(ERROR) << "Have invalid disabled username \"" << username << '"'; *this = Usernames(); return; } } } bool operator==(const Usernames &lhs, const Usernames &rhs) { return lhs.active_usernames_ == rhs.active_usernames_ && lhs.disabled_usernames_ == rhs.disabled_usernames_ && lhs.editable_username_pos_ == rhs.editable_username_pos_; } bool operator!=(const Usernames &lhs, const Usernames &rhs) { return !(lhs == rhs); } StringBuilder &operator<<(StringBuilder &string_builder, const Usernames &usernames) { string_builder << "Usernames["; if (usernames.has_editable_username()) { string_builder << usernames.active_usernames_[usernames.editable_username_pos_]; } if (!usernames.active_usernames_.empty()) { string_builder << ", active " << usernames.active_usernames_; } if (!usernames.disabled_usernames_.empty()) { string_builder << ", disabled " << usernames.disabled_usernames_; } return string_builder << ']'; } } // namespace td