Support structured bindings in base::flat_map.

This commit is contained in:
John Preston 2018-11-16 13:07:22 +04:00
parent d6b4448d3c
commit 8a3615281c
6 changed files with 129 additions and 6 deletions

View File

@ -662,7 +662,7 @@ namespace App {
bool found = !h || !h->lastKeyboardFrom;
auto botStatus = -1;
for (auto i = chat->participants.begin(); i != chat->participants.end();) {
auto [user, version] = *i;
const auto [user, version] = *i;
if (version < pversion) {
i = chat->participants.erase(i);
} else {
@ -761,7 +761,7 @@ namespace App {
}
if (chat->botStatus > 0 && user->botInfo) {
int32 botStatus = -1;
for (auto [participant, v] : chat->participants) {
for (const auto [participant, v] : chat->participants) {
if (participant->botInfo) {
if (true || botStatus > 0/* || !participant->botInfo->readsAllHistory*/) {
botStatus = 2;

View File

@ -76,6 +76,7 @@ struct flat_multi_map_pair_type {
const Key first;
Value second;
};
template <
@ -316,6 +317,18 @@ public:
}
flat_multi_map &operator=(flat_multi_map &&other) = default;
template <
typename Iterator,
typename = typename std::iterator_traits<Iterator>::iterator_category>
flat_multi_map(Iterator first, Iterator last)
: _data(first, last) {
std::sort(std::begin(impl()), std::end(impl()), compare());
}
flat_multi_map(std::initializer_list<pair_type> iter)
: flat_multi_map(iter.begin(), iter.end()) {
}
size_type size() const {
return impl().size();
}
@ -614,6 +627,20 @@ public:
using reverse_iterator = typename parent::reverse_iterator;
using const_reverse_iterator = typename parent::const_reverse_iterator;
flat_map() = default;
template <
typename Iterator,
typename = typename std::iterator_traits<Iterator>::iterator_category
>
flat_map(Iterator first, Iterator last) : parent(first, last) {
finalize();
}
flat_map(std::initializer_list<pair_type> iter) : parent(iter.begin(), iter.end()) {
finalize();
}
using parent::parent;
using parent::size;
using parent::empty;
@ -732,6 +759,74 @@ public:
return std::move(result);
}
private:
void finalize() {
this->impl().erase(
std::unique(
std::begin(this->impl()),
std::end(this->impl()),
[&](auto &&a, auto &&b) {
return !this->compare()(a, b);
}
),
std::end(this->impl()));
}
};
} // namespace base
// Structured bindings support.
namespace std {
template <typename Key, typename Value>
class tuple_size<base::flat_multi_map_pair_type<Key, Value>>
: public integral_constant<size_t, 2> {
};
template <typename Key, typename Value>
class tuple_element<0, base::flat_multi_map_pair_type<Key, Value>> {
public:
using type = const Key;
};
template <typename Key, typename Value>
class tuple_element<1, base::flat_multi_map_pair_type<Key, Value>> {
public:
using type = Value;
};
} // namespace std
// Structured bindings support.
namespace base {
namespace details {
template <std::size_t N, typename Key, typename Value>
using flat_multi_map_pair_element = std::tuple_element_t<
N,
flat_multi_map_pair_type<Key, Value>>;
} // namespace details
template <std::size_t N, typename Key, typename Value>
auto get(base::flat_multi_map_pair_type<Key, Value> &value)
-> details::flat_multi_map_pair_element<N, Key, Value> & {
if constexpr (N == 0) {
return value.first;
} else {
return value.second;
}
}
template <std::size_t N, typename Key, typename Value>
auto get(const base::flat_multi_map_pair_type<Key, Value> &value)
-> const details::flat_multi_map_pair_element<N, Key, Value> & {
if constexpr (N == 0) {
return value.first;
} else {
return value.second;
}
}
} // namespace base

View File

@ -91,3 +91,31 @@ TEST_CASE("flat_maps custom comparator", "[flat_map]") {
checkSorted();
}
}
TEST_CASE("flat_maps structured bindings", "[flat_map]") {
base::flat_map<int, std::unique_ptr<double>> v;
v.emplace(0, std::make_unique<double>(0.));
v.emplace(1, std::make_unique<double>(1.));
SECTION("structred binded range-based for loop") {
for (const auto &[key, value] : v) {
REQUIRE(key == int(std::round(*value)));
}
}
SECTION("non-const structured binded range-based for loop") {
base::flat_map<int, int> second = {
{ 1, 1 },
{ 2, 2 },
{ 2, 3 },
{ 3, 3 },
};
REQUIRE(second.size() == 3);
//for (auto [a, b] : second) { // #MSVC Bug, reported
// REQUIRE(a == b);
//}
for (const auto [a, b] : second) {
REQUIRE(a == b);
}
}
}

View File

@ -656,7 +656,7 @@ void EditChatAdminsBoxController::rebuildRows() {
admins.reserve(allAdmins ? _chat->participants.size() : _chat->admins.size());
others.reserve(_chat->participants.size());
for (auto [user, version] : _chat->participants) {
for (const auto [user, version] : _chat->participants) {
if (user->id == peerFromUser(_chat->creator)) continue;
if (_chat->admins.contains(user)) {
admins.push_back(user);

View File

@ -765,7 +765,7 @@ void TopBarWidget::updateOnlineDisplay() {
const auto self = Auth().user();
auto online = 0;
auto onlyMe = true;
for (auto [user, v] : chat->participants) {
for (const auto [user, v] : chat->participants) {
if (user->onlineTill > now) {
++online;
if (onlyMe && user != self) onlyMe = false;
@ -833,7 +833,7 @@ void TopBarWidget::updateOnlineDisplayTimer() {
if (const auto user = _activeChat.peer()->asUser()) {
handleUser(user);
} else if (auto chat = _activeChat.peer()->asChat()) {
for (auto [user, v] : chat->participants) {
for (const auto [user, v] : chat->participants) {
handleUser(user);
}
} else if (_activeChat.peer()->isChannel()) {

View File

@ -406,7 +406,7 @@ void GroupMembersWidget::fillChatMembers(ChatData *chat) {
reserveItemsForSize(chat->participants.size());
addUser(chat, Auth().user())->onlineForSort
= std::numeric_limits<TimeId>::max();
for (auto [user, v] : chat->participants) {
for (const auto &[user, v] : chat->participants) {
if (!user->isSelf()) {
addUser(chat, user);
}