Use ranges:: algorithms instead of base::

This commit is contained in:
John Preston 2017-11-20 16:23:20 +04:00
parent bc7c88c511
commit ac99318f34
28 changed files with 751 additions and 596 deletions

View File

@ -1873,11 +1873,15 @@ void ApiWrap::checkForUnreadMentions(const base::flat_set<MsgId> &possiblyReadMe
} }
void ApiWrap::cancelEditChatAdmins(not_null<ChatData*> chat) { void ApiWrap::cancelEditChatAdmins(not_null<ChatData*> chat) {
_chatAdminsEnabledRequests.take(chat) _chatAdminsEnabledRequests.take(
| requestCanceller(); chat
) | requestCanceller();
_chatAdminsSaveRequests.take(chat) _chatAdminsSaveRequests.take(
| base::for_each_apply(requestCanceller()); chat
) | [&](auto &&requests) {
ranges::for_each(std::move(requests), requestCanceller());
};
_chatAdminsToSave.remove(chat); _chatAdminsToSave.remove(chat);
} }
@ -1975,8 +1979,8 @@ void ApiWrap::sendSaveChatAdminsRequests(not_null<ChatData*> chat) {
} }
} }
} }
base::for_each(toRemove, removeOne); ranges::for_each(toRemove, removeOne);
base::for_each(toAppoint, appointOne); ranges::for_each(toAppoint, appointOne);
requestSendDelayed(); requestSendDelayed();
} }

View File

@ -32,109 +32,4 @@ inline constexpr size_t array_size(const Type(&)[Size]) {
return Size; return Size;
} }
template <typename Range, typename Method>
decltype(auto) for_each(Range &&range, Method &&method) {
return std::for_each(
std::begin(std::forward<Range>(range)),
std::end(std::forward<Range>(range)),
std::forward<Method>(method));
}
template <typename Method>
decltype(auto) for_each_apply(Method &&method) {
return [&method](auto &&range) {
return for_each(std::forward<decltype(range)>(range), std::forward<Method>(method));
};
}
template <typename Range, typename Value>
decltype(auto) find(Range &&range, Value &&value) {
return std::find(
std::begin(std::forward<Range>(range)),
std::end(std::forward<Range>(range)),
std::forward<Value>(value));
}
template <typename Range, typename Predicate>
decltype(auto) find_if(Range &&range, Predicate &&predicate) {
return std::find_if(
std::begin(std::forward<Range>(range)),
std::end(std::forward<Range>(range)),
std::forward<Predicate>(predicate));
}
template <typename Range, typename Type>
decltype(auto) lower_bound(Range &&range, Type &&value) {
return std::lower_bound(
std::begin(std::forward<Range>(range)),
std::end(std::forward<Range>(range)),
std::forward<Type>(value));
}
template <typename Range, typename Type, typename Predicate>
decltype(auto) lower_bound(Range &&range, Type &&value, Predicate &&predicate) {
return std::lower_bound(
std::begin(std::forward<Range>(range)),
std::end(std::forward<Range>(range)),
std::forward<Type>(value),
std::forward<Predicate>(predicate));
}
template <typename Range, typename Type>
decltype(auto) upper_bound(Range &&range, Type &&value) {
return std::upper_bound(
std::begin(std::forward<Range>(range)),
std::end(std::forward<Range>(range)),
std::forward<Type>(value));
}
template <typename Range, typename Type, typename Predicate>
decltype(auto) upper_bound(Range &&range, Type &&value, Predicate &&predicate) {
return std::upper_bound(
std::begin(std::forward<Range>(range)),
std::end(std::forward<Range>(range)),
std::forward<Type>(value),
std::forward<Predicate>(predicate));
}
template <typename Range, typename Type>
decltype(auto) equal_range(Range &&range, Type &&value) {
return std::equal_range(
std::begin(std::forward<Range>(range)),
std::end(std::forward<Range>(range)),
std::forward<Type>(value));
}
template <typename Range, typename Type, typename Predicate>
decltype(auto) equal_range(Range &&range, Type &&value, Predicate &&predicate) {
return std::equal_range(
std::begin(std::forward<Range>(range)),
std::end(std::forward<Range>(range)),
std::forward<Type>(value),
std::forward<Predicate>(predicate));
}
template <typename Range>
decltype(auto) sort(Range &&range) {
return std::sort(
std::begin(std::forward<Range>(range)),
std::end(std::forward<Range>(range)));
}
template <typename Range, typename Predicate>
decltype(auto) sort(Range &&range, Predicate &&predicate) {
return std::sort(
std::begin(std::forward<Range>(range)),
std::end(std::forward<Range>(range)),
std::forward<Predicate>(predicate));
}
template <typename Range, typename Predicate>
decltype(auto) stable_partition(Range &&range, Predicate &&predicate) {
return std::stable_partition(
std::begin(std::forward<Range>(range)),
std::end(std::forward<Range>(range)),
std::forward<Predicate>(predicate));
}
} // namespace base } // namespace base

View File

