// // optional_stream.hpp // optional.stream // // Created by Sam Jaffe on 1/28/17. // #pragma once #if __cplusplus > 201402L #include #else #include namespace std { using experimental::optional; using experimental::nullopt; } #endif namespace stream { namespace optional { namespace detail { template struct flatmap_impl_t; template struct flatmap_impl_t> { using type = T; }; template class optional_stream { private: template using map_f = decltype(std::declval()(std::declval())); template using flatmap_f = typename flatmap_impl_t>::type; public: explicit optional_stream() : value(std::nullopt) {} explicit optional_stream(T const & v) : value(v) {} explicit optional_stream(T && v) : value(std::forward(v)) {} explicit optional_stream(std::optional const & v) : value(v) {} explicit optional_stream(std::optional && v) : value(std::forward>(v)) {} operator std::optional() const { return value; } template optional_stream> map(F && fun) const { using next_t = optional_stream>; return !value ? next_t{} : next_t{fun(*value)}; } template optional_stream> flatmap(F && fun) const { using next_t = optional_stream>; return !value ? next_t{} : next_t{fun(*value)}; } private: std::optional value; }; } template auto make_stream(std::optional const & opt) -> detail::optional_stream { return detail::optional_stream{opt}; } template auto make_stream(T const & val) -> detail::optional_stream { return detail::optional_stream{val}; } template auto make_stream() -> detail::optional_stream { return detail::optional_stream{}; } } }