| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788 |
- //
- // either_stream.hpp
- // optional.stream
- //
- // Created by Sam Jaffe on 1/28/17.
- //
- #pragma once
- #include <type_traits>
- #if __cplusplus > 201402L
- #include <variant>
- template <typename T, typename E>
- using either = std::variant<T, E>;
- #else
- #include "variant/variant.hpp"
- template <typename T, typename E>
- using either = variant<T, E>;
- #endif
- namespace stream { namespace either {
- namespace detail {
- 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, typename E>
- class either_stream<::either<T, E>> {
- private:
- template <typename F, typename T2>
- using map_f = decltype(std::declval<F>()(std::declval<T2>()));
-
- template <typename F, typename T2>
- using flatmap_f = typename either_left<decltype(std::declval<F>()(std::declval<T2>()))>::type;
- 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, T>, E>> map(F && fun) const {
- using next_t = either_stream<::either<map_f<F, T>, 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, T>, E>> flatmap(F && fun) const {
- using next_t = either_stream<::either<flatmap_f<F, T>, 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, T>>::value && std::is_void<map_f<FE, E>>::value)>::type>
- typename std::common_type<map_f<FT, T>, 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, T>>::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));
- }
- private:
- ::either<T, E> value;
- };
- }
-
- template <typename T, typename E>
- auto make_stream(T const & opt) -> detail::either_stream<::either<T, E>> {
- return {{opt}};
- }
- template <typename E, typename T>
- auto make_stream(T const & opt) -> detail::either_stream<::either<T, E>> {
- return {{opt}};
- }
- template <typename E>
- auto make_stream(typename detail::either_left<E>::type const & opt) -> detail::either_stream<E> {
- return {{opt}};
- }
- } }
|