Try-inl.h 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326
  1. /*
  2. * Copyright 2014-present Facebook, Inc.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #pragma once
  17. #include <folly/Utility.h>
  18. #include <folly/functional/Invoke.h>
  19. #include <stdexcept>
  20. #include <tuple>
  21. namespace folly {
  22. template <class T>
  23. Try<T>::Try(Try<T>&& t) noexcept(std::is_nothrow_move_constructible<T>::value)
  24. : contains_(t.contains_) {
  25. if (contains_ == Contains::VALUE) {
  26. new (&value_) T(std::move(t.value_));
  27. } else if (contains_ == Contains::EXCEPTION) {
  28. new (&e_) exception_wrapper(std::move(t.e_));
  29. }
  30. }
  31. template <class T>
  32. template <class T2>
  33. Try<T>::Try(typename std::enable_if<
  34. std::is_same<Unit, T2>::value,
  35. Try<void> const&>::type t) noexcept
  36. : contains_(Contains::NOTHING) {
  37. if (t.hasValue()) {
  38. contains_ = Contains::VALUE;
  39. new (&value_) T();
  40. } else if (t.hasException()) {
  41. contains_ = Contains::EXCEPTION;
  42. new (&e_) exception_wrapper(t.exception());
  43. }
  44. }
  45. template <class T>
  46. Try<T>& Try<T>::operator=(Try<T>&& t) noexcept(
  47. std::is_nothrow_move_constructible<T>::value) {
  48. if (this == &t) {
  49. return *this;
  50. }
  51. destroy();
  52. if (t.contains_ == Contains::VALUE) {
  53. new (&value_) T(std::move(t.value_));
  54. } else if (t.contains_ == Contains::EXCEPTION) {
  55. new (&e_) exception_wrapper(std::move(t.e_));
  56. }
  57. contains_ = t.contains_;
  58. return *this;
  59. }
  60. template <class T>
  61. Try<T>::Try(const Try<T>& t) noexcept(
  62. std::is_nothrow_copy_constructible<T>::value) {
  63. static_assert(
  64. std::is_copy_constructible<T>::value,
  65. "T must be copyable for Try<T> to be copyable");
  66. contains_ = t.contains_;
  67. if (contains_ == Contains::VALUE) {
  68. new (&value_) T(t.value_);
  69. } else if (contains_ == Contains::EXCEPTION) {
  70. new (&e_) exception_wrapper(t.e_);
  71. }
  72. }
  73. template <class T>
  74. Try<T>& Try<T>::operator=(const Try<T>& t) noexcept(
  75. std::is_nothrow_copy_constructible<T>::value) {
  76. static_assert(
  77. std::is_copy_constructible<T>::value,
  78. "T must be copyable for Try<T> to be copyable");
  79. if (this == &t) {
  80. return *this;
  81. }
  82. destroy();
  83. if (t.contains_ == Contains::VALUE) {
  84. new (&value_) T(t.value_);
  85. } else if (t.contains_ == Contains::EXCEPTION) {
  86. new (&e_) exception_wrapper(t.e_);
  87. }
  88. contains_ = t.contains_;
  89. return *this;
  90. }
  91. template <class T>
  92. Try<T>::~Try() {
  93. if (LIKELY(contains_ == Contains::VALUE)) {
  94. value_.~T();
  95. } else if (UNLIKELY(contains_ == Contains::EXCEPTION)) {
  96. e_.~exception_wrapper();
  97. }
  98. }
  99. template <typename T>
  100. template <typename... Args>
  101. T& Try<T>::emplace(Args&&... args) noexcept(
  102. std::is_nothrow_constructible<T, Args&&...>::value) {
  103. this->destroy();
  104. new (&value_) T(static_cast<Args&&>(args)...);
  105. contains_ = Contains::VALUE;
  106. return value_;
  107. }
  108. template <typename T>
  109. template <typename... Args>
  110. exception_wrapper& Try<T>::emplaceException(Args&&... args) noexcept(
  111. std::is_nothrow_constructible<exception_wrapper, Args&&...>::value) {
  112. this->destroy();
  113. new (&e_) exception_wrapper(static_cast<Args&&>(args)...);
  114. contains_ = Contains::EXCEPTION;
  115. return e_;
  116. }
  117. template <class T>
  118. T& Try<T>::value() & {
  119. throwIfFailed();
  120. return value_;
  121. }
  122. template <class T>
  123. T&& Try<T>::value() && {
  124. throwIfFailed();
  125. return std::move(value_);
  126. }
  127. template <class T>
  128. const T& Try<T>::value() const& {
  129. throwIfFailed();
  130. return value_;
  131. }
  132. template <class T>
  133. const T&& Try<T>::value() const&& {
  134. throwIfFailed();
  135. return std::move(value_);
  136. }
  137. template <class T>
  138. void Try<T>::throwIfFailed() const {
  139. switch (contains_) {
  140. case Contains::VALUE:
  141. return;
  142. case Contains::EXCEPTION:
  143. e_.throw_exception();
  144. default:
  145. throw_exception<UsingUninitializedTry>();
  146. }
  147. }
  148. template <class T>
  149. void Try<T>::destroy() noexcept {
  150. auto oldContains = folly::exchange(contains_, Contains::NOTHING);
  151. if (LIKELY(oldContains == Contains::VALUE)) {
  152. value_.~T();
  153. } else if (UNLIKELY(oldContains == Contains::EXCEPTION)) {
  154. e_.~exception_wrapper();
  155. }
  156. }
  157. Try<void>& Try<void>::operator=(const Try<void>& t) noexcept {
  158. if (t.hasException()) {
  159. if (hasException()) {
  160. e_ = t.e_;
  161. } else {
  162. new (&e_) exception_wrapper(t.e_);
  163. hasValue_ = false;
  164. }
  165. } else {
  166. if (hasException()) {
  167. e_.~exception_wrapper();
  168. hasValue_ = true;
  169. }
  170. }
  171. return *this;
  172. }
  173. template <typename... Args>
  174. exception_wrapper& Try<void>::emplaceException(Args&&... args) noexcept(
  175. std::is_nothrow_constructible<exception_wrapper, Args&&...>::value) {
  176. if (hasException()) {
  177. e_.~exception_wrapper();
  178. }
  179. new (&e_) exception_wrapper(static_cast<Args&&>(args)...);
  180. hasValue_ = false;
  181. return e_;
  182. }
  183. void Try<void>::throwIfFailed() const {
  184. if (hasException()) {
  185. e_.throw_exception();
  186. }
  187. }
  188. template <typename F>
  189. typename std::enable_if<
  190. !std::is_same<invoke_result_t<F>, void>::value,
  191. Try<invoke_result_t<F>>>::type
  192. makeTryWith(F&& f) {
  193. using ResultType = invoke_result_t<F>;
  194. try {
  195. return Try<ResultType>(f());
  196. } catch (std::exception& e) {
  197. return Try<ResultType>(exception_wrapper(std::current_exception(), e));
  198. } catch (...) {
  199. return Try<ResultType>(exception_wrapper(std::current_exception()));
  200. }
  201. }
  202. template <typename F>
  203. typename std::
  204. enable_if<std::is_same<invoke_result_t<F>, void>::value, Try<void>>::type
  205. makeTryWith(F&& f) {
  206. try {
  207. f();
  208. return Try<void>();
  209. } catch (std::exception& e) {
  210. return Try<void>(exception_wrapper(std::current_exception(), e));
  211. } catch (...) {
  212. return Try<void>(exception_wrapper(std::current_exception()));
  213. }
  214. }
  215. template <typename T, typename... Args>
  216. T* tryEmplace(Try<T>& t, Args&&... args) noexcept {
  217. try {
  218. return std::addressof(t.emplace(static_cast<Args&&>(args)...));
  219. } catch (const std::exception& ex) {
  220. t.emplaceException(std::current_exception(), ex);
  221. return nullptr;
  222. } catch (...) {
  223. t.emplaceException(std::current_exception());
  224. return nullptr;
  225. }
  226. }
  227. void tryEmplace(Try<void>& t) noexcept {
  228. t.emplace();
  229. }
  230. template <typename T, typename Func>
  231. T* tryEmplaceWith(Try<T>& t, Func&& func) noexcept {
  232. static_assert(
  233. std::is_constructible<T, folly::invoke_result_t<Func>>::value,
  234. "Unable to initialise a value of type T with the result of 'func'");
  235. try {
  236. return std::addressof(t.emplace(static_cast<Func&&>(func)()));
  237. } catch (const std::exception& ex) {
  238. t.emplaceException(std::current_exception(), ex);
  239. return nullptr;
  240. } catch (...) {
  241. t.emplaceException(std::current_exception());
  242. return nullptr;
  243. }
  244. }
  245. template <typename Func>
  246. bool tryEmplaceWith(Try<void>& t, Func&& func) noexcept {
  247. static_assert(
  248. std::is_void<folly::invoke_result_t<Func>>::value,
  249. "Func returns non-void. Cannot be used to emplace Try<void>");
  250. try {
  251. static_cast<Func&&>(func)();
  252. t.emplace();
  253. return true;
  254. } catch (const std::exception& ex) {
  255. t.emplaceException(std::current_exception(), ex);
  256. return false;
  257. } catch (...) {
  258. t.emplaceException(std::current_exception());
  259. return false;
  260. }
  261. }
  262. namespace try_detail {
  263. /**
  264. * Trait that removes the layer of Try abstractions from the passed in type
  265. */
  266. template <typename Type>
  267. struct RemoveTry;
  268. template <template <typename...> class TupleType, typename... Types>
  269. struct RemoveTry<TupleType<folly::Try<Types>...>> {
  270. using type = TupleType<Types...>;
  271. };
  272. template <std::size_t... Indices, typename Tuple>
  273. auto unwrapTryTupleImpl(folly::index_sequence<Indices...>, Tuple&& instance) {
  274. using std::get;
  275. using ReturnType = typename RemoveTry<typename std::decay<Tuple>::type>::type;
  276. return ReturnType{(get<Indices>(std::forward<Tuple>(instance)).value())...};
  277. }
  278. } // namespace try_detail
  279. template <typename Tuple>
  280. auto unwrapTryTuple(Tuple&& instance) {
  281. using TupleDecayed = typename std::decay<Tuple>::type;
  282. using Seq = folly::make_index_sequence<std::tuple_size<TupleDecayed>::value>;
  283. return try_detail::unwrapTryTupleImpl(Seq{}, std::forward<Tuple>(instance));
  284. }
  285. } // namespace folly