--- /dev/null
+/*
+ * Copyright 2014 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.
+ */
+
+#ifndef FOLLY_EXCEPTIONWRAPPER_H
+#define FOLLY_EXCEPTIONWRAPPER_H
+
+#include <exception>
+#include <memory>
+#include "folly/detail/ExceptionWrapper.h"
+
+namespace folly {
+
+class exception_wrapper {
+ public:
+ exception_wrapper() : throwfn_(nullptr) { }
+
+ void throwException() {
+ if (throwfn_) {
+ throwfn_(item_.get());
+ }
+ }
+
+ std::exception* get() {
+ return item_.get();
+ }
+
+ private:
+ std::shared_ptr<std::exception> item_;
+ void (*throwfn_)(void*);
+
+ template <class T, class... Args>
+ friend exception_wrapper make_exception_wrapper(Args... args);
+};
+
+template <class T, class... Args>
+exception_wrapper make_exception_wrapper(Args... args) {
+ exception_wrapper ew;
+ ew.item_ = std::make_shared<T>(std::forward<Args>(args)...);
+ ew.throwfn_ = folly::detail::thrower<T>::doThrow;
+ return ew;
+}
+
+}
+#endif
--- /dev/null
+/*
+ * Copyright 2014 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.
+ */
+#include "folly/ExceptionWrapper.h"
+
+#include <gflags/gflags.h>
+#include <atomic>
+#include <exception>
+#include <vector>
+#include <stdexcept>
+#include <thread>
+
+#include "folly/Benchmark.h"
+
+DEFINE_int32(num_threads, 32, "Number of threads to run concurrency "
+ "benchmarks");
+
+/*
+ * Use case 1: Library wraps errors in either exception_wrapper or
+ * exception_ptr, but user does not care what the exception is after learning
+ * that there is one.
+ */
+BENCHMARK(exception_ptr_create_and_test, iters) {
+ std::runtime_error e("payload");
+ for (int i = 0; i < iters; ++i) {
+ auto ep = std::make_exception_ptr(e);
+ assert(ep);
+ }
+}
+
+BENCHMARK_RELATIVE(exception_wrapper_create_and_test, iters) {
+ std::runtime_error e("payload");
+ for (int i = 0; i < iters; ++i) {
+ auto ew = folly::make_exception_wrapper<std::runtime_error>(e);
+ assert(ew.get());
+ }
+}
+
+BENCHMARK_DRAW_LINE()
+
+BENCHMARK(exception_ptr_create_and_test_concurrent, iters) {
+ std::atomic<bool> go(false);
+ std::vector<std::thread> threads;
+ BENCHMARK_SUSPEND {
+ for (int t = 0; t < FLAGS_num_threads; ++t) {
+ threads.emplace_back([&go, iters] {
+ while (!go) { }
+ std::runtime_error e("payload");
+ for (int i = 0; i < iters; ++i) {
+ auto ep = std::make_exception_ptr(e);
+ assert(ep);
+ }
+ });
+ }
+ }
+ go.store(true);
+ for (auto& t : threads) {
+ t.join();
+ }
+}
+
+BENCHMARK_RELATIVE(exception_wrapper_create_and_test_concurrent, iters) {
+ std::atomic<bool> go(false);
+ std::vector<std::thread> threads;
+ BENCHMARK_SUSPEND {
+ for (int t = 0; t < FLAGS_num_threads; ++t) {
+ threads.emplace_back([&go, iters] {
+ while (!go) { }
+ std::runtime_error e("payload");
+ for (int i = 0; i < iters; ++i) {
+ auto ew = folly::make_exception_wrapper<std::runtime_error>(e);
+ assert(ew.get());
+ }
+ });
+ }
+ }
+ go.store(true);
+ for (auto& t : threads) {
+ t.join();
+ }
+}
+
+BENCHMARK_DRAW_LINE()
+
+/*
+ * Use case 2: Library wraps errors in either exception_wrapper or
+ * exception_ptr, and user wants to handle std::runtime_error. This can be done
+ * either by rehtrowing or with dynamic_cast.
+ */
+BENCHMARK(exception_ptr_create_and_throw, iters) {
+ std::runtime_error e("payload");
+ for (int i = 0; i < iters; ++i) {
+ auto ep = std::make_exception_ptr(e);
+ try {
+ std::rethrow_exception(ep);
+ assert(false);
+ } catch (std::runtime_error& e) {
+ }
+ }
+}
+
+BENCHMARK_RELATIVE(exception_wrapper_create_and_throw, iters) {
+ std::runtime_error e("payload");
+ for (int i = 0; i < iters; ++i) {
+ auto ew = folly::make_exception_wrapper<std::runtime_error>(e);
+ try {
+ ew.throwException();
+ assert(false);
+ } catch (std::runtime_error& e) {
+ }
+ }
+}
+
+BENCHMARK_RELATIVE(exception_wrapper_create_and_cast, iters) {
+ std::runtime_error e("payload");
+ for (int i = 0; i < iters; ++i) {
+ auto ew = folly::make_exception_wrapper<std::runtime_error>(e);
+ std::exception* basePtr = static_cast<std::exception*>(ew.get());
+ auto ep = dynamic_cast<std::runtime_error*>(basePtr);
+ assert(ep);
+ }
+}
+
+
+BENCHMARK_DRAW_LINE()
+
+BENCHMARK(exception_ptr_create_and_throw_concurrent, iters) {
+ std::atomic<bool> go(false);
+ std::vector<std::thread> threads;
+ BENCHMARK_SUSPEND {
+ for (int t = 0; t < FLAGS_num_threads; ++t) {
+ threads.emplace_back([&go, iters] {
+ while (!go) { }
+ std::runtime_error e("payload");
+ for (int i = 0; i < iters; ++i) {
+ auto ep = std::make_exception_ptr(e);
+ try {
+ std::rethrow_exception(ep);
+ assert(false);
+ } catch (std::runtime_error& e) {
+ }
+ }
+ });
+ }
+ }
+ go.store(true);
+ for (auto& t : threads) {
+ t.join();
+ }
+}
+
+BENCHMARK_RELATIVE(exception_wrapper_create_and_throw_concurrent, iters) {
+ std::atomic<bool> go(false);
+ std::vector<std::thread> threads;
+ BENCHMARK_SUSPEND {
+ for (int t = 0; t < FLAGS_num_threads; ++t) {
+ threads.emplace_back([&go, iters] {
+ while (!go) { }
+ std::runtime_error e("payload");
+ for (int i = 0; i < iters; ++i) {
+ auto ew = folly::make_exception_wrapper<std::runtime_error>(e);
+ try {
+ ew.throwException();
+ assert(false);
+ } catch (std::runtime_error& e) {
+ }
+ }
+ });
+ }
+ }
+ go.store(true);
+ for (auto& t : threads) {
+ t.join();
+ }
+}
+
+BENCHMARK_RELATIVE(exception_wrapper_create_and_cast_concurrent, iters) {
+ std::atomic<bool> go(false);
+ std::vector<std::thread> threads;
+ BENCHMARK_SUSPEND {
+ for (int t = 0; t < FLAGS_num_threads; ++t) {
+ threads.emplace_back([&go, iters] {
+ while (!go) { }
+ std::runtime_error e("payload");
+ for (int i = 0; i < iters; ++i) {
+ auto ew = folly::make_exception_wrapper<std::runtime_error>(e);
+ std::exception* basePtr = static_cast<std::exception*>(ew.get());
+ auto ep = dynamic_cast<std::runtime_error*>(basePtr);
+ assert(ep);
+ }
+ });
+ }
+ }
+ go.store(true);
+ for (auto& t : threads) {
+ t.join();
+ }
+}
+
+int main(int argc, char *argv[]) {
+ google::ParseCommandLineFlags(&argc, &argv, true);
+ folly::runBenchmarks();
+ return 0;
+}
+
+/*
+_bin/folly/test/exception_wrapper_benchmark --bm_min_iters=100000
+============================================================================
+folly/test/ExceptionWrapperBenchmark.cpp relative time/iter iters/s
+============================================================================
+exception_ptr_create_and_test 2.03us 492.88K
+exception_wrapper_create_and_test 2542.59% 79.80ns 12.53M
+----------------------------------------------------------------------------
+exception_ptr_create_and_test_concurrent 162.39us 6.16K
+exception_wrapper_create_and_test_concurrent 95847.91% 169.43ns 5.90M
+----------------------------------------------------------------------------
+exception_ptr_create_and_throw 4.24us 236.06K
+exception_wrapper_create_and_throw 141.15% 3.00us 333.20K
+exception_wrapper_create_and_cast 5321.54% 79.61ns 12.56M
+----------------------------------------------------------------------------
+exception_ptr_create_and_throw_concurrent 330.88us 3.02K
+exception_wrapper_create_and_throw_concurrent 143.66% 230.32us 4.34K
+exception_wrapper_create_and_cast_concurrent 194828.54% 169.83ns 5.89M
+============================================================================
+*/
--- /dev/null
+/*
+ * Copyright 2014 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.
+ */
+
+#include <gtest/gtest.h>
+#include <stdexcept>
+#include "folly/ExceptionWrapper.h"
+
+using namespace folly;
+
+// Tests that when we call throwException, the proper type is thrown (derived)
+TEST(ExceptionWrapper, throw_test) {
+ std::runtime_error e("payload");
+ auto ew = make_exception_wrapper<std::runtime_error>(e);
+
+ std::vector<exception_wrapper> container;
+ container.push_back(ew);
+
+ try {
+ container[0].throwException();
+ } catch (std::runtime_error& e) {
+ std::string expected = "payload";
+ std::string actual = e.what();
+ EXPECT_EQ(expected, actual);
+ }
+}