2021-01-01 13:59:53 +01:00
|
|
|
//
|
2022-01-01 01:35:39 +01:00
|
|
|
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2022
|
2021-01-01 13:59:53 +01:00
|
|
|
//
|
|
|
|
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
|
|
|
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|
|
|
//
|
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include "td/utils/common.h"
|
|
|
|
|
|
|
|
#include <functional>
|
|
|
|
#include <type_traits>
|
|
|
|
#include <utility>
|
|
|
|
|
|
|
|
namespace td {
|
|
|
|
|
|
|
|
namespace detail {
|
|
|
|
|
|
|
|
template <typename V>
|
|
|
|
struct transform_helper {
|
|
|
|
template <class Func>
|
|
|
|
auto transform(const V &v, const Func &f) {
|
|
|
|
vector<decltype(f(*v.begin()))> result;
|
|
|
|
result.reserve(v.size());
|
|
|
|
for (auto &x : v) {
|
|
|
|
result.push_back(f(x));
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class Func>
|
|
|
|
auto transform(V &&v, const Func &f) {
|
|
|
|
vector<decltype(f(std::move(*v.begin())))> result;
|
|
|
|
result.reserve(v.size());
|
|
|
|
for (auto &x : v) {
|
|
|
|
result.push_back(f(std::move(x)));
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
} // namespace detail
|
|
|
|
|
|
|
|
template <class V, class Func>
|
|
|
|
auto transform(V &&v, const Func &f) {
|
|
|
|
return detail::transform_helper<std::decay_t<V>>().transform(std::forward<V>(v), f);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class V, class Func>
|
|
|
|
bool remove_if(V &v, const Func &f) {
|
|
|
|
size_t i = 0;
|
|
|
|
while (i != v.size() && !f(v[i])) {
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
if (i == v.size()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t j = i;
|
|
|
|
while (++i != v.size()) {
|
|
|
|
if (!f(v[i])) {
|
|
|
|
v[j++] = std::move(v[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
v.erase(v.begin() + j, v.end());
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class V, class T>
|
|
|
|
bool remove(V &v, const T &value) {
|
|
|
|
size_t i = 0;
|
|
|
|
while (i != v.size() && v[i] != value) {
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
if (i == v.size()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t j = i;
|
|
|
|
while (++i != v.size()) {
|
|
|
|
if (v[i] != value) {
|
|
|
|
v[j++] = std::move(v[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
v.erase(v.begin() + j, v.end());
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class V>
|
|
|
|
void unique(V &v) {
|
|
|
|
if (v.empty()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// use ADL to find std::sort
|
|
|
|
// caller will need to #include <algorithm>
|
|
|
|
sort(v.begin(), v.end(), std::less<void>());
|
|
|
|
|
|
|
|
size_t j = 1;
|
|
|
|
for (size_t i = 1; i < v.size(); i++) {
|
2021-01-07 02:03:38 +01:00
|
|
|
if (v[i] != v[j - 1]) {
|
2021-01-01 13:59:53 +01:00
|
|
|
if (i != j) {
|
|
|
|
v[j] = std::move(v[i]);
|
|
|
|
}
|
|
|
|
j++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
v.resize(j);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class V, class T>
|
|
|
|
bool contains(const V &v, const T &value) {
|
|
|
|
for (auto &x : v) {
|
|
|
|
if (x == value) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
2022-01-31 13:56:44 +01:00
|
|
|
|
2022-01-28 13:50:59 +01:00
|
|
|
template <class V, class F>
|
|
|
|
bool all_of(const V &v, F &&f) {
|
2022-01-31 13:56:44 +01:00
|
|
|
for (const auto &x : v) {
|
2022-01-28 13:50:59 +01:00
|
|
|
if (!f(x)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
2021-01-01 13:59:53 +01:00
|
|
|
|
|
|
|
template <class T>
|
|
|
|
void reset_to_empty(T &value) {
|
|
|
|
using std::swap;
|
|
|
|
std::decay_t<T> tmp;
|
|
|
|
swap(tmp, value);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class T>
|
|
|
|
void append(vector<T> &destination, const vector<T> &source) {
|
|
|
|
destination.insert(destination.end(), source.begin(), source.end());
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class T>
|
|
|
|
void append(vector<T> &destination, vector<T> &&source) {
|
|
|
|
if (destination.empty()) {
|
|
|
|
destination.swap(source);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
destination.reserve(destination.size() + source.size());
|
|
|
|
for (auto &elem : source) {
|
|
|
|
destination.push_back(std::move(elem));
|
|
|
|
}
|
|
|
|
reset_to_empty(source);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class T>
|
|
|
|
void combine(vector<T> &destination, const vector<T> &source) {
|
|
|
|
append(destination, source);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class T>
|
|
|
|
void combine(vector<T> &destination, vector<T> &&source) {
|
|
|
|
if (destination.size() < source.size()) {
|
|
|
|
destination.swap(source);
|
|
|
|
}
|
|
|
|
if (source.empty()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
destination.reserve(destination.size() + source.size());
|
|
|
|
for (auto &elem : source) {
|
|
|
|
destination.push_back(std::move(elem));
|
|
|
|
}
|
|
|
|
reset_to_empty(source);
|
|
|
|
}
|
|
|
|
|
|
|
|
namespace detail {
|
|
|
|
template <typename T>
|
|
|
|
struct reversion_wrapper {
|
|
|
|
T &iterable;
|
|
|
|
};
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
auto begin(reversion_wrapper<T> w) {
|
|
|
|
return w.iterable.rbegin();
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
auto end(reversion_wrapper<T> w) {
|
|
|
|
return w.iterable.rend();
|
|
|
|
}
|
|
|
|
} // namespace detail
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
detail::reversion_wrapper<T> reversed(T &iterable) {
|
|
|
|
return {iterable};
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace td
|