geode/loader/include/Geode/utils/ranges.hpp

265 lines
8.1 KiB
C++
Raw Normal View History

#pragma once
#include <Geode/DefaultInclude.hpp>
#include <algorithm>
2022-10-30 14:59:20 -04:00
#include <string>
#undef min
#undef max
namespace geode::utils::ranges {
2022-10-30 14:59:20 -04:00
template <class C>
concept ValidConstContainer = requires(C const& c) {
c.begin();
c.end();
{ c.size() } -> std::convertible_to<size_t>;
typename C::value_type;
typename C::iterator;
typename C::const_iterator;
};
2022-10-30 14:59:20 -04:00
template <class C>
concept ValidMutContainer = requires(C& c) {
c.begin();
c.end();
{ c.size() } -> std::convertible_to<size_t>;
typename C::value_type;
typename C::iterator;
typename C::const_iterator;
};
2022-10-30 14:59:20 -04:00
template <class C>
concept ValidContainer = ValidConstContainer<C> && ValidMutContainer<C>;
2022-10-30 14:59:20 -04:00
template <class P, class C>
concept ValidCUnaryPredicate = requires(P p, typename C::value_type const& t) {
{ p(t) } -> std::convertible_to<bool>;
};
2022-10-30 14:59:20 -04:00
template <class P, class From, class Into>
concept ValidIntoConverter = requires(P p, From const& t) {
{ p(t) } -> std::convertible_to<Into>;
};
2022-10-30 14:59:20 -04:00
template <ValidConstContainer C>
bool contains(C const& cont, typename C::value_type const& elem) {
return std::find(cont.begin(), cont.end(), elem) != cont.end();
}
2022-10-30 14:59:20 -04:00
template <ValidConstContainer C, ValidCUnaryPredicate<C> Predicate>
bool contains(C const& cont, Predicate fun) {
return std::find_if(cont.begin(), cont.end(), fun) != cont.end();
}
2022-11-02 07:44:45 -04:00
template <ValidConstContainer C, ValidCUnaryPredicate<C> Predicate>
std::optional<typename C::value_type> find(C const& cont, Predicate fun) {
auto it = std::find_if(cont.begin(), cont.end(), fun);
if (it != cont.end()) {
return std::optional(*it);
}
return std::nullopt;
}
2022-11-02 07:44:45 -04:00
template <ValidConstContainer C>
std::optional<size_t> indexOf(C const& cont, typename C::value_type const& elem) {
auto it = std::find(cont.begin(), cont.end(), elem);
if (it != cont.end()) {
return std::optional(std::distance(cont.begin(), it));
}
return std::nullopt;
}
2022-11-02 07:44:45 -04:00
template <ValidConstContainer C, ValidCUnaryPredicate<C> Predicate>
std::optional<size_t> indexOf(C const& cont, Predicate fun) {
auto it = std::find_if(cont.begin(), cont.end(), fun);
if (it != cont.end()) {
return std::optional(std::distance(cont.begin(), it));
}
return std::nullopt;
}
2022-11-02 07:44:45 -04:00
template <ValidMutContainer C>
bool move(C& cont, typename C::value_type const& elem, size_t where) {
if (where > cont.size() - 1) {
return false;
}
auto ix = indexOf(cont, elem);
if (ix) {
if (ix.value() > where) {
std::rotate(
cont.rend() - ix.value() - 1,
cont.rend() - ix.value(),
cont.rend() - where
);
} else {
std::rotate(
cont.begin() + ix.value(),
cont.begin() + ix.value() + 1,
cont.begin() + where + 1
);
}
return true;
}
return false;
}
2022-11-02 07:44:45 -04:00
template <ValidConstContainer C, class Output>
requires
std::is_default_constructible_v<Output> &&
std::is_convertible_v<Output, typename C::value_type>
Output join(C const& cont, Output const& separator) {
auto res = Output();
bool first = true;
for (auto& p : cont) {
if (!first) {
res += separator;
2022-10-30 14:59:20 -04:00
}
else {
first = false;
}
res += p;
}
return res;
}
2022-10-30 14:59:20 -04:00
template <ValidConstContainer C>
std::string join(C const& cont, std::string const& separator) {
auto res = std::string();
bool first = true;
for (auto& p : cont) {
if (!first) {
res += separator;
2022-10-30 14:59:20 -04:00
}
else {
first = false;
}
res += p;
}
return res;
}
2022-10-30 14:59:20 -04:00
template <
ValidConstContainer C, class Output,
ValidIntoConverter<typename C::value_type, Output> Conv>
requires std::is_default_constructible_v<Output> Output
join(C const& cont, Output const& separator, Conv converter) {
auto res = Output();
bool first = true;
for (auto& p : cont) {
if (!first) {
res += separator;
2022-10-30 14:59:20 -04:00
}
else {
first = false;
}
2022-10-24 15:46:39 -04:00
res += converter(p);
}
return res;
}
2022-10-30 14:59:20 -04:00
template <ValidContainer C>
C& push(C& container, C const& toAdd) {
container.insert(container.end(), toAdd.begin(), toAdd.end());
return container;
}
2022-10-30 14:59:20 -04:00
template <ValidMutContainer C>
C& remove(C& container, typename C::value_type const& value) {
2022-10-30 14:59:20 -04:00
container.erase(std::remove(container.begin(), container.end(), value), container.end());
2022-10-27 08:12:31 -04:00
return container;
}
2022-11-02 06:57:03 -04:00
template <ValidMutContainer C, ValidCUnaryPredicate<C> Predicate>
2022-10-27 08:12:31 -04:00
C& remove(C& container, Predicate fun) {
container.erase(
std::remove_if(container.begin(), container.end(), fun),
container.end()
);
return container;
}
2022-10-30 14:59:20 -04:00
template <ValidContainer C, ValidCUnaryPredicate<C> Predicate>
C filter(C const& container, Predicate filterFun) {
auto res = C();
std::copy_if(container.begin(), container.end(), res.end(), filterFun);
return res;
}
2022-10-30 14:59:20 -04:00
template <class R, ValidConstContainer C, class Reducer>
requires requires(Reducer r, R& acc, typename C::value_type t) {
r(acc, t);
}
R reduce(C const& container, Reducer reducer) {
auto res = R();
for (auto& item : container) {
reducer(res, item);
}
return res;
}
2022-10-30 14:59:20 -04:00
template <
ValidContainer Into, ValidConstContainer From,
2022-10-30 14:59:20 -04:00
ValidIntoConverter<typename From::value_type, typename Into::value_type> Mapper>
Into map(From const& from, Mapper mapper) {
auto res = Into();
std::transform(from.begin(), from.end(), std::back_inserter(res), mapper);
return res;
}
template <ValidConstContainer C>
typename C::value_type min(C const& container) {
auto it = std::min_element(container.begin(), container.end());
if (it == container.end()) {
return C::value_type();
}
return *it;
}
template <class T, ValidConstContainer C, ValidIntoConverter<typename C::value_type, T> Member>
requires requires(T a, T b) {
a < b;
}
T min(C const& container, Member member) {
auto it = std::min_element(
container.begin(), container.end(),
[member](auto const& a, auto const& b) -> bool {
return member(a) < member(b);
}
);
if (it == container.end()) {
return T();
}
return member(*it);
}
template <ValidConstContainer C>
typename C::value_type max(C const& container) {
auto it = std::max_element(container.begin(), container.end());
if (it == container.end()) {
return C::value_type();
}
return *it;
}
template <class T, ValidConstContainer C, ValidIntoConverter<typename C::value_type, T> Member>
requires requires(T a, T b) {
a < b;
T();
}
T max(C const& container, Member member) {
auto it = std::max_element(
container.begin(), container.end(),
[member](auto const& a, auto const& b) -> bool {
return member(a) < member(b);
}
);
if (it == container.end()) {
return T();
}
return member(*it);
}
}