// // minmax.h // stream // // Created by Sam Jaffe on 3/30/23. // #pragma once #include #include #include #include #define FWD(x) std::forward(x) namespace stream::detail { template bool compare(T const & l, T const & r, Comp comp, Proj proj) { return std::invoke(comp, std::invoke(proj, l), std::invoke(proj, r)); } } namespace stream::ranges { template , typename Proj = detail::identity> auto minmax(It it, S end, Comp comp = {}, Proj proj = {}) { detail::min_max_result v(*it, *it); for (++it; it != end; ++it) { if (detail::compare(v.max, *it, std::ref(comp), std::ref(proj))) { v.max = *it; } if (detail::compare(*it, v.min, std::ref(comp), std::ref(proj))) { v.min = *it; } } return v; } template , typename Proj = detail::identity> auto minmax(Stream const & stream, Comp comp = {}, Proj proj = {}) { return minmax(stream.begin(), stream.end(), std::move(comp), std::move(proj)); } template , typename Proj = detail::identity> auto min(It it, S end, Comp comp = {}, Proj proj = {}) { auto v = *it; for (++it; it != end; ++it) { if (detail::compare(*it, v, std::ref(comp), std::ref(proj))) { v = *it; } } return v; } template , typename Proj = detail::identity> auto min(Stream const & stream, Comp comp = {}, Proj proj = {}) { return min(stream.begin(), stream.end(), std::move(comp), std::move(proj)); } template , typename Proj = detail::identity> auto max(It it, S end, Comp comp = {}, Proj proj = {}) { auto v = *it; for (++it; it != end; ++it) { if (detail::compare(v, *it, std::ref(comp), std::ref(proj))) { v = *it; } } return v; } template , typename Proj = detail::identity> auto max(Stream const & stream, Comp comp = {}, Proj proj = {}) { return max(stream.begin(), stream.end(), std::move(comp), std::move(proj)); } } #undef FWD