optional_stream.hpp 2.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172
  1. //
  2. // optional_stream.hpp
  3. // optional.stream
  4. //
  5. // Created by Sam Jaffe on 1/28/17.
  6. //
  7. #pragma once
  8. #if __cplusplus > 201402L
  9. #include <optional>
  10. #else
  11. #include <experimental/optional>
  12. namespace std {
  13. using experimental::optional;
  14. using experimental::nullopt;
  15. }
  16. #endif
  17. namespace stream { namespace optional {
  18. namespace detail {
  19. template <typename T> struct flatmap_impl_t;
  20. template <typename T>
  21. struct flatmap_impl_t<std::optional<T>> { using type = T; };
  22. template <typename T>
  23. class optional_stream {
  24. private:
  25. template <typename F>
  26. using map_f = decltype(std::declval<F>()(std::declval<T>()));
  27. template <typename F>
  28. using flatmap_f = typename flatmap_impl_t<map_f<F>>::type;
  29. public:
  30. explicit optional_stream() : value(std::nullopt) {}
  31. explicit optional_stream(T const & v) : value(v) {}
  32. explicit optional_stream(T && v) : value(std::forward<T>(v)) {}
  33. explicit optional_stream(std::optional<T> const & v) : value(v) {}
  34. explicit optional_stream(std::optional<T> && v) : value(std::forward<std::optional<T>>(v)) {}
  35. operator std::optional<T>() const { return value; }
  36. template <typename F>
  37. optional_stream<map_f<F>> map(F && fun) const {
  38. using next_t = optional_stream<map_f<F>>;
  39. return !value ? next_t{} : next_t{fun(*value)};
  40. }
  41. template <typename F>
  42. optional_stream<flatmap_f<F>> flatmap(F && fun) const {
  43. using next_t = optional_stream<flatmap_f<F>>;
  44. return !value ? next_t{} : next_t{fun(*value)};
  45. }
  46. private:
  47. std::optional<T> value;
  48. };
  49. }
  50. template <typename T>
  51. auto make_stream(std::optional<T> const & opt) -> detail::optional_stream<T> {
  52. return detail::optional_stream<T>{opt};
  53. }
  54. template <typename T>
  55. auto make_stream(T const & val) -> detail::optional_stream<T> {
  56. return detail::optional_stream<T>{val};
  57. }
  58. template <typename T>
  59. auto make_stream() -> detail::optional_stream<T> {
  60. return detail::optional_stream<T>{};
  61. }
  62. } }