Browse Source

Streamline either stream functions.

Sam Jaffe 5 years ago
parent
commit
0e71950f03
1 changed files with 52 additions and 39 deletions
  1. 52 39
      include/stream/either_stream.hpp

+ 52 - 39
include/stream/either_stream.hpp

@@ -13,22 +13,38 @@
 template <typename T, typename E> using either = std::variant<T, E>;
 
 namespace stream {
-  template <typename T> class either_stream;
+  template <typename, typename> class either_stream;
+}
+
+namespace stream::traits {
 
-  template <typename T> struct either_left;
-  template <typename T, typename E> struct either_left<::either<T, E>> {
-    using type = T;
+  template <typename Either> struct either_traits;
+  template <typename T, typename E> struct either_traits<::either<T, E>> {
+    using stream_type = either_stream<T, E>;
+    using value_type = T;
+    using error_type = E;
   };
 
-  template <typename T> using either_left_t = typename either_left<T>::type;
+  template <typename Either>
+  using either_stream_t = typename either_traits<Either>::stream_type;
+  template <typename Either>
+  using either_value_t = typename either_traits<Either>::value_type;
+
+}
+
+namespace stream {
 
-  template <typename T, typename E> class either_stream<::either<T, E>> {
+  template <typename T, typename E> class either_stream {
   private:
     template <typename F, typename T2 = T>
     using map_f = decltype(std::declval<F>()(std::declval<T2>()));
 
     template <typename F, typename T2 = T>
-    using flatmap_f = either_left_t<map_f<F, T2>>;
+    using flatmap_f = traits::either_value_t<map_f<F, T2>>;
+
+    template <typename FT, typename FE>
+    inline static constexpr bool is_consumer_v =
+        std::is_void_v<map_f<FT, T>> && std::is_void_v<map_f<FE, E>>;
 
   private:
     ::either<T, E> value_;
@@ -43,50 +59,46 @@ namespace stream {
     either_stream(::either<T, E> && v)
         : value_(std::forward<::either<T, E>>(v)) {}
 
-    template <typename F>
-    either_stream<::either<map_f<F>, E>> map(F && fun) const {
-      using next_t = either_stream<::either<map_f<F>, E>>;
-      return value_.index() == 0 ? next_t{fun(std::get<0>(value_))}
-                                 : next_t{std::get<1>(value_)};
+    template <typename F> either_stream<map_f<F>, E> map(F && fun) const {
+      if (value_.index() == 0) {
+        return fun(std::get<0>(value_));
+      } else {
+        return std::get<1>(value_);
+      }
     }
 
     template <typename F>
-    either_stream<::either<flatmap_f<F>, E>> flatmap(F && fun) const {
-      using next_t = either_stream<::either<flatmap_f<F>, E>>;
-      return value_.index() == 0 ? next_t{fun(std::get<0>(value_))}
-                                 : next_t{std::get<1>(value_)};
+    either_stream<flatmap_f<F>, E> flatmap(F && fun) const {
+      if (value_.index() == 0) {
+        return fun(std::get<0>(value_));
+      } else {
+        return std::get<1>(value_);
+      }
     }
 
-    template <typename FT, typename FE,
-              typename = typename std::enable_if<
-                  !(std::is_void<map_f<FT>>::value &&
-                    std::is_void<map_f<FE, E>>::value)>::type>
-    typename std::common_type<map_f<FT>, map_f<FE, E>>::type
-    match(FT && left, FE && right) {
-      return value_.index() == 0 ? left(std::get<0>(value_))
-                                 : right(std::get<1>(value_));
-    }
-
-    template <typename FT, typename FE,
-              typename = typename std::enable_if<
-                  std::is_void<map_f<FT>>::value &&
-                  std::is_void<map_f<FE, E>>::value>::type>
-    void match(FT && left, FE && right) {
-      value_.index() == 0 ? left(std::get<0>(value_))
-                          : right(std::get<1>(value_));
+    template <typename FT, typename FE>
+    auto match(FT && left, FE && right)
+        -> std::common_type_t<map_f<FT, T>, map_f<FE, E>> {
+      if (value_.index() == 0) {
+        return left(std::get<0>(value_));
+      } else {
+        return right(std::get<1>(value_));
+      }
     }
 
     ::either<T, E> const & value() const { return value_; }
   };
+
 }
 
-namespace stream { namespace either {
+namespace stream::either {
+
   /**
    * Construct a stream from the given type while explicitly providing both the
    * type and the error class
    */
   template <typename T, typename E>
-  auto make_stream(T const & opt) -> either_stream<::either<T, E>> {
+  either_stream<T, E> make_stream(T const & opt) {
     return {{opt}};
   }
 
@@ -95,7 +107,7 @@ namespace stream { namespace either {
    * property
    */
   template <typename E, typename T>
-  auto make_stream(T const & opt) -> either_stream<::either<T, E>> {
+  either_stream<T, E> make_stream(T const & opt) {
     return {{opt}};
   }
 
@@ -103,7 +115,8 @@ namespace stream { namespace either {
    * Construct a stream with the given either-type as a template parameter.
    */
   template <typename E>
-  auto make_stream(either_left_t<E> const & opt) -> either_stream<E> {
-    return {{opt}};
+  auto make_stream(traits::either_value_t<E> const & opt) {
+    return traits::either_stream_t<E>{opt};
   }
-}}
+
+}