@ -21,8 +21,8 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#pragma once #pragma once
#include <deque> #include <deque>
#include <algorithm>
#include "base/optional.h" #include "base/optional.h"
#include "base/algorithm.h"
namespace base { namespace base {
@ -39,18 +39,41 @@ template <
class flat_multi_map; class flat_multi_map;
template < template <
typename Me,
typename Key, typename Key,
typename Type, typename Type,
typename Compare,
typename iterator_impl, typename iterator_impl,
typename pointer_impl, typename pointer_impl,
typename reference_impl> typename reference_impl>
class flat_multi_map_iterator_base_impl; class flat_multi_map_iterator_base_impl;
template <typename Key>
class flat_multi_map_key_const_wrap {
public:
constexpr flat_multi_map_key_const_wrap(const Key &value)
: _value(value) {
}
constexpr flat_multi_map_key_const_wrap(Key &&value)
: _value(std::move(value)) {
}
inline constexpr operator const Key&() const {
return _value;
}
private:
Key _value;
};
template <typename Key, typename Type>
using flat_multi_map_pair_type = std::pair<
flat_multi_map_key_const_wrap<Key>,
Type>;
template < template <
typename Me,
typename Key, typename Key,
typename Type, typename Type,
typename Compare,
typename iterator_impl, typename iterator_impl,
typename pointer_impl, typename pointer_impl,
typename reference_impl> typename reference_impl>
@ -58,12 +81,13 @@ class flat_multi_map_iterator_base_impl {
public: public:
using iterator_category = typename iterator_impl::iterator_category; using iterator_category = typename iterator_impl::iterator_category;
using value_type = typename flat_multi_map<Key, Type, Compare>::value_type; using pair_type = flat_multi_map_pair_type<Key, Type>;
using value_type = pair_type;
using difference_type = typename iterator_impl::difference_type; using difference_type = typename iterator_impl::difference_type;
using pointer = pointer_impl; using pointer = pointer_impl;
using const_pointer = typename flat_multi_map<Key, Type, Compare>::const_pointer; using const_pointer = const pair_type*;
using reference = reference_impl; using reference = reference_impl;
using const_reference = typename flat_multi_map<Key, Type, Compare>::const_reference; using const_reference = const pair_type&;
flat_multi_map_iterator_base_impl(iterator_impl impl = iterator_impl()) flat_multi_map_iterator_base_impl(iterator_impl impl = iterator_impl())
: _impl(impl) { : _impl(impl) {
@ -81,43 +105,44 @@ public:
const_pointer operator->() const { const_pointer operator->() const {
return std::addressof(**this); return std::addressof(**this);
} }
flat_multi_map_iterator_base_impl &operator++() { Me &operator++() {
++_impl; ++_impl;
return *this; return static_cast<Me&>(*this);
} }
flat_multi_map_iterator_base_impl operator++(int) { Me operator++(int) {
return _impl++; return _impl++;
} }
flat_multi_map_iterator_base_impl &operator--() { Me &operator--() {
--_impl; --_impl;
return *this; return static_cast<Me&>(*this);
} }
flat_multi_map_iterator_base_impl operator--(int) { Me operator--(int) {
return _impl--; return _impl--;
} }
flat_multi_map_iterator_base_impl &operator+=(difference_type offset) { Me &operator+=(difference_type offset) {
_impl += offset; _impl += offset;
return *this; return static_cast<Me&>(*this);
} }
flat_multi_map_iterator_base_impl operator+(difference_type offset) const { Me operator+(difference_type offset) const {
return _impl + offset; return _impl + offset;
} }
flat_multi_map_iterator_base_impl &operator-=(difference_type offset) { Me &operator-=(difference_type offset) {
_impl -= offset; _impl -= offset;
return *this; return static_cast<Me&>(*this);
} }
flat_multi_map_iterator_base_impl operator-(difference_type offset) const { Me operator-(difference_type offset) const {
return _impl - offset; return _impl - offset;
} }
template < template <
typename other_me,
typename other_iterator_impl, typename other_iterator_impl,
typename other_pointer_impl, typename other_pointer_impl,
typename other_reference_impl> typename other_reference_impl>
difference_type operator-( difference_type operator-(
const flat_multi_map_iterator_base_impl< const flat_multi_map_iterator_base_impl<
other_me,
Key, Key,
Type, Type,
Compare,
other_iterator_impl, other_iterator_impl,
other_pointer_impl, other_pointer_impl,
other_reference_impl> &right) const { other_reference_impl> &right) const {
@ -131,42 +156,45 @@ public:
} }
template < template <
typename other_me,
typename other_iterator_impl, typename other_iterator_impl,
typename other_pointer_impl, typename other_pointer_impl,
typename other_reference_impl> typename other_reference_impl>
bool operator==( bool operator==(
const flat_multi_map_iterator_base_impl< const flat_multi_map_iterator_base_impl<
other_me,
Key, Key,
Type, Type,
Compare,
other_iterator_impl, other_iterator_impl,
other_pointer_impl, other_pointer_impl,
other_reference_impl> &right) const { other_reference_impl> &right) const {
return _impl == right._impl; return _impl == right._impl;
} }
template < template <
typename other_me,
typename other_iterator_impl, typename other_iterator_impl,
typename other_pointer_impl, typename other_pointer_impl,
typename other_reference_impl> typename other_reference_impl>
bool operator!=( bool operator!=(
const flat_multi_map_iterator_base_impl< const flat_multi_map_iterator_base_impl<
other_me,
Key, Key,
Type, Type,
Compare,
other_iterator_impl, other_iterator_impl,
other_pointer_impl, other_pointer_impl,
other_reference_impl> &right) const { other_reference_impl> &right) const {
return _impl != right._impl; return _impl != right._impl;
} }
template < template <
typename other_me,
typename other_iterator_impl, typename other_iterator_impl,
typename other_pointer_impl, typename other_pointer_impl,
typename other_reference_impl> typename other_reference_impl>
bool operator<( bool operator<(
const flat_multi_map_iterator_base_impl< const flat_multi_map_iterator_base_impl<
other_me,
Key, Key,
Type, Type,
Compare,
other_iterator_impl, other_iterator_impl,
other_pointer_impl, other_pointer_impl,
other_reference_impl> &right) const { other_reference_impl> &right) const {
@ -175,12 +203,17 @@ public:
private: private:
iterator_impl _impl; iterator_impl _impl;
friend class flat_multi_map<Key, Type, Compare>;
template < template <
typename OtherKey, typename OtherKey,
typename OtherType, typename OtherType,
typename OtherCompare, typename OtherCompare>
friend class flat_multi_map;
template <
typename OtherMe,
typename OtherKey,
typename OtherType,
typename other_iterator_impl, typename other_iterator_impl,
typename other_pointer_impl, typename other_pointer_impl,
typename other_reference_impl> typename other_reference_impl>
@ -190,131 +223,50 @@ private:
template <typename Key, typename Type, typename Compare> template <typename Key, typename Type, typename Compare>
class flat_multi_map { class flat_multi_map {
class key_const_wrap { public:
public: class iterator;
constexpr key_const_wrap(const Key &value) : _value(value) { class const_iterator;
} class reverse_iterator;
constexpr key_const_wrap(Key &&value) : _value(std::move(value)) { class const_reverse_iterator;
}
inline constexpr operator const Key&() const {
return _value;
}
private: private:
Key _value; using key_const_wrap = flat_multi_map_key_const_wrap<Key>;
using pair_type = flat_multi_map_pair_type<Key, Type>;
}; using impl_t = std::deque<pair_type>;
using pair_type = std::pair<key_const_wrap, Type>;
class compare {
public:
template <
typename OtherType1,
typename OtherType2,
typename = std::enable_if_t<
!std::is_same_v<std::decay_t<OtherType1>, key_const_wrap> &&
!std::is_same_v<std::decay_t<OtherType1>, pair_type> &&
!std::is_same_v<std::decay_t<OtherType2>, key_const_wrap> &&
!std::is_same_v<std::decay_t<OtherType2>, pair_type>>>
inline constexpr auto operator()(
OtherType1 &&a,
OtherType2 &b) const {
return Compare()(
std::forward<OtherType1>(a),
std::forward<OtherType2>(b));
}
inline constexpr auto operator()(
const key_const_wrap &a,
const key_const_wrap &b) const {
return operator()(
static_cast<const Key&>(a),
static_cast<const Key&>(b));
}
template <
typename OtherType,
typename = std::enable_if_t<
!std::is_same_v<std::decay_t<OtherType>, key_const_wrap> &&
!std::is_same_v<std::decay_t<OtherType>, pair_type>>>
inline constexpr auto operator()(
const key_const_wrap &a,
OtherType &&b) const {
return operator()(
static_cast<const Key&>(a),
std::forward<OtherType>(b));
}
template <
typename OtherType,
typename = std::enable_if_t<
!std::is_same_v<std::decay_t<OtherType>, key_const_wrap> &&
!std::is_same_v<std::decay_t<OtherType>, pair_type>>>
inline constexpr auto operator()(
OtherType &&a,
const key_const_wrap &b) const {
return operator()(
std::forward<OtherType>(a),
static_cast<const Key&>(b));
}
inline constexpr auto operator()(
const pair_type &a,
const pair_type &b) const {
return operator()(a.first, b.first);
}
template <
typename OtherType,
typename = std::enable_if_t<
!std::is_same_v<std::decay_t<OtherType>, pair_type>>>
inline constexpr auto operator()(
const pair_type &a,
OtherType &&b) const {
return operator()(a.first, std::forward<OtherType>(b));
}
template <
typename OtherType,
typename = std::enable_if_t<
!std::is_same_v<std::decay_t<OtherType>, pair_type>>>
inline constexpr auto operator()(
OtherType &&a,
const pair_type &b) const {
return operator()(std::forward<OtherType>(a), b.first);
}
};
using impl = std::deque<pair_type>;
using iterator_base = flat_multi_map_iterator_base_impl< using iterator_base = flat_multi_map_iterator_base_impl<
iterator,
Key, Key,
Type, Type,
Compare, typename impl_t::iterator,
typename impl::iterator,
pair_type*, pair_type*,
pair_type&>; pair_type&>;
using const_iterator_base = flat_multi_map_iterator_base_impl< using const_iterator_base = flat_multi_map_iterator_base_impl<
const_iterator,
Key, Key,
Type, Type,
Compare, typename impl_t::const_iterator,
typename impl::const_iterator,
const pair_type*, const pair_type*,
const pair_type&>; const pair_type&>;
using reverse_iterator_base = flat_multi_map_iterator_base_impl< using reverse_iterator_base = flat_multi_map_iterator_base_impl<
reverse_iterator,
Key, Key,
Type, Type,
Compare, typename impl_t::reverse_iterator,
typename impl::reverse_iterator,
pair_type*, pair_type*,
pair_type&>; pair_type&>;
using const_reverse_iterator_base = flat_multi_map_iterator_base_impl< using const_reverse_iterator_base = flat_multi_map_iterator_base_impl<
const_reverse_iterator,
Key, Key,
Type, Type,
Compare, typename impl_t::const_reverse_iterator,
typename impl::const_reverse_iterator,
const pair_type*, const pair_type*,
const pair_type&>; const pair_type&>;
public: public:
using value_type = pair_type; using value_type = pair_type;
using size_type = typename impl::size_type; using size_type = typename impl_t::size_type;
using difference_type = typename impl::difference_type; using difference_type = typename impl_t::difference_type;
using pointer = pair_type*; using pointer = pair_type*;
using const_pointer = const pair_type*; using const_pointer = const pair_type*;
using reference = pair_type&; using reference = pair_type&;
@ -324,6 +276,7 @@ public:
class iterator : public iterator_base { class iterator : public iterator_base {
public: public:
using iterator_base::iterator_base; using iterator_base::iterator_base;
iterator() = default;
iterator(const iterator_base &other) : iterator_base(other) { iterator(const iterator_base &other) : iterator_base(other) {
} }
friend class const_iterator; friend class const_iterator;
@ -332,6 +285,7 @@ public:
class const_iterator : public const_iterator_base { class const_iterator : public const_iterator_base {
public: public:
using const_iterator_base::const_iterator_base; using const_iterator_base::const_iterator_base;
const_iterator() = default;
const_iterator(const_iterator_base other) : const_iterator_base(other) { const_iterator(const_iterator_base other) : const_iterator_base(other) {
} }
const_iterator(const iterator &other) : const_iterator_base(other._impl) { const_iterator(const iterator &other) : const_iterator_base(other._impl) {
@ -342,6 +296,7 @@ public:
class reverse_iterator : public reverse_iterator_base { class reverse_iterator : public reverse_iterator_base {
public: public:
using reverse_iterator_base::reverse_iterator_base; using reverse_iterator_base::reverse_iterator_base;
reverse_iterator() = default;
reverse_iterator(reverse_iterator_base other) : reverse_iterator_base(other) { reverse_iterator(reverse_iterator_base other) : reverse_iterator_base(other) {
} }
friend class const_reverse_iterator; friend class const_reverse_iterator;
@ -350,6 +305,7 @@ public:
class const_reverse_iterator : public const_reverse_iterator_base { class const_reverse_iterator : public const_reverse_iterator_base {
public: public:
using const_reverse_iterator_base::const_reverse_iterator_base; using const_reverse_iterator_base::const_reverse_iterator_base;
const_reverse_iterator() = default;
const_reverse_iterator(const_reverse_iterator_base other) : const_reverse_iterator_base(other) { const_reverse_iterator(const_reverse_iterator_base other) : const_reverse_iterator_base(other) {
} }
const_reverse_iterator(const reverse_iterator &other) : const_reverse_iterator_base(other._impl) { const_reverse_iterator(const reverse_iterator &other) : const_reverse_iterator_base(other._impl) {
@ -358,50 +314,50 @@ public:
}; };
size_type size() const { size_type size() const {
return _impl.size(); return impl().size();
} }
bool empty() const { bool empty() const {
return _impl.empty(); return impl().empty();
} }
void clear() { void clear() {
_impl.clear(); impl().clear();
} }
iterator begin() { iterator begin() {
return _impl.begin(); return impl().begin();
} }
iterator end() { iterator end() {
return _impl.end(); return impl().end();
} }
const_iterator begin() const { const_iterator begin() const {
return _impl.begin(); return impl().begin();
} }
const_iterator end() const { const_iterator end() const {
return _impl.end(); return impl().end();
} }
const_iterator cbegin() const { const_iterator cbegin() const {
return _impl.cbegin(); return impl().cbegin();
} }
const_iterator cend() const { const_iterator cend() const {
return _impl.cend(); return impl().cend();
} }
reverse_iterator rbegin() { reverse_iterator rbegin() {
return _impl.rbegin(); return impl().rbegin();
} }
reverse_iterator rend() { reverse_iterator rend() {
return _impl.rend(); return impl().rend();
} }
const_reverse_iterator rbegin() const { const_reverse_iterator rbegin() const {
return _impl.rbegin(); return impl().rbegin();
} }
const_reverse_iterator rend() const { const_reverse_iterator rend() const {
return _impl.rend(); return impl().rend();
} }
const_reverse_iterator crbegin() const { const_reverse_iterator crbegin() const {
return _impl.crbegin(); return impl().crbegin();
} }
const_reverse_iterator crend() const { const_reverse_iterator crend() const {
return _impl.crend(); return impl().crend();
} }
reference front() { reference front() {
@ -419,25 +375,25 @@ public:
iterator insert(const value_type &value) { iterator insert(const value_type &value) {
if (empty() || compare()(value.first, front().first)) { if (empty() || compare()(value.first, front().first)) {
_impl.push_front(value); impl().push_front(value);
return begin(); return begin();
} else if (!compare()(value.first, back().first)) { } else if (!compare()(value.first, back().first)) {
_impl.push_back(value); impl().push_back(value);
return (end() - 1); return (end() - 1);
} }
auto where = getUpperBound(value.first); auto where = getUpperBound(value.first);
return _impl.insert(where, value); return impl().insert(where, value);
} }
iterator insert(value_type &&value) { iterator insert(value_type &&value) {
if (empty() || compare()(value.first, front().first)) { if (empty() || compare()(value.first, front().first)) {
_impl.push_front(std::move(value)); impl().push_front(std::move(value));
return begin(); return begin();
} else if (!compare()(value.first, back().first)) { } else if (!compare()(value.first, back().first)) {
_impl.push_back(std::move(value)); impl().push_back(std::move(value));
return (end() - 1); return (end() - 1);
} }
auto where = getUpperBound(value.first); auto where = getUpperBound(value.first);
return _impl.insert(where, std::move(value)); return impl().insert(where, std::move(value));
} }
template <typename... Args> template <typename... Args>
iterator emplace(Args&&... args) { iterator emplace(Args&&... args) {
@ -454,7 +410,7 @@ public:
if (compare()(key, where->first)) { if (compare()(key, where->first)) {
return false; return false;
} }
_impl.erase(where); impl().erase(where);
return true; return true;
} }
int removeAll(const Key &key) { int removeAll(const Key &key) {
@ -467,15 +423,15 @@ public:
if (range.first == range.second) { if (range.first == range.second) {
return 0; return 0;
} }
_impl.erase(range.first, range.second); impl().erase(range.first, range.second);
return (range.second - range.first); return (range.second - range.first);
} }
iterator erase(const_iterator where) { iterator erase(const_iterator where) {
return _impl.erase(where._impl); return impl().erase(where._impl);
} }
iterator erase(const_iterator from, const_iterator till) { iterator erase(const_iterator from, const_iterator till) {
return _impl.erase(from._impl, till._impl); return impl().erase(from._impl, till._impl);
} }
iterator findFirst(const Key &key) { iterator findFirst(const Key &key) {
@ -485,7 +441,7 @@ public:
return end(); return end();
} }
auto where = getLowerBound(key); auto where = getLowerBound(key);
return compare()(key, where->first) ? _impl.end() : where; return compare()(key, where->first) ? impl().end() : where;
} }
const_iterator findFirst(const Key &key) const { const_iterator findFirst(const Key &key) const {
@ -495,7 +451,7 @@ public:
return end(); return end();
} }
auto where = getLowerBound(key); auto where = getLowerBound(key);
return compare()(key, where->first) ? _impl.end() : where; return compare()(key, where->first) ? impl().end() : where;
} }
bool contains(const Key &key) const { bool contains(const Key &key) const {
@ -512,32 +468,167 @@ public:
} }
private: private:
impl _impl;
friend class flat_map<Key, Type, Compare>; friend class flat_map<Key, Type, Compare>;
typename impl::iterator getLowerBound(const Key &key) { struct transparent_compare : Compare {
return base::lower_bound(_impl, key, compare()); inline constexpr const Compare &initial() const noexcept {
return *this;
}
template <
typename OtherType1,
typename OtherType2,
typename = std::enable_if_t<
!std::is_same_v<std::decay_t<OtherType1>, key_const_wrap> &&
!std::is_same_v<std::decay_t<OtherType1>, pair_type> &&
!std::is_same_v<std::decay_t<OtherType2>, key_const_wrap> &&
!std::is_same_v<std::decay_t<OtherType2>, pair_type>>>
inline constexpr auto operator()(
OtherType1 &&a,
OtherType2 &&b) const {
return initial()(
std::forward<OtherType1>(a),
std::forward<OtherType2>(b));
}
template <
typename OtherType1,
typename OtherType2>
inline constexpr auto operator()(
OtherType1 &&a,
OtherType2 &&b) const -> std::enable_if_t<
std::is_same_v<std::decay_t<OtherType1>, key_const_wrap> &&
std::is_same_v<std::decay_t<OtherType2>, key_const_wrap>, bool> {
return initial()(
static_cast<const Key&>(a),
static_cast<const Key&>(b));
}
template <
typename OtherType,
typename = std::enable_if_t<
!std::is_same_v<std::decay_t<OtherType>, key_const_wrap> &&
!std::is_same_v<std::decay_t<OtherType>, pair_type>>>
inline constexpr auto operator()(
const key_const_wrap &a,
OtherType &&b) const {
return initial()(
static_cast<const Key&>(a),
std::forward<OtherType>(b));
}
template <
typename OtherType,
typename = std::enable_if_t<
!std::is_same_v<std::decay_t<OtherType>, key_const_wrap> &&
!std::is_same_v<std::decay_t<OtherType>, pair_type>>>
inline constexpr auto operator()(
OtherType &&a,
const key_const_wrap &b) const {
return initial()(
std::forward<OtherType>(a),
static_cast<const Key&>(b));
}
template <
typename OtherType1,
typename OtherType2>
inline constexpr auto operator()(
OtherType1 &&a,
OtherType2 &&b) const -> std::enable_if_t<
std::is_same_v<std::decay_t<OtherType1>, pair_type> &&
std::is_same_v<std::decay_t<OtherType2>, pair_type>, bool> {
return initial()(
static_cast<const Key&>(a.first),
static_cast<const Key&>(b.first));
}
template <
typename OtherType,
typename = std::enable_if_t<
!std::is_same_v<std::decay_t<OtherType>, pair_type>>>
inline constexpr auto operator()(
const pair_type &a,
OtherType &&b) const {
return operator()(
static_cast<const Key&>(a.first),
std::forward<OtherType>(b));
}
template <
typename OtherType,
typename = std::enable_if_t<
!std::is_same_v<std::decay_t<OtherType>, pair_type>>>
inline constexpr auto operator()(
OtherType &&a,
const pair_type &b) const {
return operator()(
std::forward<OtherType>(a),
static_cast<const Key&>(b.first));
}
};
struct Data : transparent_compare {
template <typename ...Args>
Data(Args &&...args)
: elements(std::forward<Args>(args)...) {
}
impl_t elements;
};
Data _data;
const transparent_compare &compare() const noexcept {
return _data;
} }
typename impl::const_iterator getLowerBound(const Key &key) const { const impl_t &impl() const noexcept {
return base::lower_bound(_impl, key, compare()); return _data.elements;
} }
typename impl::iterator getUpperBound(const Key &key) { impl_t &impl() noexcept {
return base::upper_bound(_impl, key, compare()); return _data.elements;
} }
typename impl::const_iterator getUpperBound(const Key &key) const {
return base::upper_bound(_impl, key, compare()); typename impl_t::iterator getLowerBound(const Key &key) {
return std::lower_bound(
std::begin(impl()),
std::end(impl()),
key,
compare());
}
typename impl_t::const_iterator getLowerBound(const Key &key) const {
return std::lower_bound(
std::begin(impl()),
std::end(impl()),
key,
compare());
}
typename impl_t::iterator getUpperBound(const Key &key) {
return std::upper_bound(
std::begin(impl()),
std::end(impl()),
key,
compare());
}
typename impl_t::const_iterator getUpperBound(const Key &key) const {
return std::upper_bound(
std::begin(impl()),
std::end(impl()),
key,
compare());
} }
std::pair< std::pair<
typename impl::iterator, typename impl_t::iterator,
typename impl::iterator typename impl_t::iterator
> getEqualRange(const Key &key) { > getEqualRange(const Key &key) {
return base::equal_range(_impl, key, compare()); return std::equal_range(
std::begin(impl()),
std::end(impl()),
key,
compare());
} }
std::pair< std::pair<
typename impl::const_iterator, typename impl_t::const_iterator,
typename impl::const_iterator typename impl_t::const_iterator
> getEqualRange(const Key &key) const { > getEqualRange(const Key &key) const {
return base::equal_range(_impl, key, compare()); return std::equal_range(
std::begin(impl()),
std::end(impl()),
key,
compare());
} }
}; };
@ -545,7 +636,6 @@ private:
template <typename Key, typename Type, typename Compare> template <typename Key, typename Type, typename Compare>
class flat_map : private flat_multi_map<Key, Type, Compare> { class flat_map : private flat_multi_map<Key, Type, Compare> {
using parent = flat_multi_map<Key, Type, Compare>; using parent = flat_multi_map<Key, Type, Compare>;
using compare = typename parent::compare;
using pair_type = typename parent::pair_type; using pair_type = typename parent::pair_type;
public: public:
@ -579,30 +669,30 @@ public:
using parent::contains; using parent::contains;
std::pair<iterator, bool> insert(const value_type &value) { std::pair<iterator, bool> insert(const value_type &value) {
if (this->empty() || compare()(value.first, this->front().first)) { if (this->empty() || this->compare()(value.first, this->front().first)) {
this->_impl.push_front(value); this->impl().push_front(value);
return { this->begin(), true }; return { this->begin(), true };
} else if (compare()(this->back().first, value.first)) { } else if (this->compare()(this->back().first, value.first)) {
this->_impl.push_back(value); this->impl().push_back(value);
return { this->end() - 1, true }; return { this->end() - 1, true };
} }
auto where = this->getLowerBound(value.first); auto where = this->getLowerBound(value.first);
if (compare()(value.first, where->first)) { if (this->compare()(value.first, where->first)) {
return { this->_impl.insert(where, value), true }; return { this->impl().insert(where, value), true };
} }
return { where, false }; return { where, false };
} }
std::pair<iterator, bool> insert(value_type &&value) { std::pair<iterator, bool> insert(value_type &&value) {
if (this->empty() || compare()(value.first, this->front().first)) { if (this->empty() || this->compare()(value.first, this->front().first)) {
this->_impl.push_front(std::move(value)); this->impl().push_front(std::move(value));
return { this->begin(), true }; return { this->begin(), true };
} else if (compare()(this->back().first, value.first)) { } else if (this->compare()(this->back().first, value.first)) {
this->_impl.push_back(std::move(value)); this->impl().push_back(std::move(value));
return { this->end() - 1, true }; return { this->end() - 1, true };
} }
auto where = this->getLowerBound(value.first); auto where = this->getLowerBound(value.first);
if (compare()(value.first, where->first)) { if (this->compare()(value.first, where->first)) {
return { this->_impl.insert(where, std::move(value)), true }; return { this->impl().insert(where, std::move(value)), true };
} }
return { where, false }; return { where, false };
} }
@ -618,21 +708,21 @@ public:
std::pair<iterator, bool> try_emplace( std::pair<iterator, bool> try_emplace(
const Key &key, const Key &key,
Args&&... args) { Args&&... args) {
if (this->empty() || compare()(key, this->front().first)) { if (this->empty() || this->compare()(key, this->front().first)) {
this->_impl.push_front(value_type( this->impl().push_front(value_type(
key, key,
Type(std::forward<Args>(args)...))); Type(std::forward<Args>(args)...)));
return { this->begin(), true }; return { this->begin(), true };
} else if (compare()(this->back().first, key)) { } else if (this->compare()(this->back().first, key)) {
this->_impl.push_back(value_type( this->impl().push_back(value_type(
key, key,
Type(std::forward<Args>(args)...))); Type(std::forward<Args>(args)...)));
return { this->end() - 1, true }; return { this->end() - 1, true };
} }
auto where = this->getLowerBound(key); auto where = this->getLowerBound(key);
if (compare()(key, where->first)) { if (this->compare()(key, where->first)) {
return { return {
this->_impl.insert( this->impl().insert(
where, where,
value_type( value_type(
key, key,
@ -655,16 +745,16 @@ public:
} }
Type &operator[](const Key &key) { Type &operator[](const Key &key) {
if (this->empty() || compare()(key, this->front().first)) { if (this->empty() || this->compare()(key, this->front().first)) {
this->_impl.push_front({ key, Type() }); this->impl().push_front({ key, Type() });
return this->front().second; return this->front().second;
} else if (compare()(this->back().first, key)) { } else if (this->compare()(this->back().first, key)) {
this->_impl.push_back({ key, Type() }); this->impl().push_back({ key, Type() });
return this->back().second; return this->back().second;
} }
auto where = this->getLowerBound(key); auto where = this->getLowerBound(key);
if (compare()(key, where->first)) { if (this->compare()(key, where->first)) {
return this->_impl.insert(where, { key, Type() })->second; return this->impl().insert(where, { key, Type() })->second;
} }
return where->second; return where->second;
} }

View File

@ -23,6 +23,15 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include "base/flat_map.h" #include "base/flat_map.h"
#include <string> #include <string>
struct int_wrap {
int value;
};
struct int_wrap_comparator {
inline bool operator()(const int_wrap &a, const int_wrap &b) const {
return a.value < b.value;
}
};
using namespace std; using namespace std;
TEST_CASE("flat_maps should keep items sorted by key", "[flat_map]") { TEST_CASE("flat_maps should keep items sorted by key", "[flat_map]") {
@ -49,3 +58,28 @@ TEST_CASE("flat_maps should keep items sorted by key", "[flat_map]") {
checkSorted(); checkSorted();
} }
} }
TEST_CASE("flat_maps custom comparator", "[flat_map]") {
base::flat_map<int_wrap, string, int_wrap_comparator> v;
v.emplace({ 0 }, "a");
v.emplace({ 5 }, "b");
v.emplace({ 4 }, "d");
v.emplace({ 2 }, "e");
auto checkSorted = [&] {
auto prev = v.begin();
REQUIRE(prev != v.end());
for (auto i = prev + 1; i != v.end(); prev = i, ++i) {
REQUIRE(int_wrap_comparator()(prev->first, i->first));
}
};
REQUIRE(v.size() == 4);
checkSorted();
SECTION("adding item puts it in the right position") {
v.emplace({ 3 }, "c");
REQUIRE(v.size() == 5);
REQUIRE(v.find({ 3 }) != v.end());
checkSorted();
}
}

View File

@ -21,7 +21,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#pragma once #pragma once
#include <deque> #include <deque>
#include "base/algorithm.h" #include <algorithm>
namespace base { namespace base {
@ -31,28 +31,29 @@ class flat_set;
template <typename Type, typename Compare = std::less<>> template <typename Type, typename Compare = std::less<>>
class flat_multi_set; class flat_multi_set;
template <typename Type, typename Compare, typename iterator_impl> template <typename Type, typename iterator_impl>
class flat_multi_set_iterator_impl; class flat_multi_set_iterator_impl;
template <typename Type, typename Compare, typename iterator_impl> template <typename Type, typename iterator_impl>
class flat_multi_set_iterator_impl { class flat_multi_set_iterator_impl {
public: public:
using iterator_category = typename iterator_impl::iterator_category; using iterator_category = typename iterator_impl::iterator_category;
using value_type = typename flat_multi_set<Type, Compare>::value_type; using value_type = Type;
using difference_type = typename iterator_impl::difference_type; using difference_type = typename iterator_impl::difference_type;
using pointer = typename flat_multi_set<Type, Compare>::pointer; using pointer = const Type*;
using reference = typename flat_multi_set<Type, Compare>::reference; using reference = const Type&;
flat_multi_set_iterator_impl(iterator_impl impl = iterator_impl()) flat_multi_set_iterator_impl(
: _impl(impl) { iterator_impl impl = iterator_impl())
: _impl(impl) {
} }
template <typename other_iterator_impl> template <typename other_iterator_impl>
flat_multi_set_iterator_impl( flat_multi_set_iterator_impl(
const flat_multi_set_iterator_impl< const flat_multi_set_iterator_impl<
Type, Type,
Compare, other_iterator_impl> &other)
other_iterator_impl> &other) : _impl(other._impl) { : _impl(other._impl) {
} }
reference operator*() const { reference operator*() const {
@ -91,10 +92,9 @@ public:
} }
template <typename other_iterator_impl> template <typename other_iterator_impl>
difference_type operator-( difference_type operator-(
const flat_multi_set_iterator_impl< const flat_multi_set_iterator_impl<
Type, Type,
Compare, other_iterator_impl> &right) const {
other_iterator_impl> &right) const {
return _impl - right._impl; return _impl - right._impl;
} }
reference operator[](difference_type offset) const { reference operator[](difference_type offset) const {
@ -103,37 +103,37 @@ public:
template <typename other_iterator_impl> template <typename other_iterator_impl>
bool operator==( bool operator==(
const flat_multi_set_iterator_impl< const flat_multi_set_iterator_impl<
Type, Type,
Compare, other_iterator_impl> &right) const {
other_iterator_impl> &right) const {
return _impl == right._impl; return _impl == right._impl;
} }
template <typename other_iterator_impl> template <typename other_iterator_impl>
bool operator!=( bool operator!=(
const flat_multi_set_iterator_impl< const flat_multi_set_iterator_impl<
Type, Type,
Compare, other_iterator_impl> &right) const {
other_iterator_impl> &right) const {
return _impl != right._impl; return _impl != right._impl;
} }
template <typename other_iterator_impl> template <typename other_iterator_impl>
bool operator<( bool operator<(
const flat_multi_set_iterator_impl< const flat_multi_set_iterator_impl<
Type, Type,
Compare, other_iterator_impl> &right) const {
other_iterator_impl> &right) const {
return _impl < right._impl; return _impl < right._impl;
} }
private: private:
iterator_impl _impl; iterator_impl _impl;
friend class flat_multi_set<Type, Compare>;
friend class flat_set<Type, Compare>; template <typename OtherType, typename OtherCompare>
friend class flat_multi_set;
template <typename OtherType, typename OtherCompare>
friend class flat_set;
template < template <
typename OtherType, typename OtherType,
typename OtherCompare,
typename other_iterator_impl> typename other_iterator_impl>
friend class flat_multi_set_iterator_impl; friend class flat_multi_set_iterator_impl;
@ -143,159 +143,111 @@ private:
}; };
template <typename Type>
class flat_multi_set_const_wrap {
public:
constexpr flat_multi_set_const_wrap(const Type &value)
: _value(value) {
}
constexpr flat_multi_set_const_wrap(Type &&value)
: _value(std::move(value)) {
}
inline constexpr operator const Type&() const {
return _value;
}
constexpr Type &wrapped() {
return _value;
}
private:
Type _value;
};
template <typename Type, typename Compare> template <typename Type, typename Compare>
class flat_multi_set { class flat_multi_set {
class const_wrap { using const_wrap = flat_multi_set_const_wrap<Type>;
public: using impl_t = std::deque<const_wrap>;
constexpr const_wrap(const Type &value)
: _value(value) {
}
constexpr const_wrap(Type &&value)
: _value(std::move(value)) {
}
inline constexpr operator const Type&() const {
return _value;
}
constexpr Type &wrapped() {
return _value;
}
private:
Type _value;
};
class compare {
public:
template <
typename OtherType1,
typename OtherType2,
typename = std::enable_if_t<
!std::is_same_v<std::decay_t<OtherType1>, const_wrap> &&
!std::is_same_v<std::decay_t<OtherType2>, const_wrap>>>
inline constexpr auto operator()(
OtherType1 &&a,
OtherType2 &b) const {
return Compare()(
std::forward<OtherType1>(a),
std::forward<OtherType2>(b));
}
inline constexpr auto operator()(
const const_wrap &a,
const const_wrap &b) const {
return operator()(
static_cast<const Type&>(a),
static_cast<const Type&>(b));
}
template <
typename OtherType,
typename = std::enable_if_t<
!std::is_same_v<std::decay_t<OtherType>, const_wrap>>>
inline constexpr auto operator()(
const const_wrap &a,
OtherType &&b) const {
return operator()(
static_cast<const Type&>(a),
std::forward<OtherType>(b));
}
template <
typename OtherType,
typename = std::enable_if_t<
!std::is_same_v<std::decay_t<OtherType>, const_wrap>>>
inline constexpr auto operator()(
OtherType &&a,
const const_wrap &b) const {
return operator()(
std::forward<OtherType>(a),
static_cast<const Type&>(b));
}
};
using impl = std::deque<const_wrap>;
public: public:
using value_type = Type; using value_type = Type;
using size_type = typename impl::size_type; using size_type = typename impl_t::size_type;
using difference_type = typename impl::difference_type; using difference_type = typename impl_t::difference_type;
using pointer = const Type*; using pointer = const Type*;
using reference = const Type&; using reference = const Type&;
using iterator = flat_multi_set_iterator_impl< using iterator = flat_multi_set_iterator_impl<
Type, Type,
Compare, typename impl_t::iterator>;
typename impl::iterator>;
using const_iterator = flat_multi_set_iterator_impl< using const_iterator = flat_multi_set_iterator_impl<
Type, Type,
Compare, typename impl_t::const_iterator>;
typename impl::const_iterator>;
using reverse_iterator = flat_multi_set_iterator_impl< using reverse_iterator = flat_multi_set_iterator_impl<
Type, Type,
Compare, typename impl_t::reverse_iterator>;
typename impl::reverse_iterator>;
using const_reverse_iterator = flat_multi_set_iterator_impl< using const_reverse_iterator = flat_multi_set_iterator_impl<
Type, Type,
Compare, typename impl_t::const_reverse_iterator>;
typename impl::const_reverse_iterator>;
flat_multi_set() = default; flat_multi_set() = default;
template < template <
typename Iterator, typename Iterator,
typename = typename std::iterator_traits<Iterator>::iterator_category> typename = typename std::iterator_traits<Iterator>::iterator_category>
flat_multi_set(Iterator first, Iterator last) : _impl(first, last) { flat_multi_set(Iterator first, Iterator last)
base::sort(_impl, compare()); : _data(first, last) {
std::sort(std::begin(impl()), std::end(impl()), compare());
} }
flat_multi_set(std::initializer_list<Type> iter) flat_multi_set(std::initializer_list<Type> iter)
: flat_multi_set(iter.begin(), iter.end()) { : flat_multi_set(iter.begin(), iter.end()) {
} }
size_type size() const { size_type size() const {
return _impl.size(); return impl().size();
} }
bool empty() const { bool empty() const {
return _impl.empty(); return impl().empty();
} }
void clear() { void clear() {
_impl.clear(); impl().clear();
} }
iterator begin() { iterator begin() {
return _impl.begin(); return impl().begin();
} }
iterator end() { iterator end() {
return _impl.end(); return impl().end();
} }
const_iterator begin() const { const_iterator begin() const {
return _impl.begin(); return impl().begin();
} }
const_iterator end() const { const_iterator end() const {
return _impl.end(); return impl().end();
} }
const_iterator cbegin() const { const_iterator cbegin() const {
return _impl.cbegin(); return impl().cbegin();
} }
const_iterator cend() const { const_iterator cend() const {
return _impl.cend(); return impl().cend();
} }
reverse_iterator rbegin() { reverse_iterator rbegin() {
return _impl.rbegin(); return impl().rbegin();
} }
reverse_iterator rend() { reverse_iterator rend() {
return _impl.rend(); return impl().rend();
} }
const_reverse_iterator rbegin() const { const_reverse_iterator rbegin() const {
return _impl.rbegin(); return impl().rbegin();
} }
const_reverse_iterator rend() const { const_reverse_iterator rend() const {
return _impl.rend(); return impl().rend();
} }
const_reverse_iterator crbegin() const { const_reverse_iterator crbegin() const {
return _impl.crbegin(); return impl().crbegin();
} }
const_reverse_iterator crend() const { const_reverse_iterator crend() const {
return _impl.crend(); return impl().crend();
} }
reference front() const { reference front() const {
@ -307,25 +259,25 @@ public:
iterator insert(const Type &value) { iterator insert(const Type &value) {
if (empty() || compare()(value, front())) { if (empty() || compare()(value, front())) {
_impl.push_front(value); impl().push_front(value);
return begin(); return begin();
} else if (!compare()(value, back())) { } else if (!compare()(value, back())) {
_impl.push_back(value); impl().push_back(value);
return (end() - 1); return (end() - 1);
} }
auto where = getUpperBound(value); auto where = getUpperBound(value);
return _impl.insert(where, value); return impl().insert(where, value);
} }
iterator insert(Type &&value) { iterator insert(Type &&value) {
if (empty() || compare()(value, front())) { if (empty() || compare()(value, front())) {
_impl.push_front(std::move(value)); impl().push_front(std::move(value));
return begin(); return begin();
} else if (!compare()(value, back())) { } else if (!compare()(value, back())) {
_impl.push_back(std::move(value)); impl().push_back(std::move(value));
return (end() - 1); return (end() - 1);
} }
auto where = getUpperBound(value); auto where = getUpperBound(value);
return _impl.insert(where, std::move(value)); return impl().insert(where, std::move(value));
} }
template <typename... Args> template <typename... Args>
iterator emplace(Args&&... args) { iterator emplace(Args&&... args) {
@ -342,7 +294,7 @@ public:
if (compare()(value, *where)) { if (compare()(value, *where)) {
return false; return false;
} }
_impl.erase(where); impl().erase(where);
return true; return true;
} }
int removeAll(const Type &value) { int removeAll(const Type &value) {
@ -355,15 +307,15 @@ public:
if (range.first == range.second) { if (range.first == range.second) {
return 0; return 0;
} }
_impl.erase(range.first, range.second); impl().erase(range.first, range.second);
return (range.second - range.first); return (range.second - range.first);
} }
iterator erase(const_iterator where) { iterator erase(const_iterator where) {
return _impl.erase(where._impl); return impl().erase(where._impl);
} }
iterator erase(const_iterator from, const_iterator till) { iterator erase(const_iterator from, const_iterator till) {
return _impl.erase(from._impl, till._impl); return impl().erase(from._impl, till._impl);
} }
iterator findFirst(const Type &value) { iterator findFirst(const Type &value) {
@ -373,7 +325,7 @@ public:
return end(); return end();
} }
auto where = getLowerBound(value); auto where = getLowerBound(value);
return compare()(value, *where) ? _impl.end() : where; return compare()(value, *where) ? impl().end() : where;
} }
const_iterator findFirst(const Type &value) const { const_iterator findFirst(const Type &value) const {
@ -383,33 +335,33 @@ public:
return end(); return end();
} }
auto where = getLowerBound(value); auto where = getLowerBound(value);
return compare()(value, *where) ? _impl.end() : where; return compare()(value, *where) ? impl().end() : where;
} }
template < template <
typename OtherType, typename OtherType,
typename = typename Compare::is_transparent> typename = typename Compare::is_transparent>
iterator findFirst(const OtherType &value) { iterator findFirst(const OtherType &value) {
if (empty() if (empty()
|| compare()(value, front()) || compare()(value, front())
|| compare()(back(), value)) { || compare()(back(), value)) {
return end(); return end();
} }
auto where = getLowerBound(value); auto where = getLowerBound(value);
return compare()(value, *where) ? _impl.end() : where; return compare()(value, *where) ? impl().end() : where;
} }
template < template <
typename OtherType, typename OtherType,
typename = typename Compare::is_transparent> typename = typename Compare::is_transparent>
const_iterator findFirst(const OtherType &value) const { const_iterator findFirst(const OtherType &value) const {
if (empty() if (empty()
|| compare()(value, front()) || compare()(value, front())
|| compare()(back(), value)) { || compare()(back(), value)) {
return end(); return end();
} }
auto where = getLowerBound(value); auto where = getLowerBound(value);
return compare()(value, *where) ? _impl.end() : where; return compare()(value, *where) ? impl().end() : where;
} }
bool contains(const Type &value) const { bool contains(const Type &value) const {
@ -450,8 +402,8 @@ public:
typename Iterator, typename Iterator,
typename = typename std::iterator_traits<Iterator>::iterator_category> typename = typename std::iterator_traits<Iterator>::iterator_category>
void merge(Iterator first, Iterator last) { void merge(Iterator first, Iterator last) {
_impl.insert(_impl.end(), first, last); impl().insert(impl().end(), first, last);
base::sort(_impl, compare()); std::sort(std::begin(impl()), std::end(impl()), compare());
} }
void merge(const flat_multi_set<Type, Compare> &other) { void merge(const flat_multi_set<Type, Compare> &other) {
@ -463,44 +415,149 @@ public:
} }
private: private:
impl _impl;
friend class flat_set<Type, Compare>; friend class flat_set<Type, Compare>;
typename impl::iterator getLowerBound(const Type &value) { struct transparent_compare : Compare {
return base::lower_bound(_impl, value, compare()); inline constexpr const Compare &initial() const noexcept {
return *this;
}
template <
typename OtherType1,
typename OtherType2,
typename = std::enable_if_t<
!std::is_same_v<std::decay_t<OtherType1>, const_wrap> &&
!std::is_same_v<std::decay_t<OtherType2>, const_wrap>>>
inline constexpr auto operator()(
OtherType1 &&a,
OtherType2 &&b) const {
return initial()(
std::forward<OtherType1>(a),
std::forward<OtherType2>(b));
}
template <
typename OtherType1,
typename OtherType2>
inline constexpr auto operator()(
OtherType1 &&a,
OtherType2 &&b) const -> std::enable_if_t<
std::is_same_v<std::decay_t<OtherType1>, const_wrap> &&
std::is_same_v<std::decay_t<OtherType2>, const_wrap>, bool> {
return initial()(
static_cast<const Type&>(a),
static_cast<const Type&>(b));
}
template <
typename OtherType,
typename = std::enable_if_t<
!std::is_same_v<std::decay_t<OtherType>, const_wrap>>>
inline constexpr auto operator()(
const const_wrap &a,
OtherType &&b) const {
return initial()(
static_cast<const Type&>(a),
std::forward<OtherType>(b));
}
template <
typename OtherType,
typename = std::enable_if_t<
!std::is_same_v<std::decay_t<OtherType>, const_wrap>>>
inline constexpr auto operator()(
OtherType &&a,
const const_wrap &b) const {
return initial()(
std::forward<OtherType>(a),
static_cast<const Type&>(b));
}
};
struct Data : transparent_compare {
template <typename ...Args>
Data(Args &&...args)
: elements(std::forward<Args>(args)...) {
}
impl_t elements;
};
Data _data;
const transparent_compare &compare() const {
return _data;
} }
typename impl::const_iterator getLowerBound(const Type &value) const { const impl_t &impl() const {
return base::lower_bound(_impl, value, compare()); return _data.elements;
}
impl_t &impl() {
return _data.elements;
}
typename impl_t::iterator getLowerBound(const Type &value) {
return std::lower_bound(
std::begin(impl()),
std::end(impl()),
value,
compare());
}
typename impl_t::const_iterator getLowerBound(const Type &value) const {
return std::lower_bound(
std::begin(impl()),
std::end(impl()),
value,
compare());
} }
template < template <
typename OtherType, typename OtherType,
typename = typename Compare::is_transparent> typename = typename Compare::is_transparent>
typename impl::iterator getLowerBound(const OtherType &value) { typename impl_t::iterator getLowerBound(const OtherType &value) {
return base::lower_bound(_impl, value, compare()); return std::lower_bound(
std::begin(impl()),
std::end(impl()),
value,
compare());
} }
template < template <
typename OtherType, typename OtherType,
typename = typename Compare::is_transparent> typename = typename Compare::is_transparent>
typename impl::const_iterator getLowerBound(const OtherType &value) const { typename impl_t::const_iterator getLowerBound(const OtherType &value) const {
return base::lower_bound(_impl, value, compare()); return std::lower_bound(
std::begin(impl()),
std::end(impl()),
value,
compare());
} }
typename impl::iterator getUpperBound(const Type &value) { typename impl_t::iterator getUpperBound(const Type &value) {
return base::upper_bound(_impl, value, compare()); return std::upper_bound(
std::begin(impl()),
std::end(impl()),
value,
compare());
} }
typename impl::const_iterator getUpperBound(const Type &value) const { typename impl_t::const_iterator getUpperBound(const Type &value) const {
return base::upper_bound(_impl, value, compare()); return std::upper_bound(
std::begin(impl()),
std::end(impl()),
value,
compare());
} }
std::pair< std::pair<
typename impl::iterator, typename impl_t::iterator,
typename impl::iterator typename impl_t::iterator
> getEqualRange(const Type &value) { > getEqualRange(const Type &value) {
return base::equal_range(_impl, value, compare()); return std::equal_range(
std::begin(impl()),
std::end(impl()),
value,
compare());
} }
std::pair< std::pair<
typename impl::const_iterator, typename impl_t::const_iterator,
typename impl::const_iterator typename impl_t::const_iterator
> getEqualRange(const Type &value) const { > getEqualRange(const Type &value) const {
return base::equal_range(_impl, value, compare()); return std::equal_range(
std::begin(impl()),
std::end(impl()),
value,
compare());
} }
}; };
@ -508,7 +565,6 @@ private:
template <typename Type, typename Compare> template <typename Type, typename Compare>
class flat_set : private flat_multi_set<Type, Compare> { class flat_set : private flat_multi_set<Type, Compare> {
using parent = flat_multi_set<Type, Compare>; using parent = flat_multi_set<Type, Compare>;
using compare = typename parent::compare;
public: public:
using iterator = typename parent::iterator; using iterator = typename parent::iterator;
@ -553,30 +609,30 @@ public:
using parent::erase; using parent::erase;
iterator insert(const Type &value) { iterator insert(const Type &value) {
if (this->empty() || compare()(value, this->front())) { if (this->empty() || this->compare()(value, this->front())) {
this->_impl.push_front(value); this->impl().push_front(value);
return this->begin(); return this->begin();
} else if (compare()(this->back(), value)) { } else if (this->compare()(this->back(), value)) {
this->_impl.push_back(value); this->impl().push_back(value);
return (this->end() - 1); return (this->end() - 1);
} }
auto where = this->getLowerBound(value); auto where = this->getLowerBound(value);
if (compare()(value, *where)) { if (this->compare()(value, *where)) {
return this->_impl.insert(where, value); return this->impl().insert(where, value);
} }
return this->end(); return this->end();
} }
iterator insert(Type &&value) { iterator insert(Type &&value) {
if (this->empty() || compare()(value, this->front())) { if (this->empty() || this->compare()(value, this->front())) {
this->_impl.push_front(std::move(value)); this->impl().push_front(std::move(value));
return this->begin(); return this->begin();
} else if (compare()(this->back(), value)) { } else if (this->compare()(this->back(), value)) {
this->_impl.push_back(std::move(value)); this->impl().push_back(std::move(value));
return (this->end() - 1); return (this->end() - 1);
} }
auto where = this->getLowerBound(value); auto where = this->getLowerBound(value);
if (compare()(value, *where)) { if (this->compare()(value, *where)) {
return this->_impl.insert(where, std::move(value)); return this->impl().insert(where, std::move(value));
} }
return this->end(); return this->end();
} }
@ -612,9 +668,9 @@ public:
void modify(iterator which, Action action) { void modify(iterator which, Action action) {
action(which.wrapped()); action(which.wrapped());
for (auto i = iterator(which + 1), e = end(); i != e; ++i) { for (auto i = iterator(which + 1), e = end(); i != e; ++i) {
if (compare()(*i, *which)) { if (this->compare()(*i, *which)) {
std::swap(i.wrapped(), which.wrapped()); std::swap(i.wrapped(), which.wrapped());
} else if (!compare()(*which, *i)) { } else if (!this->compare()(*which, *i)) {
erase(which); erase(which);
return; return;
} else{ } else{
@ -623,9 +679,9 @@ public:
} }
for (auto i = which, b = begin(); i != b;) { for (auto i = which, b = begin(); i != b;) {
--i; --i;
if (compare()(*which, *i)) { if (this->compare()(*which, *i)) {
std::swap(i.wrapped(), which.wrapped()); std::swap(i.wrapped(), which.wrapped());
} else if (!compare()(*i, *which)) { } else if (!this->compare()(*i, *which)) {
erase(which); erase(which);
return; return;
} else { } else {
@ -652,12 +708,15 @@ public:
private: private:
void finalize() { void finalize() {
this->_impl.erase( this->impl().erase(
std::unique( std::unique(
this->_impl.begin(), std::begin(this->impl()),
this->_impl.end(), std::end(this->impl()),
[](auto &&a, auto &&b) { return !compare()(a, b); }), [&](auto &&a, auto &&b) {
this->_impl.end()); return !this->compare()(a, b);
}
),
std::end(this->impl()));
} }
}; };

View File

@ -22,7 +22,27 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include "base/flat_set.h" #include "base/flat_set.h"
struct int_wrap {
int value;
};
struct int_wrap_comparator {
using is_transparent = void;
inline bool operator()(const int &a, const int_wrap &b) const {
return a < b.value;
}
inline bool operator()(const int_wrap &a, const int_wrap &b) const {
return a.value < b.value;
}
inline bool operator()(const int_wrap &a, const int &b) const {
return a.value < b;
}
inline bool operator()(const int &a, const int &b) const {
return a < b;
}
};
TEST_CASE("flat_sets should keep items sorted", "[flat_set]") { TEST_CASE("flat_sets should keep items sorted", "[flat_set]") {
base::flat_set<int> v; base::flat_set<int> v;
v.insert(0); v.insert(0);
v.insert(5); v.insert(5);
@ -48,3 +68,30 @@ TEST_CASE("flat_sets should keep items sorted", "[flat_set]") {
checkSorted(); checkSorted();
} }
} }
TEST_CASE("flat_sets with custom comparators", "[flat_set]") {
base::flat_set<int_wrap, int_wrap_comparator> v;
v.insert({ 0 });
v.insert({ 5 });
v.insert({ 4 });
v.insert({ 2 });
REQUIRE(v.find(4) != v.end());
auto checkSorted = [&] {
auto prev = v.begin();
REQUIRE(prev != v.end());
for (auto i = prev + 1; i != v.end(); prev = i, ++i) {
REQUIRE(prev->value < i->value);
}
};
REQUIRE(v.size() == 4);
checkSorted();
SECTION("adding item puts it in the right position") {
v.insert({ 3 });
REQUIRE(v.size() == 5);
REQUIRE(v.find(3) != v.end());
checkSorted();
}
}

View File

@ -593,8 +593,8 @@ void PeerListContent::addRowEntry(not_null<PeerListRow*> row) {
void PeerListContent::invalidatePixmapsCache() { void PeerListContent::invalidatePixmapsCache() {
auto invalidate = [](auto &&row) { row->invalidatePixmapsCache(); }; auto invalidate = [](auto &&row) { row->invalidatePixmapsCache(); };
base::for_each(_rows, invalidate); ranges::for_each(_rows, invalidate);
base::for_each(_searchRows, invalidate); ranges::for_each(_searchRows, invalidate);
} }
bool PeerListContent::addingToSearchIndex() const { bool PeerListContent::addingToSearchIndex() const {

View File

@ -648,11 +648,11 @@ void EditChatAdminsBoxController::rebuildRows() {
admins.insert(admins.end(), others.begin(), others.end()); admins.insert(admins.end(), others.begin(), others.end());
others.clear(); others.clear();
} }
auto sortByName = [](auto a, auto b) { auto sortByName = [](not_null<UserData*> a, auto b) {
return (a->name.compare(b->name, Qt::CaseInsensitive) < 0); return (a->name.compare(b->name, Qt::CaseInsensitive) < 0);
}; };
base::sort(admins, sortByName); ranges::sort(admins, sortByName);
base::sort(others, sortByName); ranges::sort(others, sortByName);
auto addOne = [this](not_null<UserData*> user) { auto addOne = [this](not_null<UserData*> user) {
if (auto row = createRow(user)) { if (auto row = createRow(user)) {
@ -664,8 +664,8 @@ void EditChatAdminsBoxController::rebuildRows() {
addOne(creator); addOne(creator);
} }
} }
base::for_each(admins, addOne); ranges::for_each(admins, addOne);
base::for_each(others, addOne); ranges::for_each(others, addOne);
delegate()->peerListRefreshRows(); delegate()->peerListRefreshRows();
} }

View File

@ -538,7 +538,7 @@ void Controller::usernameChanged() {
_checkUsernameTimer.cancel(); _checkUsernameTimer.cancel();
return; return;
} }
auto bad = base::find_if(username, [](QChar ch) { auto bad = ranges::find_if(username, [](QChar ch) {
return (ch < 'A' || ch > 'Z') return (ch < 'A' || ch > 'Z')
&& (ch < 'a' || ch > 'z') && (ch < 'a' || ch > 'z')
&& (ch < '0' || ch > '9') && (ch < '0' || ch > '9')

View File

@ -51,10 +51,10 @@ public:
bool canAddItem(not_null<const HistoryItem*> item) const { bool canAddItem(not_null<const HistoryItem*> item) const {
return (ComputeType(item) == _type && item->date.date() == _date); return (ComputeType(item) == _type && item->date.date() == _date);
} }
void addItem(HistoryItem *item) { void addItem(not_null<HistoryItem*> item) {
Expects(canAddItem(item)); Expects(canAddItem(item));
_items.push_back(item); _items.push_back(item);
base::sort(_items, [](HistoryItem *a, HistoryItem *b) { ranges::sort(_items, [](not_null<HistoryItem*> a, auto b) {
return (a->id > b->id); return (a->id > b->id);
}); });
refreshStatus(); refreshStatus();
@ -116,7 +116,7 @@ private:
void refreshStatus(); void refreshStatus();
static Type ComputeType(not_null<const HistoryItem*> item); static Type ComputeType(not_null<const HistoryItem*> item);
std::vector<HistoryItem*> _items; std::vector<not_null<HistoryItem*>> _items;
QDate _date; QDate _date;
Type _type; Type _type;

View File

@ -62,7 +62,7 @@ base::optional<int> SparseIdsSlice::distance(
} }
base::optional<MsgId> SparseIdsSlice::nearest(MsgId msgId) const { base::optional<MsgId> SparseIdsSlice::nearest(MsgId msgId) const {
if (auto it = base::lower_bound(_ids, msgId); it != _ids.end()) { if (auto it = ranges::lower_bound(_ids, msgId); it != _ids.end()) {
return *it; return *it;
} else if (_ids.empty()) { } else if (_ids.empty()) {
return base::none; return base::none;
@ -342,7 +342,7 @@ void SparseIdsSliceBuilder::sliceToLimits() {
return; return;
} }
auto requestedSomething = false; auto requestedSomething = false;
auto aroundIt = base::lower_bound(_ids, _key); auto aroundIt = ranges::lower_bound(_ids, _key);
auto removeFromBegin = (aroundIt - _ids.begin() - _limitBefore); auto removeFromBegin = (aroundIt - _ids.begin() - _limitBefore);
auto removeFromEnd = (_ids.end() - aroundIt - _limitAfter - 1); auto removeFromEnd = (_ids.end() - aroundIt - _limitAfter - 1);
if (removeFromBegin > 0) { if (removeFromBegin > 0) {

View File

@ -60,7 +60,8 @@ private:
}; };
UserPhotosSlice::UserPhotosSlice(Key key) : UserPhotosSlice( UserPhotosSlice::UserPhotosSlice(Key key)
: UserPhotosSlice(
key, key,
{}, {},
base::none, base::none,
@ -74,15 +75,15 @@ UserPhotosSlice::UserPhotosSlice(
base::optional<int> fullCount, base::optional<int> fullCount,
base::optional<int> skippedBefore, base::optional<int> skippedBefore,
int skippedAfter) int skippedAfter)
: _key(key) : _key(key)
, _ids(ids) , _ids(ids)
, _fullCount(fullCount) , _fullCount(fullCount)
, _skippedBefore(skippedBefore) , _skippedBefore(skippedBefore)
, _skippedAfter(skippedAfter) { , _skippedAfter(skippedAfter) {
} }
base::optional<int> UserPhotosSlice::indexOf(PhotoId photoId) const { base::optional<int> UserPhotosSlice::indexOf(PhotoId photoId) const {
auto it = base::find(_ids, photoId); auto it = ranges::find(_ids, photoId);
if (it != _ids.end()) { if (it != _ids.end()) {
return (it - _ids.begin()); return (it - _ids.begin());
} }
@ -190,7 +191,7 @@ void UserPhotosSliceBuilder::mergeSliceData(
} }
void UserPhotosSliceBuilder::sliceToLimits() { void UserPhotosSliceBuilder::sliceToLimits() {
auto aroundIt = base::find(_ids, _key.photoId); auto aroundIt = ranges::find(_ids, _key.photoId);
auto removeFromBegin = (aroundIt - _ids.begin() - _limitBefore); auto removeFromBegin = (aroundIt - _ids.begin() - _limitBefore);
auto removeFromEnd = (_ids.end() - aroundIt - _limitAfter - 1); auto removeFromEnd = (_ids.end() - aroundIt - _limitAfter - 1);
if (removeFromEnd > 0) { if (removeFromEnd > 0) {

View File

@ -73,7 +73,7 @@ QString TopBarOverride::generateText() const {
} }
bool TopBarOverride::computeCanDelete() const { bool TopBarOverride::computeCanDelete() const {
return base::find_if(_items.list, [](const SelectedItem &item) { return ranges::find_if(_items.list, [](const SelectedItem &item) {
return !item.canDelete; return !item.canDelete;
}) == _items.list.end(); }) == _items.list.end();
} }

View File

@ -104,6 +104,10 @@ public:
return _height; return _height;
} }
int bottom() const {
return top() + height();
}
bool removeItem(UniversalMsgId universalId); bool removeItem(UniversalMsgId universalId);
FoundItem findItemNearId(UniversalMsgId universalId) const; FoundItem findItemNearId(UniversalMsgId universalId) const;
FoundItem findItemByPoint(QPoint point) const; FoundItem findItemByPoint(QPoint point) const;
@ -302,12 +306,11 @@ auto ListWidget::Section::findItemByPoint(
auto ListWidget::Section::findItemNearId( auto ListWidget::Section::findItemNearId(
UniversalMsgId universalId) const -> FoundItem { UniversalMsgId universalId) const -> FoundItem {
Expects(!_items.empty()); Expects(!_items.empty());
auto itemIt = base::lower_bound( auto itemIt = ranges::lower_bound(
_items, _items,
universalId, universalId,
[this](const auto &item, UniversalMsgId universalId) { std::greater<>(),
return (item.first > universalId); [](const auto &item) -> UniversalMsgId { return item.first; });
});
if (itemIt == _items.end()) { if (itemIt == _items.end()) {
--itemIt; --itemIt;
} }
@ -318,36 +321,39 @@ auto ListWidget::Section::findItemNearId(
auto ListWidget::Section::findItemAfterTop( auto ListWidget::Section::findItemAfterTop(
int top) -> Items::iterator { int top) -> Items::iterator {
return base::lower_bound( return ranges::lower_bound(
_items, _items,
top, top,
[this](const auto &item, int top) { std::less_equal<>(),
[this](const auto &item) {
auto itemTop = item.second->position() / _itemsInRow; auto itemTop = item.second->position() / _itemsInRow;
return (itemTop + item.second->height()) <= top; return itemTop + item.second->height();
}); });
} }
auto ListWidget::Section::findItemAfterTop( auto ListWidget::Section::findItemAfterTop(
int top) const -> Items::const_iterator { int top) const -> Items::const_iterator {
return base::lower_bound( return ranges::lower_bound(
_items, _items,
top, top,
[this](const auto &item, int top) { std::less_equal<>(),
auto itemTop = item.second->position() / _itemsInRow; [this](const auto &item) {
return (itemTop + item.second->height()) <= top; auto itemTop = item.second->position() / _itemsInRow;
}); return itemTop + item.second->height();
});
} }
auto ListWidget::Section::findItemAfterBottom( auto ListWidget::Section::findItemAfterBottom(
Items::const_iterator from, Items::const_iterator from,
int bottom) const -> Items::const_iterator { int bottom) const -> Items::const_iterator {
return std::lower_bound( return ranges::lower_bound(
from, from,
_items.end(), _items.end(),
bottom, bottom,
[this](const auto &item, int bottom) { std::less<>(),
[this](const auto &item) {
auto itemTop = item.second->position() / _itemsInRow; auto itemTop = item.second->position() / _itemsInRow;
return itemTop < bottom; return itemTop;
}); });
} }
@ -1182,12 +1188,12 @@ void ListWidget::showContextMenu(
} }
auto canDeleteAll = [&] { auto canDeleteAll = [&] {
return base::find_if(_selected, [](auto &item) { return ranges::find_if(_selected, [](auto &&item) {
return !item.second.canDelete; return !item.second.canDelete;
}) == _selected.end(); }) == _selected.end();
}; };
auto canForwardAll = [&] { auto canForwardAll = [&] {
return base::find_if(_selected, [](auto &item) { return ranges::find_if(_selected, [](auto &&item) {
return !item.second.canForward; return !item.second.canForward;
}) == _selected.end(); }) == _selected.end();
}; };
@ -2042,44 +2048,40 @@ void ListWidget::clearStaleLayouts() {
auto ListWidget::findSectionByItem( auto ListWidget::findSectionByItem(
UniversalMsgId universalId) -> std::vector<Section>::iterator { UniversalMsgId universalId) -> std::vector<Section>::iterator {
return base::lower_bound( return ranges::lower_bound(
_sections, _sections,
universalId, universalId,
[](const Section &section, int universalId) { std::greater<>(),
return section.minId() > universalId; [](const Section &section) { return section.minId(); });
});
} }
auto ListWidget::findSectionAfterTop( auto ListWidget::findSectionAfterTop(
int top) -> std::vector<Section>::iterator { int top) -> std::vector<Section>::iterator {
return base::lower_bound( return ranges::lower_bound(
_sections, _sections,
top, top,
[](const Section &section, int top) { std::less_equal<>(),
return (section.top() + section.height()) <= top; [](const Section &section) { return section.bottom(); });
});
} }
auto ListWidget::findSectionAfterTop( auto ListWidget::findSectionAfterTop(
int top) const -> std::vector<Section>::const_iterator { int top) const -> std::vector<Section>::const_iterator {
return base::lower_bound( return ranges::lower_bound(
_sections, _sections,
top, top,
[](const Section &section, int top) { std::less_equal<>(),
return (section.top() + section.height()) <= top; [](const Section &section) { return section.bottom(); });
});
} }
auto ListWidget::findSectionAfterBottom( auto ListWidget::findSectionAfterBottom(
std::vector<Section>::const_iterator from, std::vector<Section>::const_iterator from,
int bottom) const -> std::vector<Section>::const_iterator { int bottom) const -> std::vector<Section>::const_iterator {
return std::lower_bound( return ranges::lower_bound(
from, from,
_sections.end(), _sections.end(),
bottom, bottom,
[](const Section &section, int bottom) { std::less<>(),
return section.top() < bottom; [](const Section &section) { return section.top(); });
});
} }
ListWidget::~ListWidget() = default; ListWidget::~ListWidget() = default;

View File

@ -341,7 +341,7 @@ DcOptions::Ids DcOptions::configEnumDcIds() const {
} }
} }
} }
base::sort(result); ranges::sort(result);
return result; return result;
} }

View File

@ -181,7 +181,7 @@ bool UnsafeShowOpenWithDropdown(const QString &filepath, QPoint menuPosition) {
if (!handlers.empty()) { if (!handlers.empty()) {
HMENU menu = CreatePopupMenu(); HMENU menu = CreatePopupMenu();
base::sort(handlers, [](const OpenWithApp &a, const OpenWithApp &b) { ranges::sort(handlers, [](const OpenWithApp &a, auto &b) {
return a.name() < b.name(); return a.name() < b.name();
}); });
for (int32 i = 0, l = handlers.size(); i < l; ++i) { for (int32 i = 0, l = handlers.size(); i < l; ++i) {

View File

@ -277,13 +277,13 @@ std::unique_ptr<PeerListState> ParticipantsBoxController::saveState() {
return; return;
} }
} }
auto pos = base::find(weak->list, user); auto pos = ranges::find(weak->list, user);
if (pos == weak->list.cend()) { if (pos == weak->list.cend()) {
weak->list.push_back(user); weak->list.push_back(user);
} }
base::stable_partition(weak->list, [user](not_null<PeerData*> peer) { ranges::stable_partition(
return (peer == user); weak->list,
}); [user](auto peer) { return (peer == user); });
}, my->lifetime); }, my->lifetime);
Auth().data().megagroupParticipantRemoved(_channel) Auth().data().megagroupParticipantRemoved(_channel)
| rpl::start_with_next([weak](not_null<UserData*> user) { | rpl::start_with_next([weak](not_null<UserData*> user) {

View File

@ -326,7 +326,7 @@ inline auto combine(
state->latest.push_back( state->latest.push_back(
std::move(*value)); std::move(*value));
} }
base::take(state->accumulated); details::take(state->accumulated);
consumer.put_next_copy(state->latest); consumer.put_next_copy(state->latest);
} }
} }

View File

@ -128,7 +128,7 @@ template <typename Value, typename Error>
inline void type_erased_handlers<Value, Error>::terminate() { inline void type_erased_handlers<Value, Error>::terminate() {
if (!_terminated) { if (!_terminated) {
_terminated = true; _terminated = true;
base::take(_lifetime).destroy(); details::take(_lifetime).destroy();
} }
} }

View File

@ -25,7 +25,6 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include <rpl/then.h> #include <rpl/then.h>
#include <rpl/range.h> #include <rpl/range.h>
#include <algorithm> #include <algorithm>
#include "base/algorithm.h"
#include "base/assertion.h" #include "base/assertion.h"
#include "base/index_based_iterator.h" #include "base/index_based_iterator.h"
@ -54,8 +53,9 @@ public:
if (auto strong = weak.lock()) { if (auto strong = weak.lock()) {
auto result = [weak, consumer] { auto result = [weak, consumer] {
if (auto strong = weak.lock()) { if (auto strong = weak.lock()) {
auto it = base::find( auto it = std::find(
strong->consumers, strong->consumers.begin(),
strong->consumers.end(),
consumer); consumer);
if (it != strong->consumers.end()) { if (it != strong->consumers.end()) {
it->terminate(); it->terminate();
@ -94,13 +94,13 @@ inline event_stream<Value>::event_stream() {
template <typename Value> template <typename Value>
inline event_stream<Value>::event_stream(event_stream &&other) inline event_stream<Value>::event_stream(event_stream &&other)
: _data(base::take(other._data)) { : _data(details::take(other._data)) {
} }
template <typename Value> template <typename Value>
inline event_stream<Value> &event_stream<Value>::operator=( inline event_stream<Value> &event_stream<Value>::operator=(
event_stream &&other) { event_stream &&other) {
_data = base::take(other._data); _data = details::take(other._data);
return *this; return *this;
} }
@ -164,7 +164,7 @@ inline auto event_stream<Value>::weak() const
template <typename Value> template <typename Value>
inline event_stream<Value>::~event_stream() { inline event_stream<Value>::~event_stream() {
if (auto data = base::take(_data)) { if (auto data = details::take(_data)) {
for (auto &consumer : data->consumers) { for (auto &consumer : data->consumers) {
consumer.put_done(); consumer.put_done();
} }

View File

@ -21,10 +21,17 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#pragma once #pragma once
#include "base/lambda.h" #include "base/lambda.h"
#include "base/algorithm.h"
#include <deque> #include <deque>
namespace rpl { namespace rpl {
namespace details {
template <typename Type>
inline Type take(Type &value) {
return std::exchange(value, Type{});
}
} // namespace details
class lifetime { class lifetime {
public: public:
@ -47,7 +54,7 @@ public:
auto result = new Type(std::forward<Args>(args)...); auto result = new Type(std::forward<Args>(args)...);
add([result]() mutable { add([result]() mutable {
static_assert(sizeof(Type) > 0, "Can't delete unknown type."); static_assert(sizeof(Type) > 0, "Can't delete unknown type.");
delete base::take(result); delete details::take(result);
}); });
return result; return result;
} }
@ -60,7 +67,7 @@ private:
}; };
inline lifetime::lifetime(lifetime &&other) inline lifetime::lifetime(lifetime &&other)
: _callbacks(base::take(other._callbacks)) { : _callbacks(details::take(other._callbacks)) {
} }
inline lifetime &lifetime::operator=(lifetime &&other) { inline lifetime &lifetime::operator=(lifetime &&other) {
@ -80,7 +87,7 @@ inline void lifetime::add(Destroy &&destroy) {
} }
inline void lifetime::add(lifetime &&other) { inline void lifetime::add(lifetime &&other) {
auto callbacks = base::take(other._callbacks); auto callbacks = details::take(other._callbacks);
_callbacks.insert( _callbacks.insert(
_callbacks.begin(), _callbacks.begin(),
std::make_move_iterator(callbacks.begin()), std::make_move_iterator(callbacks.begin()),
@ -88,7 +95,7 @@ inline void lifetime::add(lifetime &&other) {
} }
inline void lifetime::destroy() { inline void lifetime::destroy() {
for (auto &callback : base::take(_callbacks)) { for (auto &callback : details::take(_callbacks)) {
callback(); callback();
} }
} }

View File

@ -57,8 +57,8 @@ public:
} }
} }
InvokeCounter(InvokeCounter &&other) InvokeCounter(InvokeCounter &&other)
: _copyCounter(base::take(other._copyCounter)) : _copyCounter(details::take(other._copyCounter))
, _moveCounter(base::take(other._moveCounter)) { , _moveCounter(details::take(other._moveCounter)) {
if (_moveCounter) { if (_moveCounter) {
++*_moveCounter; ++*_moveCounter;
} }
@ -72,8 +72,8 @@ public:
return *this; return *this;
} }
InvokeCounter &operator=(InvokeCounter &&other) { InvokeCounter &operator=(InvokeCounter &&other) {
_copyCounter = base::take(other._copyCounter); _copyCounter = details::take(other._copyCounter);
_moveCounter = base::take(other._moveCounter); _moveCounter = details::take(other._moveCounter);
if (_moveCounter) { if (_moveCounter) {
++*_moveCounter; ++*_moveCounter;
} }

View File

@ -80,14 +80,16 @@ int SparseIdsList::addRangeItemsAndCountNew(
return 0; return 0;
} }
auto uniteFrom = base::lower_bound( auto uniteFrom = ranges::lower_bound(
_slices, _slices,
noSkipRange.from, noSkipRange.from,
[](const Slice &slice, MsgId from) { return slice.range.till < from; }); std::less<>(),
auto uniteTill = base::upper_bound( [](const Slice &slice) { return slice.range.till; });
auto uniteTill = ranges::upper_bound(
_slices, _slices,
noSkipRange.till, noSkipRange.till,
[](MsgId till, const Slice &slice) { return till < slice.range.from; }); std::less<>(),
[](const Slice &slice) { return slice.range.from; });
if (uniteFrom < uniteTill) { if (uniteFrom < uniteTill) {
return uniteAndAdd(update, uniteFrom, uniteTill, messages, noSkipRange); return uniteAndAdd(update, uniteFrom, uniteTill, messages, noSkipRange);
} }
@ -151,10 +153,11 @@ void SparseIdsList::addSlice(
} }
void SparseIdsList::removeOne(MsgId messageId) { void SparseIdsList::removeOne(MsgId messageId) {
auto slice = base::lower_bound( auto slice = ranges::lower_bound(
_slices, _slices,
messageId, messageId,
[](const Slice &slice, MsgId from) { return slice.range.till < from; }); std::less<>(),
[](const Slice &slice) { return slice.range.till; });
if (slice != _slices.end() && slice->range.from <= messageId) { if (slice != _slices.end() && slice->range.from <= messageId) {
_slices.modify(slice, [messageId](Slice &slice) { _slices.modify(slice, [messageId](Slice &slice) {
return slice.messages.remove(messageId); return slice.messages.remove(messageId);
@ -175,12 +178,11 @@ rpl::producer<SparseIdsListResult> SparseIdsList::query(
SparseIdsListQuery &&query) const { SparseIdsListQuery &&query) const {
return [this, query = std::move(query)](auto consumer) { return [this, query = std::move(query)](auto consumer) {
auto slice = query.aroundId auto slice = query.aroundId
? base::lower_bound( ? ranges::lower_bound(
_slices, _slices,
query.aroundId, query.aroundId,
[](const Slice &slice, MsgId id) { std::less<>(),
return slice.range.till < id; [](const Slice &slice) { return slice.range.till; })
})
: _slices.end(); : _slices.end();
if (slice != _slices.end() if (slice != _slices.end()
&& slice->range.from <= query.aroundId) { && slice->range.from <= query.aroundId) {
@ -199,7 +201,7 @@ SparseIdsListResult SparseIdsList::queryFromSlice(
const SparseIdsListQuery &query, const SparseIdsListQuery &query,
const Slice &slice) const { const Slice &slice) const {
auto result = SparseIdsListResult {}; auto result = SparseIdsListResult {};
auto position = base::lower_bound(slice.messages, query.aroundId); auto position = ranges::lower_bound(slice.messages, query.aroundId);
auto haveBefore = int(position - slice.messages.begin()); auto haveBefore = int(position - slice.messages.begin());
auto haveEqualOrAfter = int(slice.messages.end() - position); auto haveEqualOrAfter = int(slice.messages.end() - position);
auto before = qMin(haveBefore, query.limitBefore); auto before = qMin(haveBefore, query.limitBefore);

View File

@ -51,7 +51,7 @@ void UserPhotos::List::addSlice(
} }
void UserPhotos::List::removeOne(PhotoId photoId) { void UserPhotos::List::removeOne(PhotoId photoId) {
auto position = base::find(_photoIds, photoId); auto position = ranges::find(_photoIds, photoId);
if (position == _photoIds.end()) { if (position == _photoIds.end()) {
_count = base::none; _count = base::none;
} else { } else {
@ -64,7 +64,7 @@ void UserPhotos::List::removeOne(PhotoId photoId) {
} }
void UserPhotos::List::removeAfter(PhotoId photoId) { void UserPhotos::List::removeAfter(PhotoId photoId) {
auto position = base::find(_photoIds, photoId); auto position = ranges::find(_photoIds, photoId);
if (position == _photoIds.end()) { if (position == _photoIds.end()) {
_count = base::none; _count = base::none;
_photoIds.clear(); _photoIds.clear();
@ -90,7 +90,7 @@ rpl::producer<UserPhotosResult> UserPhotos::List::query(
auto result = UserPhotosResult {}; auto result = UserPhotosResult {};
result.count = _count; result.count = _count;
auto position = base::find(_photoIds, query.key.photoId); auto position = ranges::find(_photoIds, query.key.photoId);
if (position != _photoIds.end()) { if (position != _photoIds.end()) {
auto haveBefore = int(position - _photoIds.begin()); auto haveBefore = int(position - _photoIds.begin());
auto haveEqualOrAfter = int(_photoIds.end() - position); auto haveEqualOrAfter = int(_photoIds.end() - position);

View File

@ -21,6 +21,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include "ui/wrap/slide_wrap.h" #include "ui/wrap/slide_wrap.h"
#include <rpl/combine.h> #include <rpl/combine.h>
#include <range/v3/algorithm/find.hpp>
namespace Ui { namespace Ui {
@ -156,7 +157,7 @@ rpl::producer<bool> MultiSlideTracker::atLeastOneShownValue() const {
return rpl::combine( return rpl::combine(
std::move(shown), std::move(shown),
[](const std::vector<bool> &values) { [](const std::vector<bool> &values) {
return base::find(values, true) != values.end(); return ranges::find(values, true) != values.end();
}); });
} }

View File

@ -131,7 +131,7 @@ RpWidget *VerticalLayout::addChild(
} }
void VerticalLayout::childHeightUpdated(RpWidget *child) { void VerticalLayout::childHeightUpdated(RpWidget *child) {
auto it = base::find_if(_rows, [child](const Row &row) { auto it = ranges::find_if(_rows, [child](const Row &row) {
return (row.widget == child); return (row.widget == child);
}); });
@ -158,7 +158,7 @@ void VerticalLayout::childHeightUpdated(RpWidget *child) {
} }
void VerticalLayout::removeChild(RpWidget *child) { void VerticalLayout::removeChild(RpWidget *child) {
auto it = base::find_if(_rows, [child](const Row &row) { auto it = ranges::find_if(_rows, [child](const Row &row) {
return (row.widget == child); return (row.widget == child);
}); });
auto end = _rows.end(); auto end = _rows.end();

View File

@ -386,17 +386,23 @@ int Completer::findEqualCharsCount(int position, const utf16string *word) {
std::vector<Suggestion> Completer::prepareResult() { std::vector<Suggestion> Completer::prepareResult() {
auto firstCharOfQuery = _query[0]; auto firstCharOfQuery = _query[0];
base::stable_partition(_result, [firstCharOfQuery](Result &result) { auto reorder = [&](auto &&predicate) {
std::stable_partition(
std::begin(_result),
std::end(_result),
std::forward<decltype(predicate)>(predicate));
};
reorder([firstCharOfQuery](Result &result) {
auto firstCharAfterColon = result.replacement->replacement[1]; auto firstCharAfterColon = result.replacement->replacement[1];
return (firstCharAfterColon == firstCharOfQuery); return (firstCharAfterColon == firstCharOfQuery);
}); });
base::stable_partition(_result, [](Result &result) { reorder([](Result &result) {
return (result.wordsUsed < 2); return (result.wordsUsed < 2);
}); });
base::stable_partition(_result, [](Result &result) { reorder([](Result &result) {
return (result.wordsUsed < 3); return (result.wordsUsed < 3);
}); });
base::stable_partition(_result, [this](Result &result) { reorder([&](Result &result) {
return isExactMatch(result.replacement->replacement); return isExactMatch(result.replacement->replacement);
}); });
@ -412,13 +418,19 @@ std::vector<Suggestion> Completer::prepareResult() {
} }
string_span Completer::findWordsStartingWith(utf16char ch) { string_span Completer::findWordsStartingWith(utf16char ch) {
auto begin = base::lower_bound(_currentItemWords, ch, [](utf16string word, utf16char ch) { auto begin = std::lower_bound(
return word[0] < ch; std::begin(_currentItemWords),
}); std::end(_currentItemWords),
auto end = base::upper_bound(_currentItemWords, ch, [](utf16char ch, utf16string word) { ch,
return ch < word[0]; [](utf16string word, utf16char ch) { return word[0] < ch; });
}); auto end = std::upper_bound(
return _currentItemWords.subspan(begin - _currentItemWords.begin(), end - begin); std::begin(_currentItemWords),
std::end(_currentItemWords),
ch,
[](utf16char ch, utf16string word) { return ch < word[0]; });
return _currentItemWords.subspan(
begin - _currentItemWords.begin(),
end - begin);
} }
} // namespace } // namespace

View File

@ -26,7 +26,8 @@
'<(src_loc)', '<(src_loc)',
'<(submodules_loc)/GSL/include', '<(submodules_loc)/GSL/include',
'<(submodules_loc)/variant/include', '<(submodules_loc)/variant/include',
'<(submodules_loc)/Catch/include' '<(submodules_loc)/Catch/include',
'<(libs_loc)/range-v3/include',
], ],
'sources': [ 'sources': [
'<(src_loc)/base/tests_main.cpp', '<(src_loc)/base/tests_main.cpp',