Outcome.Experimental has had C representation support since the beginning, however it had
+been mainly intended that C++ would originate Results, they would pass through C, and back
+into C++. It hadn’t really been expected that C would want to do much with Results other than
+inspect them for happy or sad path.
+
+
+
It turns out there is more demand than expected for a more functional Result from within C,
+so this release adds the power to create Results in success and two types of failure, semantic
+comparison of Results, and printing of Result messages. You can also wrap a C enum into a
+quick status code from enum, allowing easy custom C error coding from 100% within C.
This was fixed in Standalone Outcome in the last release, but the fix came too late for Boost.Outcome
+which ended up shipping with inline GDB pretty printers with the wrong escaping which caused
+failure to load.
Something I’ve been meaning to do for far too long now is make the GDB pretty printers
auto-loading so you don’t have to set up .gdbinit. This is now done. I also improved
@@ -2860,7 +2934,7 @@
Enhancements:
Experimental Outcome’s status_code has also gained its own auto-loading GDB pretty printer
with display of strerror() if the code domain is POSIX or generic.
-
Bug fixes:
+
Bug fixes:
The status enumeration used to track state internally did not list all possible enum
@@ -2871,7 +2945,7 @@
@@ -2806,10 +2851,13 @@
+
-
+ Worked example: Custom domain (the short way)
+
@@ -2875,6 +2923,10 @@
The main advantages
and the dual target source code, being written to tighter discipline,
is faster and more deterministic in the default target than it was before
the (non-trivial) port to <outcome/experimental>.
+
+
If you want ‘official’ C support, experimental Outcome is able to
+provide that in a way not possible for default Outcome which cannot make
+sufficiently strong C compatibility assumptions about std::error_code.
If you are building a codebase on top of Outcome expecting long term
@@ -2916,7 +2968,7 @@
The main advantages
- Last update on 05/02/2019
+ Last update on 16/07/2024
diff --git a/experimental/c-api/from-c/declare/index.html b/experimental/c-api/from-c/declare/index.html
index 266646f5a5..bb34ac899a 100644
--- a/experimental/c-api/from-c/declare/index.html
+++ b/experimental/c-api/from-c/declare/index.html
@@ -5,7 +5,7 @@
-
+
Declare a Result :: Outcome documentation
diff --git a/experimental/c-api/from-c/index.html b/experimental/c-api/from-c/index.html
index 41308d4d6b..9f99c3b04e 100644
--- a/experimental/c-api/from-c/index.html
+++ b/experimental/c-api/from-c/index.html
@@ -5,7 +5,7 @@
-
+
C Results :: Outcome documentation
diff --git a/experimental/c-api/from-c/system_code/index.html b/experimental/c-api/from-c/system_code/index.html
index a25d7d9c01..45c17849ac 100644
--- a/experimental/c-api/from-c/system_code/index.html
+++ b/experimental/c-api/from-c/system_code/index.html
@@ -5,7 +5,7 @@
-
+
C system error results :: Outcome documentation
diff --git a/experimental/c-api/from-c/try/index.html b/experimental/c-api/from-c/try/index.html
index fbbef055c5..80bee1dd58 100644
--- a/experimental/c-api/from-c/try/index.html
+++ b/experimental/c-api/from-c/try/index.html
@@ -5,7 +5,7 @@
-
+
TRY a C Result :: Outcome documentation
@@ -1086,252 +1086,6 @@
Policies
@@ -2807,18 +2852,15 @@
+
-
-
-
-
-
-
-
+ Worked example: Custom domain (the short way)
+
-
+
@@ -2855,41 +2897,72 @@
-
Worked example: Custom domain
+
Worked example: Custom domain (the short way)
+
The section after this one will take the long way through defining a custom domain
+which sometimes is necessary if you have particularly bespoke requirements.
+If however you just want to wrap a custom enum type of yours into its
+own custom code domain, the boilerplate can be automated away
+by filling in a few simple fields like this:
+
// My custom enum type
+enumclasscustom_failure
+{
+ not_found,
+ bad_argument
+};
-
Here follows a worked example of use of Experimental Outcome. It presents
-the same sample program I sent to the San Diego 2018 WG21 standards meeting
-after I was asked by the committee to demonstrate how P1095 implements P0709
-in a working code example they could study and discuss.
-
-
We will walk through this worked example, step by step, explaining how each
-part works in detail. This will help you implement your own code based on
-Experimental Outcome.
+// Tell `status_code` to stamp out a custom code domain for this enum type
+SYSTEM_ERROR2_NAMESPACE_BEGIN
+template<>structquick_status_code_from_enum<custom_failure>:quick_status_code_from_enum_defaults<custom_failure>
+{
+ // Text name of the enum
+staticconstexprconstautodomain_name="My custom failure";
+ // Unique UUID for the enum. PLEASE use https://www.random.org/cgi-bin/randbyte?nbytes=16&format=h
+staticconstexprconstautodomain_uuid="{be201f65-3962-dd0e-1266-a72e63776a42}";
+ // Map of each enum value to its text string, and list of semantically equivalent errc's
+staticconststd::initializer_list<mapping>&value_mappings()
+ {
+ staticconststd::initializer_list<mapping>v={
+ // Format is: { enum value, "string representation", { list of errc mappings ... } }
+{custom_failure::not_found,"item not found",{errc::no_such_file_or_directory}},//
+{custom_failure::bad_argument,"invoked wrong",{errc::invalid_argument}},//
+};
+ returnv;
+ }
+ // Completely optional definition of mixin for the status code synthesised from `Enum`. It can be omitted.
+template<classBase>structmixin:Base
+ {
+ usingBase::Base;
+ constexprintcustom_method()const{return42;}
+ };
+};
+SYSTEM_ERROR2_NAMESPACE_END
+
Here we supply the bare minimum requirements for a status code domain:
-
We are going to define a simple custom code domain which defines that
-the status code’s payload will consist of a POSIX error code, and the
-__FILE__ and __LINE__ where the failure occurred. This custom status
-code will have an implicit conversion to type erased error defined, which dynamically
-allocates memory for the original status code, and outputs an error
-which manages that dynamic allocation, indirecting all queries etc
-to the erased custom status code type such that the error instance
-quacks as if just like the original. This demonstrates that error could
-just as equally convey a std::exception_ptr, for example, or indeed
-manage the lifetime of any pointer.
For each enum value, its printable text and a sequence of errc:: enumerations
+which you think it is semantically equivalent to i.e. its mapping onto generic_code
+which is how status code defines the common mapping between status codes. If you later compare the
+status code to one of those values (or to another status code which also provides
+a mapping), if the generic codes are equivalent then the comparison will return true.
+This means code like if(sc == errc::no_such_file_or_directory) ... would match
+all custom error codes which mean ‘something was not found’.
+
OPTIONAL: if you would like the custom status code type generated by this
+to have additional member functions or additional payload, you can define a mixin
+here to inject either data or functions or both. If you omit this, nothing gets
+injected.
+
@@ -2897,8 +2970,8 @@
Goal of this section
-
-
+
+
@@ -2913,7 +2986,7 @@
Goal of this section
- Last update on 26/01/2019
+ Last update on 16/07/2024
diff --git a/experimental/worked-example/index.xml b/experimental/worked-example/index.xml
index 5a7e9e743a..e51bbceca6 100644
--- a/experimental/worked-example/index.xml
+++ b/experimental/worked-example/index.xml
@@ -1,85 +1,23 @@
- Worked example: Custom domain on Outcome documentation
+ Worked example: Custom domain (the short way) on Outcome documentation
https://ned14.github.io/outcome/experimental/worked-example/
- Recent content in Worked example: Custom domain on Outcome documentation
+ Recent content in Worked example: Custom domain (the short way) on Outcome documentationHugo -- gohugo.io
- Sat, 26 Jan 2019 23:38:56 +0000
+ Tue, 16 Jul 2024 21:33:35 +0100
- Define a custom code domain
- https://ned14.github.io/outcome/experimental/worked-example/preamble/
+ Implicit construction
+ https://ned14.github.io/outcome/experimental/worked-example/implicit-construction/
Mon, 01 Jan 0001 00:00:00 +0000
- https://ned14.github.io/outcome/experimental/worked-example/preamble/
- Firstly let’s alias the experimental Outcome namespace into something less tedious to type, declare our custom status code type, and get started on defining the custom status code domain implementation.
-namespace outcome_e = OUTCOME_V2_NAMESPACE::experimental; // To define a `file_io_error` which participates in the P1028 world // of `std::error`, we must first declare, then define, a custom code // domain which extends `posix_code` (the std error coding for POSIX // failures). The following is fairly standard boilerplate for defining // a custom code domain.
-
-
-
- The payload
- https://ned14.github.io/outcome/experimental/worked-example/value_type/
- Mon, 01 Jan 0001 00:00:00 +0000
-
- https://ned14.github.io/outcome/experimental/worked-example/value_type/
- We define the code domain’s value_type – the payload to be transported by status codes using this code domain – to be a POSIX errno value, an integer line number and a const char pointer.
-public: // This is the value type for `file_io_error`. We add line number and source file path. struct value_type { typename outcome_e::posix_code::value_type errcode; // from POSIX, as we inherit from _posix_code_domain // Our additional payload int lineno; // from __LINE__ const char *file; // from __FILE__ // Could also place a backtrace of void *[16] here .
-
-
-
- The constructor
- https://ned14.github.io/outcome/experimental/worked-example/constructor/
- Mon, 01 Jan 0001 00:00:00 +0000
-
- https://ned14.github.io/outcome/experimental/worked-example/constructor/
- Code domains are 100% constexpr to construct and destruct, as are status codes. This enables the compiler to 100% instantiate both only in its mind, and to emit zero code and thus zero overhead.
-Unfortunately it also means that it must be possible for each domain to be instantiated an infinite number of times, and being 100% in constexpr, any instances never have a unique address in memory either. Thus we cannot compare domains for equivalence using their address in memory, as std::error_category does.
-
-
-
- String refs
- https://ned14.github.io/outcome/experimental/worked-example/string_ref/
- Mon, 01 Jan 0001 00:00:00 +0000
-
- https://ned14.github.io/outcome/experimental/worked-example/string_ref/
- <system_error2> does not use std::string to return possibly statically or dynamically allocated strings, and thus avoids dragging in a lot of the standard library which impacts build times.
-Instead status code domains have a string_ref, which has a polymorphic implementation which may or may not manage a dynamic memory allocation using an atomic reference counter. Due to this polymorphism, you don’t need to worry which implementation is actually in use under the bonnet when you pass around string_ref instances.
-
-
-
- Redefining `message()`
- https://ned14.github.io/outcome/experimental/worked-example/message/
- Mon, 01 Jan 0001 00:00:00 +0000
-
- https://ned14.github.io/outcome/experimental/worked-example/message/
- You may remember that our custom _file_io_error_domain inherits from outcome_e::posix_code::domain_type, and thus does not have to implement the many pure virtual functions required by outcome_e::status_code_domain.
-What we do need to do is reimplement _do_message() to append the file and line information to the POSIX error description string returned by outcome_e::posix_code::domain_type. This causes the status code’s .message() observer to return a string with the extra payload information represented in text.
-// Return a string describing a specific code.
-
-
-
- Constexpr domain source
- https://ned14.github.io/outcome/experimental/worked-example/source/
- Mon, 01 Jan 0001 00:00:00 +0000
-
- https://ned14.github.io/outcome/experimental/worked-example/source/
- Back in The constructor, we declared but did not implement a .get() function which returns a constexpr static instance of the domain. We implement this now:
-// 100% constexpr instantiation constexpr _file_io_error_domain file_io_error_domain; inline constexpr const _file_io_error_domain &_file_io_error_domain::get() { return file_io_error_domain; } View this code on Github As this is 100% constexpr, it can be (and is under optimisation) implemented entirely in the mind of the compiler with no run time representation.
-
-
-
- Implicit conversion
- https://ned14.github.io/outcome/experimental/worked-example/implicit_conversion/
- Mon, 01 Jan 0001 00:00:00 +0000
-
- https://ned14.github.io/outcome/experimental/worked-example/implicit_conversion/
- Back in The payload, we mentioned that there was no default implicit conversion of file_io_error (status_code<_file_io_error_domain>) to error, as error is too small to hold _file_io_error_domain::value_type.
-We can tell the framework about available implicit conversions by defining an ADL discovered free function make_status_code() which takes our custom status code as input, and returns an error:
-// Now tell `error` how it can implicitly construct from `file_io_error`. // This is done by us defining a free function called `make_status_code()` // which is discovered using ADL.
+ https://ned14.github.io/outcome/experimental/worked-example/implicit-construction/
+ The preceding code had the compiler stamp out a custom status code domain for a user supplied enum. You now get the following types:
+// This is the status code generated for your custom enum type. It will implicitly construct from // values of enum custom_failure. using custom_failure_code = SYSTEM_ERROR2_NAMESPACE::quick_status_code_from_enum_code<custom_failure>; namespace outcome_e = OUTCOME_V2_NAMESPACE::experimental; // You don't usually need to use the status code type explicitly, because this "just works": outcome_e::status_result<int> positive_only(int x) { if(x < 0) { // Outcome's result sees that status_code will implicitly construct from this enum, // and it returns an errored result return custom_failure::bad_argument; } return x; } // Semantic comparisons work bool test(int x) { if(auto r = positive_only(x); !
diff --git a/faq/index.html b/faq/index.html
index e643e352f7..a5fc677bd4 100644
--- a/faq/index.html
+++ b/faq/index.html
@@ -5,7 +5,7 @@
-
+
Frequently asked questions :: Outcome documentation
@@ -597,108 +597,153 @@
status_result and status_outcome
+
there is an external requirement (such as a company-wide policy) that failure handling paths are explicitly indicated in the code.
where interoperation with C code, without having to resort to C++ exception wrapper shims, is important.
+
+
where your mostly C code base needs exception-like error handling, and the subset of Outcome’s functionality available in C is sufficient for your needs.
Outcome addresses failure handling through returning a special type from functions, which is able to store either a successfully computed value (or void), or the information about failure. Outcome also comes with a set of idioms for dealing with such types.
The main workhorse in the Outcome library is result<T>: it represents either a successfully computed value of type T, or a std::error_code/boost::system::error_code2 representing the reason for failure. You use it in the function’s return type:
@@ -2924,6 +2971,43 @@
Sample usage
OUTCOME_TRY is a control statement. If the returned result<T> object contains an error information, the enclosing function is immediately returned with result<U> containing the same failure information; otherwise an automatic object of type T
is available in scope.
+
Sample usage (C)
+
+
Equivalent to the C++ API: CXX_DECLARE_RESULT_SYSTEM(ident, T) declares the C type, thereafter CXX_RESULT_SYSTEM(ident) refers to it. You use it in the function’s return type:
The C Result is guaranteed to be layout identical to its C++ equivalent. Convenience conversion functions are available, but you can reinterpret cast too.
- Last update on 18/03/2022
+ Last update on 16/07/2024
diff --git a/index.json b/index.json
index efddbc2699..f788fcf78a 100644
--- a/index.json
+++ b/index.json
@@ -32,7 +32,7 @@
"title": "The main advantages",
"tags": [],
"description": "",
- "content": "The main advantages of choosing \u0026lt;outcome/experimental\u0026gt; over default Outcome:\n Codegen is tighter and less verbose1, sometimes remarkably so.\n Build time impact is markedly lower, barely above the inclusion of naked \u0026lt;basic_result.hpp\u0026gt;, as the STL allocator machinery and std::string et al is not dragged into inclusion by including \u0026lt;system_error\u0026gt;. Note that \u0026lt;outcome/experimental/status_outcome.hpp\u0026gt; bring in \u0026lt;exception\u0026gt;, however \u0026lt;outcome/experimental/status_result.hpp\u0026gt; brings in no extra system headers.\n More discipline is imposed on your use of Outcome, leading to less ambiguous code which is easier to optimise by the compiler, lower cost to maintain, and lower cognitive load to audit code based on experimental Outcome for correctness.\n Code written to \u0026lt;outcome/experimental\u0026gt; can be fairly easily dual targeted, with just a few switching type aliases, to default Outcome. This author has several Outcome-based libraries with identical source code which can target either configuration of Outcome. The experimental Outcome build regularly beats the default Outcome build in benchmarks by 2-3%, and the dual target source code, being written to tighter discipline, is faster and more deterministic in the default target than it was before the (non-trivial) port to \u0026lt;outcome/experimental\u0026gt;.\n If you are building a codebase on top of Outcome expecting long term maintenance, the author\u0026rsquo;s personal recommendation is that you design, write, test and optimise it for \u0026lt;outcome/experimental\u0026gt;. What you ship to your customers ought to be targeted at default Outcome however, so employ type aliases and macros as appropriate to switch the build configuration for production releases. This is what the Outcome author does himself, to date with great success, despite the fundamental architectural differences between \u0026lt;system_error\u0026gt; and proposed \u0026lt;system_error2\u0026gt;.\n Boost.System\u0026rsquo;s error_code has incorporated some of the design improvements of experimental status_code, and produces codegen somewhere in between experimental status_code and std::error_code. [return] "
+ "content": "The main advantages of choosing \u0026lt;outcome/experimental\u0026gt; over default Outcome:\n Codegen is tighter and less verbose1, sometimes remarkably so.\n Build time impact is markedly lower, barely above the inclusion of naked \u0026lt;basic_result.hpp\u0026gt;, as the STL allocator machinery and std::string et al is not dragged into inclusion by including \u0026lt;system_error\u0026gt;. Note that \u0026lt;outcome/experimental/status_outcome.hpp\u0026gt; bring in \u0026lt;exception\u0026gt;, however \u0026lt;outcome/experimental/status_result.hpp\u0026gt; brings in no extra system headers.\n More discipline is imposed on your use of Outcome, leading to less ambiguous code which is easier to optimise by the compiler, lower cost to maintain, and lower cognitive load to audit code based on experimental Outcome for correctness.\n Code written to \u0026lt;outcome/experimental\u0026gt; can be fairly easily dual targeted, with just a few switching type aliases, to default Outcome. This author has several Outcome-based libraries with identical source code which can target either configuration of Outcome. The experimental Outcome build regularly beats the default Outcome build in benchmarks by 2-3%, and the dual target source code, being written to tighter discipline, is faster and more deterministic in the default target than it was before the (non-trivial) port to \u0026lt;outcome/experimental\u0026gt;.\n If you want \u0026lsquo;official\u0026rsquo; C support, experimental Outcome is able to provide that in a way not possible for default Outcome which cannot make sufficiently strong C compatibility assumptions about std::error_code.\n If you are building a codebase on top of Outcome expecting long term maintenance, the author\u0026rsquo;s personal recommendation is that you design, write, test and optimise it for \u0026lt;outcome/experimental\u0026gt;. What you ship to your customers ought to be targeted at default Outcome however, so employ type aliases and macros as appropriate to switch the build configuration for production releases. This is what the Outcome author does himself, to date with great success, despite the fundamental architectural differences between \u0026lt;system_error\u0026gt; and proposed \u0026lt;system_error2\u0026gt;.\n Boost.System\u0026rsquo;s error_code has incorporated some of the design improvements of experimental status_code, and produces codegen somewhere in between experimental status_code and std::error_code. [return] "
},
{
"uri": "https://ned14.github.io/outcome/tutorial/advanced/interop/value-or-error/",
@@ -76,6 +76,13 @@
"description": "",
"content": "Much of the design of Boost.System (which went on to become \u0026lt;system_error\u0026gt;) has been retained in proposed \u0026lt;system_error2\u0026gt;, so an approximate map between \u0026lt;system_error2\u0026gt; and \u0026lt;system_error\u0026gt; and Boost.System can be given:\n C++ 17 \u0026lt;system_error\u0026gt;Boost.SystemProposed \u0026lt;system_error2\u0026gt; std::errc boost::system::errc experimental::errc (almost identical) std::error_category boost::system::error_category experimental::status_code_domain std::generic_category boost::system::generic_category experimental::generic_code_domain std::system_category boost::system::system_category One of: experimental::posix_code_domain (POSIX systems) experimental::win32_code_domain (Microsoft Windows) experimental::nt_code_domain (Microsoft Windows) Note that there are more precanned code categories though they require additional header inclusions: com_code, getaddrinfo_code. std::error_condition boost::system::error_condition No equivalent (deliberately removed as hindsight proved it to be a design mistake leading to much confusing and hard to audit for correctness code) std::error_code boost::system::error_code One of: experimental::status_code\u0026lt;DomainType\u0026gt; const experimental::status_code\u0026lt;void\u0026gt; \u0026amp; experimental::status_code\u0026lt;erased\u0026lt;intptr_t\u0026gt;\u0026gt; (aliased to experimental::system_code) experimental::errored_status_code\u0026lt;DomainType\u0026gt; const experimental::errored_status_code\u0026lt;void\u0026gt; \u0026amp; experimental::errored_status_code\u0026lt;erased\u0026lt;intptr_t\u0026gt;\u0026gt; (aliased to experimental::error) The difference between status codes and errored status codes is that the latter are guaranteed to refer to a failure, whereas the former may refer to a success (including warnings and informationals). std::system_error boost::system::system_error One of: const experimental::status_error\u0026lt;void\u0026gt; \u0026amp; experimental::status_error\u0026lt;DomainType\u0026gt; As is obvious from the above, in \u0026lt;system_error2\u0026gt; one must be much more specific and accurate with respect to intent and specification and desired semantics than with \u0026lt;system_error\u0026gt;. Much ambiguity and incorrectness which flies silently in \u0026lt;system_error\u0026gt; will refuse to compile in \u0026lt;system_error2\u0026gt;.\n"
},
+{
+ "uri": "https://ned14.github.io/outcome/experimental/c-api/from-c/system_code/",
+ "title": "C system error results",
+ "tags": [],
+ "description": "Status code's `std::error` in C",
+ "content": "In v2.2.11, C Result support went from second tier to first tier status, and now you can create, query and manipulate a subset of Result types entirely from within C by including \u0026lt;outcome/experimental/result.h\u0026gt;.\nThe subset supported are those result\u0026lt;T, E\u0026gt; which are a status_result\u0026lt;T\u0026gt; i.e. the E is hardcoded to experimental::error which is the type erased runtime polymorphic holder for any errored status_code whose payload is not bigger than an intptr_t. This is the most useful subset of Outcome Experimental\u0026rsquo;s possible Result types, allowing arbitrary custom error coding schemes from any unknown source to work seamlessly with all others, including errors from the system or third party libraries.\nThe operations available to C are:\n CXX_DECLARE_RESULT_SYSTEM(ident, T) Declares to C a status_result type uniquely identified by ident. T is available at the member variable .value, and struct cxx_status_code_system is available at the member variable .error. If in C++, implements C extern functions for making successful and failure results of this type. If you call this from within C++, make SURE it is not within a extern \"C\" block! CXX_RESULT_SYSTEM(ident) A reference to a previously declared status_result type with unique ident. CXX_MAKE_RESULT_SYSTEM_SUCCESS(ident, expr) (needs C++ counterpart linked into final binary) This invokes the aforementioned extern function which creates a status_result with a successful value of type T. CXX_MAKE_RESULT_SYSTEM_FAILURE_POSIX(ident, expr) (needs C++ counterpart linked into final binary) This invokes the aforementioned extern function which creates a status_result with a failure of type posix_code representing a POSIX errno. CXX_MAKE_RESULT_SYSTEM_FAILURE_SYSTEM(ident, expr) (needs C++ counterpart linked into final binary) This invokes the aforementioned extern function which creates a status_result with a failure of type posix_code representing a POSIX errno if on POSIX; if on Windows then a failure of type win32_code representing a Win32 error code from a Windows API. CXX_RESULT_HAS_VALUE(r) Evaluates to 1 (true) if the input result has a value. CXX_RESULT_HAS_ERROR(r) Evaluates to 1 (true) if the input result has an error. CXX_RESULT_ERROR_IS_ERRNO(r) Evaluates to 1 (true) if the input result's error value is a code in the POSIX errno domain. CXX_RESULT_SYSTEM_TRY(expr) If the status_result returned by expr is errored, exit the current function returning the result. This obviously requires that the return type of the current function matches that of expr. CXX_RESULT_SYSTEM_TRY(cleanup, expr) Same as the above, but execute cleanup just before exiting the function if returning failure. CXX_RESULT_SYSTEM_TRY(var, cleanup, expr) Same as the above, but set var equal to the result's .value on success. CXX_RESULT_SYSTEM_TRY(var, ident, cleanup, expr) Same as the above, but use ident as the return type instead. This allows the return type of the calling function to differ from that of expr. CXX_DECLARE_RESULT_SYSTEM_FROM_ENUM(ident, enum_name, uuid, {enum mapping-sequence, ...}) This declares to C an extern function which creates a status_result from a C enum. If in C++, it implements a quick_status_code_from_enum for the C enum and the associated extern function, and you will need to supply uuid and the appropriate enum value mapping sequence as per the quick_status_code_from_enum documentation. CXX_MAKE_RESULT_SYSTEM_FROM_ENUM(ident, enum_name, expr) (needs C++ counterpart linked into final binary) This invokes the aforementioned extern function which creates a status_result from a C enum. The operations available to C++ are:\n CXX_TO_RESULT_SYSTEM_CODE(ident, status_code\u0026lt;T\u0026gt;) Returns a previously declared C Result from its matching C++ status_code. NOTE that the destructor of the C++ status code is NOT called. If this is important to your status code, it is 100% on you to ensure that your C Result reenters a C++ Result at the end of its lifetime. to_result(any C Result) This is an overloaded C++ free function which returns the C++ status_code\u0026lt;T\u0026gt; matching its input C Result. Using the above you can write C code using Outcome.Experimental\u0026rsquo;s Result type quite effectively. Let\u0026rsquo;s look at an example of use next.\n"
+},
{
"uri": "https://ned14.github.io/outcome/tutorial/essential/coroutines/try/",
"title": "Coroutine TRY operation",
@@ -84,7 +91,7 @@
"content": "As one cannot call statement return from within a Coroutine, the very first part of Outcome\u0026rsquo;s support for Coroutines is OUTCOME_CO_TRYV(expr)/OUTCOME_CO_TRY(expr) , which is literally the same as OUTCOME_TRY() except that co_return is called to return early instead of return.\neager\u0026lt;result\u0026lt;std::string\u0026gt;\u0026gt; to_string(int x) { if(x \u0026gt;= 0) { OUTCOME_CO_TRY(convert(x)); } co_return \u0026#34;out of range\u0026#34;; } "
},
{
- "uri": "https://ned14.github.io/outcome/experimental/worked-example/preamble/",
+ "uri": "https://ned14.github.io/outcome/experimental/worked-example-long/preamble/",
"title": "Define a custom code domain",
"tags": [],
"description": "",
@@ -104,6 +111,13 @@
"description": "Exceptions with their good and bad sides.",
"content": " Exceptions are the default mechanism in C++ for reporting, propagating and processing the information about function failures. Their main advantage is the ability to describe the \u0026ldquo;success dependency\u0026rdquo; between functions: if you want to say that calling function g() depends on the successful execution of function f(), you just put g() below f() and that\u0026rsquo;s it:\nint a() { f(); g(); // don\u0026#39;t call g() and further if f() fails return h(); // don\u0026#39;t call h() if g() fails } In the C++ Standard terms this means that f() is sequenced before g(). This makes failure handling extremely easy: in a lot of cases you do not have to do anything.\nAlso, while next operations are being canceled, the exception object containing the information about the initial failure is kept on the side. When at some point the cancellation cascade is stopped by an exception handler, the exception object can be inspected. It can contain arbitrarily big amount of data about the failure reason, including the entire call stack.\nDownsides There are two kinds of overheads caused by the exception handling mechanism. The first is connected with storing the exceptions on the side. Stack unwinding works independently in each thread of execution; each thread can be potentially handling a number of exceptions (even though only one exception can be active in one thread). This requires being prepared for storing an arbitrary number of exceptions of arbitrary types per thread. Additional things like jump tables also need to be stored in the program binaries.\nSecond overhead is experienced when throwing an exception and trying to find the handler. Since nearly any function can throw an exception of any time, this is a dynamic memory allocation. The type of an exception is erased and a run-time type identification (RTTI) is required to asses the type of the active exception object. The worst case time required for matching exceptions against handlers cannot be easily predicted and therefore exceptions are not suitable for real-time or low-latency systems.\nAnother problem connected with exceptions is that while they are good for program flows with linear \u0026ldquo;success dependency\u0026rdquo;, they become inconvenient in situations where this success dependency does not occur. One such notable example is releasing acquired resources which needs to be performed even if previous operations have failed. Another example is when some function c() depends on the success of at least one of two functions a() and b() (which try, for instance, to store user data by two different means), another example is when implementing a strong exception safety guarantee we may need to apply some fallback actions when previous operations have failed. When failures are reported by exceptions, the semantics of canceling all subsequent operations is a hindrance rather than help; these situations require special and non-trivial idioms to be employed.\nFor these reasons in some projects using exceptions is forbidden. Compilers offer switches to disable exceptions altogether (they refuse to compile a throw, and turn already compiled throws into calls to std::abort()).\n"
},
+{
+ "uri": "https://ned14.github.io/outcome/experimental/worked-example/implicit-construction/",
+ "title": "Implicit construction",
+ "tags": [],
+ "description": "",
+ "content": "The preceding code had the compiler stamp out a custom status code domain for a user supplied enum. You now get the following types:\n// This is the status code generated for your custom enum type. It will implicitly construct from // values of enum custom_failure. using custom_failure_code = SYSTEM_ERROR2_NAMESPACE::quick_status_code_from_enum_code\u0026lt;custom_failure\u0026gt;; namespace outcome_e = OUTCOME_V2_NAMESPACE::experimental; // You don\u0026#39;t usually need to use the status code type explicitly, because this \u0026#34;just works\u0026#34;: outcome_e::status_result\u0026lt;int\u0026gt; positive_only(int x) { if(x \u0026lt; 0) { // Outcome\u0026#39;s result sees that status_code will implicitly construct from this enum, // and it returns an errored result return custom_failure::bad_argument; } return x; } // Semantic comparisons work bool test(int x) { if(auto r = positive_only(x); !r) { if(r.error() == outcome_e::errc::invalid_argument) { std::cerr \u0026lt;\u0026lt; \u0026#34;Positive numbers only!\u0026#34; \u0026lt;\u0026lt; std::endl; return false; } } return true; } View this code on Github As you can see, this is less work than plugging your custom enum into std::error_code. It also has C compatibility, and generates better codegen.\n"
+},
{
"uri": "https://ned14.github.io/outcome/tutorial/advanced/hooks/keeping_state/",
"title": "Keeping state",
@@ -111,13 +125,6 @@
"description": "",
"content": "The first thing we are going to need is somewhere to store the stack backtrace. We could take the easier route and simply store it into an allocated block and keep the pointer as a custom payload in a result\u0026lt;T, std::pair\u0026lt;error_code, std::unique_ptr\u0026lt;stack_backtrace\u0026gt;\u0026gt;\u0026gt; (see previous section on Custom payloads). But let us assume that we care so deeply about bounded execution times that ever calling malloc is unacceptable.\nWe therefore are going to need some completely static and trivially typed storage perhaps kept per-thread to avoid the need to keep mutexes.\n/* Outcome\u0026#39;s hook mechanism works vis ADL, so we will need a custom namespace to ensure the hooks apply only to the types declared in this namespace only */ namespace error_code_extended { // The extra error information we will keep struct extended_error_info { std::array\u0026lt;void *, 16\u0026gt; backtrace; // The backtrace size_t items; // Items in backtrace array which are valid }; struct mythreadlocaldata_t { // Keep 16 slots of extended error info as a ringbuffer extended_error_info slots[16]; // The current oldest slot uint16_t current{0}; // Return the oldest slot extended_error_info \u0026amp;next() { return slots[(current++) % 16]; } // Retrieve a previously stored slot, detecting if it is stale extended_error_info *get(uint16_t idx) { // If the idx is stale, return not found if(idx - current \u0026gt;= 16) { return nullptr; } return slots + (idx % 16); } }; // Meyers\u0026#39; singleton returning a thread local data structure for this thread inline mythreadlocaldata_t \u0026amp;mythreadlocaldata() { static thread_local mythreadlocaldata_t v; return v; } } View this code on Github The extended error info is kept in a sixteen item long, thread local, ring buffer. We continuously increment the current index pointer which is a 16 bit value which will wrap after 65,535. This lets us detect an attempt to access recycled storage, and thus return item-not-found instead of the wrong extended error info.\n"
},
-{
- "uri": "https://ned14.github.io/outcome/experimental/c-api/limitations/",
- "title": "Limitations",
- "tags": [],
- "description": "",
- "content": "C++ has excellent two-way compatibility with the C ABI, but there are some limitations you must observe to write C++ code which C code can call without marshalling at the ABI boundary:\n A C++ function may not throw exceptions if it is safe to call from C, and so should always be marked noexcept.\n A C++ function should be annotated with extern \u0026quot;C\u0026quot; to prevent its symbol being mangled, and thus give it the C rather than C++ ABI.\n You cannot use overloading in your extern \u0026quot;C\u0026quot; functions.\n You may only use types in your C++ function declaration for which these traits are both true:\n std::is_standard_layout_v\u0026lt;T\u0026gt; std::is_trivially_copyable_v\u0026lt;T\u0026gt; (Note that std::is_trivially_copyable_v\u0026lt;T\u0026gt; requires trivial destruction, but NOT trivial construction. This means that C++ can do non-trivial construction of otherwise trivial types)\n The above is what the standard officially requires for well defined C and C++ interop. However, all of the three major compilers MSVC, GCC and clang are considerably more relaxed. In those three major compilers, \u0026ldquo;almost-standard-layout\u0026rdquo; C++ types work fine in C.\n\u0026ldquo;Almost-standard-layout\u0026rdquo; C++ types have these requirements:\n No virtual functions or virtual base classes i.e. std::is_polymorphic_v\u0026lt;T\u0026gt; must be false. This is because the vptrs offset the proper front of the data layout in an unknowable way to C. Non-static data members of reference type appear to C as pointers. You must never supply from C to C++ a non-null pointer which is seen as a reference in C++. C++ inheritance is seen in C data layout as if the most derived class has nested variables of the inherited types at the top, in order of inheritance. Types with non-trivial destructors work fine so long as at least move construction and assignment is the same as copying bits like memcpy(). You just need to make sure instances of the type return to C++, and don\u0026rsquo;t get orphaned in C. This was referred to in previous pages in this section as \u0026ldquo;move relocating\u0026rdquo; types. Experimental Outcome\u0026rsquo;s support for being used from C does not meet the current strict requirements, and thus relies on the (very common) implementation defined behaviour just described (it is hoped that future C++ standards can relax the requirements to those just described).\nSpecifically, proposed status_code is an almost-standard-layout type, and thus while it can\u0026rsquo;t be returned from extern \u0026quot;C\u0026quot; functions as the compiler will complain, it is perfectly safe to return from C++ functions to C code on the three major compilers, as it is an \u0026ldquo;almost-standard-layout\u0026rdquo; C++ type if T is an \u0026ldquo;almost-standard-layout\u0026rdquo; C++ type.\n"
-},
{
"uri": "https://ned14.github.io/outcome/reference/macros/",
"title": "Macros",
@@ -223,6 +230,13 @@
"description": "",
"content": "These are the predefined policies built into Outcome:\n\u0026nbsp;\nall_narrow If there is an observation of a value/error/exception which is not present, the program is put into a hard undefined behaviour situation. The compiler literally compiles no code for an invalid observation \u0026ndash; the CPU \u0026ldquo;runs off\u0026rdquo; into the unknown.\nAs bad as this may sound, it generates the most optimal code, and such hard UB is very tool-friendly for detection e.g. undefined behaviour sanitiser, valgrind memcheck, etc.\nIf you are considering choosing this policy, definitely read static void _ub(Impl \u0026amp;\u0026amp;) first.\nNote that unchecked\u0026lt;T, E = varies\u0026gt; aliases a basic_result with the all_narrow no-value policy.\n\u0026nbsp;\nterminate Observation of a missing value/error/exception causes a call to std::terminate().\nNote that configuring EC = void or EP = void causes default_policy to choose terminate as the no-value policy.\n\u0026nbsp;\nerror_code_throw_as_system_error\u0026lt;T, EC, EP\u0026gt; This policy assumes that EC has the interface of std::error_code, and EP has the interface of std::exception_ptr. Upon missing value observation:\n if an exception is stored through pointer of type EP it is rethrown; otherwise, if an error of type EC is stored, it is converted to error_code and then thrown as system_error. Upon missing error observation throws:\n bad_result_access(\u0026quot;no error\u0026quot;) from instances of basic_result\u0026lt;\u0026gt;. bad_outcome_access(\u0026quot;no error\u0026quot;) from instances of basic_outcome\u0026lt;\u0026gt;. Upon missing exception observation throws bad_outcome_access(\u0026quot;no exception\u0026quot;).\nOverloads are provided for boost::system::error_code and boost::exception_ptr.\nNote that if is_error_code_available\u0026lt;T\u0026gt; is true for EC, and (if basic_outcome) is_exception_ptr_available\u0026lt;T\u0026gt; is true for EP, default_policy chooses error_code_throw_as_system_error\u0026lt;T, EC, EP\u0026gt; as the no-value policy.\n\u0026nbsp;\nexception_ptr_rethrow\u0026lt;T, EC, EP\u0026gt; This policy assumes that either EC or EP (unless void) has the interface of std::exception_ptr. Upon missing value observation:\n in instances of basic_result\u0026lt;\u0026gt;, rethrows exception pointed to by EC; in instances of basic_outcome\u0026lt;\u0026gt;, if exception EP is present rethrows it, otherwise rethrows EC. Upon missing error observation:\n in instances of basic_result\u0026lt;\u0026gt;, throws bad_result_access(\u0026quot;no error\u0026quot;) ; in instances of basic_outcome\u0026lt;\u0026gt;, throws bad_outcome_access(\u0026quot;no error\u0026quot;). Upon missing exception observation throws bad_outcome_access(\u0026quot;no exception\u0026quot;).\nOverloads are provided for boost::exception_ptr.\nNote that if is_exception_ptr_available\u0026lt;T\u0026gt; is true for EC, or (if basic_outcome) is_exception_ptr_available\u0026lt;T\u0026gt; is true for EP, default_policy chooses exception_ptr_rethrow\u0026lt;T, EC, EP\u0026gt; as the no-value policy.\n\u0026nbsp;\nthrow_bad_result_access\u0026lt;EC\u0026gt; Upon missing value observation throws bad_result_access_with\u0026lt;EC\u0026gt;(ec), where ec is the value of the stored error. If error is not stored, the behaviour is undefined.\nUpon missing error observation throws bad_result_access(\u0026quot;no error\u0026quot;).\nThis policy can be used with basic_outcome\u0026lt;\u0026gt; instances, where it always throws bad_outcome_access for all no-value/error/exception observations.\nNote that checked\u0026lt;T, E = varies\u0026gt; aliases a basic_result with the throw_bad_result_access\u0026lt;EC\u0026gt; no-value policy.\n"
},
+{
+ "uri": "https://ned14.github.io/outcome/experimental/c-api/from-cxx/",
+ "title": "Calling C++ from C",
+ "tags": [],
+ "description": "",
+ "content": "C++ has excellent two-way compatibility with the C ABI, but there are some limitations you must observe to write C++ code which C code can call without marshalling at the ABI boundary:\n A C++ function may not throw exceptions if it is safe to call from C, and so should always be marked noexcept.\n A C++ function should be annotated with extern \u0026quot;C\u0026quot; to prevent its symbol being mangled, and thus give it the C rather than C++ ABI.\n You cannot use overloading in your extern \u0026quot;C\u0026quot; functions.\n You may only use types in your C++ function declaration for which these traits are both true:\n std::is_standard_layout_v\u0026lt;T\u0026gt; std::is_trivially_copyable_v\u0026lt;T\u0026gt; (Note that std::is_trivially_copyable_v\u0026lt;T\u0026gt; requires trivial destruction, but NOT trivial construction. This means that C++ can do non-trivial construction of otherwise trivial types)\n The above is what the standard officially requires for well defined C and C++ interop. However, all of the three major compilers MSVC, GCC and clang are considerably more relaxed. In those three major compilers, \u0026ldquo;almost-standard-layout\u0026rdquo; C++ types work fine in C.\n\u0026ldquo;Almost-standard-layout\u0026rdquo; C++ types have these requirements:\n No virtual functions or virtual base classes i.e. std::is_polymorphic_v\u0026lt;T\u0026gt; must be false. This is because the vptrs offset the proper front of the data layout in an unknowable way to C. Non-static data members of reference type appear to C as pointers. You must never supply from C to C++ a non-null pointer which is seen as a reference in C++. C++ inheritance is seen in C data layout as if the most derived class has nested variables of the inherited types at the top, in order of inheritance. Types with non-trivial destructors work fine so long as at least move construction and assignment is the same as copying bits like memcpy(). You just need to make sure instances of the type return to C++, and don\u0026rsquo;t get orphaned in C. This was referred to in previous pages in this section as \u0026ldquo;move relocating\u0026rdquo; types. Experimental Outcome\u0026rsquo;s support for being used from C does not meet the current strict requirements, and thus relies on the (very common) implementation defined behaviour just described (it is hoped that future C++ standards can relax the requirements to those just described).\nSpecifically, proposed status_code is an almost-standard-layout type, and thus while it can\u0026rsquo;t be returned from extern \u0026quot;C\u0026quot; functions as the compiler will complain, it is perfectly safe to return from C++ functions to C code on the three major compilers, as it is an \u0026ldquo;almost-standard-layout\u0026rdquo; C++ type if T is an \u0026ldquo;almost-standard-layout\u0026rdquo; C++ type.\n"
+},
{
"uri": "https://ned14.github.io/outcome/reference/concepts/",
"title": "Concepts",
@@ -238,7 +252,14 @@
"content": "The second part of the support is provided by header \u0026lt;outcome/coroutine_support.hpp\u0026gt; (or \u0026lt;outcome/experimental/coroutine_support.hpp\u0026gt; if you want Coroutine support for Experimental Outcome). This adds into namespace OUTCOME_V2_NAMESPACE::awaitables (or OUTCOME_V2_NAMESPACE::experimental::awaitables) these awaitable types suitable for returning from a Coroutinised function:\n eager\u0026lt;T, Executor = void\u0026gt; An eagerly evaluated Coroutine: invoking co_await upon a function returning one of these immediately begins the execution of the function now. If the function never suspends, the overhead is similar to calling an ordinary function.\n lazy\u0026lt;T, Executor = void\u0026gt; A lazily evaluated Coroutine (often named task\u0026lt;T\u0026gt; in most C++ Coroutine literature): invoking co_await upon a function returning one of these causes the function to be immediately suspended as soon as execution begins. Only resuming the execution of the coroutine proceeds execution.\n generator\u0026lt;T, Executor = void\u0026gt; A lazily evaluated generator of values: the coroutine is resumed to generate the next value, upon which it is suspended until the next iteration.\n atomic_eager\u0026lt;T, Executor = void\u0026gt;\neager\u0026lt;T\u0026gt; does not employ thread synchronisation during resumption of dependent coroutines which is fine if you do not traverse kernel threads during a suspend-resume cycle. If you do however potentially traverse kernel threads during suspend-resume, you ought to use atomic_eager\u0026lt;T\u0026gt; instead \u0026ndash; this uses atomics to synchronise the setting and checking of state to ensure correctness.\n atomic_lazy\u0026lt;T, Executor = void\u0026gt;\nSame for lazy\u0026lt;T\u0026gt; as atomic_eager\u0026lt;T\u0026gt; is for eager\u0026lt;T\u0026gt;.\n "
},
{
- "uri": "https://ned14.github.io/outcome/experimental/c-api/example/",
+ "uri": "https://ned14.github.io/outcome/experimental/c-api/from-c/declare/",
+ "title": "Declare a Result",
+ "tags": [],
+ "description": "Declaring a C Result",
+ "content": "// Declare to C a Result with a happy value of intptr_t CXX_DECLARE_RESULT_SYSTEM(result_int, intptr_t) // Save oneself typing out CXX_RESULT_SYSTEM(result_int) all the time typedef CXX_RESULT_SYSTEM(result_int) result; // Our custom C enum enum c_enum { c_enum_not_found, c_enum_bad_argument }; // Make a custom status code domain for this C enum CXX_DECLARE_RESULT_SYSTEM_FROM_ENUM(result_int, // The C Result type declared above c_enum, // The C enum we wish to wrap \u0026#34;{74ceb994-7622-3a21-07f0-b016aa705585}\u0026#34;, // Unique UUID for this domain // Mappings of C enum values to textual description and semantic equivalances to generic codes {c_enum::c_enum_not_found, \u0026#34;item not found\u0026#34;, {errc::no_such_file_or_directory}}, {c_enum::c_enum_bad_argument, \u0026#34;invoked wrong\u0026#34;, {errc::invalid_argument}}) // Make helper macros #define SUCCESS(v) CXX_MAKE_RESULT_SYSTEM_SUCCESS(result_int, (v)) #define FAILURE(v) CXX_MAKE_RESULT_SYSTEM_FROM_ENUM(result_int, c_enum, (v)) View this code on Github The key to making C programming easy is to alias the long complex things into short easy thing. Obviously SUCCESS(expr) and FAILURE(expr) is too generic, but for the purposes of this documentation it makes thing easier.\n"
+},
+{
+ "uri": "https://ned14.github.io/outcome/experimental/c-api/from-cxx/example/",
"title": "Example C++ function",
"tags": [],
"description": "",
@@ -266,7 +287,7 @@
"content": "The File I/O library we shall be using is very similar to the one we saw earlier in this tutorial:\n// You may remember this from the tutorial section on Custom Payloads namespace filelib { // Error code + paths related to a failure. Also causes ADL discovery // to check this namespace. struct failure_info { std::error_code ec; path path1{}, path2{}; }; // Tell Outcome that failure_info is to be treated as a std::error_code inline const std::error_code \u0026amp;make_error_code(const failure_info \u0026amp;fi) { return fi.ec; } // Tell Outcome that no-value observation should throw a custom exception inline void outcome_throw_as_system_error_with_payload(failure_info fi) { // If the error code is not filesystem related e.g. ENOMEM, throw that // as a standard STL exception. OUTCOME_V2_NAMESPACE::try_throw_std_exception_from_error(fi.ec); // Throw the exact same filesystem_error exception which the throwing // copy_file() edition does. throw filesystem_error(fi.ec.message(), std::move(fi.path1), std::move(fi.path2), fi.ec); } // Localise a result implementation specific to this namespace. template \u0026lt;classT\u0026gt; using result = OUTCOME_V2_NAMESPACE::result\u0026lt;T, failure_info\u0026gt;; // Writes a chunk of data to some file. Returns bytes written, or // failure_info. Never throws exceptions. result\u0026lt;size_t\u0026gt; write_file(string_view chunk) noexcept; } // namespace filelib View this code on Github This uses the advanced Outcome feature of programming the lazy synthesis of custom C++ exception throws from a payload carrying E type called failure_info. Like the HTTP library, it too template aliases a localised result implementation into its namespace with ADL bridging so Outcome customisation points can be discovered.\n"
},
{
- "uri": "https://ned14.github.io/outcome/experimental/worked-example/value_type/",
+ "uri": "https://ned14.github.io/outcome/experimental/worked-example-long/value_type/",
"title": "The payload",
"tags": [],
"description": "",
@@ -336,11 +357,18 @@
"content": "Something not mentioned at all until now (and properly described in the next section, Default actions) is that Outcome can be programmed take various actions when the user tries to observe .value() when there is no value, and so on for the other possible state observations.\nSeeing as we are replacing the throwing overload of copy_file() in the Filesystem TS with a result returning edition instead, it would make sense if an attempt to observe the value of an unsuccessful fs_result threw the exact same filesystem_error as the Filesystem TS does.\nTelling Outcome how to throw a filesystem_error with payload of the failing paths is easy:\nnamespace filesystem2 { // If we would like Outcome to do something other than the default action (see next // section), we can declare this ADL discovered free function to customise what // to do instead. // // Note that rvalue semantics are propagated internally by Outcome, so if the user // called .value() on a rvalued result, failure_info will be moved rather than // copied from the result. That means we can overload once with value semantics, // and not need to overload for lvalue and rvalue situations unless we really feel // we need to for some reason. inline void outcome_throw_as_system_error_with_payload(failure_info fi) { // If the error code is not filesystem related e.g. ENOMEM, throw that as a // standard STL exception. outcome::try_throw_std_exception_from_error(fi.ec); // Throw the exact same filesystem_error exception which the throwing copy_file() // edition does. throw filesystem_error(fi.ec.message(), std::move(fi.path1), // std::move(fi.path2), fi.ec); } } View this code on Github Reference documentation for the above functions:\n List of builtin outcome_throw_as_system_error_with_payload() overloads void try_throw_std_exception_from_error(std::error_code ec, const std::string \u0026amp;msg = std::string{}) Usage of our new \u0026ldquo;upgraded\u0026rdquo; Filesystem copy_file() might now be as follows:\n// Non-throwing use case auto o = filesystem2::copy_file(\u0026#34;dontexist\u0026#34;, \u0026#34;alsodontexist\u0026#34;); if(!o) { std::cerr \u0026lt;\u0026lt; \u0026#34;Copy file failed with error \u0026#34; \u0026lt;\u0026lt; o.error().ec.message() // \u0026lt;\u0026lt; \u0026#34; (path1 = \u0026#34; \u0026lt;\u0026lt; o.error().path1 \u0026lt;\u0026lt; \u0026#34;, path2 = \u0026#34; \u0026lt;\u0026lt; o.error().path2 \u0026lt;\u0026lt; \u0026#34;)\u0026#34; // \u0026lt;\u0026lt; std::endl; } // Throwing use case try { // Try to observe the successful value, thus triggering default actions which invokes // our outcome_throw_as_system_error_with_payload() above which then throws filesystem_error // exactly like the Filesystem TS does for its throwing overload. filesystem2::copy_file(\u0026#34;dontexist\u0026#34;, \u0026#34;alsodontexist\u0026#34;).value(); } catch(const filesystem2::filesystem_error \u0026amp;e) { std::cerr \u0026lt;\u0026lt; \u0026#34;Copy file failed with exception \u0026#34; \u0026lt;\u0026lt; e.what() // \u0026lt;\u0026lt; \u0026#34; (path1 = \u0026#34; \u0026lt;\u0026lt; e.path1() \u0026lt;\u0026lt; \u0026#34;, path2 = \u0026#34; \u0026lt;\u0026lt; e.path2() \u0026lt;\u0026lt; \u0026#34;)\u0026#34; // \u0026lt;\u0026lt; std::endl; } catch(const std::exception \u0026amp;e) { std::cerr \u0026lt;\u0026lt; \u0026#34;Copy file failed with exception \u0026#34; \u0026lt;\u0026lt; e.what() // \u0026lt;\u0026lt; std::endl; } View this code on Github "
},
{
- "uri": "https://ned14.github.io/outcome/experimental/c-api/example2/",
+ "uri": "https://ned14.github.io/outcome/experimental/c-api/from-c/",
+ "title": "C Results",
+ "tags": [],
+ "description": "Outcome's C Result support",
+ "content": "The C macro API header \u0026lt;outcome/experimental/result.h\u0026gt; has some macros for working with any kind of Result:\n CXX_DECLARE_RESULT(ident, T, E) Declares to C a basic_result type uniquely identified by ident. T is available at the member variable .value, and E is available at the member variable .error. If you call this from within C++, make SURE it is not within a extern \"C\" block! CXX_RESULT(ident) A reference to a previously declared result type with unique ident. CXX_RESULT_HAS_VALUE(r) Evaluates to 1 (true) if the input result has a value. CXX_RESULT_HAS_ERROR(r) Evaluates to 1 (true) if the input result has an error. CXX_RESULT_ERROR_IS_ERRNO(r) Evaluates to 1 (true) if the input result's error value is a code in the POSIX errno domain. The above let you work, somewhat awkwardly, with any C-compatible basic_result\u0026lt;T, E\u0026gt;. basic_result\u0026lt;T, E\u0026gt; is trivially copyable and standard layout if its T and E are both so, and it has the C layout:\nstruct cxx_result_##ident { union { T value; E error; }; unsigned flags; }; Note that this layout is different to that of CXX_DECLARE_STATUS_CODE as the C++ result has a different layout if E is a status code.\n"
+},
+{
+ "uri": "https://ned14.github.io/outcome/experimental/c-api/from-cxx/example2/",
"title": "Calling it from C",
"tags": [],
"description": "",
- "content": "Firstly we need to declare to C our result returning C++ function:\n// Declare our C++ function\u0026#39;s returning result type. Only needs to be done once. // This declares an `status_result\u0026lt;size_t, system_code\u0026gt;` which is an alias to // `basic_result\u0026lt;size_t, status_code\u0026lt;erased\u0026lt;intptr_t\u0026gt;\u0026gt;\u0026gt;`. // // The first parameter is some unique identifier for this type which will be used // whenever we reference this type in the future. CXX_DECLARE_RESULT_SYSTEM(to_string_rettype, size_t); // Tell C about our extern C++ function `to_string()` extern CXX_RESULT_SYSTEM(to_string_rettype) _Z9to_stringPcmi(char *buffer, size_t bufferlen, int v); View this code on Github Now let\u0026rsquo;s call the C++ function from C:\nvoid print(int v) { char buffer[4]; CXX_RESULT_SYSTEM(to_string_rettype) res; res = _Z9to_stringPcmi(buffer, sizeof(buffer), v); if(CXX_RESULT_HAS_VALUE(res)) { printf(\u0026#34;to_string(%d) fills buffer with \u0026#39;%s\u0026#39; of %zu characters\\n\u0026#34;, v, buffer, res.value); return; } // Is the error returned in the POSIX domain and thus an errno? if(CXX_RESULT_ERROR_IS_ERRNO(res)) { fprintf(stderr, \u0026#34;to_string(%d) failed with error code %d (%s)\\n\u0026#34;, v, (int) res.error.value, strerror((int) res.error.value)); return; } fprintf(stderr, \u0026#34;to_string(%d) failed with unknown error code %lld\\n\u0026#34;, v, (long long) res.error.value); } int main(void) { print(9); print(99); print(999); print(9999); return 0; } View this code on Github Running this C program yields:\nto_string(9) fills buffer with '9' of 1 characters to_string(99) fills buffer with '99' of 2 characters to_string(999) fills buffer with '999' of 3 characters to_string(9999) failed with error code 105 (No buffer space available) "
+ "content": "Firstly we need to declare to C our result returning C++ function:\n// Declare our C++ function\u0026#39;s returning result type. Only needs to be done once. // This declares an `status_result\u0026lt;size_t, system_code\u0026gt;` which is an alias to // `basic_result\u0026lt;size_t, status_code\u0026lt;erased\u0026lt;intptr_t\u0026gt;\u0026gt;\u0026gt;`. // // The first parameter is some unique identifier for this type which will be used // whenever we reference this type in the future. CXX_DECLARE_RESULT_SYSTEM(to_string_rettype, size_t) // Tell C about our extern C++ function `to_string()` extern CXX_RESULT_SYSTEM(to_string_rettype) _Z9to_stringPcmi(char *buffer, size_t bufferlen, int v); View this code on Github Now let\u0026rsquo;s call the C++ function from C:\nvoid print(int v) { char buffer[4]; CXX_RESULT_SYSTEM(to_string_rettype) res; res = _Z9to_stringPcmi(buffer, sizeof(buffer), v); if(CXX_RESULT_HAS_VALUE(res)) { printf(\u0026#34;to_string(%d) fills buffer with \u0026#39;%s\u0026#39; of %zu characters\\n\u0026#34;, v, buffer, res.value); return; } // Is the error returned in the POSIX domain and thus an errno? if(CXX_RESULT_ERROR_IS_ERRNO(res)) { fprintf(stderr, \u0026#34;to_string(%d) failed with error code %d (%s)\\n\u0026#34;, v, (int) res.error.value, strerror((int) res.error.value)); return; } fprintf(stderr, \u0026#34;to_string(%d) failed with unknown error code %lld\\n\u0026#34;, v, (long long) res.error.value); } int main(void) { print(9); print(99); print(999); print(9999); return 0; } View this code on Github Running this C program yields:\nto_string(9) fills buffer with '9' of 1 characters to_string(99) fills buffer with '99' of 2 characters to_string(999) fills buffer with '999' of 3 characters to_string(9999) failed with error code 105 (No buffer space available) "
},
{
"uri": "https://ned14.github.io/outcome/tutorial/essential/coroutines/",
@@ -420,7 +448,7 @@
"content": " In the implementation of function print_half we have seen the usage of the macro OUTCOME_TRYV(expr)/OUTCOME_TRY(expr) :\nOUTCOME_TRY (auto i, BigInt::fromString(text)); The OUTCOME_TRY macro uses C macro overloading to select between two implementations based on the number of input parameters. If there is exactly one input parameter i.e. without the i, the control statement is roughly equivalent to:\nauto __result = BigInt::fromString(text); if (!__result) return __result.as_failure(); Where __result is a compile time generated unique name. This single argument form is equivalent to OUTCOME_TRYV(expr), incidentally.\nIf there are between two and eight parameters, this control statement is roughly equivalent to:\nauto __result = BigInt::fromString(text); if (!__result) return __result.as_failure(); auto i = __result.value(); So here i as the first C macro parameter is set to the value of any successful result.\nC macro overloads are provided for up to eight arguments. To prevent the confounding of the C preprocessor by commas in template specifications causing more than eight arguments appearing to the C preprocessor, you should consider wrapping the second argument in brackets.\nIf you are within a C++ Coroutine, you ought to use OUTCOME_CO_TRYV(expr)/OUTCOME_CO_TRY(expr) instead.\n Compiler-specific extension: OUTCOME_TRYX This macro makes use of a proprietary extension in GCC and clang, and is not portable. The macro is not made available on unsupported compilers, so you can test for its presence using #ifdef OUTCOME_TRYX.\n GCC and Clang provide an extension to C++ known as statement expressions. These make it possible to use a more convenient macro: OUTCOME_TRYX, which is an expression. With the above macro, the above declaration of variable i can be rewritten to:\nint i = OUTCOME_TRYX (BigInt::fromString(text)); This has an advantage that you can use it any place where you can put an expression, e.g., in \u0026ldquo;simple initialization\u0026rdquo;:\nif (int i = OUTCOME_TRYX(BigInt::fromString(text))) use_a_non_zero_int(i); or in as a subexpression of a bigger full expression:\nint ans = OUTCOME_TRYX(BigInt::fromString(\u0026#34;1\u0026#34;)) + OUTCOME_TRYX(BigInt::fromString(\u0026#34;2\u0026#34;)); There is also an OUTCOME_CO_TRYX(expr) if you are inside a C++ Coroutine.\n"
},
{
- "uri": "https://ned14.github.io/outcome/experimental/worked-example/constructor/",
+ "uri": "https://ned14.github.io/outcome/experimental/worked-example-long/constructor/",
"title": "The constructor",
"tags": [],
"description": "",
@@ -433,6 +461,13 @@
"description": "",
"content": " is_basic_outcome\u0026lt;T\u0026gt; An integral constant type true for basic_outcome\u0026lt;T, EC, EP, NoValuePolicy\u0026gt; types.\n is_basic_result\u0026lt;T\u0026gt; An integral constant type true for basic_result\u0026lt;T, E, NoValuePolicy\u0026gt; types.\n is_error_code_available\u0026lt;T\u0026gt; True if an error code can be constructed from a T.\n is_error_type\u0026lt;E\u0026gt; A customisable integral constant type true for E types which are to receive error throwing no-value policies.\n is_error_type_enum\u0026lt;E, Enum\u0026gt; A customisable integral constant type true for E types constructible from Enum types which are to receive error throwing no-value policies.\n is_exception_ptr_available\u0026lt;T\u0026gt; True if an exception ptr can be constructed from a T.\n is_failure_type\u0026lt;T\u0026gt; An integral constant boolean variable true for failure_type\u0026lt;EC, E = void\u0026gt; types.\n is_move_bitcopying\u0026lt;T\u0026gt; (\u0026gt;= Outcome v2.2.0) A customisable integral constant type true for T types which are move bitcopying safe.\n is_success_type\u0026lt;T\u0026gt; An integral constant boolean variable true for success_type\u0026lt;T\u0026gt; types.\n type_can_be_used_in_basic_result\u0026lt;R\u0026gt; A constexpr boolean true for types permissible in basic_result\u0026lt;T, E, NoValuePolicy\u0026gt;.\n "
},
+{
+ "uri": "https://ned14.github.io/outcome/experimental/c-api/from-c/use/",
+ "title": "Using a Result",
+ "tags": [],
+ "description": "Using a C Result",
+ "content": "This models the earlier C++ example of use, and its C equivalent isn\u0026rsquo;t much more verbose thanks to our helper typedefs and macros:\nresult positive_only(int x) { if(x \u0026lt; 0) { return FAILURE(c_enum_bad_argument); } return SUCCESS(x); } bool test(int x) { result r = positive_only(x); if(CXX_RESULT_HAS_ERROR(r)) { if(outcome_status_code_equal_generic(\u0026amp;r.error, EINVAL)) { fprintf(stderr, \u0026#34;Positive numbers only!\\n\u0026#34;); return false; } } return true; } View this code on Github For this to link, the CXX_DECLARE_RESULT_SYSTEM_FROM_ENUM macro needs to be compiled at least once within C++ within the final binary to emit the extern functions needed by C.\n"
+},
{
"uri": "https://ned14.github.io/outcome/alternatives/expected/",
"title": "std expected",
@@ -504,12 +539,19 @@
"content": " auto basic_outcome_failure_exception_from_error(const EC \u0026amp;) ADL discovered free function synthesising an exception type from an error type, used by the .failure() observers.\n decltype(auto) error_code(T \u0026amp;\u0026amp;) Extracts a boost::system::error_code or std::error_code from the input via ADL discovery of a suitable make_error_code(T) function.\n decltype(auto) exception_ptr(T \u0026amp;\u0026amp;) Extracts a boost::exception_ptr or std::exception_ptr from the input via ADL discovery of a suitable make_exception_ptr(T) function.\n void outcome_throw_as_system_error_with_payload(BoostErrorCodeEnum \u0026amp;\u0026amp;) Specialisation of outcome_throw_as_system_error_with_payload() for input types where boost::system::is_error_code_enum\u0026lt;BoostErrorCodeEnum\u0026gt; or boost::system::is_error_condition_enum\u0026lt;BoostErrorCodeEnum\u0026gt; is true.\n void outcome_throw_as_system_error_with_payload(ErrorCodeEnum \u0026amp;\u0026amp;) Specialisation of outcome_throw_as_system_error_with_payload() for input types where std::is_error_code_enum\u0026lt;ErrorCodeEnum\u0026gt; or std::is_error_condition_enum\u0026lt;ErrorCodeEnum\u0026gt; is true.\n void outcome_throw_as_system_error_with_payload(const boost::system::error_code \u0026amp;) Specialisation of outcome_throw_as_system_error_with_payload() for boost::system::error_code.\n void outcome_throw_as_system_error_with_payload(const std::error_code \u0026amp;) Specialisation of outcome_throw_as_system_error_with_payload() for std::error_code.\n "
},
{
- "uri": "https://ned14.github.io/outcome/experimental/worked-example/string_ref/",
+ "uri": "https://ned14.github.io/outcome/experimental/worked-example-long/string_ref/",
"title": "String refs",
"tags": [],
"description": "",
"content": "\u0026lt;system_error2\u0026gt; does not use std::string to return possibly statically or dynamically allocated strings, and thus avoids dragging in a lot of the standard library which impacts build times.\nInstead status code domains have a string_ref, which has a polymorphic implementation which may or may not manage a dynamic memory allocation using an atomic reference counter. Due to this polymorphism, you don\u0026rsquo;t need to worry which implementation is actually in use under the bonnet when you pass around string_ref instances.\nstring_ref provides the same member functions as a span\u0026lt;const char\u0026gt;, and so participates ordinarily in STL algorithms and containers. In particular, if you need to string search or slice it, you can construct a string_view on top easily.\n// Return the name of our custom code domain virtual _base::string_ref name() const noexcept override final // NOLINT { static string_ref v(\u0026#34;file i/o error domain\u0026#34;); return v; // NOLINT } View this code on Github Now you understand what string_ref does, returning the name of the status code domain is self describing. Note we use the non-managing constructor of string_ref, as the string \u0026quot;file i/o error domain\u0026quot; is statically stored. We cache the returned value locally in static storage.\n"
},
+{
+ "uri": "https://ned14.github.io/outcome/experimental/c-api/from-c/try/",
+ "title": "TRY a C Result",
+ "tags": [],
+ "description": "Operation TRY on a C Result",
+ "content": "Thanks to much of the magic of OUTCOME_TRY(var, expr) being implemented using C preprocessor metaprogramming, we can offer a very similar experience for the C try operation and without needing anything compiled in C++ as support functions:\nresult test2(int x) { CXX_RESULT_SYSTEM_TRY(int v, // what to set to value if successful fprintf(stderr, \u0026#34;Positive numbers only!\\n\u0026#34;), // what cleanup to run if unsuccessful positive_only(x)); return SUCCESS(v + 1); } View this code on Github The principle difference is that you can specify a cleanup routine to perform if failure is encountered. This is especially useful in C, which has no stack unwinding.\nAlso due to lack of type sugaring and user defined implicit conversions, if your callers result type isn\u0026rsquo;t your callee\u0026rsquo;s, you may need to specify what your caller\u0026rsquo;s result type is so the error state can be correctly propagated.\n"
+},
{
"uri": "https://ned14.github.io/outcome/tutorial/essential/result/try_greedy/",
"title": "TRY is greedy",
@@ -559,13 +601,6 @@
"description": "How to metaprogram construction of objects which use result<T, EC> to return failure instead of throwing a C++ exception.",
"content": "An oft-asked question during conference talks on Expected/Outcome is how to exclusively use result to implement constructor failure. This is asked because whilst almost every member function in a class can return a result, constructors do not return values and thus cannot return a result. The implication is that one cannot avoid throwing C++ exceptions to abort a construction.\nAs with most things in C++, one can achieve zero-exception-throw object construction using a lot of extra typing of boilerplate, and a little bit of simple C++ metaprogramming. This section shows you how to implement these for those who are absolutely adverse to ever throwing an exception, or cannot because C++ exceptions have been globally disabled.\nThe technique described here is not suitable for non-copyable and non-movable types. There is also an assumption that moving your type is cheap.\n"
},
-{
- "uri": "https://ned14.github.io/outcome/experimental/c-api/reference/",
- "title": "C Macro API Reference",
- "tags": [],
- "description": "",
- "content": " The C macro API header \u0026lt;outcome/experimental/result.h\u0026gt; consists of these macros:\n CXX_DECLARE_RESULT(ident, T, E) Declares to C a basic_result type uniquely identified by ident. T is available at the member variable .value, and E is available at the member variable .error. CXX_RESULT(ident) A reference to a previously declared result type with unique ident. CXX_RESULT_HAS_VALUE(r) Evaluates to 1 (true) if the input result has a value. CXX_RESULT_HAS_ERROR(r) Evaluates to 1 (true) if the input result has an error. CXX_RESULT_ERROR_IS_ERRNO(r) Evaluates to 1 (true) if the input result's error value is a code in the POSIX errno domain. The above let you work, somewhat awkwardly, with any C-compatible basic_result\u0026lt;T, E\u0026gt;. basic_result\u0026lt;T, E\u0026gt; is trivially copyable and standard layout if its T and E are both so, and it has the C layout:\nstruct cxx_result_##ident { union { T value; E error; }; unsigned flags; }; \u0026lt;system_error2\u0026gt; support Because erased status codes are not trivially copyable and therefore do not have union based storage, we have separate C macros for results whose E is an erased status code:\n CXX_DECLARE_STATUS_CODE(ident, value_type) Declares to C a status code type with domain value_type available at the member variable .value. The ident must be any identifier fragment unique in this translation unit. It is used to uniquely identify this status code type in other macros. CXX_STATUS_CODE(ident) A reference to a previously declared status code type with unique ident. CXX_DECLARE_RESULT_STATUS_CODE(ident, T, E) Declares to C a basic_result type uniquely identified by ident. T is available at the member variable .value, and E is available at the member variable .error. CXX_RESULT_STATUS_CODE(ident) A reference to a previously declared result type with unique ident. There is a high likelihood that C++ functions regularly called by C code will return their failures either in erased system_code or in posix_code (i.e. errno code domain). Via querying the returned value using CXX_RESULT_ERROR_IS_ERRNO(r), one can determine if the returned code is in the errno code domain, and thus can be fed to strerror() and so on. Therefore there are convenience macro APIs for those particular use cases.\n CXX_DECLARE_RESULT_ERRNO(ident, T) Declares to C a basic_result\u0026lt;T, posix_code\u0026gt; type uniquely identified by ident. CXX_RESULT_ERRNO(ident) A reference to a previously declared basic_result\u0026lt;T, posix_code\u0026gt; type with unique ident. CXX_DECLARE_RESULT_SYSTEM(ident, T) Declares to C a basic_result\u0026lt;T, system_code\u0026gt; type uniquely identified by ident. CXX_RESULT_SYSTEM(ident) A reference to a previously declared basic_result\u0026lt;T, system_code\u0026gt; type with unique ident. "
-},
{
"uri": "https://ned14.github.io/outcome/tutorial/advanced/hooks/hook_outcome/",
"title": "Hook outcome",
@@ -602,7 +637,7 @@
"content": "See here for this guide, but for boost::system::error_code.\nThis section illustrates how you can hook into the std::error_code system from the Standard Library in order to work with your own set of error codes. As is usually the case in C++, doing this is straightforward but requires typing boilerplate to tell the C++ STL about your custom error type. This is not part of Outcome library, but we still provide this short guide here, because how to do this is not well documented [1].\nSuppose you want to report all reasons for failure in converting a std::string to a non-negative int. The list is:\n EmptyString \u0026ndash; the input string is empty, IllegalChar \u0026ndash; input contains characters that are not digits, TooLong \u0026ndash; input represents a number, but this number would not fit into a variable of type int. #include \u0026lt;iostream\u0026gt;#include \u0026lt;string\u0026gt; // for string printing#include \u0026lt;system_error\u0026gt; // bring in std::error_code et al // This is the custom error code enum enum classConversionErrc { Success = 0, // 0 should not represent an error EmptyString = 1, IllegalChar = 2, TooLong = 3, }; namespace std { // Tell the C++ 11 STL metaprogramming that enum ConversionErrc // is registered with the standard error code system template \u0026lt;\u0026gt; struct is_error_code_enum\u0026lt;ConversionErrc\u0026gt; : true_type { }; } namespace detail { // Define a custom error code category derived from std::error_category classConversionErrc_category : public std::error_category { public: // Return a short descriptive name for the category virtual const char *name() const noexcept override final { return \u0026#34;ConversionError\u0026#34;; } // Return what each enum means in text virtual std::string message(int c) const override final { switch (static_cast\u0026lt;ConversionErrc\u0026gt;(c)) { case ConversionErrc::Success: return \u0026#34;conversion successful\u0026#34;; case ConversionErrc::EmptyString: return \u0026#34;converting empty string\u0026#34;; case ConversionErrc::IllegalChar: return \u0026#34;got non-digit char when converting to a number\u0026#34;; case ConversionErrc::TooLong: return \u0026#34;the number would not fit into memory\u0026#34;; default: return \u0026#34;unknown\u0026#34;; } } // OPTIONAL: Allow generic error conditions to be compared to me virtual std::error_condition default_error_condition(int c) const noexcept override final { switch (static_cast\u0026lt;ConversionErrc\u0026gt;(c)) { case ConversionErrc::EmptyString: return make_error_condition(std::errc::invalid_argument); case ConversionErrc::IllegalChar: return make_error_condition(std::errc::invalid_argument); case ConversionErrc::TooLong: return make_error_condition(std::errc::result_out_of_range); default: // I have no mapping for this code return std::error_condition(c, *this); } } }; } // Define the linkage for this function to be used by external code. // This would be the usual __declspec(dllexport) or __declspec(dllimport) // if we were in a Windows DLL etc. But for this example use a global // instance but with inline linkage so multiple definitions do not collide. #define THIS_MODULE_API_DECL extern inline // Declare a global function returning a static instance of the custom category THIS_MODULE_API_DECL const detail::ConversionErrc_category \u0026amp;ConversionErrc_category() { static detail::ConversionErrc_category c; return c; } // Overload the global make_error_code() free function with our // custom enum. It will be found via ADL by the compiler if needed. inline std::error_code make_error_code(ConversionErrc e) { return {static_cast\u0026lt;int\u0026gt;(e), ConversionErrc_category()}; } int main(void) { // Note that we can now supply ConversionErrc directly to error_code std::error_code ec = ConversionErrc::IllegalChar; std::cout \u0026lt;\u0026lt; \u0026#34;ConversionErrc::IllegalChar is printed by std::error_code as \u0026#34; \u0026lt;\u0026lt; ec \u0026lt;\u0026lt; \u0026#34; with explanatory message \u0026#34; \u0026lt;\u0026lt; ec.message() \u0026lt;\u0026lt; std::endl; // We can compare ConversionErrc containing error codes to generic conditions std::cout \u0026lt;\u0026lt; \u0026#34;ec is equivalent to std::errc::invalid_argument = \u0026#34; \u0026lt;\u0026lt; (ec == std::errc::invalid_argument) \u0026lt;\u0026lt; std::endl; std::cout \u0026lt;\u0026lt; \u0026#34;ec is equivalent to std::errc::result_out_of_range = \u0026#34; \u0026lt;\u0026lt; (ec == std::errc::result_out_of_range) \u0026lt;\u0026lt; std::endl; return 0; } View this code on Github This might look like a lot of extra boilerplate over simply using your custom error code enum directly, but look at the advantages:\n Any code which can speak std::error_code can now work with errors from your code, AND without being recompiled. std::system_error can now wrap your custom error codes seamlessly, allowing your custom error code to be converted into a C++ exception and back out again without losing information. std::error_code knows how to print itself, and will print your custom error code without extra work from you. As usually you\u0026rsquo;d need to define a print routine for any custom error code you\u0026rsquo;d write anyway, there is actually very little extra boilerplate here. If you implement the default_error_condition() override, you can allow code exclusively written to understand std::errc alone to examine your custom error code domain for equivalence to the standard error conditions, AND without being recompiled. This documentation recommends that when you define your custom enum for representing error_codes, you should always make sure that value 0 never represents an actual error: it should either represent a success or should not be provided at all. If you only intend to use your enum inside result\u0026lt;\u0026gt; or outcome\u0026lt;\u0026gt; you can just start your enumerations from 1. If you intend to also return std::error_code directly from functions, you should probably define value 0 as success, so that you are able to inform about function\u0026rsquo;s success by returning MyEnum::Success. This is because error_code\u0026rsquo;s contextual conversion to bool (which some people use to check if there was an error or not) only checks for the numeric value of the error code (without looking at error domain (category)).\n [1]: The only documentation I\u0026rsquo;m aware of is the quite old guide by Chris Kohlhoff, founder of ASIO and the Networking TS:\n http://blog.think-async.com/2010/04/system-error-support-in-c0x-part-1.html http://blog.think-async.com/2010/04/system-error-support-in-c0x-part-2.html http://blog.think-async.com/2010/04/system-error-support-in-c0x-part-3.html http://blog.think-async.com/2010/04/system-error-support-in-c0x-part-4.html http://blog.think-async.com/2010/04/system-error-support-in-c0x-part-5.html "
},
{
- "uri": "https://ned14.github.io/outcome/experimental/worked-example/message/",
+ "uri": "https://ned14.github.io/outcome/experimental/worked-example-long/message/",
"title": "Redefining `message()`",
"tags": [],
"description": "",
@@ -658,7 +693,7 @@
"content": "No doubt many will dislike the two-stage invocation pattern i.e.\nmake\u0026lt;file_handle\u0026gt;{\u0026#34;hello\u0026#34;}(); So let us examine the most obvious alternative: a templated free function make\u0026lt;T\u0026gt;.\nDue to the inability to partially specialise templated functions in C++, you need to use tagged overloading e.g.\ntemplate\u0026lt;class... Args\u0026gt; inline outcome::result\u0026lt;file_handle\u0026gt; make(std::in_place_type_t\u0026lt;file_handle\u0026gt;, Args\u0026amp;\u0026amp; ... args) { return file_handle::file(std::forward\u0026lt;Args\u0026gt;(args)...); } ... // Now you must always write this: make(std::in_place_type\u0026lt;file_handle\u0026gt;, \u0026#34;hello\u0026#34;); Tagged overloading is fine for smaller projects, but for larger code bases:\n It takes longer to type make(std::in_place_type\u0026lt;file_handle\u0026gt;, \u0026quot;hello\u0026quot;), and is possibly less intuitive to write, than it does make\u0026lt;file_handle\u0026gt;{\u0026quot;hello\u0026quot;}(). Compiler error messages are enormously clearer if you encode the permitted overloads for construction into the make\u0026lt;file_handle\u0026gt; type rather than letting a variadic free function fail to resolve an appropriate overload. Resolving variadic free function overloads is not constant time for the compiler, whereas resolving the type specialisation for make\u0026lt;file_handle\u0026gt; is constant time. In other words, free functions are expensive on build times, whereas fully specialised types are not. It actually turns out to be quite useful when writing generic code to pass around object constructing factory objects all of which have no parameters for their call operator. It becomes, effectively, a lazy construction mechanism. "
},
{
- "uri": "https://ned14.github.io/outcome/experimental/worked-example/source/",
+ "uri": "https://ned14.github.io/outcome/experimental/worked-example-long/source/",
"title": "Constexpr domain source",
"tags": [],
"description": "",
@@ -679,18 +714,25 @@
"content": " Hooks Functions used to hook into the functionality of basic_result and basic_outcome.\n uint16_t spare_storage(const basic_result|basic_outcome *) noexcept Returns the sixteen bits of spare storage in the specified result or outcome.\n void hook_outcome_construction(T *, U \u0026amp;\u0026amp;) noexcept (Until v2.2.0) ADL discovered free function hook invoked by the implicit constructors of basic_outcome.\n void hook_outcome_construction(T *, U \u0026amp;\u0026amp;, V \u0026amp;\u0026amp;) noexcept (Until v2.2.0) ADL discovered free function hook invoked by the implicit constructors of basic_outcome.\n void hook_outcome_copy_construction(T *, U \u0026amp;\u0026amp;) noexcept (Until v2.2.0) ADL discovered free function hook invoked by the converting copy constructors of basic_outcome.\n void hook_outcome_copy_construction(T *, U \u0026amp;\u0026amp;, V \u0026amp;\u0026amp;) noexcept (Until v2.2.0) ADL discovered free function hook invoked by the converting copy constructors of basic_outcome.\n void hook_outcome_in_place_construction(T *, in_place_type_t\u0026lt;U\u0026gt;, Args \u0026amp;\u0026amp;...) noexcept (Until v2.2.0) ADL discovered free function hook invoked by the in-place constructors of basic_outcome.\n void hook_outcome_move_construction(T *, U \u0026amp;\u0026amp;) noexcept (Until v2.2.0) ADL discovered free function hook invoked by the converting move constructors of basic_outcome.\n void hook_outcome_move_construction(T *, U \u0026amp;\u0026amp;, V \u0026amp;\u0026amp;) noexcept (Until v2.2.0) ADL discovered free function hook invoked by the converting move constructors of basic_outcome.\n void hook_result_construction(T *, U \u0026amp;\u0026amp;) noexcept (Until v2.2.0) ADL discovered free function hook invoked by the implicit constructors of basic_result.\n void hook_result_copy_construction(T *, U \u0026amp;\u0026amp;) noexcept (Until v2.2.0) ADL discovered free function hook invoked by the converting copy constructors of basic_result.\n void hook_result_in_place_construction(T *, in_place_type_t\u0026lt;U\u0026gt;, Args \u0026amp;\u0026amp;...) noexcept (Until v2.2.0) ADL discovered free function hook invoked by the in-place constructors of basic_result.\n void hook_result_move_construction(T *, U \u0026amp;\u0026amp;) noexcept (Until v2.2.0) ADL discovered free function hook invoked by the converting move constructors of basic_result.\n void override_outcome_exception(basic_outcome\u0026lt;T, EC, EP, NoValuePolicy\u0026gt; *, U \u0026amp;\u0026amp;) noexcept Overrides the exception to something other than what was constructed.\n void set_spare_storage(basic_result|basic_outcome *, uint16_t) noexcept Sets the sixteen bits of spare storage in the specified result or outcome.\n Iostream Functions used to print, serialise and deserialise basic_result and basic_outcome.\n std::istream \u0026amp;operator\u0026gt;\u0026gt;(std::istream \u0026amp;, basic_outcome\u0026lt;T, EC, EP, NoValuePolicy\u0026gt; \u0026amp;) Deserialises a basic_outcome from a std::istream.\n std::istream \u0026amp;operator\u0026gt;\u0026gt;(std::istream \u0026amp;, basic_result\u0026lt;T, E, NoValuePolicy\u0026gt; \u0026amp;) Deserialises a basic_result from a std::istream.\n std::ostream \u0026amp;operator\u0026lt;\u0026lt;(std::ostream \u0026amp;, const basic_outcome\u0026lt;T, EC, EP, NoValuePolicy\u0026gt; \u0026amp;) Serialises a basic_outcome to a std::ostream.\n std::ostream \u0026amp;operator\u0026lt;\u0026lt;(std::ostream \u0026amp;, const basic_result\u0026lt;T, E, NoValuePolicy\u0026gt; \u0026amp;) Serialises a basic_result to a std::ostream.\n std::string print(const basic_outcome\u0026lt;T, EC, EP, NoValuePolicy\u0026gt; \u0026amp;) Returns a string containing a human readable rendition of the basic_outcome.\n std::string print(const basic_result\u0026lt;T, E, NoValuePolicy\u0026gt; \u0026amp;) Returns a string containing a human readable rendition of the basic_result.\n Policy Functions used to customise how the policy classes operate.\n auto basic_outcome_failure_exception_from_error(const EC \u0026amp;) ADL discovered free function synthesising an exception type from an error type, used by the .failure() observers.\n decltype(auto) error_code(T \u0026amp;\u0026amp;) Extracts a boost::system::error_code or std::error_code from the input via ADL discovery of a suitable make_error_code(T) function.\n decltype(auto) exception_ptr(T \u0026amp;\u0026amp;) Extracts a boost::exception_ptr or std::exception_ptr from the input via ADL discovery of a suitable make_exception_ptr(T) function.\n void outcome_throw_as_system_error_with_payload(BoostErrorCodeEnum \u0026amp;\u0026amp;) Specialisation of outcome_throw_as_system_error_with_payload() for input types where boost::system::is_error_code_enum\u0026lt;BoostErrorCodeEnum\u0026gt; or boost::system::is_error_condition_enum\u0026lt;BoostErrorCodeEnum\u0026gt; is true.\n void outcome_throw_as_system_error_with_payload(ErrorCodeEnum \u0026amp;\u0026amp;) Specialisation of outcome_throw_as_system_error_with_payload() for input types where std::is_error_code_enum\u0026lt;ErrorCodeEnum\u0026gt; or std::is_error_condition_enum\u0026lt;ErrorCodeEnum\u0026gt; is true.\n void outcome_throw_as_system_error_with_payload(const boost::system::error_code \u0026amp;) Specialisation of outcome_throw_as_system_error_with_payload() for boost::system::error_code.\n void outcome_throw_as_system_error_with_payload(const std::error_code \u0026amp;) Specialisation of outcome_throw_as_system_error_with_payload() for std::error_code.\n auto failure(T \u0026amp;\u0026amp;, ...) Returns appropriate type sugar for constructing an unsuccessful result or outcome.\n auto success(T \u0026amp;\u0026amp;, ...) Returns appropriate type sugar for constructing a successful result or outcome.\n bool try_operation_has_value(X) Default implementation of try_operation_has_value(X) ADL customisation point for OUTCOME_TRY.\n decltype(auto) try_operation_extract_value(X) Default implementation of try_operation_extract_value(X) ADL customisation point for OUTCOME_TRY.\n decltype(auto) try_operation_return_as(X) Default implementation of try_operation_return_as(X) ADL customisation point for OUTCOME_TRY.\n std::error_code error_from_exception(std::exception_ptr \u0026amp;\u0026amp;ep = std::current_exception(), std::error_code not_matched = std::make_error_code(std::errc::resource_unavailable_try_again)) noexcept Returns an error code matching a thrown standard library exception.\n void strong_swap(bool \u0026amp;all_good, T \u0026amp;a, T \u0026amp;b) Tries to perform a strong guarantee swap.\n void try_throw_std_exception_from_error(std::error_code ec, const std::string \u0026amp;msg = std::string{}) Try to throw a standard library exception type matching an error code.\n "
},
{
- "uri": "https://ned14.github.io/outcome/experimental/worked-example/implicit_conversion/",
+ "uri": "https://ned14.github.io/outcome/experimental/worked-example-long/implicit_conversion/",
"title": "Implicit conversion",
"tags": [],
"description": "",
"content": "Back in The payload, we mentioned that there was no default implicit conversion of file_io_error (status_code\u0026lt;_file_io_error_domain\u0026gt;) to error, as error is too small to hold _file_io_error_domain::value_type.\nWe can tell the framework about available implicit conversions by defining an ADL discovered free function make_status_code() which takes our custom status code as input, and returns an error:\n// Now tell `error` how it can implicitly construct from `file_io_error`. // This is done by us defining a free function called `make_status_code()` // which is discovered using ADL. `error` is an alias to the refinement // `status_code\u0026lt;erased\u0026lt;intptr_t\u0026gt;\u0026gt;` which is a status code whose value type // has been erased into an `intptr_t`. `status_code\u0026lt;erased\u0026lt;intptr_t\u0026gt;\u0026gt;` // (i.e. `error`) are move bitcopying (P1029) i.e. they are move-only // types whose move operation is defined to leave the source in the same // representation as a default constructed instance, and for whose // non-trivial destructor when called upon a default constructed instance // is guaranteed to do nothing. inline outcome_e::system_code make_status_code(file_io_error v) { // `make_nested_status_code()` dynamically allocates memory to store an // instance of `file_io_error`, then returns a status code whose domain // specifies that its value type is a pointer to `file_io_error`. The // domain is a templated instance which indirects all observers of the // status code to the pointed-to status code. // // Note that the status code returned\u0026#39;s value type is a pointer, which // by definition fits into `intptr_t` and is trivially copyable. // Therefore `system_code` (which is also a type alias to // `status_code\u0026lt;erased\u0026lt;intptr_t\u0026gt;\u0026gt;`) is happy to implicitly construct // from the status code returned by `make_nested_status_code()`. return make_nested_status_code(std::move(v)); } View this code on Github We are now ready to use Experimental Outcome!\n"
},
+{
+ "uri": "https://ned14.github.io/outcome/experimental/outcome/",
+ "title": "Tying it all together",
+ "tags": [],
+ "description": "",
+ "content": " Firstly let\u0026rsquo;s alias a more convenient form of status_result:\ntemplate \u0026lt;classT, classE = outcome_e::error\u0026gt; using result = // outcome_e::status_result\u0026lt;T, E, outcome_e::policy::default_status_result_policy\u0026lt;T, E\u0026gt;\u0026gt;; View this code on Github (The defaulting of default_result_policy is superfluous, it\u0026rsquo;s already the default)\nWhat follows now is very standard Outcome code. Indeed, it would compile just fine under standard Outcome with only a few typedefs.\nresult\u0026lt;file_handle, file_io_error\u0026gt; open_file(const char *path) // models throws(file_io_error) { file_handle ret(::fopen(path, \u0026#34;r\u0026#34;)); if(ret) return ret; return file_io_error({errno, __LINE__, __FILE__}); } result\u0026lt;void\u0026gt; open_resource() // models throws(std::error) { for(;;) { result\u0026lt;file_handle, file_io_error\u0026gt; r = open_file(\u0026#34;some file\u0026#34;); if(r) break; file_io_error e = r.error(); if(e != outcome_e::errc::resource_unavailable_try_again) { // NOTE this implicitly converts from `file_io_error` to `error` via the // `make_status_code()` free function customisation point defined above. return e; } } // success continues here ... return outcome_e::success(); } int main(void) { result\u0026lt;void\u0026gt; r = open_resource(); if(r) printf(\u0026#34;Success!\\n\u0026#34;); else { auto e = std::move(r).error(); // A quick demonstration that the indirection works as indicated printf(\u0026#34;Returned error has a code domain of \u0026#39;%s\u0026#39;, a message of \u0026#39;%s\u0026#39;\\n\u0026#34;, e.domain().name().c_str(), e.message().c_str()); printf(\u0026#34;\\nAnd semantically comparing it to \u0026#39;errc::no_such_file_or_directory\u0026#39; = %d\\n\u0026#34;, e == outcome_e::errc::no_such_file_or_directory); } } View this code on Github And running this program yields:\nReturned error has a code domain of 'file i/o error domain', a message of 'No such file or directory (c:\\users\\ned\\documents\\boostish\\outcome\\doc\\src\\snippets\\experimental_status_code.cpp:195)' And semantically comparing it to 'errc::no_such_file_or_directory' = 1 Conclusion Once you get used to \u0026lt;system_error2\u0026gt; and the fact that any result with E = error is always move-only, using experimental Outcome is just like using normal Outcome. Except that codegen will be better, custom domains are safe to use in headers, semantic comparisons have guaranteed complexity bounds, and build times are much reduced.\nWhat\u0026rsquo;s not to like? :)\nFinally, if you have feedback on using experimental Outcome which you think would be of use to the standards committee when evaluating possible implementations of P0709 Zero overhead exceptions: Throwing values, please do get in touch! This especially includes successful experiences!!!\n"
+},
{
"uri": "https://ned14.github.io/outcome/changelog/",
"title": "Changelog",
"tags": [],
"description": "",
- "content": " v2.2.10 ? (Boost 1.86) [release] Enhancements: Something I\u0026rsquo;ve been meaning to do for far too long now is make the GDB pretty printers auto-loading so you don\u0026rsquo;t have to set up .gdbinit. This is now done. I also improved the pretty printers to also pretty print the C result type which can be very useful if working with that type, as it will print the error message in GDB. Experimental Outcome\u0026rsquo;s status_code has also gained its own auto-loading GDB pretty printer with display of strerror() if the code domain is POSIX or generic.\nBug fixes: The status enumeration used to track state internally did not list all possible enum values. This caused static analysers to complain. v2.2.9 15th April 2024 (Boost 1.85) [release] Enhancements: #293 - Some users wished that Outcome would be clean with -Wpedantic, this is now turned on for the test suite.\n#294 - All use of assert() has been replaced with OUTCOME_ASSERT, which can be user overridden at compile time.\n#295 - In git commit 12b14e1533848e9a0f7f3c38e41da0ee4e819770 (Aug 11 2022) status code had its paths changed due to its headers not previously having the right path convention. It was not realised at the time that in Boost.Outcome this resulted in \u0026lt;boost/outcome/experimental/status-code/status-code/headers.hpp\u0026gt; which is not desirable. This has now been remedied to remove the double status-code, which will obviously break any Boost.Outcome code which relies on the double status-code. Standalone Outcome is unaffected.\nv2.2.8 13th December 2023 (Boost 1.84) [release] Enhancements: cmake 3.9 is now the minimum required for standalone Outcome. This fixes a long standing cmake issue with probing for standard library facilities. cmake 3.9 is what RHEL7 ships with, when RHEL7 EOLs we may raise the minimum cmake version at that point. Bug fixes: There was a bug in the Outcome C++ coroutine awaitables whereby we were over eagerly resuming execution of coroutines which return one of our awaitables. It is surprising how many years have passed before this was noticed, but it is now fixed. It is believed that this has been fixed without affecting ABI stability, however mixing old Outcome and new Outcome in the same binary without recompiling all the C++ coroutine code to use new Outcome will not fix the bug. #291 - A Result or Outcome with void value type and move-only non-value type was only usable in const use cases, due to the lack of provision of non-const member functions in relevant observers injection layers for the void specialisation. The missing non-const member functions have now been added.\nv2.2.7 13th August 2023 (Boost 1.83) [release] Enhancements: Update the list of known compiler issues in the docs.\n Update Outcome.Experimental to match latest changes requested of status_code by WG21. This as usual will cause minor breakage due to LEWG renaming of things.\n Outcome previously took addresses of things not using std::addressof(), and until now nobody complained because custom operator\u0026amp; which doesn\u0026rsquo;t return an address is an abomination not used in much modern C++. But finally someone did complain, so for both normal Outcome and Experimental.Outcome, if you set OUTCOME_USE_STD_ADDRESSOF = 1, Outcome will use std::addressof()\n Bug fixes: #273 - Changes to other Boost libraries had caused Boost.Outcome\u0026rsquo;s test suite to fail to compile for some compiler and C++ language configurations in recent releases. Thanks to work contributed by @alandefreitas and @pdimov, Boost.Outcome now CI tests a wide range of compilers and configurations and it is believed all those corner case issues have been fixed or worked around, for the compilers and configurations within that CI matrix.\nStandalone Outcome\u0026rsquo;s test suite was never affected, as it did not have Boost changing underneath it. Nevertheless, a few of the compiler parse bug workarounds will have improved compatibility there too for atyical toolchain choices.\n Experimental.Outcome now supports big endian architectures. Implementation for them simply wasn\u0026rsquo;t done before under the assumption that nobody would be using Experimental.Outcome on big endian architectures. Turns out that was a wrong assumption! v2.2.6 24th March 2023 (Boost 1.82) [release] Enhancements: Update to latest status-code in Experimental.Outcome, which relocates its header files and may cause some end user inclusions to need path changes. Bug fixes: Latest status-code fixes a number of nasty bugs, some mild build breakage in Experimental.Outcome may occur as a result. See its commit log for more information. v2.2.4 11th August 2022 (Boost 1.80) [release] Enhancements: Update to latest status-code in Experimental.Outcome, which has some breaking changes and important bug fixes.\n Add generator\u0026lt;T, Executor = void\u0026gt; to coroutine awaitables.\n Add optional Executor template parameter to all Outcome awaitable types for improved compatibility with third party software such as ASIO.\n To Experimental.Outcome add clone() for basic_result and basic_outcome types whose EC is a status_code. Erased status codes are move-only which makes the Result/Outcome type move-only, but they provide a cloning function, so this convenience function both clones the status code and propagates the spare storage so stack backtraces etc are also cloned.\n Add type constraints to success() and failure() to disable them if they aren\u0026rsquo;t available.\n Work around a bug in GCC\u0026rsquo;s C++ Coroutines implementation whereby one gets an ICE from gimplify_expr in any OUTCOME_CO_TRY taking even a mildly complex expression, which obviously is a showstopper. The work around assigns the failure type to a stack temporary before co_return-ing that temporary. Thanks to RVO pre-17 and copy elision since, this should add no runtime overhead.\n Bug fixes: #261 Move assignable with move constructible not available did not work with void. v2.2.3 17th March 2022 (Boost 1.79) [release] Enhancements: Standalone Outcome permanently locks ABI to v2.2.3 release From this release onwards, you are guaranteed that any code compiled with v2.2.3 Outcome or newer will link without issue with any code compiled with a different version of Outcome after v2.2.3. As a result, OUTCOME_UNSTABLE_VERSION is no longer defined by default, and therefore OUTCOME_V2_NAMESPACE is now hard coded to outcome_v2 rather than a namespace which permutes per commit. Bug fixes: #255 Fix enabling of move assignable was not calculated correctly. v2.2.2 8th December 2021 (Boost 1.78) [release] Enhancements: #255 Restore Experimental Outcome constexpr compatibility in C++ 20 which was an undocumented property of the Outcome v2.1 series, and which had been dropped in the v2.2 series. GCC Coroutines support Coroutine support in GCCs after 10 is now correctly detected. Bug fixes: None. v2.2.1 13th August 2021 (Boost 1.77) [release] Bug fixes: #251 Fix failure to compile Boost.Outcome when the compiler declares support for C++ modules.\n Don\u0026rsquo;t use [[likely]] in GCCs before 9.\n #251 Make support for C++ modules opt-in.\n v2.2.0 16th April 2021 (Boost 1.76) [release] BREAKING CHANGE As announced for a year and three Boost releases, Outcome v2.2 became the default, replacing v2.1. All v2.1 Outcome code will need to be upgraded as described in the v2.1 =\u0026gt; v2.2 upgrade guide. This branch has a number of major breaking changes to Outcome v2.1, see the list of v2.2 major changes. Enhancements: VS2019.8 compatibility VS2019.8 changed how to enable Coroutines, which caused Outcome to not compile on that compiler. #237 If on C++ 20, we now use C++ 20 [[likely]] instead of compiler-specific markup to indicate when TRY has likely success or failure. BREAKING CHANGE #247 Previously the value of spare_storage(const basic_result|basic_outcome *) noexcept was not propagated over OUTCOME_TRY, which causes things like stack backtraces captured at the point of construction of an errored result to get dropped at every TRY point. This has been fixed by adding an optional spare_storage to success_type\u0026lt;T\u0026gt; and failure_type\u0026lt;T\u0026gt; , as well as to auto success(T \u0026amp;\u0026amp;, ...) and auto failure(T \u0026amp;\u0026amp;, ...) .\nYou should not notice this in your code, except that where before spare storage values did not propagate through TRY, now they do, which is a breaking change.\n Bug fixes: BREAKING CHANGE #244 It came as a shock to learn that OUTCOME_TRY had been broken since the inception of this library for certain corner case code:\noutcome::result\u0026lt;Foo\u0026gt; get_foo(); outcome::result\u0026lt;Foo\u0026gt; filter1(outcome::result\u0026lt;Foo\u0026gt; \u0026amp;\u0026amp;); outcome::result\u0026lt;Foo\u0026gt; \u0026amp;\u0026amp; filter2(outcome::result\u0026lt;Foo\u0026gt; \u0026amp;\u0026amp;); // This works fine, and always has OUTCOME_TRY(auto v, filter1(get_foo())) // This causes UB due to result\u0026lt;Foo\u0026gt; being destructed before move of value into v OUTCOME_TRY(auto v, filter2(get_foo())) Whilst reference passthrough filter functions are not common, they can turn up in highly generic code, where destruction before copy/move is not helpful.\nThe cause is that TRY used to work by binding the result of the expression to an auto \u0026amp;\u0026amp;unique, testing if that unique if successful or not, and if successful then moving from unique.value() into the user\u0026rsquo;s output variable. If the expression returned is a prvalue, the Result\u0026rsquo;s lifetime is extended by the bound reference to outside of the statement, and all is good. If the expression returned is an xvalue or lvalue, then the lifetime extension does not exceed that of the statement, and the Result is destructed after the semicolon succeeding the assignment to auto \u0026amp;\u0026amp;unique.\nThis bug has been fixed by TRY deducing the value category of its input expression as follows:\n prvalues =\u0026gt; auto unique = (expr) (breaking change) xvalue =\u0026gt; auto unique = (expr) (breaking change) lvalue =\u0026gt; auto unique = (expr) (breaking change) This ensures that xvalue and lvalue inputs do not cause unhelpfully early lifetime end, though it does silently change the behaviour of existing code which relied on rvalues and lvalues being passed through, as a new construct-move-destruct or construct-copy-destruct cycle is introduced to where there was none before. Also, before C++ 17, there is now an added copy/move for prvalue inputs, which does not affect runtime codegen due to Return Value Optimisation (RVO), but does cause Results containing non-copying non-moving types to fail to compile, which is a breaking change from beforehand.\nIf one wishes rvalues or lvalues to be passed through, one can avail of a new TRY syntax based on preprocessor overloading:\n OUTCOME_TRY((refspec, varname), expr) OUTCOME_TRYV2(refspec, expr) Here refspec is the storage to be used for both the internal temporary unique, AND varname. So if you write:\nFoo \u0026amp;\u0026amp;foo; OUTCOME_TRY((auto \u0026amp;\u0026amp;, v), filter2(foo)) \u0026hellip; then the internal unique is declared as auto \u0026amp;\u0026amp;unique = (filter2(foo)), and the output variable is declared as auto \u0026amp;\u0026amp;v = std::move(unique).assume_value(). This passes through the rvalue referencing, and completely avoids copies and moves of Foo. If you wish to not extract the value but also specify unique storage, there is a new OUTCOME_TRYV2(refspec, expr).\nMy thanks to KamilCuk from https://stackoverflow.com/questions/66069152/token-detection-within-a-c-preprocessor-macro-argument for all their help in designing the new overloaded TRY syntax. My thanks also to vasama for reporting this issue and working through how best to fix it with me.\n #249 The preprocessor logic for choosing when to use bool with concept on GCC was yet again refactored. This should fix those choices of GCC configuration which caused failure due to the wrong combination being chosen.\n v2.1.5 11th December 2020 (Boost 1.75) [release] Enhancements: The ADL discovered event hooks have been replaced with policy-specified event hooks instead This is due to brittleness (where hooks would quietly self-disable if somebody changed something), compiler bugs (a difference in compiler settings causes the wrong hooks, or some but not all hooks, to get discovered), and end user difficulty in using them at all. The policy-specified event hooks can be told to default to ADL discovered hooks for backwards compatibility: set OUTCOME_ENABLE_LEGACY_SUPPORT_FOR to less than 220 to enable emulation. Improve configuring OUTCOME_GCC6_CONCEPT_BOOL Older GCCs had boolean based concepts syntax, whereas newer GCCs are standards conforming. However the precise logic of when to use legacy and conforming syntax was not well understood, which caused Outcome to fail to compile depending on what options you pass to GCC. The new logic always uses the legacy syntax if on GCC 8 or older, otherwise we use conforming syntax if and only if GCC is in C++ 20 mode or later. This hopefully will resolve the corner case build failures on GCC. Bug fixes: Boost.Outcome should now compile with BOOST_NO_EXCEPTIONS defined Thanks to Emil, maintainer of Boost.Exception, making a change for me, Boost.Outcome should now compile with C++ exceptions globally disabled. You won\u0026rsquo;t be able to use boost::exception_ptr as it can\u0026rsquo;t be included if C++ exceptions are globally disabled. #236 In the Coroutine support the final_suspend() was not noexcept, despite being required to be so in the C++ 20 standard. This has been fixed, but only if your compiler implements noop_coroutine. Additionally, if noop_coroutine is available, we use the much more efficient coroutine handle returning variant of await_suspend() which should significantly improve codegen and context switching performance. v2.1.4 14th August 2020 (Boost 1.74) [release] Enhancements: BREAKING CHANGE void results and outcomes no longer default construct types during explicit construction Previously if you explicitly constructed a result\u0026lt;T\u0026gt; from a non-errored result\u0026lt;void\u0026gt;, it default constructed T. This was found to cause unhelpful surprise, so it has been disabled. New macro OUTCOME_ENABLE_LEGACY_SUPPORT_FOR The macro OUTCOME_ENABLE_LEGACY_SUPPORT_FOR can be used to enable aliasing of older naming and features to newer naming and features when using a newer version of Outcome. Concepts now have snake case style naming instead of camel case style When Outcome was first implemented, it was thought that C++ 20 concepts were going to have camel case style. This was changed before the C++ 20 release, and Outcome\u0026rsquo;s concepts have been renamed similarly. This won\u0026rsquo;t break any code in Outcome v2.1, as compatibility aliases are provided. However code compiled against Outcome v2.2 will need to be upgraded, unless OUTCOME_ENABLE_LEGACY_SUPPORT_FOR is set to less than 220. Concepts now live in OUTCOME_V2_NAMESPACE::concepts namespace Previously concepts lived in the convert namespace, now they live in their own namespace. New concepts basic_result\u0026lt;T\u0026gt; and basic_outcome\u0026lt;T\u0026gt; added End users were finding an unhelpful gap in between is_basic_result\u0026lt;T\u0026gt; and value_or_error\u0026lt;T\u0026gt; where they wanted a concept that matched types which were basic_result, but not exactly one of those. Concepts filling that gap were added. Operation TRY works differently from Outcome v2.2 onwards This is a severely code breaking change which change the syntax of how one uses OUTCOME_TRY(). A regular expression suitable for upgrading code can be found in the list of changes between Outcome v2.1 and v2.2. Bug fixes: #224 The clang Apple ships in Xcode 11.4 (currently the latest) has not been patched with the fixes to LLVM clang that fix noexcept(std::is_constructible\u0026lt;T, void\u0026gt;) failing to compile which I originally submitted years ago. So give up waiting on Apple to fix their clang, add a workaround to Outcome. Use of void in T or E caused noexcept(false) Direct traits examination of void was causing nothrow detection to return false, fixed. Spare storage could not be used from within no-value policy classes Due to an obvious brain fart when writing the code at the time, the spare storage APIs had the wrong prototype which prevented them working from within policy classes. Sorry. v2.1.3 29th April 2020 (Boost 1.73) [release] Enhancements: Performance of Outcome-based code compiled by clang has been greatly improved The previous implementation of Outcome\u0026rsquo;s status bitfield confused clang\u0026rsquo;s optimiser, which caused low quality codegen. Unlike most codegen issues, this was noticeably in empirical benchmarks of real world code, as was shown by P1886 Error speed benchmarking.\nThe safe part of the better_optimisation Outcome v2.2.0 future branch was merged to Outcome v2.1.3 which includes a new status bitfield implementation. This appears to not confuse clang\u0026rsquo;s optimiser, and clang 9 produces code which routinely beats GCC 9\u0026rsquo;s code for various canned use cases.\n Precompiled headers are automatically enabled on new enough cmake\u0026rsquo;s for standalone Outcome If on cmake 3.16 or later, its new precompiled headers build support is used to tell consumers of the outcome::hl cmake target to precompile Outcome, if and only if outcome_IS_DEPENDENCY is false. outcome_IS_DEPENDENCY is set by Outcome\u0026rsquo;s CMakeLists.txt if it detects that it was included using add_subdirectory(), so for the vast majority of Outcome end users, the use of precompiled headers will NOT be enabled.\nExported targets do NOT request precompilation of headers, as it is assumed that importers of the Outcome cmake targets will configure their own precompiled headers which incorporate Outcome.\n Installability is now CI tested per commit Due to installability of standalone Outcome (e.g. make install) breaking itself rather more frequently than is ideal, installability is now tested on CI per commit.\n Coroutines support has been documented The coroutines support added in v2.1.2 has now been properly documented.\n Bug fixes: #214 Newer Concepts implementing compilers were unhappy with the early check for destructibility of T and E, so removed template constraints, falling back to static assert which runs later in the type instantiation sequence. #215 For standalone Outcome, CMAKE_TOOLCHAIN_FILE is now passed through during dependency superbuild. This should solve build issues for some embedded toolchain users. #220 A false positive undefined behaviour sanitiser failure in some use cases of Experimental Outcome was worked around to avoid the failure message. #221 Restored compatibility with x86 on Windows, which was failing with link errors. It was quite surprising that this bug was not reported sooner, but obviously almost nobody is using Outcome with x86 on Windows. #223 Fix a segfault in Debug builds only when cloning a status_code_ptr in Experimental.Outcome only. v2.1.2 11th December 2019 (Boost 1.72) [release] Enhancements: Improved compatibility with cmake tooling Standalone outcome is now make install-able, and cmake find_package() can find it. Note that you must separately install and find_package() Outcome\u0026rsquo;s dependency, quickcpplib, else find_package() of Outcome will fail. Non-permissive parsing is now default in Visual Studio The default targets in standalone Outcome\u0026rsquo;s cmake now enable non-permissive parsing. This was required partially because VS2019 16.3\u0026rsquo;s quite buggy Concepts implementation is unusuable in permissive parsing mode. Even then, lazy ADL two phase lookup is broken in VS2019 16.3 with /std:latest, you may wish to use an earlier language standard. Breaking change! The git submodule mechanism used by standalone Outcome of specifying dependent libraries has been replaced with a cmake superbuild of dependencies mechanism instead. Upon cmake configure, an internal copy of quickcpplib will be git cloned, built and installed into the build directory from where an internal find_package() uses it. This breaks the use of the unconfigured Outcome repo as an implementation of Outcome, one must now do one of: Add Outcome as subdirectory to cmake build. Use cmake superbuild (i.e. ExternalProject_Add()) to build and install Outcome into a local installation. Use one of the single header editions. Breaking change! For standalone Outcome, the current compiler is now checked for whether it will compile code containing C++ Concepts, and if it does, all cmake consumers of Outcome will enable C++ Concepts. Set the cmake variable CXX_CONCEPTS_FLAGS to an empty string to prevent auto detection and enabling of C++ Concepts support occurring. OUTCOME_TRY operation now hints to the compiler that operation will be successful P1886 Error speed benchmarking showed that there is considerable gain in very small functions by hinting to the compiler whether the expression is expected to be successful or not. OUTCOME_TRY previously did not hint to the compiler at all, but now it does. A new suite of macros OUTCOME_TRY_FAILURE_LIKELY hint to the compiler that failure is expected. If you wish to return to the previously unhinted behaviour, define OUTCOME_TRY_LIKELY(expr) to (!!expr). #199 Support for C++ Coroutines has been added. This comes in two parts, firstly there is now an OUTCOME_CO_TRY() operation suitable for performing the TRY operation from within a C++ Coroutine. Secondly, in the header outcome/coroutine_support.hpp there are implementations of eager\u0026lt;OutcomeType\u0026gt; and lazy\u0026lt;OutcomeType\u0026gt; which let you more naturally and efficiently use basic_result or basic_outcome from within C++ Coroutines \u0026ndash; specifically, if the result or outcome will construct from an exception pointer, exceptions thrown in the coroutine return an errored or excepted result with the thrown exception instead of throwing the exception through the coroutine machinery (which in current compilers, has a high likelihood of blowing up the program). Both eager\u0026lt;T\u0026gt; and lazy\u0026lt;T\u0026gt; can accept any T as well. Both have been tested and found working on VS2019 and clang 9. #210 make_error_code() and make_exception_ptr() are now additionally considered for compatible copy and move conversions for basic_result\u0026lt;\u0026gt;. This lets you construct a basic_result\u0026lt;T, E\u0026gt; into a basic_result\u0026lt;T, error_code\u0026gt;, where E is a custom type which has implemented the ADL discovered free function error_code make_error_code(E), but is otherwise unrelated to error_code. The same availability applies for exception_ptr with make_exception_ptr() being the ADL discovered free function. basic_outcome\u0026lt;\u0026gt; has less support for this than basic_result\u0026lt;\u0026gt; in order to keep constructor count down, but it will accept via this mechanism conversions from basic_result\u0026lt;\u0026gt; and failure_type\u0026lt;\u0026gt;. Bug fixes: #184 The detection of [[nodiscard]] support in the compiler was very mildly broken. v2.1.1 19th August 2019 (Boost 1.71) [release] Enhancements: #184 As per request from Boost release managers, relocated version.hpp and revision.hpp into detail, and added the Boost licence boilerplate to the top of every source file which was missing one (I think). Also took the opportunity to run the licence restamping script over all Outcome, so copyright dates are now up to date. #185 Add FAQ item explaining issue #185, and why we will do nothing to fix it right now. #189 Refactored the OUTCOME_TRY implementation to use more clarified customisation points capable of accepting very foreign inputs. Removed the std::experimental::expected\u0026lt;T, E\u0026gt; specialisations, as those are no longer necessary. Fixed the documentation for the customisation points which previously claimed that they are ADL discovered, which they are not. Added a recipe describing how to add in support for foreign input types. #183 Added a separate motivation/plug_error_code specifically for Boost. Bug fixes: - OUTCOME_VERSION_MINOR hadn\u0026rsquo;t been updated to 1. #181 Fix issue #181 where Outcome didn\u0026rsquo;t actually implement the strong swap guarantee, despite being documented as doing so. #190 Fix issue #190 in Boost edition where unit test suite was not runnable from the Boost release distro. #182 Fix issue #182 where trait::is_exception_ptr_available\u0026lt;T\u0026gt; was always true, thus causing much weirdness, like not printing diagnostics and trying to feed everything to make_exception_ptr(). #194 Fix issue #192 where the std::basic_outcome_failure_exception_from_error() was being defined twice for translation units which combine standalone and Boost Outcome\u0026rsquo;s. v2.1 12th Apr 2019 (Boost 1.70) [release] #180\n success() and failure() now produce types marked [[nodiscard]]. include/outcome/outcome.natvis is now namespace permuted like the rest of Outcome, so debugging Outcome based code in Visual Studio should look much prettier than before.\n #162\n .has_failure() was returning false at times when it should have returned true. #152\n GCC 5 no longer can compile Outcome at all due to https://stackoverflow.com/questions/45607450/gcc5-nested-variable-template-is-not-a-function-template. Added explicit version trap for GCC 5 to say it can not work. Note this is not a breaking change, GCC 5 was never supported officially in any v2 Outcome. #150\n BREAKING CHANGE result\u0026lt;T, E\u0026gt;, boost_result\u0026lt;T, E\u0026gt; and std_result\u0026lt;T, E\u0026gt; no longer implement hard UB on fetching a value from a valueless instance if E is a UDT, they now fail to compile with a useful error message. If you wish hard UB, use unchecked\u0026lt;T, E\u0026gt;, boost_unchecked\u0026lt;T, E\u0026gt; or std_unchecked\u0026lt;T, E\u0026gt; instead. #140\n Fixed a nasty corner case bug where value type\u0026rsquo;s without a copy constructor but with a move constructor would indicate via traits that copy construction was available. Thanks to Microsoft\u0026rsquo;s compiler team for reporting this issue. Added experimental status_result and status_outcome based on experimental status_code.\n Boost edition is now 100% Boost, so defaults for result and outcome are boost::system::error_code::errc_t and boost::exception_ptr. Moreover, the test suite in the Boost edition now exclusively tests the Boost edition. One can, of course, freely use the standalone edition with Boost, and the Boost edition with std types.\n Renamed ADL discovered customisation point throw_as_system_error_with_payload() to outcome_throw_as_system_error_with_payload().\n #135\n Added much clearer compile failure when user tries result\u0026lt;T, T\u0026gt; or outcome where two or more types are identical. Thanks to Andrzej Krzemieński for suggesting a technique which combines SFINAE correctness with the remaining ability for result\u0026lt;T, T\u0026gt; etc to be a valid type, but not constructible. #67\n Fixed one of the oldest long open bugs in Outcome, that the noexcept unit tests failed on OS X for an unknown reason. #115\n Outcome did not construct correctly from failure_type. Inexplicably outcome\u0026rsquo;s error + exception constructor had been removed. Nobody noticed during the Boost peer review, which is worrying seeing as that constructor is needed for one of the main advertised features to Boost!\n #107 and #116\n operator== and operator!= now become disabled if the value, error and exception types do not implement the same operator. Relatedly, both comparison operators simply didn\u0026rsquo;t work right. Fixed. #109\n swap() now has correct noexcept calculation and now correctly orders the swaps to be whichever is the throwing swap first. Added reference dump of v2.1 ABI so we can check if ABI breakage detection works in the next set of changes, plus Travis job to check ABI and API compatibility per commit.\n #124\n OUTCOME_TRY is now overloaded and selects void or auto edition according to input parameter count. #120\n Fix generation of double underscored temporary variables in OUTCOME_UNIQUE_NAME, which is UB. #110\n Separated result from its hard coded dependency on the \u0026lt;system_error\u0026gt; header. Renamed result and outcome to basic_result and basic_outcome. Renamed result.hpp into basic_result.hpp. Moved \u0026lt;system_error\u0026gt; and \u0026lt;exception\u0026gt; dependent code into new std_result.hpp and std_outcome.hpp header files. Added boost_result.hpp and boost_outcome.hpp which use Boost.System and Boost.Exception (these are result.hpp and outcome.hpp in the Boost edition). v2.0 18th Jan 2018 [release] Boost peer review edition. This is what was reviewed. Changelog from v1 can be found in the release notes for this release. "
+ "content": " v2.2.11 ? (Boost 1.87) [release] Enhancements: Outcome.Experimental has had C representation support since the beginning, however it had been mainly intended that C++ would originate Results, they would pass through C, and back into C++. It hadn\u0026rsquo;t really been expected that C would want to do much with Results other than inspect them for happy or sad path. It turns out there is more demand than expected for a more functional Result from within C, so this release adds the power to create Results in success and two types of failure, semantic comparison of Results, and printing of Result messages. You can also wrap a C enum into a quick status code from enum, allowing easy custom C error coding from 100% within C.\nThe documentation for the C support has been updated to reflect the new facilities.\nBug fixes: This was fixed in Standalone Outcome in the last release, but the fix came too late for Boost.Outcome which ended up shipping with inline GDB pretty printers with the wrong escaping which caused failure to load. v2.2.10 14th August 2024 (Boost 1.86) [release] Enhancements: Something I\u0026rsquo;ve been meaning to do for far too long now is make the GDB pretty printers auto-loading so you don\u0026rsquo;t have to set up .gdbinit. This is now done. I also improved the pretty printers to also pretty print the C result type which can be very useful if working with that type, as it will print the error message in GDB. Experimental Outcome\u0026rsquo;s status_code has also gained its own auto-loading GDB pretty printer with display of strerror() if the code domain is POSIX or generic.\nBug fixes: The status enumeration used to track state internally did not list all possible enum values. This caused static analysers to complain. v2.2.9 15th April 2024 (Boost 1.85) [release] Enhancements: #293 - Some users wished that Outcome would be clean with -Wpedantic, this is now turned on for the test suite.\n#294 - All use of assert() has been replaced with OUTCOME_ASSERT, which can be user overridden at compile time.\n#295 - In git commit 12b14e1533848e9a0f7f3c38e41da0ee4e819770 (Aug 11 2022) status code had its paths changed due to its headers not previously having the right path convention. It was not realised at the time that in Boost.Outcome this resulted in \u0026lt;boost/outcome/experimental/status-code/status-code/headers.hpp\u0026gt; which is not desirable. This has now been remedied to remove the double status-code, which will obviously break any Boost.Outcome code which relies on the double status-code. Standalone Outcome is unaffected.\nv2.2.8 13th December 2023 (Boost 1.84) [release] Enhancements: cmake 3.9 is now the minimum required for standalone Outcome. This fixes a long standing cmake issue with probing for standard library facilities. cmake 3.9 is what RHEL7 ships with, when RHEL7 EOLs we may raise the minimum cmake version at that point. Bug fixes: There was a bug in the Outcome C++ coroutine awaitables whereby we were over eagerly resuming execution of coroutines which return one of our awaitables. It is surprising how many years have passed before this was noticed, but it is now fixed. It is believed that this has been fixed without affecting ABI stability, however mixing old Outcome and new Outcome in the same binary without recompiling all the C++ coroutine code to use new Outcome will not fix the bug. #291 - A Result or Outcome with void value type and move-only non-value type was only usable in const use cases, due to the lack of provision of non-const member functions in relevant observers injection layers for the void specialisation. The missing non-const member functions have now been added.\nv2.2.7 13th August 2023 (Boost 1.83) [release] Enhancements: Update the list of known compiler issues in the docs.\n Update Outcome.Experimental to match latest changes requested of status_code by WG21. This as usual will cause minor breakage due to LEWG renaming of things.\n Outcome previously took addresses of things not using std::addressof(), and until now nobody complained because custom operator\u0026amp; which doesn\u0026rsquo;t return an address is an abomination not used in much modern C++. But finally someone did complain, so for both normal Outcome and Experimental.Outcome, if you set OUTCOME_USE_STD_ADDRESSOF = 1, Outcome will use std::addressof()\n Bug fixes: #273 - Changes to other Boost libraries had caused Boost.Outcome\u0026rsquo;s test suite to fail to compile for some compiler and C++ language configurations in recent releases. Thanks to work contributed by @alandefreitas and @pdimov, Boost.Outcome now CI tests a wide range of compilers and configurations and it is believed all those corner case issues have been fixed or worked around, for the compilers and configurations within that CI matrix.\nStandalone Outcome\u0026rsquo;s test suite was never affected, as it did not have Boost changing underneath it. Nevertheless, a few of the compiler parse bug workarounds will have improved compatibility there too for atyical toolchain choices.\n Experimental.Outcome now supports big endian architectures. Implementation for them simply wasn\u0026rsquo;t done before under the assumption that nobody would be using Experimental.Outcome on big endian architectures. Turns out that was a wrong assumption! v2.2.6 24th March 2023 (Boost 1.82) [release] Enhancements: Update to latest status-code in Experimental.Outcome, which relocates its header files and may cause some end user inclusions to need path changes. Bug fixes: Latest status-code fixes a number of nasty bugs, some mild build breakage in Experimental.Outcome may occur as a result. See its commit log for more information. v2.2.4 11th August 2022 (Boost 1.80) [release] Enhancements: Update to latest status-code in Experimental.Outcome, which has some breaking changes and important bug fixes.\n Add generator\u0026lt;T, Executor = void\u0026gt; to coroutine awaitables.\n Add optional Executor template parameter to all Outcome awaitable types for improved compatibility with third party software such as ASIO.\n To Experimental.Outcome add clone() for basic_result and basic_outcome types whose EC is a status_code. Erased status codes are move-only which makes the Result/Outcome type move-only, but they provide a cloning function, so this convenience function both clones the status code and propagates the spare storage so stack backtraces etc are also cloned.\n Add type constraints to success() and failure() to disable them if they aren\u0026rsquo;t available.\n Work around a bug in GCC\u0026rsquo;s C++ Coroutines implementation whereby one gets an ICE from gimplify_expr in any OUTCOME_CO_TRY taking even a mildly complex expression, which obviously is a showstopper. The work around assigns the failure type to a stack temporary before co_return-ing that temporary. Thanks to RVO pre-17 and copy elision since, this should add no runtime overhead.\n Bug fixes: #261 Move assignable with move constructible not available did not work with void. v2.2.3 17th March 2022 (Boost 1.79) [release] Enhancements: Standalone Outcome permanently locks ABI to v2.2.3 release From this release onwards, you are guaranteed that any code compiled with v2.2.3 Outcome or newer will link without issue with any code compiled with a different version of Outcome after v2.2.3. As a result, OUTCOME_UNSTABLE_VERSION is no longer defined by default, and therefore OUTCOME_V2_NAMESPACE is now hard coded to outcome_v2 rather than a namespace which permutes per commit. Bug fixes: #255 Fix enabling of move assignable was not calculated correctly. v2.2.2 8th December 2021 (Boost 1.78) [release] Enhancements: #255 Restore Experimental Outcome constexpr compatibility in C++ 20 which was an undocumented property of the Outcome v2.1 series, and which had been dropped in the v2.2 series. GCC Coroutines support Coroutine support in GCCs after 10 is now correctly detected. Bug fixes: None. v2.2.1 13th August 2021 (Boost 1.77) [release] Bug fixes: #251 Fix failure to compile Boost.Outcome when the compiler declares support for C++ modules.\n Don\u0026rsquo;t use [[likely]] in GCCs before 9.\n #251 Make support for C++ modules opt-in.\n v2.2.0 16th April 2021 (Boost 1.76) [release] BREAKING CHANGE As announced for a year and three Boost releases, Outcome v2.2 became the default, replacing v2.1. All v2.1 Outcome code will need to be upgraded as described in the v2.1 =\u0026gt; v2.2 upgrade guide. This branch has a number of major breaking changes to Outcome v2.1, see the list of v2.2 major changes. Enhancements: VS2019.8 compatibility VS2019.8 changed how to enable Coroutines, which caused Outcome to not compile on that compiler. #237 If on C++ 20, we now use C++ 20 [[likely]] instead of compiler-specific markup to indicate when TRY has likely success or failure. BREAKING CHANGE #247 Previously the value of spare_storage(const basic_result|basic_outcome *) noexcept was not propagated over OUTCOME_TRY, which causes things like stack backtraces captured at the point of construction of an errored result to get dropped at every TRY point. This has been fixed by adding an optional spare_storage to success_type\u0026lt;T\u0026gt; and failure_type\u0026lt;T\u0026gt; , as well as to auto success(T \u0026amp;\u0026amp;, ...) and auto failure(T \u0026amp;\u0026amp;, ...) .\nYou should not notice this in your code, except that where before spare storage values did not propagate through TRY, now they do, which is a breaking change.\n Bug fixes: BREAKING CHANGE #244 It came as a shock to learn that OUTCOME_TRY had been broken since the inception of this library for certain corner case code:\noutcome::result\u0026lt;Foo\u0026gt; get_foo(); outcome::result\u0026lt;Foo\u0026gt; filter1(outcome::result\u0026lt;Foo\u0026gt; \u0026amp;\u0026amp;); outcome::result\u0026lt;Foo\u0026gt; \u0026amp;\u0026amp; filter2(outcome::result\u0026lt;Foo\u0026gt; \u0026amp;\u0026amp;); // This works fine, and always has OUTCOME_TRY(auto v, filter1(get_foo())) // This causes UB due to result\u0026lt;Foo\u0026gt; being destructed before move of value into v OUTCOME_TRY(auto v, filter2(get_foo())) Whilst reference passthrough filter functions are not common, they can turn up in highly generic code, where destruction before copy/move is not helpful.\nThe cause is that TRY used to work by binding the result of the expression to an auto \u0026amp;\u0026amp;unique, testing if that unique if successful or not, and if successful then moving from unique.value() into the user\u0026rsquo;s output variable. If the expression returned is a prvalue, the Result\u0026rsquo;s lifetime is extended by the bound reference to outside of the statement, and all is good. If the expression returned is an xvalue or lvalue, then the lifetime extension does not exceed that of the statement, and the Result is destructed after the semicolon succeeding the assignment to auto \u0026amp;\u0026amp;unique.\nThis bug has been fixed by TRY deducing the value category of its input expression as follows:\n prvalues =\u0026gt; auto unique = (expr) (breaking change) xvalue =\u0026gt; auto unique = (expr) (breaking change) lvalue =\u0026gt; auto unique = (expr) (breaking change) This ensures that xvalue and lvalue inputs do not cause unhelpfully early lifetime end, though it does silently change the behaviour of existing code which relied on rvalues and lvalues being passed through, as a new construct-move-destruct or construct-copy-destruct cycle is introduced to where there was none before. Also, before C++ 17, there is now an added copy/move for prvalue inputs, which does not affect runtime codegen due to Return Value Optimisation (RVO), but does cause Results containing non-copying non-moving types to fail to compile, which is a breaking change from beforehand.\nIf one wishes rvalues or lvalues to be passed through, one can avail of a new TRY syntax based on preprocessor overloading:\n OUTCOME_TRY((refspec, varname), expr) OUTCOME_TRYV2(refspec, expr) Here refspec is the storage to be used for both the internal temporary unique, AND varname. So if you write:\nFoo \u0026amp;\u0026amp;foo; OUTCOME_TRY((auto \u0026amp;\u0026amp;, v), filter2(foo)) \u0026hellip; then the internal unique is declared as auto \u0026amp;\u0026amp;unique = (filter2(foo)), and the output variable is declared as auto \u0026amp;\u0026amp;v = std::move(unique).assume_value(). This passes through the rvalue referencing, and completely avoids copies and moves of Foo. If you wish to not extract the value but also specify unique storage, there is a new OUTCOME_TRYV2(refspec, expr).\nMy thanks to KamilCuk from https://stackoverflow.com/questions/66069152/token-detection-within-a-c-preprocessor-macro-argument for all their help in designing the new overloaded TRY syntax. My thanks also to vasama for reporting this issue and working through how best to fix it with me.\n #249 The preprocessor logic for choosing when to use bool with concept on GCC was yet again refactored. This should fix those choices of GCC configuration which caused failure due to the wrong combination being chosen.\n v2.1.5 11th December 2020 (Boost 1.75) [release] Enhancements: The ADL discovered event hooks have been replaced with policy-specified event hooks instead This is due to brittleness (where hooks would quietly self-disable if somebody changed something), compiler bugs (a difference in compiler settings causes the wrong hooks, or some but not all hooks, to get discovered), and end user difficulty in using them at all. The policy-specified event hooks can be told to default to ADL discovered hooks for backwards compatibility: set OUTCOME_ENABLE_LEGACY_SUPPORT_FOR to less than 220 to enable emulation. Improve configuring OUTCOME_GCC6_CONCEPT_BOOL Older GCCs had boolean based concepts syntax, whereas newer GCCs are standards conforming. However the precise logic of when to use legacy and conforming syntax was not well understood, which caused Outcome to fail to compile depending on what options you pass to GCC. The new logic always uses the legacy syntax if on GCC 8 or older, otherwise we use conforming syntax if and only if GCC is in C++ 20 mode or later. This hopefully will resolve the corner case build failures on GCC. Bug fixes: Boost.Outcome should now compile with BOOST_NO_EXCEPTIONS defined Thanks to Emil, maintainer of Boost.Exception, making a change for me, Boost.Outcome should now compile with C++ exceptions globally disabled. You won\u0026rsquo;t be able to use boost::exception_ptr as it can\u0026rsquo;t be included if C++ exceptions are globally disabled. #236 In the Coroutine support the final_suspend() was not noexcept, despite being required to be so in the C++ 20 standard. This has been fixed, but only if your compiler implements noop_coroutine. Additionally, if noop_coroutine is available, we use the much more efficient coroutine handle returning variant of await_suspend() which should significantly improve codegen and context switching performance. v2.1.4 14th August 2020 (Boost 1.74) [release] Enhancements: BREAKING CHANGE void results and outcomes no longer default construct types during explicit construction Previously if you explicitly constructed a result\u0026lt;T\u0026gt; from a non-errored result\u0026lt;void\u0026gt;, it default constructed T. This was found to cause unhelpful surprise, so it has been disabled. New macro OUTCOME_ENABLE_LEGACY_SUPPORT_FOR The macro OUTCOME_ENABLE_LEGACY_SUPPORT_FOR can be used to enable aliasing of older naming and features to newer naming and features when using a newer version of Outcome. Concepts now have snake case style naming instead of camel case style When Outcome was first implemented, it was thought that C++ 20 concepts were going to have camel case style. This was changed before the C++ 20 release, and Outcome\u0026rsquo;s concepts have been renamed similarly. This won\u0026rsquo;t break any code in Outcome v2.1, as compatibility aliases are provided. However code compiled against Outcome v2.2 will need to be upgraded, unless OUTCOME_ENABLE_LEGACY_SUPPORT_FOR is set to less than 220. Concepts now live in OUTCOME_V2_NAMESPACE::concepts namespace Previously concepts lived in the convert namespace, now they live in their own namespace. New concepts basic_result\u0026lt;T\u0026gt; and basic_outcome\u0026lt;T\u0026gt; added End users were finding an unhelpful gap in between is_basic_result\u0026lt;T\u0026gt; and value_or_error\u0026lt;T\u0026gt; where they wanted a concept that matched types which were basic_result, but not exactly one of those. Concepts filling that gap were added. Operation TRY works differently from Outcome v2.2 onwards This is a severely code breaking change which change the syntax of how one uses OUTCOME_TRY(). A regular expression suitable for upgrading code can be found in the list of changes between Outcome v2.1 and v2.2. Bug fixes: #224 The clang Apple ships in Xcode 11.4 (currently the latest) has not been patched with the fixes to LLVM clang that fix noexcept(std::is_constructible\u0026lt;T, void\u0026gt;) failing to compile which I originally submitted years ago. So give up waiting on Apple to fix their clang, add a workaround to Outcome. Use of void in T or E caused noexcept(false) Direct traits examination of void was causing nothrow detection to return false, fixed. Spare storage could not be used from within no-value policy classes Due to an obvious brain fart when writing the code at the time, the spare storage APIs had the wrong prototype which prevented them working from within policy classes. Sorry. v2.1.3 29th April 2020 (Boost 1.73) [release] Enhancements: Performance of Outcome-based code compiled by clang has been greatly improved The previous implementation of Outcome\u0026rsquo;s status bitfield confused clang\u0026rsquo;s optimiser, which caused low quality codegen. Unlike most codegen issues, this was noticeably in empirical benchmarks of real world code, as was shown by P1886 Error speed benchmarking.\nThe safe part of the better_optimisation Outcome v2.2.0 future branch was merged to Outcome v2.1.3 which includes a new status bitfield implementation. This appears to not confuse clang\u0026rsquo;s optimiser, and clang 9 produces code which routinely beats GCC 9\u0026rsquo;s code for various canned use cases.\n Precompiled headers are automatically enabled on new enough cmake\u0026rsquo;s for standalone Outcome If on cmake 3.16 or later, its new precompiled headers build support is used to tell consumers of the outcome::hl cmake target to precompile Outcome, if and only if outcome_IS_DEPENDENCY is false. outcome_IS_DEPENDENCY is set by Outcome\u0026rsquo;s CMakeLists.txt if it detects that it was included using add_subdirectory(), so for the vast majority of Outcome end users, the use of precompiled headers will NOT be enabled.\nExported targets do NOT request precompilation of headers, as it is assumed that importers of the Outcome cmake targets will configure their own precompiled headers which incorporate Outcome.\n Installability is now CI tested per commit Due to installability of standalone Outcome (e.g. make install) breaking itself rather more frequently than is ideal, installability is now tested on CI per commit.\n Coroutines support has been documented The coroutines support added in v2.1.2 has now been properly documented.\n Bug fixes: #214 Newer Concepts implementing compilers were unhappy with the early check for destructibility of T and E, so removed template constraints, falling back to static assert which runs later in the type instantiation sequence. #215 For standalone Outcome, CMAKE_TOOLCHAIN_FILE is now passed through during dependency superbuild. This should solve build issues for some embedded toolchain users. #220 A false positive undefined behaviour sanitiser failure in some use cases of Experimental Outcome was worked around to avoid the failure message. #221 Restored compatibility with x86 on Windows, which was failing with link errors. It was quite surprising that this bug was not reported sooner, but obviously almost nobody is using Outcome with x86 on Windows. #223 Fix a segfault in Debug builds only when cloning a status_code_ptr in Experimental.Outcome only. v2.1.2 11th December 2019 (Boost 1.72) [release] Enhancements: Improved compatibility with cmake tooling Standalone outcome is now make install-able, and cmake find_package() can find it. Note that you must separately install and find_package() Outcome\u0026rsquo;s dependency, quickcpplib, else find_package() of Outcome will fail. Non-permissive parsing is now default in Visual Studio The default targets in standalone Outcome\u0026rsquo;s cmake now enable non-permissive parsing. This was required partially because VS2019 16.3\u0026rsquo;s quite buggy Concepts implementation is unusuable in permissive parsing mode. Even then, lazy ADL two phase lookup is broken in VS2019 16.3 with /std:latest, you may wish to use an earlier language standard. Breaking change! The git submodule mechanism used by standalone Outcome of specifying dependent libraries has been replaced with a cmake superbuild of dependencies mechanism instead. Upon cmake configure, an internal copy of quickcpplib will be git cloned, built and installed into the build directory from where an internal find_package() uses it. This breaks the use of the unconfigured Outcome repo as an implementation of Outcome, one must now do one of: Add Outcome as subdirectory to cmake build. Use cmake superbuild (i.e. ExternalProject_Add()) to build and install Outcome into a local installation. Use one of the single header editions. Breaking change! For standalone Outcome, the current compiler is now checked for whether it will compile code containing C++ Concepts, and if it does, all cmake consumers of Outcome will enable C++ Concepts. Set the cmake variable CXX_CONCEPTS_FLAGS to an empty string to prevent auto detection and enabling of C++ Concepts support occurring. OUTCOME_TRY operation now hints to the compiler that operation will be successful P1886 Error speed benchmarking showed that there is considerable gain in very small functions by hinting to the compiler whether the expression is expected to be successful or not. OUTCOME_TRY previously did not hint to the compiler at all, but now it does. A new suite of macros OUTCOME_TRY_FAILURE_LIKELY hint to the compiler that failure is expected. If you wish to return to the previously unhinted behaviour, define OUTCOME_TRY_LIKELY(expr) to (!!expr). #199 Support for C++ Coroutines has been added. This comes in two parts, firstly there is now an OUTCOME_CO_TRY() operation suitable for performing the TRY operation from within a C++ Coroutine. Secondly, in the header outcome/coroutine_support.hpp there are implementations of eager\u0026lt;OutcomeType\u0026gt; and lazy\u0026lt;OutcomeType\u0026gt; which let you more naturally and efficiently use basic_result or basic_outcome from within C++ Coroutines \u0026ndash; specifically, if the result or outcome will construct from an exception pointer, exceptions thrown in the coroutine return an errored or excepted result with the thrown exception instead of throwing the exception through the coroutine machinery (which in current compilers, has a high likelihood of blowing up the program). Both eager\u0026lt;T\u0026gt; and lazy\u0026lt;T\u0026gt; can accept any T as well. Both have been tested and found working on VS2019 and clang 9. #210 make_error_code() and make_exception_ptr() are now additionally considered for compatible copy and move conversions for basic_result\u0026lt;\u0026gt;. This lets you construct a basic_result\u0026lt;T, E\u0026gt; into a basic_result\u0026lt;T, error_code\u0026gt;, where E is a custom type which has implemented the ADL discovered free function error_code make_error_code(E), but is otherwise unrelated to error_code. The same availability applies for exception_ptr with make_exception_ptr() being the ADL discovered free function. basic_outcome\u0026lt;\u0026gt; has less support for this than basic_result\u0026lt;\u0026gt; in order to keep constructor count down, but it will accept via this mechanism conversions from basic_result\u0026lt;\u0026gt; and failure_type\u0026lt;\u0026gt;. Bug fixes: #184 The detection of [[nodiscard]] support in the compiler was very mildly broken. v2.1.1 19th August 2019 (Boost 1.71) [release] Enhancements: #184 As per request from Boost release managers, relocated version.hpp and revision.hpp into detail, and added the Boost licence boilerplate to the top of every source file which was missing one (I think). Also took the opportunity to run the licence restamping script over all Outcome, so copyright dates are now up to date. #185 Add FAQ item explaining issue #185, and why we will do nothing to fix it right now. #189 Refactored the OUTCOME_TRY implementation to use more clarified customisation points capable of accepting very foreign inputs. Removed the std::experimental::expected\u0026lt;T, E\u0026gt; specialisations, as those are no longer necessary. Fixed the documentation for the customisation points which previously claimed that they are ADL discovered, which they are not. Added a recipe describing how to add in support for foreign input types. #183 Added a separate motivation/plug_error_code specifically for Boost. Bug fixes: - OUTCOME_VERSION_MINOR hadn\u0026rsquo;t been updated to 1. #181 Fix issue #181 where Outcome didn\u0026rsquo;t actually implement the strong swap guarantee, despite being documented as doing so. #190 Fix issue #190 in Boost edition where unit test suite was not runnable from the Boost release distro. #182 Fix issue #182 where trait::is_exception_ptr_available\u0026lt;T\u0026gt; was always true, thus causing much weirdness, like not printing diagnostics and trying to feed everything to make_exception_ptr(). #194 Fix issue #192 where the std::basic_outcome_failure_exception_from_error() was being defined twice for translation units which combine standalone and Boost Outcome\u0026rsquo;s. v2.1 12th Apr 2019 (Boost 1.70) [release] #180\n success() and failure() now produce types marked [[nodiscard]]. include/outcome/outcome.natvis is now namespace permuted like the rest of Outcome, so debugging Outcome based code in Visual Studio should look much prettier than before.\n #162\n .has_failure() was returning false at times when it should have returned true. #152\n GCC 5 no longer can compile Outcome at all due to https://stackoverflow.com/questions/45607450/gcc5-nested-variable-template-is-not-a-function-template. Added explicit version trap for GCC 5 to say it can not work. Note this is not a breaking change, GCC 5 was never supported officially in any v2 Outcome. #150\n BREAKING CHANGE result\u0026lt;T, E\u0026gt;, boost_result\u0026lt;T, E\u0026gt; and std_result\u0026lt;T, E\u0026gt; no longer implement hard UB on fetching a value from a valueless instance if E is a UDT, they now fail to compile with a useful error message. If you wish hard UB, use unchecked\u0026lt;T, E\u0026gt;, boost_unchecked\u0026lt;T, E\u0026gt; or std_unchecked\u0026lt;T, E\u0026gt; instead. #140\n Fixed a nasty corner case bug where value type\u0026rsquo;s without a copy constructor but with a move constructor would indicate via traits that copy construction was available. Thanks to Microsoft\u0026rsquo;s compiler team for reporting this issue. Added experimental status_result and status_outcome based on experimental status_code.\n Boost edition is now 100% Boost, so defaults for result and outcome are boost::system::error_code::errc_t and boost::exception_ptr. Moreover, the test suite in the Boost edition now exclusively tests the Boost edition. One can, of course, freely use the standalone edition with Boost, and the Boost edition with std types.\n Renamed ADL discovered customisation point throw_as_system_error_with_payload() to outcome_throw_as_system_error_with_payload().\n #135\n Added much clearer compile failure when user tries result\u0026lt;T, T\u0026gt; or outcome where two or more types are identical. Thanks to Andrzej Krzemieński for suggesting a technique which combines SFINAE correctness with the remaining ability for result\u0026lt;T, T\u0026gt; etc to be a valid type, but not constructible. #67\n Fixed one of the oldest long open bugs in Outcome, that the noexcept unit tests failed on OS X for an unknown reason. #115\n Outcome did not construct correctly from failure_type. Inexplicably outcome\u0026rsquo;s error + exception constructor had been removed. Nobody noticed during the Boost peer review, which is worrying seeing as that constructor is needed for one of the main advertised features to Boost!\n #107 and #116\n operator== and operator!= now become disabled if the value, error and exception types do not implement the same operator. Relatedly, both comparison operators simply didn\u0026rsquo;t work right. Fixed. #109\n swap() now has correct noexcept calculation and now correctly orders the swaps to be whichever is the throwing swap first. Added reference dump of v2.1 ABI so we can check if ABI breakage detection works in the next set of changes, plus Travis job to check ABI and API compatibility per commit.\n #124\n OUTCOME_TRY is now overloaded and selects void or auto edition according to input parameter count. #120\n Fix generation of double underscored temporary variables in OUTCOME_UNIQUE_NAME, which is UB. #110\n Separated result from its hard coded dependency on the \u0026lt;system_error\u0026gt; header. Renamed result and outcome to basic_result and basic_outcome. Renamed result.hpp into basic_result.hpp. Moved \u0026lt;system_error\u0026gt; and \u0026lt;exception\u0026gt; dependent code into new std_result.hpp and std_outcome.hpp header files. Added boost_result.hpp and boost_outcome.hpp which use Boost.System and Boost.Exception (these are result.hpp and outcome.hpp in the Boost edition). v2.0 18th Jan 2018 [release] Boost peer review edition. This is what was reviewed. Changelog from v1 can be found in the release notes for this release. "
},
{
"uri": "https://ned14.github.io/outcome/tutorial/essential/conventions/",
@@ -707,18 +749,18 @@
"content": "This is the final section of the tutorial, and it is unavoidably quite lengthy as we are going to tie together all of the material covered in the tutorial so far into a single, unified, application of Outcome\u0026rsquo;s facilities.\nOne thing which Outcome solves \u0026ndash; and which alternatives do not \u0026ndash; is how to non-intrusively tie together multiple third party libraries, each using Outcome \u0026ndash; or some other T|E implementatation like P0323 std::expected\u0026lt;T, E\u0026gt; \u0026ndash; with custom incommensurate E types, or indeed arbitrary return types which are \u0026ldquo;split\u0026rdquo; T|E return types. Solving this well is the coup de grâce of Outcome against alternative approaches to this problem domain, including std::expected\u0026lt;T, E\u0026gt;. It is the major reason why you should consider using Outcome over alternatives, including Expected.\nFirstly we shall explore some of the problems faced by the software developer when T|E return type based code proliferates at scale, where dozens of libraries may be using completely incompatible T|E return types.\nSecondly we shall introduce the ValueOrError concept support in Outcome, which implements a subset of the proposed WG21 ValueOrError concept framework.\nFinally, we shall then step through a worked example which mocks up a realistic situation that the software developer may find themselves in: tying together disparate third party libraries, whose source code cannot be modified, into an application-wide, mixed-mode T|E and exception throwing universal error handling system which is capable of accurately representing the original failure, but also propagating it in a way that the application can deal with universally.\n"
},
{
- "uri": "https://ned14.github.io/outcome/experimental/outcome/",
- "title": "Tying it all together",
+ "uri": "https://ned14.github.io/outcome/experimental/worked-example/",
+ "title": "Worked example: Custom domain (the short way)",
"tags": [],
"description": "",
- "content": " Firstly let\u0026rsquo;s alias a more convenient form of status_result:\ntemplate \u0026lt;classT, classE = outcome_e::error\u0026gt; using result = // outcome_e::status_result\u0026lt;T, E, outcome_e::policy::default_status_result_policy\u0026lt;T, E\u0026gt;\u0026gt;; View this code on Github (The defaulting of default_result_policy is superfluous, it\u0026rsquo;s already the default)\nWhat follows now is very standard Outcome code. Indeed, it would compile just fine under standard Outcome with only a few typedefs.\nresult\u0026lt;file_handle, file_io_error\u0026gt; open_file(const char *path) // models throws(file_io_error) { file_handle ret(::fopen(path, \u0026#34;r\u0026#34;)); if(ret) return ret; return file_io_error({errno, __LINE__, __FILE__}); } result\u0026lt;void\u0026gt; open_resource() // models throws(std::error) { for(;;) { result\u0026lt;file_handle, file_io_error\u0026gt; r = open_file(\u0026#34;some file\u0026#34;); if(r) break; file_io_error e = r.error(); if(e != outcome_e::errc::resource_unavailable_try_again) { // NOTE this implicitly converts from `file_io_error` to `error` via the // `make_status_code()` free function customisation point defined above. return e; } } // success continues here ... return outcome_e::success(); } int main(void) { result\u0026lt;void\u0026gt; r = open_resource(); if(r) printf(\u0026#34;Success!\\n\u0026#34;); else { auto e = std::move(r).error(); // A quick demonstration that the indirection works as indicated printf(\u0026#34;Returned error has a code domain of \u0026#39;%s\u0026#39;, a message of \u0026#39;%s\u0026#39;\\n\u0026#34;, e.domain().name().c_str(), e.message().c_str()); printf(\u0026#34;\\nAnd semantically comparing it to \u0026#39;errc::no_such_file_or_directory\u0026#39; = %d\\n\u0026#34;, e == outcome_e::errc::no_such_file_or_directory); } } View this code on Github And running this program yields:\nReturned error has a code domain of 'file i/o error domain', a message of 'No such file or directory (c:\\users\\ned\\documents\\boostish\\outcome\\doc\\src\\snippets\\experimental_status_code.cpp:195)' And semantically comparing it to 'errc::no_such_file_or_directory' = 1 Conclusion Once you get used to \u0026lt;system_error2\u0026gt; and the fact that any result with E = error is always move-only, using experimental Outcome is just like using normal Outcome. Except that codegen will be better, custom domains are safe to use in headers, semantic comparisons have guaranteed complexity bounds, and build times are much reduced.\nWhat\u0026rsquo;s not to like? :)\nFinally, if you have feedback on using experimental Outcome which you think would be of use to the standards committee when evaluating possible implementations of P0709 Zero overhead exceptions: Throwing values, please do get in touch! This especially includes successful experiences!!!\n"
+ "content": "The section after this one will take the long way through defining a custom domain which sometimes is necessary if you have particularly bespoke requirements. If however you just want to wrap a custom enum type of yours into its own custom code domain, the boilerplate can be automated away by filling in a few simple fields like this:\n// My custom enum type enum classcustom_failure { not_found, bad_argument }; // Tell `status_code` to stamp out a custom code domain for this enum type SYSTEM_ERROR2_NAMESPACE_BEGIN template \u0026lt;\u0026gt; struct quick_status_code_from_enum\u0026lt;custom_failure\u0026gt; : quick_status_code_from_enum_defaults\u0026lt;custom_failure\u0026gt; { // Text name of the enum static constexpr const auto domain_name = \u0026#34;My custom failure\u0026#34;; // Unique UUID for the enum. PLEASE use https://www.random.org/cgi-bin/randbyte?nbytes=16\u0026amp;format=h static constexpr const auto domain_uuid = \u0026#34;{be201f65-3962-dd0e-1266-a72e63776a42}\u0026#34;; // Map of each enum value to its text string, and list of semantically equivalent errc\u0026#39;s static const std::initializer_list\u0026lt;mapping\u0026gt; \u0026amp;value_mappings() { static const std::initializer_list\u0026lt;mapping\u0026gt; v = { // Format is: { enum value, \u0026#34;string representation\u0026#34;, { list of errc mappings ... } } {custom_failure::not_found, \u0026#34;item not found\u0026#34;, {errc::no_such_file_or_directory}}, // {custom_failure::bad_argument, \u0026#34;invoked wrong\u0026#34;, {errc::invalid_argument}}, // }; return v; } // Completely optional definition of mixin for the status code synthesised from `Enum`. It can be omitted. template \u0026lt;classBase\u0026gt; struct mixin : Base { using Base::Base; constexpr int custom_method() const { return 42; } }; }; SYSTEM_ERROR2_NAMESPACE_END View this code on Github Here we supply the bare minimum requirements for a status code domain:\n The name in text, so it can be printed. The unique UUID to identify when multiple copies of the domain are the same. PLEASE use https://www.random.org/cgi-bin/randbyte?nbytes=16\u0026amp;format=h to generate this, do not twiddle a few bits. For each enum value, its printable text and a sequence of errc:: enumerations which you think it is semantically equivalent to i.e. its mapping onto generic_code which is how status code defines the common mapping between status codes. If you later compare the status code to one of those values (or to another status code which also provides a mapping), if the generic codes are equivalent then the comparison will return true. This means code like if(sc == errc::no_such_file_or_directory) ... would match all custom error codes which mean \u0026lsquo;something was not found\u0026rsquo;. OPTIONAL: if you would like the custom status code type generated by this to have additional member functions or additional payload, you can define a mixin here to inject either data or functions or both. If you omit this, nothing gets injected. "
},
{
- "uri": "https://ned14.github.io/outcome/experimental/worked-example/",
- "title": "Worked example: Custom domain",
+ "uri": "https://ned14.github.io/outcome/experimental/worked-example-long/",
+ "title": "Worked example: Custom domain (the long way)",
"tags": [],
"description": "",
- "content": " Here follows a worked example of use of Experimental Outcome. It presents the same sample program I sent to the San Diego 2018 WG21 standards meeting after I was asked by the committee to demonstrate how P1095 implements P0709 in a working code example they could study and discuss.\nWe will walk through this worked example, step by step, explaining how each part works in detail. This will help you implement your own code based on Experimental Outcome.\nYou may find it useful to open now in a separate browser tab the reference API documentation for proposed \u0026lt;system_error2\u0026gt; at https://ned14.github.io/status-code/ (scroll half way down). The references in the comments to P1028 are to P1028 SG14 status_code and standard error object for P0709 Zero-overhead deterministic exceptions, which is the WG21 proposal paper for potential \u0026lt;system_error2\u0026gt;.\nGoal of this section We are going to define a simple custom code domain which defines that the status code\u0026rsquo;s payload will consist of a POSIX error code, and the __FILE__ and __LINE__ where the failure occurred. This custom status code will have an implicit conversion to type erased error defined, which dynamically allocates memory for the original status code, and outputs an error which manages that dynamic allocation, indirecting all queries etc to the erased custom status code type such that the error instance quacks as if just like the original. This demonstrates that error could just as equally convey a std::exception_ptr, for example, or indeed manage the lifetime of any pointer.\n"
+ "content": " Here follows a longer worked example of use of Experimental Outcome. It presents the same sample program I sent to the San Diego 2018 WG21 standards meeting after I was asked by the committee to demonstrate how P1095 implements P0709 in a working code example they could study and discuss.\nWe will walk through this worked example, step by step, explaining how each part works in detail. This will help you implement your own code based on Experimental Outcome.\nMost users will not need this level of customisation, and for them the preceding quick and easy approach will be much easier.\nYou may find it useful to open now in a separate browser tab the reference API documentation for proposed \u0026lt;system_error2\u0026gt; at https://ned14.github.io/status-code/ (scroll half way down). The references in the comments to P1028 are to P1028 SG14 status_code and standard error object for P0709 Zero-overhead deterministic exceptions, which is the WG21 proposal paper for potential \u0026lt;system_error2\u0026gt;.\nGoal of this section We are going to define a simple custom code domain which defines that the status code\u0026rsquo;s payload will consist of a POSIX error code, and the __FILE__ and __LINE__ where the failure occurred. This custom status code will have an implicit conversion to type erased error defined, which dynamically allocates memory for the original status code, and outputs an error which manages that dynamic allocation, indirecting all queries etc to the erased custom status code type such that the error instance quacks as if just like the original. This demonstrates that error could just as equally convey a std::exception_ptr, for example, or indeed manage the lifetime of any pointer.\n"
},
{
"uri": "https://ned14.github.io/outcome/history/",
@@ -2132,7 +2174,7 @@
"title": "Home",
"tags": [],
"description": "",
- "content": " Outcome 2.2 library At the end of December 2021, Standalone Outcome went guaranteed future ABI stable. From v2.2.3 onwards, you get ABI compatibilty guarantees across Outcome releases.\n Outcome is a set of tools for reporting and handling function failures in contexts where directly using C++ exception handling is unsuitable. Such contexts include:\n there are programs, or parts thereof, that are compiled with exceptions disabled;\n there are parts of program that have a lot of branches depending on types of failures, where if-statements are cleaner than try-catch blocks;\n there is a hard requirement that the failure path of execution should not cost more than the successful path of execution;\n there are situations, like in the filesystem library, where whether the failure should be handled remotely (using a C++ exception throw), or locally cannot be made inside the function and needs to be decided by the caller, and in the latter case throwing a C++ exception is not desirable for the aforementioned reasons;\n there are parts of the program/framework that themselves implement exception handling and prefer to not use exceptions to propagate failure reports across threads, tasks, fibers, etc;\n one needs to propagate exceptions through layers that do not implement exception throw safety;\n there is an external requirement (such as a company-wide policy) that failure handling paths are explicitly indicated in the code.\n where interoperation with C code, without having to resort to C++ exception wrapper shims, is important.\n Outcome addresses failure handling through returning a special type from functions, which is able to store either a successfully computed value (or void), or the information about failure. Outcome also comes with a set of idioms for dealing with such types.\nParticular care has been taken to ensure that Outcome has the lowest possible impact on build times, thus making it suitable for use in the global headers of really large codebases. Storage layout is guaranteed and is C-compatible for result\u0026lt;T, E\u0026gt;1, thus making Outcome based code long term ABI-stable.\nFully deterministic all-noexcept C++ Coroutine support in Outcome is particularly strong, and we supply Outcome-optimising eager\u0026lt;T, Executor = void\u0026gt;/atomic_eager\u0026lt;T, Executor = void\u0026gt; , lazy\u0026lt;T, Executor = void\u0026gt;/atomic_lazy\u0026lt;T, Executor = void\u0026gt; and generator\u0026lt;T, Executor = void\u0026gt; awaitables which work for any user type.\nSample usage The main workhorse in the Outcome library is result\u0026lt;T\u0026gt;: it represents either a successfully computed value of type T, or a std::error_code/boost::system::error_code2 representing the reason for failure. You use it in the function\u0026rsquo;s return type:\noutcome::result\u0026lt;string\u0026gt; data_from_file(string_view path) noexcept; View this code on Github It is possible to inspect the state manually:\nif (outcome::result\u0026lt;string\u0026gt; rslt = data_from_file(\u0026#34;config.cfg\u0026#34;)) use_string(rslt.value()); // returns string else throw LibError{rslt.error(), \u0026#34;config.cfg\u0026#34;}; // returns error_code View this code on Github Or, if this function is called in another function that also returns result\u0026lt;T\u0026gt;, you can use a dedicated control statement:\noutcome::result\u0026lt;int\u0026gt; process(const string\u0026amp; content) noexcept; outcome::result\u0026lt;int\u0026gt; int_from_file(string_view path) noexcept { OUTCOME_TRY(auto str, data_from_file(path)); // if control gets here data_from_file() has succeeded return process(str); // decltype(str) == string } View this code on Github OUTCOME_TRY is a control statement. If the returned result\u0026lt;T\u0026gt; object contains an error information, the enclosing function is immediately returned with result\u0026lt;U\u0026gt; containing the same failure information; otherwise an automatic object of type T is available in scope.\nThis library joined the Boost C++ libraries in the 1.70 release (Spring 2019). It can be grafted into much older Boost releases if desired.\n If you choose a C-compatible T and E type. [return] result\u0026lt;T\u0026gt; defaults to std::error_code for Standalone Outcome, and to boost::system::error_code for Boost.Outcome. You can mandate a choice using std_result\u0026lt;T\u0026gt; or boost_result\u0026lt;T\u0026gt;. [return] "
+ "content": " Outcome 2.2 library At the end of December 2021, Standalone Outcome went guaranteed future ABI stable. From v2.2.3 onwards, you get ABI compatibilty guarantees across Outcome releases.\n Outcome is a set of tools for reporting and handling function failures in contexts where directly using C++ exception handling is unsuitable. Such contexts include:\n there are programs, or parts thereof, that are compiled with exceptions disabled;\n there are parts of program that have a lot of branches depending on types of failures, where if-statements are cleaner than try-catch blocks;\n there is a hard requirement that the failure path of execution should not cost more than the successful path of execution;\n there are situations, like in the filesystem library, where whether the failure should be handled remotely (using a C++ exception throw), or locally cannot be made inside the function and needs to be decided by the caller, and in the latter case throwing a C++ exception is not desirable for the aforementioned reasons;\n there are parts of the program/framework that themselves implement exception handling and prefer to not use exceptions to propagate failure reports across threads, tasks, fibers, etc;\n one needs to propagate exceptions through layers that do not implement exception throw safety;\n there is an external requirement (such as a company-wide policy) that failure handling paths are explicitly indicated in the code.\n where interoperation with C code, without having to resort to C++ exception wrapper shims, is important.\n where your mostly C code base needs exception-like error handling, and the subset of Outcome\u0026rsquo;s functionality available in C is sufficient for your needs.\n Outcome addresses failure handling through returning a special type from functions, which is able to store either a successfully computed value (or void), or the information about failure. Outcome also comes with a set of idioms for dealing with such types.\nParticular care has been taken to ensure that Outcome has the lowest possible impact on build times, thus making it suitable for use in the global headers of really large codebases. Storage layout is guaranteed and is C-compatible for result\u0026lt;T, E\u0026gt;1, thus making Outcome based code long term ABI-stable.\nFully deterministic all-noexcept C++ Coroutine support in Outcome is particularly strong, and we supply Outcome-optimising eager\u0026lt;T, Executor = void\u0026gt;/atomic_eager\u0026lt;T, Executor = void\u0026gt; , lazy\u0026lt;T, Executor = void\u0026gt;/atomic_lazy\u0026lt;T, Executor = void\u0026gt; and generator\u0026lt;T, Executor = void\u0026gt; awaitables which work for any user type.\nSample usage (C++) The main workhorse in the Outcome library is result\u0026lt;T\u0026gt;: it represents either a successfully computed value of type T, or a std::error_code/boost::system::error_code2 representing the reason for failure. You use it in the function\u0026rsquo;s return type:\noutcome::result\u0026lt;string\u0026gt; data_from_file(string_view path) noexcept; View this code on Github It is possible to inspect the state manually:\nif (outcome::result\u0026lt;string\u0026gt; rslt = data_from_file(\u0026#34;config.cfg\u0026#34;)) use_string(rslt.value()); // returns string else throw LibError{rslt.error(), \u0026#34;config.cfg\u0026#34;}; // returns error_code View this code on Github Or, if this function is called in another function that also returns result\u0026lt;T\u0026gt;, you can use a dedicated control statement:\noutcome::result\u0026lt;int\u0026gt; process(const string\u0026amp; content) noexcept; outcome::result\u0026lt;int\u0026gt; int_from_file(string_view path) noexcept { OUTCOME_TRY(auto str, data_from_file(path)); // if control gets here data_from_file() has succeeded return process(str); // decltype(str) == string } View this code on Github OUTCOME_TRY is a control statement. If the returned result\u0026lt;T\u0026gt; object contains an error information, the enclosing function is immediately returned with result\u0026lt;U\u0026gt; containing the same failure information; otherwise an automatic object of type T is available in scope.\nSample usage (C) Equivalent to the C++ API: CXX_DECLARE_RESULT_SYSTEM(ident, T) declares the C type, thereafter CXX_RESULT_SYSTEM(ident) refers to it. You use it in the function\u0026rsquo;s return type:\nCXX_DECLARE_RESULT_SYSTEM(result_string, const char *) CXX_RESULT_SYSTEM(result_string) data_from_file(const char *path); View this code on Github It is possible to inspect the state manually:\nCXX_RESULT_SYSTEM(result_string) rslt = data_from_file(\u0026#34;config.cfg\u0026#34;); if(CXX_RESULT_HAS_VALUE(rslt)) use_string(rslt.value); // returns string else fprintf(stderr, \u0026#34;%s\\n\u0026#34;, outcome_status_code_message(\u0026amp;rslt.error)); View this code on Github Or, if this function is called in another function that also returns CXX_RESULT_SYSTEM(ident), you can use a dedicated control statement:\nCXX_DECLARE_RESULT_SYSTEM(result_int, int) CXX_RESULT_SYSTEM(result_int) process(const char *content); CXX_RESULT_SYSTEM(result_int) int_from_file(const char *path) { CXX_RESULT_SYSTEM_TRY(const char *str, result_int, /* cleanup on fail */, data_from_file(path)); // if control gets here data_from_file() has succeeded return process(str); // decltype(str) == string } View this code on Github The C Result is guaranteed to be layout identical to its C++ equivalent. Convenience conversion functions are available, but you can reinterpret cast too.\nThis library joined the Boost C++ libraries in the 1.70 release (Spring 2019). It can be grafted into much older Boost releases if desired.\n If you choose a C-compatible T and E type. [return] result\u0026lt;T\u0026gt; defaults to std::error_code for Standalone Outcome, and to boost::system::error_code for Boost.Outcome. You can mandate a choice using std_result\u0026lt;T\u0026gt; or boost_result\u0026lt;T\u0026gt;. [return] "
},
{
"uri": "https://ned14.github.io/outcome/tags/hooks/",
diff --git a/index.xml b/index.xml
index 83bd542508..a6c8d04228 100644
--- a/index.xml
+++ b/index.xml
@@ -5,7 +5,7 @@
https://ned14.github.io/outcome/
Recent content in Home on Outcome documentationHugo -- gohugo.io
- Fri, 18 Mar 2022 14:45:32 +0000
+ Tue, 16 Jul 2024 21:33:35 +0100
@@ -71,6 +71,16 @@ struct abort_policy : outcome::policy::base { template <classImpl>
C++ 17 <system_error>Boost.SystemProposed <system_error2> std::errc boost::system::errc experimental::errc (almost identical) std::error_category boost::system::error_category experimental::status_code_domain std::generic_category boost::system::generic_category experimental::generic_code_domain std::system_category boost::system::system_category One of: experimental::posix_code_domain (POSIX systems) experimental::win32_code_domain (Microsoft Windows) experimental::nt_code_domain (Microsoft Windows) Note that there are more precanned code categories though they require additional header inclusions: com_code, getaddrinfo_code.
+
+ C system error results
+ https://ned14.github.io/outcome/experimental/c-api/from-c/system_code/
+ Mon, 01 Jan 0001 00:00:00 +0000
+
+ https://ned14.github.io/outcome/experimental/c-api/from-c/system_code/
+ In v2.2.11, C Result support went from second tier to first tier status, and now you can create, query and manipulate a subset of Result types entirely from within C by including <outcome/experimental/result.h>.
+The subset supported are those result<T, E> which are a status_result<T> i.e. the E is hardcoded to experimental::error which is the type erased runtime polymorphic holder for any errored status_code whose payload is not bigger than an intptr_t.
+
+
Coroutine TRY operation
https://ned14.github.io/outcome/tutorial/essential/coroutines/try/
@@ -83,10 +93,10 @@ eager<result<std::string>> to_string(int x) { if(x &
Define a custom code domain
- https://ned14.github.io/outcome/experimental/worked-example/preamble/
+ https://ned14.github.io/outcome/experimental/worked-example-long/preamble/
Mon, 01 Jan 0001 00:00:00 +0000
- https://ned14.github.io/outcome/experimental/worked-example/preamble/
+ https://ned14.github.io/outcome/experimental/worked-example-long/preamble/Firstly let’s alias the experimental Outcome namespace into something less tedious to type, declare our custom status code type, and get started on defining the custom status code domain implementation.
namespace outcome_e = OUTCOME_V2_NAMESPACE::experimental; // To define a `file_io_error` which participates in the P1028 world // of `std::error`, we must first declare, then define, a custom code // domain which extends `posix_code` (the std error coding for POSIX // failures). The following is fairly standard boilerplate for defining // a custom code domain.
@@ -102,24 +112,23 @@ int a() { f(); g(); // don't call g() and further if f() fails return h
- Keeping state
- https://ned14.github.io/outcome/tutorial/advanced/hooks/keeping_state/
+ Implicit construction
+ https://ned14.github.io/outcome/experimental/worked-example/implicit-construction/
Mon, 01 Jan 0001 00:00:00 +0000
- https://ned14.github.io/outcome/tutorial/advanced/hooks/keeping_state/
- The first thing we are going to need is somewhere to store the stack backtrace. We could take the easier route and simply store it into an allocated block and keep the pointer as a custom payload in a result<T, std::pair<error_code, std::unique_ptr<stack_backtrace>>> (see previous section on Custom payloads). But let us assume that we care so deeply about bounded execution times that ever calling malloc is unacceptable.
-We therefore are going to need some completely static and trivially typed storage perhaps kept per-thread to avoid the need to keep mutexes.
+ https://ned14.github.io/outcome/experimental/worked-example/implicit-construction/
+ The preceding code had the compiler stamp out a custom status code domain for a user supplied enum. You now get the following types:
+// This is the status code generated for your custom enum type. It will implicitly construct from // values of enum custom_failure. using custom_failure_code = SYSTEM_ERROR2_NAMESPACE::quick_status_code_from_enum_code<custom_failure>; namespace outcome_e = OUTCOME_V2_NAMESPACE::experimental; // You don't usually need to use the status code type explicitly, because this "just works": outcome_e::status_result<int> positive_only(int x) { if(x < 0) { // Outcome's result sees that status_code will implicitly construct from this enum, // and it returns an errored result return custom_failure::bad_argument; } return x; } // Semantic comparisons work bool test(int x) { if(auto r = positive_only(x); !
- Limitations
- https://ned14.github.io/outcome/experimental/c-api/limitations/
+ Keeping state
+ https://ned14.github.io/outcome/tutorial/advanced/hooks/keeping_state/
Mon, 01 Jan 0001 00:00:00 +0000
- https://ned14.github.io/outcome/experimental/c-api/limitations/
- C++ has excellent two-way compatibility with the C ABI, but there are some limitations you must observe to write C++ code which C code can call without marshalling at the ABI boundary:
- A C++ function may not throw exceptions if it is safe to call from C, and so should always be marked noexcept.
- A C++ function should be annotated with extern "C" to prevent its symbol being mangled, and thus give it the C rather than C++ ABI.
+ https://ned14.github.io/outcome/tutorial/advanced/hooks/keeping_state/
+ The first thing we are going to need is somewhere to store the stack backtrace. We could take the easier route and simply store it into an allocated block and keep the pointer as a custom payload in a result<T, std::pair<error_code, std::unique_ptr<stack_backtrace>>> (see previous section on Custom payloads). But let us assume that we care so deeply about bounded execution times that ever calling malloc is unacceptable.
+We therefore are going to need some completely static and trivially typed storage perhaps kept per-thread to avoid the need to keep mutexes.
@@ -216,12 +225,21 @@ As bad as this may sound, it generates the most optimal code, and such hard UB i
eager<T, Executor = void> An eagerly evaluated Coroutine: invoking co_await upon a function returning one of these immediately begins the execution of the function now. If the function never suspends, the overhead is similar to calling an ordinary function.
+
+ Declare a Result
+ https://ned14.github.io/outcome/experimental/c-api/from-c/declare/
+ Mon, 01 Jan 0001 00:00:00 +0000
+
+ https://ned14.github.io/outcome/experimental/c-api/from-c/declare/
+ // Declare to C a Result with a happy value of intptr_t CXX_DECLARE_RESULT_SYSTEM(result_int, intptr_t) // Save oneself typing out CXX_RESULT_SYSTEM(result_int) all the time typedef CXX_RESULT_SYSTEM(result_int) result; // Our custom C enum enum c_enum { c_enum_not_found, c_enum_bad_argument }; // Make a custom status code domain for this C enum CXX_DECLARE_RESULT_SYSTEM_FROM_ENUM(result_int, // The C Result type declared above c_enum, // The C enum we wish to wrap "{74ceb994-7622-3a21-07f0-b016aa705585}", // Unique UUID for this domain // Mappings of C enum values to textual description and semantic equivalances to generic codes {c_enum::c_enum_not_found, "item not found", {errc::no_such_file_or_directory}}, {c_enum::c_enum_bad_argument, "invoked wrong", {errc::invalid_argument}}) // Make helper macros #define SUCCESS(v) CXX_MAKE_RESULT_SYSTEM_SUCCESS(result_int, (v)) #define FAILURE(v) CXX_MAKE_RESULT_SYSTEM_FROM_ENUM(result_int, c_enum, (v)) View this code on Github The key to making C programming easy is to alias the long complex things into short easy thing.
+
+
Example C++ function
- https://ned14.github.io/outcome/experimental/c-api/example/
+ https://ned14.github.io/outcome/experimental/c-api/from-cxx/example/
Mon, 01 Jan 0001 00:00:00 +0000
- https://ned14.github.io/outcome/experimental/c-api/example/
+ https://ned14.github.io/outcome/experimental/c-api/from-cxx/example/Let us start with a simple C++ function which we wish to make available to C code:
namespace outcome_e = OUTCOME_V2_NAMESPACE::experimental; // Fill the supplied buffer with the integer v converted to a string, // returning length of string minus null terminator outcome_e::status_result<size_t> to_string(char *buffer, size_t bufferlen, int v) noexcept { try { // Could throw an exception! std::string temp(std::to_string(v)); // Will this string exceed the supplied buffer? if(temp.
@@ -259,10 +277,10 @@ outcome::result<void> print_half(const std::string& text);
The payload
- https://ned14.github.io/outcome/experimental/worked-example/value_type/
+ https://ned14.github.io/outcome/experimental/worked-example-long/value_type/
Mon, 01 Jan 0001 00:00:00 +0000
- https://ned14.github.io/outcome/experimental/worked-example/value_type/
+ https://ned14.github.io/outcome/experimental/worked-example-long/value_type/We define the code domain’s value_type – the payload to be transported by status codes using this code domain – to be a POSIX errno value, an integer line number and a const char pointer.
public: // This is the value type for `file_io_error`. We add line number and source file path. struct value_type { typename outcome_e::posix_code::value_type errcode; // from POSIX, as we inherit from _posix_code_domain // Our additional payload int lineno; // from __LINE__ const char *file; // from __FILE__ // Could also place a backtrace of void *[16] here .
@@ -329,12 +347,12 @@ Seeing as we are replacing the throwing overload of copy_file() in the Filesyste
Calling it from C
- https://ned14.github.io/outcome/experimental/c-api/example2/
+ https://ned14.github.io/outcome/experimental/c-api/from-cxx/example2/
Mon, 01 Jan 0001 00:00:00 +0000
- https://ned14.github.io/outcome/experimental/c-api/example2/
+ https://ned14.github.io/outcome/experimental/c-api/from-cxx/example2/Firstly we need to declare to C our result returning C++ function:
-// Declare our C++ function's returning result type. Only needs to be done once. // This declares an `status_result<size_t, system_code>` which is an alias to // `basic_result<size_t, status_code<erased<intptr_t>>>`. // // The first parameter is some unique identifier for this type which will be used // whenever we reference this type in the future. CXX_DECLARE_RESULT_SYSTEM(to_string_rettype, size_t); // Tell C about our extern C++ function `to_string()` extern CXX_RESULT_SYSTEM(to_string_rettype) _Z9to_stringPcmi(char *buffer, size_t bufferlen, int v); View this code on Github Now let’s call the C++ function from C:
+// Declare our C++ function's returning result type. Only needs to be done once. // This declares an `status_result<size_t, system_code>` which is an alias to // `basic_result<size_t, status_code<erased<intptr_t>>>`. // // The first parameter is some unique identifier for this type which will be used // whenever we reference this type in the future. CXX_DECLARE_RESULT_SYSTEM(to_string_rettype, size_t) // Tell C about our extern C++ function `to_string()` extern CXX_RESULT_SYSTEM(to_string_rettype) _Z9to_stringPcmi(char *buffer, size_t bufferlen, int v); View this code on Github Now let’s call the C++ function from C:
@@ -410,14 +428,24 @@ auto __result = BigInt::fromString(text); if (!__result) return __result.as_fail
The constructor
- https://ned14.github.io/outcome/experimental/worked-example/constructor/
+ https://ned14.github.io/outcome/experimental/worked-example-long/constructor/
Mon, 01 Jan 0001 00:00:00 +0000
- https://ned14.github.io/outcome/experimental/worked-example/constructor/
+ https://ned14.github.io/outcome/experimental/worked-example-long/constructor/Code domains are 100% constexpr to construct and destruct, as are status codes. This enables the compiler to 100% instantiate both only in its mind, and to emit zero code and thus zero overhead.
Unfortunately it also means that it must be possible for each domain to be instantiated an infinite number of times, and being 100% in constexpr, any instances never have a unique address in memory either. Thus we cannot compare domains for equivalence using their address in memory, as std::error_category does.
+
+ Using a Result
+ https://ned14.github.io/outcome/experimental/c-api/from-c/use/
+ Mon, 01 Jan 0001 00:00:00 +0000
+
+ https://ned14.github.io/outcome/experimental/c-api/from-c/use/
+ This models the earlier C++ example of use, and its C equivalent isn’t much more verbose thanks to our helper typedefs and macros:
+result positive_only(int x) { if(x < 0) { return FAILURE(c_enum_bad_argument); } return SUCCESS(x); } bool test(int x) { result r = positive_only(x); if(CXX_RESULT_HAS_ERROR(r)) { if(outcome_status_code_equal_generic(&r.error, EINVAL)) { fprintf(stderr, "Positive numbers only!\n"); return false; } } return true; } View this code on Github For this to link, the CXX_DECLARE_RESULT_SYSTEM_FROM_ENUM macro needs to be compiled at least once within C++ within the final binary to emit the extern functions needed by C.
+
+
std expected
https://ned14.github.io/outcome/alternatives/expected/
@@ -492,14 +520,24 @@ outcome::result<file_handle> fh2 = make<file_handle>
String refs
- https://ned14.github.io/outcome/experimental/worked-example/string_ref/
+ https://ned14.github.io/outcome/experimental/worked-example-long/string_ref/
Mon, 01 Jan 0001 00:00:00 +0000
- https://ned14.github.io/outcome/experimental/worked-example/string_ref/
+ https://ned14.github.io/outcome/experimental/worked-example-long/string_ref/<system_error2> does not use std::string to return possibly statically or dynamically allocated strings, and thus avoids dragging in a lot of the standard library which impacts build times.
Instead status code domains have a string_ref, which has a polymorphic implementation which may or may not manage a dynamic memory allocation using an atomic reference counter. Due to this polymorphism, you don’t need to worry which implementation is actually in use under the bonnet when you pass around string_ref instances.
+
+ TRY a C Result
+ https://ned14.github.io/outcome/experimental/c-api/from-c/try/
+ Mon, 01 Jan 0001 00:00:00 +0000
+
+ https://ned14.github.io/outcome/experimental/c-api/from-c/try/
+ Thanks to much of the magic of OUTCOME_TRY(var, expr) being implemented using C preprocessor metaprogramming, we can offer a very similar experience for the C try operation and without needing anything compiled in C++ as support functions:
+result test2(int x) { CXX_RESULT_SYSTEM_TRY(int v, // what to set to value if successful fprintf(stderr, "Positive numbers only!\n"), // what cleanup to run if unsuccessful positive_only(x)); return SUCCESS(v + 1); } View this code on Github The principle difference is that you can specify a cleanup routine to perform if failure is encountered.
+
+
TRY is greedy
https://ned14.github.io/outcome/tutorial/essential/result/try_greedy/
@@ -553,16 +591,6 @@ classerror_code { error_category* domain; // domain from which the error origina
namespace app { // Specialise an exception type for tidylib errors struct tidylib_error : std::system_error { // passthrough using std::system_error::system_error; tidylib_error() = default; explicit tidylib_error(int c) : std::system_error(c, std::generic_category()) { } }; // Create a C++ invoking wrapper for the tidylib C API, modifying data with the returned data, // returing a unique_ptr to release storage on scope exit.
-
- C Macro API Reference
- https://ned14.github.io/outcome/experimental/c-api/reference/
- Mon, 01 Jan 0001 00:00:00 +0000
-
- https://ned14.github.io/outcome/experimental/c-api/reference/
- The C macro API header <outcome/experimental/result.h> consists of these macros:
- CXX_DECLARE_RESULT(ident, T, E) Declares to C a basic_result type uniquely identified by ident. T is available at the member variable .value, and E is available at the member variable .error. CXX_RESULT(ident) A reference to a previously declared result type with unique ident. CXX_RESULT_HAS_VALUE(r) Evaluates to 1 (true) if the input result has a value. CXX_RESULT_HAS_ERROR(r) Evaluates to 1 (true) if the input result has an error.
-
-
Hook outcome
https://ned14.github.io/outcome/tutorial/advanced/hooks/hook_outcome/
@@ -606,10 +634,10 @@ This section illustrates how you can hook into the std::error_code system from t
Redefining `message()`
- https://ned14.github.io/outcome/experimental/worked-example/message/
+ https://ned14.github.io/outcome/experimental/worked-example-long/message/
Mon, 01 Jan 0001 00:00:00 +0000
- https://ned14.github.io/outcome/experimental/worked-example/message/
+ https://ned14.github.io/outcome/experimental/worked-example-long/message/You may remember that our custom _file_io_error_domain inherits from outcome_e::posix_code::domain_type, and thus does not have to implement the many pure virtual functions required by outcome_e::status_code_domain.
What we do need to do is reimplement _do_message() to append the file and line information to the POSIX error description string returned by outcome_e::posix_code::domain_type. This causes the status code’s .message() observer to return a string with the extra payload information represented in text.
// Return a string describing a specific code.
@@ -671,10 +699,10 @@ template<class... Args> inline outcome::result<file_handle&
Constexpr domain source
- https://ned14.github.io/outcome/experimental/worked-example/source/
+ https://ned14.github.io/outcome/experimental/worked-example-long/source/
Mon, 01 Jan 0001 00:00:00 +0000
- https://ned14.github.io/outcome/experimental/worked-example/source/
+ https://ned14.github.io/outcome/experimental/worked-example-long/source/Back in The constructor, we declared but did not implement a .get() function which returns a constexpr static instance of the domain. We implement this now:
// 100% constexpr instantiation constexpr _file_io_error_domain file_io_error_domain; inline constexpr const _file_io_error_domain &_file_io_error_domain::get() { return file_io_error_domain; } View this code on Github As this is 100% constexpr, it can be (and is under optimisation) implemented entirely in the mind of the compiler with no run time representation.
@@ -691,10 +719,10 @@ template<class... Args> inline outcome::result<file_handle&
Implicit conversion
- https://ned14.github.io/outcome/experimental/worked-example/implicit_conversion/
+ https://ned14.github.io/outcome/experimental/worked-example-long/implicit_conversion/
Mon, 01 Jan 0001 00:00:00 +0000
- https://ned14.github.io/outcome/experimental/worked-example/implicit_conversion/
+ https://ned14.github.io/outcome/experimental/worked-example-long/implicit_conversion/Back in The payload, we mentioned that there was no default implicit conversion of file_io_error (status_code<_file_io_error_domain>) to error, as error is too small to hold _file_io_error_domain::value_type.
We can tell the framework about available implicit conversions by defining an ADL discovered free function make_status_code() which takes our custom status code as input, and returns an error:
// Now tell `error` how it can implicitly construct from `file_io_error`. // This is done by us defining a free function called `make_status_code()` // which is discovered using ADL.
diff --git a/motivation/errno/index.html b/motivation/errno/index.html
index 2928bcacec..e6afb5c508 100644
--- a/motivation/errno/index.html
+++ b/motivation/errno/index.html
@@ -5,7 +5,7 @@
-
+
errno :: Outcome documentation
@@ -598,108 +598,153 @@
status_result and status_outcome
+
+