fork(2) download
  1. #include <exception>
  2. #include <functional>
  3. #include <memory>
  4.  
  5. namespace ro {
  6. /*
  7.   * A class that may or may not hold a value in it.
  8.   */
  9. template <typename T>
  10. class Maybe
  11. {
  12. public:
  13. /*
  14.   * A deleter that doesn't actually delete the pointer. This is used to make sure that
  15.   * the thread_local static instance on the stack doesn't get deleted when going out
  16.   * of scope
  17.   */
  18. struct NoopDeleter
  19. {
  20. void operator()(Maybe<T>*) {}
  21. };
  22. using pointer_t = std::shared_ptr<Maybe<T>>;
  23.  
  24. /*
  25.   * Gets an pointer to a Maybe that's nothing
  26.   */
  27. static pointer_t nothing();
  28.  
  29. /*
  30.   * Gets a pointer to a Maybe that just have a value.
  31.   */
  32. static pointer_t just(const T& value);
  33.  
  34. public:
  35. Maybe() = default;
  36. virtual ~Maybe() = default;
  37.  
  38. /*
  39.   * Returns if this Maybe is nothing
  40.   */
  41. virtual bool isNothing() const = 0;
  42.  
  43. /*
  44.   * Gets the value, if this instance has one. Throws a runtimer_error otherwise.
  45.   */
  46. virtual T get() const = 0;
  47.  
  48. /*
  49.   * Gets the value held or the passed in value otherwise.
  50.   */
  51. T getOrElse(const T& defaultValue) const
  52. {
  53. if (isNothing())
  54. {
  55. return defaultValue;
  56. }
  57. return get();
  58. }
  59.  
  60. /*
  61.   * Gets the value stored or throws the exception as supplied by the method passed in
  62.   */
  63. T getOrThrow(const std::function<std::exception()>& exceptionSupplier) const
  64. {
  65. if (isNothing())
  66. {
  67. throw exceptionSupplier();
  68. }
  69. return get();
  70. }
  71.  
  72. /*
  73.   * Binds a function to convert the stored value (if any) to another of the same type
  74.   */
  75. pointer_t bind(const std::function < T(const T&)>& func) const
  76. {
  77. return map<T>(func);
  78. }
  79.  
  80. /*
  81.   * Binds a function to convert the stored value (if any) to another Maybe of the same type
  82.   */
  83. pointer_t flatBind(const std::function<pointer_t(const T&)>& func) const
  84. {
  85. return flatMap<T>(func);
  86. }
  87.  
  88. /*
  89.   * Maps the current value (if any) to another type.
  90.   */
  91. template <typename U>
  92. typename Maybe<U>::pointer_t map(const std::function<U(const T&)>& func) const
  93. {
  94. return flatMap<U>([&](const T& val) { return Maybe<U>::just(func(val)); });
  95. }
  96.  
  97. /*
  98.   * Maps the current value (if any) to another type, using the method that returns a
  99.   * Maybe of the mapped type.
  100.   */
  101. template <typename U>
  102. typename Maybe<U>::pointer_t flatMap(const std::function<typename Maybe<U>::pointer_t(const T&)>& func) const
  103. {
  104. if (isNothing())
  105. {
  106. return Maybe<U>::nothing();
  107. }
  108. return func(get());
  109. }
  110. };
  111.  
  112. template <typename T>
  113. class Nothing : public Maybe<T>
  114. {
  115. public:
  116. virtual bool isNothing() const override
  117. {
  118. return true;
  119. }
  120.  
  121. virtual T get() const override
  122. {
  123. throw std::runtime_error("No value has been set for this.");
  124. }
  125. };
  126.  
  127. template <typename T>
  128. class Just : public Maybe<T>
  129. {
  130. public:
  131. Just(const T& value)
  132. : mValue(value)
  133. {
  134. }
  135.  
  136. virtual bool isNothing() const override
  137. {
  138. return false;
  139. }
  140.  
  141. virtual T get() const override
  142. {
  143. return mValue;
  144. }
  145.  
  146. private:
  147. const T mValue;
  148. };
  149.  
  150. template <typename T>
  151. typename Maybe<T>::pointer_t Maybe<T>::nothing()
  152. {
  153. thread_local static Nothing<T> nothingInstance;
  154. static typename Maybe<T>::pointer_t nothing(&nothingInstance, NoopDeleter());
  155. return nothing;
  156. }
  157.  
  158. template <typename T>
  159. typename Maybe<T>::pointer_t Maybe<T>::just(const T& value)
  160. {
  161. thread_local static Just<T> justInstance(value);
  162. typename Maybe<T>::pointer_t just(new (&justInstance) Just<T>(value), NoopDeleter());
  163. return just;
  164. }
  165. }
  166.  
  167. #include <iostream>
  168. #include <sstream>
  169.  
  170. int main() {
  171. try {
  172. auto meaningOfLife = ro::Maybe<int>::just(10)
  173. ->bind([](int n) {
  174. return n * 2;
  175. })
  176. ->bind([](int n) {
  177. return n + 22;
  178. })
  179. ->map<std::string>([](int n) {
  180. std::stringstream ss;
  181. ss << n;
  182. return ss.str();
  183. })
  184. ->getOrThrow([] {
  185. return std::runtime_error("There's no meaning???");
  186. });
  187. std::cout << meaningOfLife << " (" << typeid(meaningOfLife).name() << ")" << std::endl;
  188. } catch (std::exception& e) {
  189. std::cout << "EXCEPTION: " << e.what() << std::endl;
  190. }
  191. return 0;
  192. }
Success #stdin #stdout 0s 3468KB
stdin
Standard input is empty
stdout
42 (Ss)