|
|
@@ -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};
|
|
|
}
|
|
|
-}}
|
|
|
+
|
|
|
+}
|