Pārlūkot izejas kodu

refactor: separate functions out into own files, add helpers for invoke

Sam Jaffe 2 gadi atpakaļ
vecāks
revīzija
f8c0933d23

+ 6 - 0
include/stream/algorithm.h

@@ -7,9 +7,15 @@
 
 #pragma once
 
+#include <stream/algorithm/all_of.h>
+#include <stream/algorithm/any_of.h>
 #include <stream/algorithm/count.h>
+#include <stream/algorithm/count_if.h>
 #include <stream/algorithm/equal.h>
 #include <stream/algorithm/fold.h>
 #include <stream/algorithm/for_each.h>
+#include <stream/algorithm/max.h>
+#include <stream/algorithm/min.h>
 #include <stream/algorithm/minmax.h>
+#include <stream/algorithm/none_of.h>
 #include <stream/algorithm/size.h>

+ 29 - 0
include/stream/algorithm/all_of.h

@@ -0,0 +1,29 @@
+//
+//  all_of.h
+//  stream
+//
+//  Created by Sam Jaffe on 4/2/23.
+//
+
+#pragma once
+
+#include <stream/forward.h>
+
+#include <stream/detail/identity.h>
+#include <stream/detail/invoke.h>
+
+namespace stream::ranges {
+template <typename It, typename S, typename Pred,
+          typename Proj = detail::identity>
+bool all_of(It it, S end, Pred pred, Proj proj = {}) {
+  for (; it != end; ++it) {
+    if (!detail::invoke(pred, *it, proj)) { return false; }
+  }
+  return true;
+}
+
+template <typename Stream, typename Pred, typename Proj = detail::identity>
+bool all_of(Stream const & stream, Pred pred, Proj proj = {}) {
+  return all_of(stream.begin(), stream.end(), pred, proj);
+}
+}

+ 29 - 0
include/stream/algorithm/any_of.h

@@ -0,0 +1,29 @@
+//
+//  any_of.h
+//  stream
+//
+//  Created by Sam Jaffe on 4/2/23.
+//
+
+#pragma once
+
+#include <stream/forward.h>
+
+#include <stream/detail/identity.h>
+#include <stream/detail/invoke.h>
+
+namespace stream::ranges {
+template <typename It, typename S, typename Pred,
+          typename Proj = detail::identity>
+bool any_of(It it, S end, Pred pred, Proj proj = {}) {
+  for (; it != end; ++it) {
+    if (detail::invoke(pred, *it, proj)) { return true; }
+  }
+  return false;
+}
+
+template <typename Stream, typename Pred, typename Proj = detail::identity>
+bool any_of(Stream const & stream, Pred pred, Proj proj = {}) {
+  return any_of(stream.begin(), stream.end(), pred, proj);
+}
+}

+ 2 - 63
include/stream/algorithm/count.h

@@ -7,54 +7,11 @@
 
 #pragma once
 
-#include <optional>
+#include <stream/forward.h>
 
 #include <stream/detail/identity.h>
