@@ -589,29 +589,44 @@ T* exception_ptr_get_object_hint(std::exception_ptr const& ptr) noexcept {
589589
590590// / get_exception_tag_t
591591// /
592- // / Passkey: To extend `folly::get_exception<Ex>()`, a type must have the member
593- // / `get_exception<Ex>(get_exception_tag_t)`.
592+ // / A type that may contain an exception may take this passkey in the following
593+ // / member functions:
594+ // / - `get_exception<Ex>(get_exception_tag_t) const` when implementing the
595+ // / `folly::get_exception<Ex>()` protocol.
596+ // / - `get_mutable_exception<Ex>(get_exception_tag_t)` when implementing the
597+ // / `folly::get_mutable_exception<Ex>()` protocol.
594598struct get_exception_tag_t {};
595599
596600// / get_exception_fn
597601// / get_exception
602+ // / get_mutable_exception_fn
603+ // / get_mutable_exception
598604// /
599- // / `get_exception<Ex>(v)` is meant to become a uniform way for accessing
600- // / exception-containers in `folly`. It returns:
605+ // / `get_exception<Ex>(v)` is meant to become the default way for accessing
606+ // / exception-containers in `folly`.
607+ // /
608+ // / For the less-common scenario where you need mutable access to an error, use
609+ // / `get_mutable_exception<Ex>(v)`. This is a separate verb because:
610+ // / - Mutable exception access is rare. It may run into thread-safety bugs
611+ // / if a `std::current_exception()` pointer is accessed outside of the
612+ // / thread that threw it -- the standard permits reference semantics here!
613+ // / - Making mutable access explicit enables no-alloctions, no-atomics
614+ // / optimizations for the `const`-access path.
615+ // /
616+ // / Both verbs return:
601617// / - `nullptr` if `v` is of a variant type, but is not in an "error" state,
602618// / - A pointer to the `Ex` held by `v`, if it holds an error whose type
603619// / `From` permits `std::is_convertible<From*, Ex*>`,
604620// / - `nullptr` for errors incompatible with `Ex*`.
605621// /
606622// / In addition to the `std::exception_ptr` support above, a type can support
607- // / this verb by providing a `get_exception<Ex>( get_exception_tag_t)` member.
608- // / For an example, see `ExceptionWrapper.h`. Requirements:
623+ // / this verb by providing member functions taking ` get_exception_tag_t`. For
624+ // / an example, see `ExceptionWrapper.h`. Requirements:
609625// / - `noexcept`
610- // / - `const`-correct
611- // / - returns `Ex*` or `const Ex*` depending on the overload.
626+ // / - returns `Ex*` or `const Ex*` depending on the verb.
612627// /
613628// / This is most efficient when `Ex` matches the exact stored type, or when the
614- // / type alias `Ex::folly_get_exception_hint_types` has a good hint.
629+ // / type alias `Ex::folly_get_exception_hint_types` provides a correct hint.
615630// /
616631// / NB: `result<T>` supports `get_exception<Ex>(res)`, but `Try<T>` currently
617632// / omits `get_exception(get_exception_tag_t)`, because that might encourage
@@ -624,41 +639,66 @@ struct get_exception_tag_t {};
624639// / }
625640template <typename Ex>
626641class get_exception_fn {
627- private:
628- template <typename CEx, typename SrcRef>
629- CEx* impl (SrcRef src) const noexcept {
630- using Src = remove_cvref_t <SrcRef>;
642+ public:
643+ template <typename Src>
644+ const Ex* operator ()(const Src& src) const noexcept {
631645 if constexpr (std::is_same_v<Src, std::exception_ptr>) {
632- return exception_ptr_get_object_hint<CEx >(src);
646+ return exception_ptr_get_object_hint<const Ex >(src);
633647 } else {
634648 constexpr get_exception_tag_t passkey;
635649 static_assert ( // Return type & `noexcept`ness must match
636650 std::is_same_v<
637- CEx *,
651+ const Ex *,
638652 decltype (src.template get_exception <Ex>(passkey))> &&
639653 noexcept (noexcept (src.template get_exception <Ex>(passkey))));
640654 return src.template get_exception <Ex>(passkey);
641655 }
642656 }
643-
644- public:
657+ // For a mutable ptr, use `folly::get_mutable_exception<Ex>(v)` instead.
645658 template <typename Src>
646- const Ex* operator ()(const Src& src ) const noexcept {
647- return impl< const Ex, const Src&>(src );
659+ const Ex* operator ()(Src& s ) const noexcept {
660+ return operator ()( std::as_const (s) );
648661 }
662+
663+ // It is unsafe to use `get_exception()` to get a pointer into an rvalue.
664+ // If you know what you're doing, add a `static_cast`.
665+ template <typename Src>
666+ void operator ()(Src&&) const noexcept = delete;
667+ template <typename Src>
668+ void operator ()(const Src&&) const noexcept = delete;
669+ };
670+ template <typename Ex>
671+ class get_mutable_exception_fn {
672+ public:
649673 template <typename Src>
650674 Ex* operator ()(Src& src) const noexcept {
651- return impl<Ex, Src&>(src);
675+ if constexpr (std::is_same_v<Src, std::exception_ptr>) {
676+ return exception_ptr_get_object_hint<Ex>(src);
677+ } else {
678+ constexpr get_exception_tag_t passkey;
679+ static_assert ( // Return type & `noexcept`ness must match
680+ std::is_same_v<
681+ Ex*,
682+ decltype (src.template get_mutable_exception <Ex>(passkey))> &&
683+ noexcept (noexcept (src.template get_mutable_exception <Ex>(passkey))));
684+ return src.template get_mutable_exception <Ex>(passkey);
685+ }
652686 }
653- // It is unsafe to use `get_exception()` to get a pointer into an rvalue.
654- // If you know what you're doing, add a `static_cast`.
687+ // You want `folly::get_exception<Ex>(v)` instead.
688+ template <typename Src>
689+ void operator ()(const Src&) const noexcept = delete;
690+
691+ // It is unsafe to use `get_mutable_exception()` to get a pointer into an
692+ // rvalue. If you know what you're doing, add a `static_cast`.
655693 template <typename Src>
656694 void operator ()(Src&&) const noexcept = delete;
657- template <typename Src> // NB: Actually, redundant with `Src&&` overload.
695+ template <typename Src>
658696 void operator ()(const Src&&) const noexcept = delete;
659697};
660698template <typename Ex = std::exception>
661699inline constexpr get_exception_fn<Ex> get_exception{};
700+ template <typename Ex = std::exception>
701+ inline constexpr get_mutable_exception_fn<Ex> get_mutable_exception{};
662702
663703namespace detail {
664704
0 commit comments