From 4d932ecc53c7a72267179e58eeed7ec56eb7dc53 Mon Sep 17 00:00:00 2001 From: Eric Niebler Date: Mon, 15 Aug 2016 10:20:25 -0700 Subject: [PATCH] Add folly::Expected, an alternative to exceptions for non-throwing APIs that can fail. Summary: Expected is like an Optional with extra state for reporting //why// the Expected is empty. Something like it is currently under review for inclusion in the C++ standard [1], and Andrei Alexandrescu has spoken about it [2]. It corresponds to the Either Monad in Haskell, where it is used as a return type of an API that has more than one failure mode. By adding folly::Expected, we get a way to implement non-throwing APIs with a consistent and composable interface. [^1]: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4015.pdf [^2]: https://channel9.msdn.com/Shows/Going+Deep/C-and-Beyond-2012-Andrei-Alexandrescu-Systematic-Error-Handling-in-C Reviewed By: mhx Differential Revision: D3522501 fbshipit-source-id: 48b8ea2dfbd0769f26ec84d2d52fd41db75dc05a --- folly/Expected.h | 1342 +++++++++++++++++++++++++++++++++++ folly/Makefile.am | 3 +- folly/Optional.h | 6 + folly/Traits.h | 151 +++- folly/test/ExpectedTest.cpp | 717 +++++++++++++++++++ folly/test/Makefile.am | 4 + folly/test/TraitsTest.cpp | 6 +- 7 files changed, 2209 insertions(+), 20 deletions(-) create mode 100644 folly/Expected.h create mode 100644 folly/test/ExpectedTest.cpp diff --git a/folly/Expected.h b/folly/Expected.h new file mode 100644 index 00000000..cde4a04b --- /dev/null +++ b/folly/Expected.h @@ -0,0 +1,1342 @@ +/* + * Copyright 2016 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. + */ + +/** + * Like folly::Optional, but can store a value *or* and error. + * + * @author Eric Niebler (eniebler@fb.com) + */ + +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include // for construct_in_place_t +#include + +#define FOLLY_EXPECTED_ID(X) FB_CONCATENATE(FB_CONCATENATE(Folly, X), __LINE__) + +#define FOLLY_REQUIRES_IMPL(...) \ + bool FOLLY_EXPECTED_ID(Requires) = false, \ + typename std::enable_if< \ + (FOLLY_EXPECTED_ID(Requires) || static_cast(__VA_ARGS__)), \ + int>::type = 0 + +#define FOLLY_REQUIRES_TRAILING(...) , FOLLY_REQUIRES_IMPL(__VA_ARGS__) + +#define FOLLY_REQUIRES(...) template + +/** + * gcc-4.7 warns about use of uninitialized memory around the use of storage_ + * even though this is explicitly initialized at each point. + */ +#if defined(__GNUC__) && !defined(__clang__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wuninitialized" +#pragma GCC diagnostic ignored "-Wpragmas" +#pragma GCC diagnostic ignored "-Wmaybe-uninitialized" +#endif // __GNUC__ + +namespace folly { + +/** + * Forward declarations + */ +template +class Unexpected; + +template +constexpr Unexpected::type> makeUnexpected(Error&&); + +template +class Expected; + +template +constexpr Expected::type, Error> makeExpected( + Value&&); + +/** + * Alias for an Expected type's assiciated value_type + */ +template +using ExpectedValueType = + typename std::remove_reference::type::value_type; + +/** + * Alias for an Expected type's assiciated error_type + */ +template +using ExpectedErrorType = + typename std::remove_reference::type::error_type; + +// Details... +namespace expected_detail { +template