Provides very lightweight outcome and result (non-Boost edition)

Overview
master branch develop branch

CTest dashboard: https://my.cdash.org/index.php?project=Boost.Outcome

All tests passing source tarballs: https://github.com/ned14/outcome/releases

Documentation: https://ned14.github.io/outcome/

Purpose of this library

Outcome is a C++14 library for reporting and handling function failures. It can be used as a substitute for, or a complement to, the exception handling mechanism.

One use case is for contexts where using C++ exception handling is unsuitable for different reasons:

  • The high relative cost of throwing and catching a C++ exception.
  • Making some or all control paths explicitly detailed to aid code correctness auditing, as opposed to having hidden control paths caused by exceptions potentially thrown from any place.
  • Company policy to compile with exceptions disabled.
  • Maintaining a code base that was never designed with exception-safety in mind.
  • Parts of the programs/frameworks that themselves implement exception handling and cannot afford to use exceptions, like propagating failure reports across threads, tasks, fibers…

Usage as a single header file

Outcome v2 comes in single header file form. This is regenerated per commit. To fetch on Linux:

wget https://github.com/ned14/outcome/raw/master/single-header/outcome.hpp

On BSD:

fetch https://github.com/ned14/outcome/raw/master/single-header/outcome.hpp

If you have curl installed:

curl -O -J -L https://github.com/ned14/outcome/raw/master/single-header/outcome.hpp

Otherwise, simply download the raw file from above and place it wherever it suits you. If you might be debugging using Microsoft Visual Studio, you may find the debugger visualisation file at https://github.com/ned14/outcome/raw/master/include/outcome/outcome.natvis useful to include into your build.

Commits and tags in this git repository can be verified using:

-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: GnuPG v2