-#include <stream/detail/traits.h>
-
-#define FWD(x) std::forward<decltype(x)>(x)
 
 namespace stream::ranges {
-template <typename It, typename S, typename Pred,
-          typename Proj = detail::identity>
-bool any_of(It it, S end, Pred pred, Proj proj = {}) {
-  for (; it != end; ++it) {
-    if (std::invoke(pred, std::invoke(proj, *it))) { return true; }
-  }
-  return false;
-}
-
-template <typename Stream, typename Pred, typename Proj = detail::identity>
-bool any_of(Stream const & stream, Pred pred, Proj proj = {}) {
-  return any_of(stream.begin(), stream.end(), std::move(pred), std::move(proj));
-}
-
-template <typename It, typename S, typename Pred,
-          typename Proj = detail::identity>
-bool none_of(It it, S end, Pred pred, Proj proj = {}) {
-  return !any_of(it, end, std::move(pred), std::move(proj));
-}
-
-template <typename Stream, typename Pred, typename Proj = detail::identity>
-bool none_of(Stream const & stream, Pred pred, Proj proj = {}) {
-  return none_of(stream.begin(), stream.end(), std::move(pred),
-                 std::move(proj));
-}
-
-template <typename It, typename S, typename Pred,
-          typename Proj = detail::identity>
-bool all_of(It it, S end, Pred pred, Proj proj = {}) {
-  for (; it != end; ++it) {
-    if (!std::invoke(pred, std::invoke(proj, *it))) { return false; }
-  }
-  return true;
-}
-
-template <typename Stream, typename Pred, typename Proj = detail::identity>
-bool all_of(Stream const & stream, Pred pred, Proj proj = {}) {
-  return all_of(stream.begin(), stream.end(), std::move(pred), std::move(proj));
-}
-
 template <typename It, typename S, typename T, typename Proj = detail::identity>
 bool count(It it, S end, T const & value, Proj proj = {}) {
   size_t result = 0;
@@ -66,24 +23,6 @@ bool count(It it, S end, T const & value, Proj proj = {}) {
 
 template <typename Stream, typename T, typename Proj = detail::identity>
 bool count(Stream const & stream, T const & value, Proj proj = {}) {
-  return count(stream.begin(), stream.end(), value, std::move(proj));
-}
-
-template <typename It, typename S, typename Pred,
-          typename Proj = detail::identity>
-auto count_if(It it, S end, Pred pred, Proj proj = {}) {
-  size_t result = 0;
-  for (; it != end; ++it) {
-    if (std::invoke(pred, std::invoke(proj, *it))) { ++result; }
-  }
-  return result;
-}
-
-template <typename Stream, typename Pred, typename Proj = detail::identity>
-auto count_if(Stream const & stream, Pred pred, Proj proj = {}) {
-  return count_if(stream.begin(), stream.end(), std::move(pred),
-                  std::move(proj));
+  return count(stream.begin(), stream.end(), value, proj);
 }
 }
-
-#undef FWD

+ 30 - 0
include/stream/algorithm/count_if.h

@@ -0,0 +1,30 @@
+//
+//  count_if.h
+//  stream
+//
+//  Created by Sam Jaffe on 4/2/23.
+//
+
+#pragma once
+
+#include <stream/forward.h>
+
+#include <stream/detail/identity.h>
+#include <stream/detail/invoke.h>
+
+namespace stream::ranges {
+template <typename It, typename S, typename Pred,
+          typename Proj = detail::identity>
+auto count_if(It it, S end, Pred pred, Proj proj = {}) {
+  size_t result = 0;
+  for (; it != end; ++it) {
+    if (detail::invoke(pred, *it, proj)) { ++result; }
+  }
+  return result;
+}
+
+template <typename Stream, typename Pred, typename Proj = detail::identity>
+auto count_if(Stream const & stream, Pred pred, Proj proj = {}) {
+  return count_if(stream.begin(), stream.end(), pred, proj);
+}
+}

+ 21 - 8
include/stream/algorithm/equal.h

@@ -7,22 +7,35 @@
 
 #pragma once
 
-#include <algorithm>
+#include <stream/forward.h>
+
+#include <stream/detail/invoke.h>
+#include <stream/detail/traits.h>
+
+#include <stream/detail/macro.h>
 
 namespace stream::range {
 
 template <typename It1, typename S1, typename It2, typename S2,
-          typename Cmp = std::equal_to<>>
-bool equal(It1 it1, S1 end1, It2 it2, S2 end2, Cmp cmp = {}) {
+          typename Cmp = std::equal_to<>, typename Proj1 = detail::identity,
+          typename Proj2 = detail::identity,
+          REQUIRES((detail::is_comparable_v<It1, S1> &&
+                    detail::is_comparable_v<It2, S2>))>
+bool equal(It1 it1, S1 end1, It2 it2, S2 end2, Cmp cmp = {}, Proj1 proj1 = {},
+           Proj2 proj2 = {}) {
   for (; it1 != end1 && it2 != end2; ++it1, ++it2) {
-    if (!std::invoke(cmp, *it1, *it2)) { return false; }
+    if (!detail::invoke(cmp, *it1, *it2, proj1, proj2)) { return false; }
   }
-  return (it1 != end1) == (it2 != end2);
+  return (it1 == end1) && (it2 == end2);
 }
 
-template <typename S1, typename S2, typename Cmp = std::equal_to<>>
-bool equal(S1 const s1, S2 const & s2, Cmp cmp = {}) {
-  return equal(s1.begin(), s1.end(), s2.begin(), s2.end(), cmp);
+template <typename R1, typename R2, typename Cmp = std::equal_to<>,
+          typename Proj1 = detail::identity, typename Proj2 = detail::identity>
+bool equal(R1 const r1, R2 const & r2, Cmp cmp = {}, Proj1 proj1 = {},
+           Proj2 proj2 = {}) {
+  return equal(r1.begin(), r1.end(), r2.begin(), r2.end(), cmp, proj1, proj2);
 }
 
 }
+
+#include <stream/detail/undef.h>

+ 56 - 0
include/stream/algorithm/max.h

@@ -0,0 +1,56 @@
+//
+//  max.h
+//  stream
+//
+//  Created by Sam Jaffe on 4/2/23.
+//
+
+#pragma once
+
+#include <stream/forward.h>
+
+#include <stream/detail/identity.h>
+#include <stream/detail/invoke.h>
+#include <stream/detail/traits.h>
+
+#include <stream/detail/macro.h>
+
+namespace stream::ranges {
+template <typename T, typename Comp = std::less<>,
+          typename Proj = detail::identity>
+T const & max(T const & l, T const & r, Comp comp = {}, Proj proj = {}) {
+  return detail::invoke(comp, r, l, proj, proj) ? l : r;
+}
+
+template <typename It, typename S, typename Comp = std::less<>,
+          typename Proj = detail::identity,
+          REQUIRES((detail::is_comparable_v<It, S>))>
+auto max_element(It it, S end, Comp comp = {}, Proj proj = {}) {
+  auto rval = it;
+  for (++it; it != end; ++it) {
+    if (detail::invoke(comp, *rval, *it, proj, proj)) { rval = *it; }
+  }
+  return rval;
+}
+
+template <typename Stream, typename Comp = std::less<>,
+          typename Proj = detail::identity>
+auto max_element(Stream const & stream, Comp comp = {}, Proj proj = {}) {
+  return max_element(stream.begin(), stream.end(), comp, proj);
+}
+
+template <typename T, typename Comp = std::less<>,
+          typename Proj = detail::identity>
+auto max(std::initializer_list<T> const & stream, Comp comp = {},
+         Proj proj = {}) {
+  return *max_element(stream.begin(), stream.end(), comp, proj);
+}
+
+template <typename Stream, typename Comp = std::less<>,
+          typename Proj = detail::identity>
+auto max(Stream const & stream, Comp comp = {}, Proj proj = {}) {
+  return *max_element(stream.begin(), stream.end(), comp, proj);
+}
+}
+
+#include <stream/detail/undef.h>

+ 55 - 0
include/stream/algorithm/min.h

@@ -0,0 +1,55 @@
+//
+//  min.h
+//  stream
+//
+//  Created by Sam Jaffe on 4/2/23.
+//
+
+#pragma once
+
+#include <stream/forward.h>
+
+#include <stream/detail/identity.h>
+#include <stream/detail/invoke.h>
+#include <stream/detail/traits.h>
+
+#include <stream/detail/macro.h>
+
+namespace stream::ranges {
+template <typename T, typename Comp = std::less<>,
+          typename Proj = detail::identity>
+T const & min(T const & l, T const & r, Comp comp = {}, Proj proj = {}) {
+  return detail::invoke(comp, l, r, proj, proj) ? l : r;
+}
+
+template <typename It, typename S, typename Comp = std::less<>,
+          typename Proj = detail::identity,
+          REQUIRES((detail::is_comparable_v<It, S>))>
+auto min_element(It it, S end, Comp comp = {}, Proj proj = {}) {
+  auto rval = it;
+  for (++it; it != end; ++it) {
+    if (detail::invoke(comp, *it, *rval, proj, proj)) { rval = it; }
+  }
+  return rval;
+}
+
+template <typename Stream, typename Comp = std::less<>,
+          typename Proj = detail::identity>
+auto min_element(Stream const & stream, Comp comp = {}, Proj proj = {}) {
+  return min_element(stream.begin(), stream.end(), comp, proj);
+}
+
+template <typename T, typename Comp = std::less<>,
+          typename Proj = detail::identity>
+auto min(std::initializer_list<T> stream, Comp comp = {}, Proj proj = {}) {
+  return *min_element(stream.begin(), stream.end(), comp, proj);
+}
+
+template <typename Stream, typename Comp = std::less<>,
+          typename Proj = detail::identity>
+auto min(Stream const & stream, Comp comp = {}, Proj proj = {}) {
+  return *min_element(stream.begin(), stream.end(), comp, proj);
+}
+}
+
+#include <stream/detail/undef.h>

+ 28 - 44
include/stream/algorithm/minmax.h

@@ -7,74 +7,58 @@
 
 #pragma once
 
-#include <optional>
+#include <stream/forward.h>
 
 #include <stream/detail/identity.h>
+#include <stream/detail/invoke.h>
 #include <stream/detail/named_pair.h>
 #include <stream/detail/traits.h>
 
-#define FWD(x) std::forward<decltype(x)>(x)
-
-namespace stream::detail {
-template <typename T, typename Comp, typename Proj>
-bool compare(T const & l, T const & r, Comp && comp, Proj && proj) {
-  return std::invoke(FWD(comp), std::invoke(proj, l), std::invoke(proj, r));
-}
-}
+#include <stream/detail/macro.h>
 
 namespace stream::ranges {
-
-template <typename It, typename S, typename Comp = std::less<>,
-          typename Proj = detail::identity,
-          typename = std::enable_if_t<detail::is_comparable_v<It, S>>>
-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, comp, proj)) { v.max = *it; }
-    if (detail::compare(*it, v.min, comp, proj)) { v.min = *it; }
-  }
-  return v;
-}
-
-template <typename Stream, typename Comp = std::less<>,
+template <typename T, typename Comp = std::less<>,
           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));
