cppx-core
hopefully_and_fail.hpp
Go to the documentation of this file.
1 #pragma once // Source encoding: UTF-8 with BOM (π is a lowercase Greek "pi").
2 
3 #include <cppx-core/failure-handling/Abstract_source_location.hpp> // cppx::Abstract_source_location
4 #include <cppx-core/language/syntax/all.hpp> // CPPX_USE_STD, [[noreturn]]
5 #include <cppx-core/language/types/Truth.hpp> // cppx::Truth
6 
7 #include <stdexcept> // std::runtime_error
8 #include <exception> // std::throw_with_nested
9 #include <string> // std::string
10 
11 namespace cppx
12 {
13  inline namespace hopefully_and_fail {} // See bottom part of this file.
14 
15  namespace hf
16  {
17  CPPX_USE_STD( current_exception, runtime_error, string, throw_with_nested );
18 
19  //------------------------------------------ hopefully & fail
20  //
21  // The default `fail` function's exception can be caught as a `std::runtime_error`.
22  // It's the current exception, if any, that's nested. And the nested exception
23  // /can/ just be ignored at the exception handling site.
24  //
25  // The rationale of the nesting is to not discard useful information even though
26  // it carries some overhead, because throwing should be rare, not the normal case.
27  //
28  // Typical usage patterns:
29  //
30  // 1;
31  // getline( cin, s )
32  // or fail( "foo - getline failed" );
33  //
34  // 2;
35  // const ptrdiff_t n_values = to_wide_from_utf8( &s[0], &wide_s[0] );
36  // hopefully( n_values >= 0 )
37  // or fail( "foo - to_wide_from_utf8 failed" );
38  // wide_s.resize( n_values );
39  //
40  // In future `fail` may be extended to support error codes by throwing a
41  // `std::system_error`, which is derived from `std::runtime_error` and carries an
42  // error code.
43 
44  inline auto hopefully( const Truth condition )
45  -> Truth
46  { return condition; }
47 
48  template< class X = runtime_error >
49  [[noreturn]]
50  inline auto fail( const string& message )
51  -> Truth
52  {
53  // This checking is necessary for MinGW g++ 8.2.0. Not sure if the standard
54  // requires it. It would be a design to attract bugs, if it were required.
55 
56  const Truth in_exception_handling = (std::current_exception() != nullptr);
57  if( in_exception_handling )
58  {
59  throw_with_nested( X( message ) );
60  }
61  else
62  {
63  throw X( message );
64  }
65  }
66 
67  template< class X = runtime_error >
68  [[noreturn]]
69  inline auto fail( const string& message, const Abstract_source_location& throw_point )
70  -> Truth
71  {
72  fail<X>( string()
73  + throw_point.function_name_or_unspecified() + " - " + message + "\n"
74  + string( 4, ' ' ) + ">" + throw_point.file_and_line()
75  );
76  }
77 
78  //------------------------------------------ Success, Failure & `>>`
79  //
80  // A unified notation that provides separation of failure /checking/ and
81  // /throwing/ of exception with possibly costly to construct arguments.
82  //
83  // Typical usage patterns, here using a Windows' function that returns `HRESULT`:
84  //
85  // auto operator>>( const HRESULT hr, Success )
86  // -> Truth
87  // { return SUCCEEDED( hr ); }
88  //
89  // //...
90  // CoInitialize( nullptr, COINIT_MULTITHREADED )
91  // >> Success() or fail( "main - CoInitialize failed" );
92  //
93  // Since the `or` is the built-in `or` the arguments to `fail` are only evaluated
94  // in the case of failure, which means the normal case is efficient.
95 
96  struct Success{};
97  struct Failure{};
98 
99  template< class Value >
100  auto operator>>( const Value& v, Failure )
101  -> Truth
102  { return not (v >> Success{}); }
103  } // namespace hf
104 
105  inline namespace hopefully_and_fail {
106 
107  using hf::hopefully;
108  using hf::fail;
109 
110  using hf::Success;
111  using hf::Failure;
112  using hf::operator>>;
113 
114  } // inline namespace hopefully_and_fail
115 } // namespace cppx
auto fail(const string &message) -> Truth
A drop-in replacement for bool without implicit conversion from/to types other than bool.
Definition: Truth.hpp:34
CPPX_USE_STD(current_exception, runtime_error, string, throw_with_nested)
auto hopefully(const Truth condition) -> Truth
Truth is a drop-in replacement for bool without implicit conversion from/to types other than bool.
auto operator>>(const Value &v, Failure) -> Truth