minmax.h 2.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  1. //
  2. // minmax.h
  3. // stream
  4. //
  5. // Created by Sam Jaffe on 3/30/23.
  6. //
  7. #pragma once
  8. #include <optional>
  9. #include <stream/detail/identity.h>
  10. #include <stream/detail/named_pair.h>
  11. #include <stream/detail/traits.h>
  12. #define FWD(x) std::forward<decltype(x)>(x)
  13. namespace stream::detail {
  14. template <typename T, typename Comp, typename Proj>
  15. bool compare(T const & l, T const & r, Comp && comp, Proj && proj) {
  16. return std::invoke(FWD(comp), std::invoke(proj, l), std::invoke(proj, r));
  17. }
  18. }
  19. namespace stream::ranges {
  20. template <typename It, typename S, typename Comp = std::less<>,
  21. typename Proj = detail::identity,
  22. typename = std::enable_if_t<detail::is_comparable_v<It, S>>>
  23. auto minmax(It it, S end, Comp comp = {}, Proj proj = {}) {
  24. detail::min_max_result v(*it, *it);
  25. for (++it; it != end; ++it) {
  26. if (detail::compare(v.max, *it, comp, proj)) { v.max = *it; }
  27. if (detail::compare(*it, v.min, comp, proj)) { v.min = *it; }
  28. }
  29. return v;
  30. }
  31. template <typename Stream, typename Comp = std::less<>,
  32. typename Proj = detail::identity>
  33. auto minmax(Stream const & stream, Comp comp = {}, Proj proj = {}) {
  34. return minmax(stream.begin(), stream.end(), std::move(comp), std::move(proj));
  35. }
  36. template <typename It, typename S, typename Comp = std::less<>,
  37. typename Proj = detail::identity,
  38. typename = std::enable_if_t<detail::is_comparable_v<It, S>>>
  39. auto min(It it, S end, Comp comp = {}, Proj proj = {}) {
  40. auto v = *it;
  41. for (++it; it != end; ++it) {
  42. if (detail::compare(*it, v, comp, proj)) { v = *it; }
  43. }
  44. return v;
  45. }
  46. template <typename Stream, typename Comp = std::less<>,
  47. typename Proj = detail::identity>
  48. auto min(Stream const & stream, Comp comp = {}, Proj proj = {}) {
  49. return min(stream.begin(), stream.end(), std::move(comp), std::move(proj));
  50. }
  51. template <typename It, typename S, typename Comp = std::less<>,
  52. typename Proj = detail::identity,
  53. typename = std::enable_if_t<detail::is_comparable_v<It, S>>>
  54. auto max(It it, S end, Comp comp = {}, Proj proj = {}) {
  55. auto v = *it;
  56. for (++it; it != end; ++it) {
  57. if (detail::compare(v, *it, comp, proj)) { v = *it; }
  58. }
  59. return v;
  60. }
  61. template <typename Stream, typename Comp = std::less<>,
  62. typename Proj = detail::identity>
  63. auto max(Stream const & stream, Comp comp = {}, Proj proj = {}) {
  64. return max(stream.begin(), stream.end(), std::move(comp), std::move(proj));
  65. }
  66. }
  67. #undef FWD