+auto minmax(T const & l, T const & r, Comp comp = {}, Proj proj = {})
+    -> detail::min_max_result<T const &, T const &> {
+  if (detail::invoke(comp, l, r, proj, proj)) { return {l, r}; }
+  return {r, l};
 }
 
 template <typename It, typename S, typename Comp = std::less<>,
           typename Proj = detail::identity,
-          typename = std::enable_if_t<detail::is_comparable_v<It, S>>>
-auto min(It it, S end, Comp comp = {}, Proj proj = {}) {
-  auto v = *it;
+          REQUIRES((detail::is_comparable_v<It, S>))>
+auto minmax_element(It it, S end, Comp comp = {}, Proj proj = {}) {
+  detail::min_max_result rval(it, it);
   for (++it; it != end; ++it) {
-    if (detail::compare(*it, v, comp, proj)) { v = *it; }
+    if (detail::invoke(comp, it, rval.min, proj, proj)) {
+      rval.min = it;
+    } else if (detail::invoke(comp, rval.max, it, proj, proj)) {
+      rval.max = it;
+    }
   }
-  return v;
+  return rval;
 }
 
 template <typename Stream, typename Comp = std::less<>,
           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));
+auto minmax_element(Stream const & stream, Comp comp = {}, Proj proj = {}) {
+  return minmax_element(stream.begin(), stream.end(), comp, proj);
 }
 
