| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109 |
- //
- // either_stream.hpp
- // optional.stream
- //
- // Created by Sam Jaffe on 1/28/17.
- //
- #pragma once
- #include <type_traits>
- #include <variant>
- template <typename T, typename E> using either = std::variant<T, E>;
- namespace stream {
- template <typename T> class either_stream;
- template <typename T> struct either_left;
- template <typename T, typename E> struct either_left<::either<T, E>> {
- using type = T;
- };
- template <typename T> using either_left_t = typename either_left<T>::type;
- template <typename T, typename E> class either_stream<::either<T, E>> {
- 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>>;
- private:
- ::either<T, E> value_;
- public:
- either_stream(E const & v) : value_(v) {}
- either_stream(E && v) : value_(std::forward<E>(v)) {}
- either_stream(T const & v) : value_(v) {}
- either_stream(T && v) : value_(std::forward<T>(v)) {}
- either_stream(::either<T, E> const & v) : value_(v) {}
- 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<::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_)};
- }
- 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_));
- }
- ::either<T, E> const & value() const { return value_; }
- };
- }
- namespace stream { namespace 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>> {
- return {{opt}};
- }
- /**
- * Construct a stream from the given type where the real type is an inferred
- * property
- */
- template <typename E, typename T>
- auto make_stream(T const & opt) -> either_stream<::either<T, E>> {
- return {{opt}};
- }
- /**
- * 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}};
- }
- }}
|