| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121 |
- //
- // 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, typename> class either_stream;
- }
- namespace stream::traits {
- template <typename Either> struct either_traits {
- static constexpr bool const is_either = false;
- };
- template <typename T, typename E> struct either_traits<::either<T, E>> {
- static constexpr bool const is_either = true;
- using stream_type = either_stream<T, E>;
- using value_type = T;
- using error_type = E;
- };
- 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;
- template <typename Either>
- inline constexpr bool is_either_v = either_traits<Either>::is_either;
- }
- namespace stream {
- template <typename T, typename E> class either_stream {
- private:
- template <typename F, typename T2 = T>
- using result_of = decltype(std::declval<F>()(std::declval<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>
- auto map(F && fun) const -> either_stream<result_of<F>, E> {
- static_assert(!traits::is_either_v<result_of<F>>, "Cannot nest eithers");
- if (value_.index() == 0) {
- return fun(std::get<0>(value_));
- } else {
- return std::get<1>(value_);
- }
- }
- template <typename F>
- auto flatmap(F && fun) const
- -> either_stream<traits::either_value_t<result_of<F>>, E> {
- if (value_.index() == 0) {
- return fun(std::get<0>(value_));
- } else {
- return std::get<1>(value_);
- }
- }
- template <typename FT, typename FE>
- auto match(FT && left, FE && right)
- -> std::common_type_t<result_of<FT, T>, result_of<FE, E>> {
- if (value_.index() == 0) {
- return left(std::get<0>(value_));
- } else {
- return right(std::get<1>(value_));
- }
- }
- };
- }
- 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>
- either_stream<T, E> make_stream(T const & opt) {
- return {{opt}};
- }
- /**
- * Construct a stream from the given type where the real type is an inferred
- * property
- */
- template <typename E, typename T>
- either_stream<T, E> make_stream(T const & opt) {
- return {{opt}};
- }
- /**
- * Construct a stream with the given either-type as a template parameter.
- */
- template <typename E>
- auto make_stream(traits::either_value_t<E> const & opt) {
- return traits::either_stream_t<E>{opt};
- }
- }
|