-template <typename It, typename S, typename Comp = std::less<>,
-          typename Proj = detail::identity,
-          typename = std::enable_if_t<detail::is_comparable_v<It, S>>>
-auto max(It it, S end, Comp comp = {}, Proj proj = {}) {
-  auto v = *it;
-  for (++it; it != end; ++it) {
-    if (detail::compare(v, *it, comp, proj)) { v = *it; }
-  }
-  return v;
+template <typename T, typename Comp = std::less<>,
+          typename Proj = detail::identity>
+auto minmax(std::initializer_list<T> stream, Comp comp = {}, Proj proj = {}) {
+  auto result = minmax_element(stream.begin(), stream.end(), comp, proj);
+  return detail::min_max_result(*result.min, *result.max);
 }
 
 template <typename Stream, typename Comp = std::less<>,
           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));
+auto minmax(Stream const & stream, Comp comp = {}, Proj proj = {}) {
+  auto result = minmax_element(stream.begin(), stream.end(), comp, proj);
+  return detail::min_max_result(*result.min, *result.max);
 }
 }
 
-#undef FWD
+#include <stream/detail/undef.h>

+ 29 - 0
include/stream/algorithm/none_of.h

@@ -0,0 +1,29 @@
+//
+//  none_of.h
+//  stream
+//
+//  Created by Sam Jaffe on 4/2/23.
+//
+
+#pragma once
+
+#include <stream/forward.h>
+
+#include <stream/detail/identity.h>
+#include <stream/detail/invoke.h>
+
+namespace stream::ranges {
+template <typename It, typename S, typename Pred,
+          typename Proj = detail::identity>
+bool none_of(It it, S end, Pred pred, Proj proj = {}) {
+  for (; it != end; ++it) {
+    if (detail::invoke(pred, *it, proj)) { return false; }
+  }
+  return true;
+}
+
+template <typename Stream, typename Pred, typename Proj = detail::identity>
+bool none_of(Stream const & stream, Pred pred, Proj proj = {}) {
+  return none_of(stream.begin(), stream.end(), pred, proj);
+}
+}

