#pragma once #include #include #include #include #include #include #ifndef __cpp_lib_concepts namespace std { // isn't working for me lmao template concept convertible_to = std::is_convertible_v && requires { static_cast(std::declval()); }; } #endif #undef min #undef max namespace geode::utils::ranges { template concept ValidConstContainer = requires(C const& c) { c.begin(); c.end(); { c.size() } -> std::convertible_to; typename C::value_type; typename C::iterator; typename C::const_iterator; }; template concept ValidMutContainer = requires(C& c) { c.begin(); c.end(); { c.size() } -> std::convertible_to; typename C::value_type; typename C::iterator; typename C::const_iterator; }; template concept ValidContainer = ValidConstContainer && ValidMutContainer; template concept ValidCUnaryPredicate = requires(P p, typename C::value_type const& t) { { p(t) } -> std::convertible_to; }; template concept ValidIntoConverter = requires(P p, From const& t) { { p(t) } -> std::convertible_to; }; template bool contains(C const& cont, typename C::value_type const& elem) { return std::find(cont.begin(), cont.end(), elem) != cont.end(); } template Predicate> bool contains(C const& cont, Predicate fun) { return std::find_if(cont.begin(), cont.end(), fun) != cont.end(); } template Predicate> std::optional 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 std::optional 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 Predicate> std::optional 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 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 requires std::is_default_constructible_v && std::is_convertible_v 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 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 Conv> requires std::is_default_constructible_v 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 C& push(C& container, C const& toAdd) { container.insert(container.end(), toAdd.begin(), toAdd.end()); return container; } template C concat(C const& cont, typename C::value_type const& value) { auto copy = cont; copy.push_back(value); return copy; } template C concat(C const& cont1, C const& cont2) { auto copy = cont1; ranges::push(copy, cont2); return copy; } template C& remove(C& container, typename C::value_type const& value) { container.erase(std::remove(container.begin(), container.end(), value), container.end()); return container; } template Predicate> C& remove(C& container, Predicate fun) { container.erase( std::remove_if(container.begin(), container.end(), fun), container.end() ); return container; } template Predicate> C filter(C const& container, Predicate filterFun) { auto res = C(); std::copy_if(container.begin(), container.end(), res.end(), filterFun); return res; } template 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 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 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 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 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 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 struct ConstReverseWrapper { C const& iter; }; template auto begin(ConstReverseWrapper const& c) { return std::rbegin(c.iter); } template auto end(ConstReverseWrapper const& c) { return std::rend(c.iter); } template ConstReverseWrapper reverse(C const& iter) { return { iter }; } }