mDMEVvMacRYJKwYBBAHaRw8BAQdAp+Qn6djfxWQYtAEvDmv4feVmGALEQH/pYpBC
llaXNQe0WE5pYWxsIERvdWdsYXMgKHMgW3VuZGVyc2NvcmVdIHNvdXJjZWZvcmdl
IHthdH0gbmVkcHJvZCBbZG90XSBjb20pIDxzcGFtdHJhcEBuZWRwcm9kLmNvbT6I
eQQTFggAIQUCVvMacQIbAwULCQgHAgYVCAkKCwIEFgIDAQIeAQIXgAAKCRCELDV4
Zvkgx4vwAP9gxeQUsp7ARMFGxfbR0xPf6fRbH+miMUg2e7rYNuHtLQD9EUoR32We
V8SjvX4r/deKniWctvCi5JccgfUwXkVzFAk=
=puFk
-----END PGP PUBLIC KEY BLOCK-----
Issues
  • try_operation_return_as() customisation point is not ADL discovered

    try_operation_return_as() customisation point is not ADL discovered

    Suppose I am using third-party library which exposes result<T,E>from my own library which exposes result<T,F>.

    outcome::result<T,E> lib_func() {
      ...
    }
    
    outcome::result <T,F> my_func() {
      TRY(v, lib_func());
      ...
    }
    

    How can I provide a conversion from E to F when using TRY (I cannot add conversion operator into E, because it is a third-party component) ?

    bug 
    opened by nikobarli 28
  • Add conan support

    Add conan support

    Hi!

    I've added basic Conan support for Outcome, there are some issues left:

    • Do we want to build unit tests inconditionally? (gcc 7.2 crashed on my Debian)
    • I'm only packaging the single-header, since QuickCppLib is not installed by ninja install.

    I didn't want to change the CMakeLists.txt before having your feedback, let me know if you want to support more than the single-header.

    opened by theodelrieu 25
  • Consider adding the reason for existence of both result and outcome

    Consider adding the reason for existence of both result and outcome

    I haven't gone through the entire documentation for now but I'm fairly confident that this is either missing from the documentation or placed in a hard to find location...

    From what I could gather from the tutorial the main reason for the existence of both result<T, EC> and outcome<T, EC, EP> is that with:

    • result<T, EC>: the author of the function expects the user to either handle the error at the call site, determine that the error can be propagated upwards without the loss of information (example returning the result one level up will not confuse the user of that function which file failed to open as there is only one file being opened in the propagating function) or repackage the error to before returning the result/throwing an exception to something that is relevant to the callee (this is the usual case with low level errors such as opening files)

    • outcome<T, EC, EP>: the author of the function expects the error to be specific enough to be relevant even if it is not handled directly at the call site (example of this would be that XML validation failed due to missing schema file xyz, due to error on line x, node referred to by the XPath is missing in the XML... where you in most cases don't need to add additional data to the exception to be understandable by the upper levels - for example by the roll-back-transaction-and-log-the-error-before-continuing-with-processing-of-the-next-package somewhere at the top of the callstack)

    Since the distinction and the reason for the relevance of why both exist and where each should be used is important I'd add such an example towards the beginning of the documentation (and maybe a reference link to the section also at the beginning of the tutorial and the FAQ section). Maybe this should be added to the "Decision matrix" section (which should probably be renamed to "When to use result/outcome/exceptions" or something similar as "Decision matrix" was far from the first link that I've clicked on due to the current name...).

    documentation 
    opened by do-m-en 19
  • Docs are inconsistent about whether there should be a

    Docs are inconsistent about whether there should be a "success" first enum

    https://ned14.github.io/outcome/tutorial/result/

    enum class ConversionErrc
    {
      EmptyString = 1, // 0 is never an error
      IllegalChar = 2,
      TooLong     = 3,
    };
    

    https://ned14.github.io/outcome/tutorial/default-actions/enums/

      enum class err
      {
        success,   // REMEMBER it is best practice to always put "success"
        failure1,  // with value 0 as your first item in any error code
        failure2   // enum, even if you never use it.
      };
    

    These both prescribe that 0 shouldn't be an error, but one does it with adding a success and another by starting the errors at 1. These are subtly different, especially if you want to exhaustively check for errors. To me, if it's used within result<t>, the success case is redundant in the enum class. I think it would be better for outcome to have a single prescribed way in the docs to help new users.

    Should these docs be made more consistent with one another?

    documentation 
    opened by johnthagen 17
  • Document simple basic_result/basic_outcome usage

    Document simple basic_result/basic_outcome usage

    It would be very helpful to have some short documentation on how to use basic_result<> / basic_outcome<>. It's not the common case, so I think it could go in an appendix. I'd be happy to contribute something, but I'm not sure how to figure out how to use it other than looking at the code.

    For example, it seems to need a NoValuePolicy, but I don't see where it's documented what to pass to that.

    documentation 
    opened by johnthagen 15
  • What happened if the future dies before the promise sets the result?

    What happened if the future dies before the promise sets the result?

    Here's an inconsistency between the std and your version.

    #include <cstdlib>
    #include <iostream>
    #include <future>
    #include <boost/outcome/future.hpp>
    
    namespace lw = boost::outcome::lightweight_futures;
    
    int main(int argc, char *argv[])
    {
        try
        {
            lw::promise<int> p;
            //std::promise<int> p;
            p.get_future();
            p.set_value(1);
            std::cout << "done\n";
        }
        catch (std::exception& e)
        {
            std::cout << e.what() << "\n";
        }
    
        return EXIT_SUCCESS;
    }
    

    The std version prints done, but the lw version throws an exception no state.

    Is the inconsistency by design or is it a bug?

    opened by jamboree 15
  • constexpr basic_result?

    constexpr basic_result?

    The following code fails with the current master:

    constexpr outcome::experimental::status_result<int> test() {
        return outcome::success(42);
    }
    

    with an error along the lines of

    <source>: In function 'constexpr outcome_v2_35644f5c::experimental::status_result<int> test()':
    <source>:6:53: error: invalid return type 'outcome_v2_35644f5c::experimental::status_result<int>' {aka 'outcome_v2_35644f5c::basic_result<int, system_error2::errored_status_code<system_error2::erased<long int> >, outcome_v2_35644f5c::experimental::policy::status_code_throw<int, system_error2::errored_status_code<system_error2::erased<long int> >, void> >'} of 'constexpr' function 'constexpr outcome_v2_35644f5c::experimental::status_result<int> test()'
        6 | constexpr outcome::experimental::status_result<int> test() {
          |                                                     ^~~~
    In file included from <source>:2:
    outcome-experimental.hpp:4145:25: note: 'outcome_v2_35644f5c::basic_result<int, system_error2::errored_status_code<...>' is not literal because:
     4145 | class OUTCOME_NODISCARD basic_result : public detail::basic_result_final<R, S, NoValuePolicy>
          |                         ^~~~~~~~~~~~
    outcome-experimental.hpp:4145:25: note:   'outcome_v2_35644f5c::basic_result<int, system_error2::errored_status_code<...>' has a non-trivial destructor
    Compiler returned: 1
    

    (check godbolt).

    I believe that did work before - tough I'm not 100 % sure. Any thoughts?

    opened by burnpanck 14
  • Reference doc nitpicks

    Reference doc nitpicks

    Fixable by me:

    • [x] On the landing page there are several undocumented macros listed, which are presumably implementation details. (Probably already covered by #75.)
    • [x] The file content summary at the top of each page includes several detail #include lines that are probably not especially interesting to readers.
    • [x] The same also shows some quite lengthy noexcept expressions. Perhaps this can be elided to just noexcept(...) at the top and elaborated in the specific method detail further down?
    • [x] It is unclear where no_exception_type would be used. Perhaps this is explained elsewhere?
    • [x] In class outcome under "Comparison operators" appear two lines using 'hidden', which seem peculiar. A parsing artifact?
    • [x] outcome is declared as outcome<R,S,P> but its description refers to outcome<T, E, P> instead, which might be confusing. Also neither is actually true since it ignores the NoValuePolicy.
    • [x] rebind does not specify a type for NoValuePolicy, which seems like some kind of error; either there's a default parameter which is being hidden or this shouldn't compile.
    • [x] The description for outcome goes on to mention the policy behaviours in terms of various traits; while the implementation is presumably obvious I couldn't find where trait::* are documented (it would be nice if there were links). Also, it seems perhaps a little naming inconsistency between the std:: traits that have _v suffixes and the traits:: traits that don't.
    • [ ] The description of policy behaviour here seems a bit mixed up between how it selects the default policy based on the type parameters and how a policy (whether selected explicitly or by default) then behaves under particular conditions. These should probably be split into two separate sections for clarity.
    • [x] NoValuePolicy has a tiny subheading "Template parameters" by itself, which is followed by larger headings for the other template parameters, which is both out of order and hierarchically confused.
    • [x] Static template traits appear to be documented as an "unexposed entity", which seems like a peculiar wording.
    • [x] There always seems to be unnecessarily large whitespace between a heading and the code block immediately following it.
    • [x] In the All Narrow policy, wide_exception_check is described as not narrow?
    • [ ] Why are bad_result_access and bad_outcome_access unrelated exceptions?

    I didn't have much time to look at it so this was focused mainly on the outcome page and I've only just skimmed the rest. But hopefully it helps. 😁

    Standardese issues (to be copied to #75)

    • [ ] is_outcome_v is missing some whitespace (either space or newline) following the template declaration. This appears to be a general issue for all static or constexpr template values.
    • [x] On the success/failure page, near the documentation for success_type/failure_type etc, the structure itself and its contained members have the same heading level, which is hierarchically confused and makes reading it harder. Presumably it makes slightly more sense if you arrive there from an earlier hyperlink and then jump back after reading just one thing, but if you are scrolling down the page it's confusing.
    • [x] The numbering in this section keeps restarting from 1, presumably due to confusion with the nested bullets.
    documentation 
    opened by uecasm 14
  • OUTCOME_TRY for coroutines

    OUTCOME_TRY for coroutines

    This may be kind of silly but during my work on #198 I found myself wanting a co_return-flavored version of BOOST_OUTCOME_TRY. Do you think it would make sense to add something like that either to try.hpp or the ASIO recipe?

    Looking at the implementation, specifically

    #define OUTCOME_TRYV2(unique, ...)                                                                                                                                                                                                                                                                                             \
      auto && (unique) = (__VA_ARGS__);                                                                                                                                                                                                                                                                                            \
      if(!OUTCOME_V2_NAMESPACE::try_operation_has_value(unique))                                                                                                                                                                                                                                                                   \
    return OUTCOME_V2_NAMESPACE::try_operation_return_as(static_cast<decltype(unique) &&>(unique))
    

    it seems we could do something like

    #define OUTCOME_TRYV2(unique, return_keyword, ...)                                                                                                                                                                                                                                                                                             \
      auto && (unique) = (__VA_ARGS__);                                                                                                                                                                                                                                                                                            \
      if(!OUTCOME_V2_NAMESPACE::try_operation_has_value(unique))                                                                                                                                                                                                                                                                   \
    return_keyword OUTCOME_V2_NAMESPACE::try_operation_return_as(static_cast<decltype(unique) &&>(unique))
    

    and then generate implementations for return and co_return.

    Again this may be a bit silly as it could involve muddying up try.hpp and landing us with some distasteful macro name like OUTCOME_CO_TRY, but I thought I'd mention it all the same.

    enhancement 
    opened by cstratopoulos 13
  • Print useful diagnostic if user attempts to construct a `result<T, T>`

    Print useful diagnostic if user attempts to construct a `result`

    The following fails to compile with quite a long error message:

    #include "outcome.hpp"
    namespace out = OUTCOME_V2_NAMESPACE;
    
    out::result<int, int> fun()
    {
        return out::success(3);
    }
    

    I realize that using result<T, T> is fishy, but you seem to support it: I do not get any error when only declaring this function. Also, when I initialize the object as above, you seem to have sufficient information to know which int I want to initialize.

    Maybe this is just a constructor overload missing?

    enhancement 
    opened by akrzemi1 13
  • TRY/TRYX has dangling reference if xvalues are emitted from tried expression

    TRY/TRYX has dangling reference if xvalues are emitted from tried expression

    When an xvalue reference to temporary is passed to TRYX it creates a dangling reference at auto&& unique = (__VA_ARGS__); as the temporary is destroyed at the semicolon and lifetime extension does not apply.

    bug 
    opened by vasama 12
  • change of no-error path behavior leading to maybe-uninitialized warning

    change of no-error path behavior leading to maybe-uninitialized warning

    Repro and detailed description here:

    https://godbolt.org/z/YG6e8q3Y5

    Except:

    using Result =
        outcome::result<std::tuple<int, std::string>, InHouseErrorz *, MyNVP>;
    
    auto foo() {
        Result r{1, "a"};
        // r = nullptr; //< UNCOMMENT to eliminate warning
        r = {2, "b"};
        return r.assume_value();
    }
    

    Very likely that this is a GCC issue (in fact, can't be reproduced in trunk). Yet, it is a curious phenomenon and causing production hassle with our boost upgrade. I am wondering if this is an expected change with later Outcome versions, or worse and crucially if the usage in the reproduction code is somewhat making incorrect assumptions.

    Or, if there is confirmation this is just a silly GCC bug, it'd be a good enough resolution.

    thanks

    bug 
    opened by slymz 1
  • Enable noexcept unit tests in Boost.Outcome, now exceptions globally disabled works in Boost.Exception

    Enable noexcept unit tests in Boost.Outcome, now exceptions globally disabled works in Boost.Exception

    Compiling with BOOST_NO_EXCEPTIONS procuces the following output:

    /home/bernard/CMakePackageCache/release/extern/Boost/1.73.0/baremetal-cortex-m0-gnu.9/Pkg/include/boost/throw_exception.hpp:180:84: error: no matching function for call to 'throw_exception(const char [24], boost::source_location)'
      180 | #define BOOST_THROW_EXCEPTION(x) ::boost::throw_exception(x, BOOST_CURRENT_LOCATION)
          |                                                                                    ^
    /home/bernard/CMakePackageCache/release/extern/Boost/1.73.0/baremetal-cortex-m0-gnu.9/Pkg/include/boost/outcome/experimental/../config.hpp:320:45: note: in expansion of macro 'BOOST_THROW_EXCEPTION'
      320 | #define BOOST_OUTCOME_THROW_EXCEPTION(expr) BOOST_THROW_EXCEPTION(expr)
          |                                             ^~~~~~~~~~~~~~~~~~~~~
    /home/bernard/CMakePackageCache/release/extern/Boost/1.73.0/baremetal-cortex-m0-gnu.9/Pkg/include/boost/outcome/experimental/status_result.hpp:120:13: note: in expansion of macro 'BOOST_OUTCOME_THROW_EXCEPTION'
      120 |             BOOST_OUTCOME_THROW_EXCEPTION("wide value check failed");
    
    enhancement 
    opened by teajay-fr 8
  • Embed debugging pretty printer for GDB into all Outcome using binaries

    Embed debugging pretty printer for GDB into all Outcome using binaries

    Thanks to Mathias Gaunard for this tip.

    You can embed arbitrary python scripts to be run by gdb on binary load using a bit of inline assembler. See http://sourceware.org/gdb/current/onlinedocs/gdb/dotdebug_005fgdb_005fscripts-section.html

    A GDB pretty printer implementation looks like https://sourceware.org/gdb/onlinedocs/gdb/Writing-a-Pretty_002dPrinter.html#Writing-a-Pretty_002dPrinter

    It should be trivially easy to make one of these using the MSVC debugger pretty printer as a base.

    enhancement 
    opened by ned14 0
  • Add structured bindings compatibility

    Add structured bindings compatibility

    For some odd reason, some odd people want to write:

    [has_error, value, error] = func(...);
    

    ... where func() returns result<T, E>.

    Implementing this is trivial: specialise tuple_size<basic_result<>> to return 3 and implement at<I>(). But I suspect given the dragging in of <tuple>, this support needs its own header file outside the standard set of inclusions.

    enhancement 
    opened by ned14 5
Very Fast Non-Cryptographic Hash Function

KOMIHASH - Very Fast Hash Function Introduction The komihash() function available in the komihash.h file implements a very fast 64-bit hash function,

Aleksey Vaneev 70 Jun 13, 2022
The open source edition of Raising the Bar: Redux's Division 1.2 release.

//===================================================================================================================================================

null 22 Apr 12, 2022
Rajesh Kumar Sah 1 Nov 20, 2021
A fast and efficient non-iterating hashmap library

libhash: a fast and efficient non-iterating hashmap library Libhash is a fast and efficient non-iterating hashmap library Usage Usage is easy and simp

Oğuzhan Eroğlu 5 May 29, 2022
Well Factored, Non-Recursive, General & Generic BSTs in ANSI C

This one set of files implements well factored/layered binary search trees (BSTs) with 5 balancing schemes (none, avl, red-black, L(k), and splay) and

null 2 Dec 7, 2021
A family of header-only, very fast and memory-friendly hashmap and btree containers.

The Parallel Hashmap Overview This repository aims to provide a set of excellent hash map implementations, as well as a btree alternative to std::map

Gregory Popovitch 1.5k Jun 27, 2022
This repository provides implementation of an incremental k-d tree for robotic applications.

ikd-Tree ikd-Tree is an incremental k-d tree designed for robotic applications. The ikd-Tree incrementally updates a k-d tree with new coming points o

HKU-Mars-Lab 290 Jun 21, 2022
lightweight, compile-time and rust-like wrapper around the primitive numerical c++ data types

prim_wrapper header-only, fast, compile-time, rust-like wrapper around the primitive numerical c++ data types dependencies gcem - provides math functi

null 1 Oct 22, 2021
A lightweight library of Behavior Trees Library in C++.

A lightweight behavior tree library in C++. NEWS! ?? Thanks to Davide Faconti there is now a more sophisticated version of the library. The new versio

Michele Colledanchise 157 May 29, 2022
Directed Acyclic Graph Execution Engine (DAGEE) is a C++ library that enables programmers to express computation and data movement, as task graphs that are scheduled concurrently and asynchronously on both CPUs and GPUs.

Directed Acyclic Graph Execution Engine (DAGEE) is a C++ library that enables programmers to express computation and data movement, as tasks in a graph structure, where edges represent task dependencies

null 23 May 11, 2022
Is a linear data structure with O(log n) searches and O(cbrt n) insertions and index lookups.

A binary cube is a linear data structure that contains a sorted two dimensional dynamic array of nodes which each point to a sorted array

null 21 May 17, 2022
Repository of problems and solutions of labsheets used for Data Structures and Algorithms (CS F211) in Semester 2, 2020-21 at BITS Pilani - Hyderabad Campus.

CS F211 Data Structures and Algorithms (BITS Pilani - Hyderabad Campus) This repository contains the problems, solution approaches & explanations and

Rohit Dwivedula 27 Apr 13, 2022
Algo-Tree is a collection of Algorithms and data structures which are fundamentals to efficient code and good software design

Algo-Tree is a collection of Algorithms and data structures which are fundamentals to efficient code and good software design. Creating and designing excellent algorithms is required for being an exemplary programmer. It contains solutions in various languages such as C++, Python and Java.

DSC-Banasthali 53 Jun 12, 2022
C++ DataFrame for statistical, Financial, and ML analysis -- in modern C++ using native types, continuous memory storage, and no pointers are involved

C++ DataFrame for statistical, Financial, and ML analysis -- in modern C++ using native types, continuous memory storage, and no pointers are involved

Hossein Moein 1.5k Jun 21, 2022
Templates, algorithms and data structures implemented and collected for programming contests.

Templates, algorithms and data structures implemented and collected for programming contests.

Shahjalal Shohag 1.8k Jun 27, 2022
This repository aims to contain solutions and explanations to various competitive programming problems, which may be important for interviews and online tests of different companies.

Competitive Programming Solutions Compilation Hello everyone ?? This repository contains solutions and explanations to various competitive programming

Abhinav Agrawal 26 Jun 18, 2022
"Wireless Made Easy!" - Microchip MRF MiWi package is MiWi P2P and Star Stacks for MRF24J40 and MRF89XA transceivers running on MPLAB X IDE

MRF-MiWi "Wireless Made Easy!" - Microchip MiWi P2P and Star Stack Opened for MRF24J40 and MRF89XA transceiver running on MPLAB X IDE Devices: | MRF24

Microchip Technology 2 Dec 28, 2021