optional_stream.hpp 2.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970
  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 { using experimental::optional; }
  13. using std::experimental::nullopt;
  14. #endif
  15. namespace stream { namespace optional {
  16. namespace detail {
  17. template <typename T> struct flatmap_impl_t;
  18. template <typename T>
  19. struct flatmap_impl_t<std::optional<T>> { using type = T; };
  20. template <typename T>
  21. class optional_stream {
  22. private:
  23. template <typename F>
  24. using map_f = decltype(std::declval<F>()(std::declval<T>()));
  25. template <typename F>
  26. using flatmap_f = typename flatmap_impl_t<map_f<F>>::type;
  27. public:
  28. explicit optional_stream() : value(nullopt) {}
  29. explicit optional_stream(T const & v) : value(v) {}
  30. explicit optional_stream(T && v) : value(std::forward<T>(v)) {}
  31. explicit optional_stream(std::optional<T> const & v) : value(v) {}
  32. explicit optional_stream(std::optional<T> && v) : value(std::forward<std::optional<T>>(v)) {}
  33. operator std::optional<T>() const { return value; }
  34. template <typename F>
  35. optional_stream<map_f<F>> map(F && fun) const {
  36. using next_t = optional_stream<map_f<F>>;
  37. return !value ? next_t{} : next_t{fun(*value)};
  38. }
  39. template <typename F>
  40. optional_stream<flatmap_f<F>> flatmap(F && fun) const {
  41. using next_t = optional_stream<flatmap_f<F>>;
  42. return !value ? next_t{} : next_t{fun(*value)};
  43. }
  44. private:
  45. std::optional<T> value;
  46. };
  47. }
  48. template <typename T>
  49. auto make_stream(std::optional<T> const & opt) -> detail::optional_stream<T> {
  50. return detail::optional_stream<T>{opt};
  51. }
  52. template <typename T>
  53. auto make_stream(T const & val) -> detail::optional_stream<T> {
  54. return detail::optional_stream<T>{val};
  55. }
  56. template <typename T>
  57. auto make_stream() -> detail::optional_stream<T> {
  58. return detail::optional_stream<T>{};
  59. }
  60. } }