| /* |
| * Copyright 2015 Facebook, Inc. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #pragma once |
| |
| #include <stdexcept> |
| |
| #include <folly/futures/FutureException.h> |
| |
| namespace folly { |
| |
| template <class T> |
| Try<T>::Try(Try<T>&& t) noexcept : contains_(t.contains_) { |
| if (contains_ == Contains::VALUE) { |
| new (&value_)T(std::move(t.value_)); |
| } else if (contains_ == Contains::EXCEPTION) { |
| new (&e_)std::unique_ptr<exception_wrapper>(std::move(t.e_)); |
| } |
| } |
| |
| template <class T> |
| template <class T2> |
| Try<T>::Try(typename std::enable_if<std::is_same<Unit, T2>::value, |
| Try<void> const&>::type t) |
| : contains_(Contains::NOTHING) { |
| if (t.hasValue()) { |
| contains_ = Contains::VALUE; |
| new (&value_) T(); |
| } else if (t.hasException()) { |
| contains_ = Contains::EXCEPTION; |
| new (&e_) std::unique_ptr<exception_wrapper>( |
| folly::make_unique<exception_wrapper>(t.exception())); |
| } |
| } |
| |
| template <class T> |
| Try<T>& Try<T>::operator=(Try<T>&& t) noexcept { |
| if (this == &t) { |
| return *this; |
| } |
| |
| this->~Try(); |
| contains_ = t.contains_; |
| if (contains_ == Contains::VALUE) { |
| new (&value_)T(std::move(t.value_)); |
| } else if (contains_ == Contains::EXCEPTION) { |
| new (&e_)std::unique_ptr<exception_wrapper>(std::move(t.e_)); |
| } |
| return *this; |
| } |
| |
| template <class T> |
| Try<T>::Try(const Try<T>& t) { |
| static_assert( |
| std::is_copy_constructible<T>::value, |
| "T must be copyable for Try<T> to be copyable"); |
| contains_ = t.contains_; |
| if (contains_ == Contains::VALUE) { |
| new (&value_)T(t.value_); |
| } else if (contains_ == Contains::EXCEPTION) { |
| new (&e_)std::unique_ptr<exception_wrapper>(); |
| e_ = folly::make_unique<exception_wrapper>(*(t.e_)); |
| } |
| } |
| |
| template <class T> |
| Try<T>& Try<T>::operator=(const Try<T>& t) { |
| static_assert( |
| std::is_copy_constructible<T>::value, |
| "T must be copyable for Try<T> to be copyable"); |
| this->~Try(); |
| contains_ = t.contains_; |
| if (contains_ == Contains::VALUE) { |
| new (&value_)T(t.value_); |
| } else if (contains_ == Contains::EXCEPTION) { |
| new (&e_)std::unique_ptr<exception_wrapper>(); |
| e_ = folly::make_unique<exception_wrapper>(*(t.e_)); |
| } |
| return *this; |
| } |
| |
| template <class T> |
| Try<T>::~Try() { |
| if (LIKELY(contains_ == Contains::VALUE)) { |
| value_.~T(); |
| } else if (UNLIKELY(contains_ == Contains::EXCEPTION)) { |
| e_.~unique_ptr<exception_wrapper>(); |
| } |
| } |
| |
| template <class T> |
| T& Try<T>::value() { |
| throwIfFailed(); |
| return value_; |
| } |
| |
| template <class T> |
| const T& Try<T>::value() const { |
| throwIfFailed(); |
| return value_; |
| } |
| |
| template <class T> |
| void Try<T>::throwIfFailed() const { |
| if (contains_ != Contains::VALUE) { |
| if (contains_ == Contains::EXCEPTION) { |
| e_->throwException(); |
| } else { |
| throw UsingUninitializedTry(); |
| } |
| } |
| } |
| |
| void Try<void>::throwIfFailed() const { |
| if (!hasValue_) { |
| e_->throwException(); |
| } |
| } |
| |
| template <typename T> |
| inline T moveFromTry(Try<T>&& t) { |
| return std::move(t.value()); |
| } |
| |
| inline void moveFromTry(Try<void>&& t) { |
| return t.value(); |
| } |
| |
| template <typename F> |
| typename std::enable_if< |
| !std::is_same<typename std::result_of<F()>::type, void>::value, |
| Try<typename std::result_of<F()>::type>>::type |
| makeTryWith(F&& f) { |
| typedef typename std::result_of<F()>::type ResultType; |
| try { |
| return Try<ResultType>(f()); |
| } catch (std::exception& e) { |
| return Try<ResultType>(exception_wrapper(std::current_exception(), e)); |
| } catch (...) { |
| return Try<ResultType>(exception_wrapper(std::current_exception())); |
| } |
| } |
| |
| template <typename F> |
| typename std::enable_if< |
| std::is_same<typename std::result_of<F()>::type, void>::value, |
| Try<void>>::type |
| makeTryWith(F&& f) { |
| try { |
| f(); |
| return Try<void>(); |
| } catch (std::exception& e) { |
| return Try<void>(exception_wrapper(std::current_exception(), e)); |
| } catch (...) { |
| return Try<void>(exception_wrapper(std::current_exception())); |
| } |
| } |
| |
| } // folly |