Hook result
We now tell Outcome that for every instance of our localised result<T>
, that
on failure construction only, we want custom code to be run which increments the current
slot in TLS storage and writes the current stack backtrace into it.
For Outcome before v2.2, we must do this by inserting a specially named free function into a namespace searched by ADL:
namespace error_code_extended
{
// Specialise the result construction hook for our localised result
// We hook any non-copy, non-move, non-inplace construction, capturing a stack backtrace
// if the result is errored.
template <class T, class U> inline void hook_result_construction(result<T> *res, U && /*unused*/) noexcept
{
if(res->has_error())
{
// Grab the next extended info slot in the TLS
extended_error_info &eei = mythreadlocaldata().next();
// Write the index just grabbed into the spare uint16_t
OUTCOME_V2_NAMESPACE::hooks::set_spare_storage(res, mythreadlocaldata().current - 1);
// Capture a backtrace into my claimed extended info slot in the TLS
eei.items = ::backtrace(eei.backtrace.data(), eei.backtrace.size());
}
}
}
For Outcome v2.2 and later, we must do this by using a custom no value policy which contains
a function named on_result_construction()
. The function implementation is identical between
both mechanisms, just the name and placement of the function declaration differs.
The only non-obvious part above is the call to void set_spare_storage(basic_result|basic_outcome *, uint16_t) noexcept
.
Both result
and outcome
keep their internal state metadata in a uint32_t
,
half of which is not used by Outcome. As it can be very useful to keep a small
unique number attached to any particular result
or outcome
instance, we
permit user code to set those sixteen bits to anything they feel like.
The corresponding function to retrieve those sixteen bits is uint16_t spare_storage(const basic_result|basic_outcome *) noexcept
.
The state of the sixteen bits of spare storage are ignored during comparison operations.
The sixteen bits of spare storage propagate during the following operations:
- Copy and move construction between
result
’s. - Copy and move construction between
outcome
’s. - Copy and move construction from a
result
to anoutcome
. - Converting copy and move constructions for all the above.
- Assignment for all of the above.
They are NOT propagated in these operations:
- Any conversion or translation which goes through a
failure_type
orsuccess_type
. - Any conversion or translation which goes through a
ValueOrError
concept match. - Any unpacking or repacking of value/error/exception e.g. a manual repack of an
outcome
into aresult
.