// // either_stream.hpp // optional.stream // // Created by Sam Jaffe on 1/28/17. // #pragma once #include #if __cplusplus > 201402L #include template using either = std::variant; #else #include "variant/variant.hpp" template using either = variant; #endif namespace stream { namespace either { namespace detail { template class either_stream; template struct either_left; template struct either_left<::either> { using type = T; }; template class either_stream<::either> { private: template using map_f = decltype(std::declval()(std::declval())); template using flatmap_f = typename either_left()(std::declval()))>::type; public: either_stream(E const & v) : value(v) {} either_stream(E && v) : value(std::forward(v)) {} either_stream(T const & v) : value(v) {} either_stream(T && v) : value(std::forward(v)) {} either_stream(::either const & v) : value(v) {} either_stream(::either && v) : value(std::forward<::either>(v)) {} template either_stream<::either, E>> map(F && fun) const { using next_t = either_stream<::either, E>>; return value.index() == 0 ? next_t{fun(std::get<0>(value))} : next_t{std::get<1>(value)}; } template either_stream, E>> flatmap(F && fun) const { using next_t = either_stream<::either, E>>; return value.index() == 0 ? next_t{fun(std::get<0>(value))} : next_t{std::get<1>(value)}; } template >::value && std::is_void>::value)>::type> typename std::common_type, map_f>::type match(FT && left, FE && right) { return value.index() == 0 ? left(std::get<0>(value)) : right(std::get<1>(value)); } template >::value && std::is_void>::value>::type> void match(FT && left, FE && right) { value.index() == 0 ? left(std::get<0>(value)) : right(std::get<1>(value)); } private: ::either value; }; } template auto make_stream(T const & opt) -> detail::either_stream<::either> { return {{opt}}; } template auto make_stream(T const & opt) -> detail::either_stream<::either> { return {{opt}}; } template auto make_stream(typename detail::either_left::type const & opt) -> detail::either_stream { return {{opt}}; } } }