mirror of
https://github.com/geode-sdk/geode.git
synced 2024-11-26 01:18:01 -05:00
307 lines
9.1 KiB
C++
307 lines
9.1 KiB
C++
#pragma once
|
|
|
|
#include <Geode/DefaultInclude.hpp>
|
|
#include <algorithm>
|
|
#include <string>
|
|
#include <concepts>
|
|
#include <optional>
|
|
#include <iterator>
|
|
|
|
#ifndef __cpp_lib_concepts
|
|
namespace std {
|
|
// <concepts> isn't working for me lmao
|
|
template <class From, class To>
|
|
concept convertible_to = std::is_convertible_v<From, To> && requires {
|
|
static_cast<To>(std::declval<From>());
|
|
};
|
|
}
|
|
#endif
|
|
|
|
#undef min
|
|
#undef max
|
|
|
|
namespace geode::utils::ranges {
|
|
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;
|
|
};
|
|
|
|
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;
|
|
};
|
|
|
|
template <class C>
|
|
concept ValidContainer = ValidConstContainer<C> && ValidMutContainer<C>;
|
|
|
|
template <class P, class C>
|
|
concept ValidCUnaryPredicate = requires(P p, typename C::value_type const& t) {
|
|
{ p(t) } -> std::convertible_to<bool>;
|
|
};
|
|
|
|
template <class P, class From, class Into>
|
|
concept ValidIntoConverter = requires(P p, From const& t) {
|
|
{ p(t) } -> std::convertible_to<Into>;
|
|
};
|
|
|
|
template <ValidConstContainer C>
|
|
bool contains(C const& cont, typename C::value_type const& elem) {
|
|
return std::find(cont.begin(), cont.end(), elem) != cont.end();
|
|
}
|
|
|
|
template <ValidConstContainer C, ValidCUnaryPredicate<C> Predicate>
|
|
bool contains(C const& cont, Predicate fun) {
|
|
return std::find_if(cont.begin(), cont.end(), fun) != cont.end();
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
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;
|
|
}
|
|
else {
|
|
first = false;
|
|
}
|
|
res += p;
|
|
}
|
|
return res;
|
|
}
|
|
|
|
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;
|
|
}
|
|
else {
|
|
first = false;
|
|
}
|
|
res += p;
|
|
}
|
|
return res;
|
|
}
|
|
|
|
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;
|
|
}
|
|
else {
|
|
first = false;
|
|
}
|
|
res += converter(p);
|
|
}
|
|
return res;
|
|
}
|
|
|
|
template <ValidContainer C>
|
|
C& push(C& container, C const& toAdd) {
|
|
container.insert(container.end(), toAdd.begin(), toAdd.end());
|
|
return container;
|
|
}
|
|
|
|
template <ValidContainer C>
|
|
C concat(C const& cont, typename C::value_type const& value) {
|
|
auto copy = cont;
|
|
copy.push_back(value);
|
|
return copy;
|
|
}
|
|
|
|
template <ValidContainer C>
|
|
C concat(C const& cont1, C const& cont2) {
|
|
auto copy = cont1;
|
|
ranges::push(copy, cont2);
|
|
return copy;
|
|
}
|
|
|
|
template <ValidMutContainer C>
|
|
C& remove(C& container, typename C::value_type const& value) {
|
|
container.erase(std::remove(container.begin(), container.end(), value), container.end());
|
|
return container;
|
|
}
|
|
|
|
template <ValidMutContainer C, ValidCUnaryPredicate<C> Predicate>
|
|
C& remove(C& container, Predicate fun) {
|
|
container.erase(
|
|
std::remove_if(container.begin(), container.end(), fun),
|
|
container.end()
|
|
);
|
|
return container;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
template <
|
|
ValidContainer Into, ValidConstContainer From,
|
|
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);
|
|
}
|
|
|
|
template <class C>
|
|
struct ReverseWrapper {
|
|
C iter;
|
|
|
|
decltype(auto) begin() {
|
|
return std::rbegin(iter);
|
|
}
|
|
|
|
decltype(auto) end() {
|
|
return std::rend(iter);
|
|
}
|
|
};
|
|
|
|
template <class C>
|
|
auto reverse(C&& iter) {
|
|
return ReverseWrapper<C>{std::forward<C>(iter)};
|
|
}
|
|
}
|