Ver código fonte

fix: some issues exposed by pokemon

Sam Jaffe 2 anos atrás
pai
commit
5a27490c76

+ 1 - 1
external/iterator

@@ -1 +1 @@
-Subproject commit fd1f0099ced52659adaa8fefdb9cac584e3fb6d5
+Subproject commit be1b61e465e3b9ef3baaafeb76b979aa25c1949c

+ 4 - 2
include/stream/common_view.h

@@ -7,7 +7,7 @@
 
 #pragma once
 
-#include <iterator/sentinal_iterator.h>
+#include <iterator/sentinel_iterator.h>
 #include <stream/forward.h>
 
 #define FWD(x) std::forward<decltype(x)>(x)
@@ -20,11 +20,13 @@ private:
 public:
   common_view(S && stream) : stream_(FWD(stream)) {}
 
-  auto begin() const { return iterator::sentinal_iterator(stream_.begin()); }
+  auto begin() const { return iterator::sentinel_iterator(stream_.begin()); }
   auto end() const { return decltype(begin())(); }
   bool empty() const { return stream_.empty(); }
   size_t size() const { return stream_.size(); }
 };
+
+template <typename S> common_view(S &&) -> common_view<S>;
 }
 
 namespace stream::ranges::views {

+ 3 - 1
include/stream/detail/identity.h

@@ -9,6 +9,8 @@
 
 namespace stream::detail {
 struct identity {
-  template <typename T> decltype(auto) operator()(T && t) const { return t; }
+  template <typename T> decltype(auto) operator()(T && t) const {
+    return std::forward<T>(t);
+  }
 };
 }

+ 9 - 4
include/stream/detail/traits.h

@@ -34,14 +34,19 @@ struct has_size<C, exists(_val(C).size())> : std::true_type {};
 template <typename C>
 struct has_empty<C, exists(_val(C).empty())> : std::true_type {};
 
+template <typename It, typename S, typename = void>
+struct is_comparable : std::false_type {};
+
+template <typename It, typename S>
+struct is_comparable<It, S, exists(_val(It) == _val(S))> : std::true_type {};
+
 template <typename C> constexpr bool has_size_v = has_size<C>{};
 template <typename C> constexpr bool has_empty_v = has_empty<C>{};
+template <typename It, typename S>
+constexpr bool is_comparable_v = is_comparable<It, S>{};
 
-using iterator::detail::sentinal_type_t;
 template <typename S>
-constexpr bool is_sentinal_v =
-    std::is_void_v<sentinal_type_t<ranges::iter<S>>> &&
-    !std::is_same_v<begin_t<S>, end_t<S>>;
+constexpr bool is_sentinal_v = !std::is_same_v<begin_t<S>, end_t<S>>;
 }
 
 #undef _val

+ 1 - 1
include/stream/filter_view.h

@@ -13,7 +13,7 @@ namespace stream::ranges {
 template <typename S> class filter_view {
 private:
   using Pred = std::function<bool(traits::cref_t<S>)>;
-  using iterator = ::iterator::filter_iterator<iter<S>, true>;
+  using iterator = ::iterator::filter_iterator<iter<S>>;
 
 private:
   S stream_;

+ 12 - 13
include/stream/minmax.h

@@ -17,24 +17,21 @@
 
 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(comp, std::invoke(proj, l), std::invoke(proj, r));
+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));
 }
 }
 
 namespace stream::ranges {
 
 template <typename It, typename S, typename Comp = std::less<>,
-          typename Proj = detail::identity>
+          typename Proj = detail::identity,
+          typename = std::enable_if_t<traits::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, std::ref(comp), std::ref(proj))) {
-      v.max = *it;
-    }
-    if (detail::compare(*it, v.min, std::ref(comp), std::ref(proj))) {
-      v.min = *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;
 }
@@ -46,11 +43,12 @@ auto minmax(Stream const & stream, Comp comp = {}, Proj proj = {}) {
 }
 
 template <typename It, typename S, typename Comp = std::less<>,
-          typename Proj = detail::identity>
+          typename Proj = detail::identity,
+          typename = std::enable_if_t<traits::is_comparable_v<It, S>>>
 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; }
+    if (detail::compare(*it, v, comp, proj)) { v = *it; }
   }
   return v;
 }
@@ -62,11 +60,12 @@ auto min(Stream const & stream, Comp comp = {}, Proj proj = {}) {
 }
 
 template <typename It, typename S, typename Comp = std::less<>,
-          typename Proj = detail::identity>
+          typename Proj = detail::identity,
+          typename = std::enable_if_t<traits::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, std::ref(comp), std::ref(proj))) { v = *it; }
+    if (detail::compare(v, *it, comp, proj)) { v = *it; }
   }
   return v;
 }

+ 3 - 1
include/stream/transform_view.h

@@ -25,6 +25,8 @@ public:
   decltype(auto) dereference() const {
     return projection_(super_t::dereference());
   }
+
+  bool at_end() const { return super_t::impl().at_end(); }
 };
 
 template <typename S, typename Proj> class transform_view {
@@ -40,7 +42,7 @@ public:
   auto begin() const { return transform_iterator(stream_.begin(), invoke()); }
   auto end() const {
     if constexpr (traits::is_sentinal_v<S>) {
-      return iter<S>::sentinal;
+      return stream_.end();
     } else {
       return transform_iterator(stream_.end(), invoke());
     }

+ 14 - 0
test/stream_test.cxx

@@ -13,6 +13,7 @@
 
 #include "stream/streams.hpp"
 
+using ::testing::ElementsAre;
 using ::testing::ElementsAreArray;
 using ::testing::Eq;
 
@@ -131,6 +132,19 @@ TEST(StreamTest, CanFilterOutElements) {
   EXPECT_THAT(out, Eq(expected));
 }
 
+TEST(StreamTest, CanTransformFilteredElements) {
+  std::vector<int> input{1, 2, 3, 4, 5};
+
+  auto range = input | views::filter([](int i) { return i % 2 == 0; }) |
+               views::transform([](int i) { return i / 2; });
+
+  auto out = range | ranges::to_vector();
+  EXPECT_THAT(out, ElementsAre(1, 2));
+
+  ranges::for_each(range, [&](int i) { out.push_back(i); });
+  EXPECT_THAT(out, ElementsAre(1, 2, 1, 2));
+}
+
 TEST(StreamTest, AccumulateDefaultsToAdd) {
   std::vector<int> input{1, 2, 3, 4, 5};
   auto even = [](int i) { return i % 2 == 0; };