#pragma once #include #include #include #undef min #undef max namespace geode::utils::ranges { template concept ValidConstContainer = requires(C const& c) { c.begin(); c.end(); typename C::value_type; }; template concept ValidMutContainer = requires(C& c) { c.begin(); c.end(); typename C::value_type; }; 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 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 += Conv(p); } return res; } template C& push(C& container, C const& toAdd) { container.insert(container.end(), toAdd.begin(), toAdd.end()); return container; } 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 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 < ValidConstContainer From, ValidContainer Into, ValidIntoConverter Mapper> Into map(From const& from, Mapper mapper) { auto res = Into(); std::transform(from.begin(), from.end(), res.end(), 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); } }