+ 26 - 0
include/stream/detail/invoke.h

@@ -0,0 +1,26 @@
+//
+//  invoke.h
+//  stream
+//
+//  Created by Sam Jaffe on 4/2/23.
+//
+
+#pragma once
+
+#include <stream/detail/macro.h>
+
+namespace stream::detail {
+template <typename F, typename T, typename Proj>
+decltype(auto) invoke(F && func, T && t, Proj && proj) {
+  return std::invoke(FWD(func), std::invoke(FWD(proj), FWD(t)));
+}
+
+template <typename F, typename T1, typename T2, typename Proj1, typename Proj2>
+decltype(auto) invoke(F && func, T1 && t1, T2 && t2, Proj1 && proj1,
+                      Proj2 && proj2) {
+  return std::invoke(FWD(func), std::invoke(FWD(proj1), FWD(t1)),
+                     std::invoke(FWD(proj2), FWD(t2)));
+}
+}
+
+#include <stream/detail/undef.h>

+ 14 - 0
stream.xcodeproj/project.pbxproj

@@ -103,6 +103,13 @@
 		CDA37D4229D9D417000A1F97 /* iterator.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = iterator.h; sourceTree = "<group>"; };
 		CDA37D4329D9D434000A1F97 /* view.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = view.h; sourceTree = "<group>"; };
 		CDA37D4429D9D55D000A1F97 /* stream_test.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = stream_test.h; sourceTree = "<group>"; };
+		CDA37D4C29DA2150000A1F97 /* count_if.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = count_if.h; sourceTree = "<group>"; };
+		CDA37D4D29DA217C000A1F97 /* any_of.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = any_of.h; sourceTree = "<group>"; };
+		CDA37D4E29DA2186000A1F97 /* all_of.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = all_of.h; sourceTree = "<group>"; };
+		CDA37D4F29DA218E000A1F97 /* none_of.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = none_of.h; sourceTree = "<group>"; };
+		CDA37D5029DA22A7000A1F97 /* min.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = min.h; sourceTree = "<group>"; };
+		CDA37D5129DA22AA000A1F97 /* max.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = max.h; sourceTree = "<group>"; };
+		CDA54F9729DA4BFC006C0FAA /* invoke.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = invoke.h; sourceTree = "<group>"; };
 		CDAA170121A3A738007BBA11 /* stream */ = {isa = PBXFileReference; lastKnownFileType = folder; name = stream; path = include/stream; sourceTree = "<group>"; };
 		CDE8545E24DEBEBF006FE7C7 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; };
 		CDEC1D5B23514BB50091D9F2 /* GoogleMock.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = GoogleMock.xcodeproj; path = "../../../../gmock-xcode-master/GoogleMock.xcodeproj"; sourceTree = "<group>"; };
@@ -175,6 +182,7 @@
 			isa = PBXGroup;
 			children = (
 				CD52828029D51166001A84DE /* identity.h */,
+				CDA54F9729DA4BFC006C0FAA /* invoke.h */,
 				CDA37D3929D9BDED000A1F97 /* macro.h */,
 				CD5A8D3B29D63DF5008C2A4F /* named_pair.h */,
 				CD5281EC29D3B173001A84DE /* traits.h */,
@@ -215,11 +223,17 @@
 		CDA37D2F29D9BB13000A1F97 /* algorithm */ = {
 			isa = PBXGroup;
 			children = (
+				CDA37D4E29DA2186000A1F97 /* all_of.h */,
+				CDA37D4D29DA217C000A1F97 /* any_of.h */,
 				CD5A8D3529D63C05008C2A4F /* count.h */,
+				CDA37D4C29DA2150000A1F97 /* count_if.h */,
 				CDA37D3D29D9D129000A1F97 /* equal.h */,
 				CD52827F29D50E24001A84DE /* fold.h */,
 				CD52827D29D50081001A84DE /* for_each.h */,
+				CDA37D5129DA22AA000A1F97 /* max.h */,
 				CD6EBE2629D63B9E00F387C1 /* minmax.h */,
+				CDA37D5029DA22A7000A1F97 /* min.h */,
+				CDA37D4F29DA218E000A1F97 /* none_of.h */,
 				CD6EBE2329D5CAD900F387C1 /* size.h */,
 			);
 			path = algorithm;