]>
Commit | Line | Data |
---|---|---|
20effc67 TL |
1 | // Copyright (c) 2018-2020 Emil Dotchevski and Reverge Studios, Inc. |
2 | ||
3 | // Distributed under the Boost Software License, Version 1.0. (See accompanying | |
4 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | |
5 | ||
6 | // This program demonstrates the use of leaf::on_error to print the path an error takes | |
7 | // as it bubbles up the call stack. The printing code only runs if: | |
8 | // - An error occurs, and | |
9 | // - A handler that takes e_error_log argument is present. | |
10 | // Otherwise none of the error log machinery will be invoked by LEAF. | |
11 | ||
12 | // This example is similar to error_trace, except the path the error takes is not captured, | |
13 | // only printed. | |
14 | ||
15 | #include <boost/leaf/on_error.hpp> | |
16 | #include <boost/leaf/handle_errors.hpp> | |
17 | #include <boost/leaf/result.hpp> | |
18 | #include <iostream> | |
19 | #include <cstdlib> | |
20 | ||
21 | #define ENABLE_ERROR_LOG 1 | |
22 | ||
23 | namespace leaf = boost::leaf; | |
24 | ||
25 | // The error log is activated only if an error-handling scope provides a handler for e_error_log. | |
26 | struct e_error_log | |
27 | { | |
28 | struct rec | |
29 | { | |
30 | char const * file; | |
31 | int line; | |
32 | friend std::ostream & operator<<( std::ostream & os, rec const & x ) | |
33 | { | |
34 | return os << x.file << '(' << x.line << ')'; | |
35 | } | |
36 | }; | |
37 | ||
38 | e_error_log() | |
39 | { | |
40 | std::cerr << "Error! Log:" << std::endl; | |
41 | } | |
42 | ||
43 | // Our e_error_log instance is stateless, used only as a target to operator<<. | |
44 | template <class T> | |
45 | friend std::ostream & operator<<( e_error_log const &, T const & x ) | |
46 | { | |
47 | return std::cerr << x << std::endl; | |
48 | } | |
49 | }; | |
50 | ||
51 | // The ERROR_LOG macro is designed for use in functions that detect or forward errors | |
52 | // up the call stack. If an error occurs, and if an error-handling scope provides a handler | |
53 | // for e_error_log, the supplied lambda is executed as the error bubbles up. | |
54 | #define ERROR_LOG auto _log = leaf::on_error( []( e_error_log & log ) { log << e_error_log::rec{__FILE__, __LINE__}; } ) | |
55 | ||
56 | // Each function in the sequence below calls the previous function, and each function has | |
57 | // failure_percent chance of failing. If a failure occurs, the ERROR_LOG macro will cause | |
58 | // the path the error takes to be printed. | |
59 | int const failure_percent = 25; | |
60 | ||
61 | leaf::result<void> f1() | |
62 | { | |
63 | ERROR_LOG; | |
64 | if( (std::rand()%100) > failure_percent ) | |
65 | return { }; | |
66 | else | |
67 | return leaf::new_error(); | |
68 | } | |
69 | ||
70 | leaf::result<void> f2() | |
71 | { | |
72 | ERROR_LOG; | |
73 | if( (std::rand()%100) > failure_percent ) | |
74 | return f1(); | |
75 | else | |
76 | return leaf::new_error(); | |
77 | } | |
78 | ||
79 | leaf::result<void> f3() | |
80 | { | |
81 | ERROR_LOG; | |
82 | if( (std::rand()%100) > failure_percent ) | |
83 | return f2(); | |
84 | else | |
85 | return leaf::new_error(); | |
86 | } | |
87 | ||
88 | leaf::result<void> f4() | |
89 | { | |
90 | ERROR_LOG; | |
91 | if( (std::rand()%100) > failure_percent ) | |
92 | return f3(); | |
93 | else | |
94 | return leaf::new_error(); | |
95 | } | |
96 | ||
97 | leaf::result<void> f5() | |
98 | { | |
99 | ERROR_LOG; | |
100 | if( (std::rand()%100) > failure_percent ) | |
101 | return f4(); | |
102 | else | |
103 | return leaf::new_error(); | |
104 | } | |
105 | ||
106 | int main() | |
107 | { | |
108 | for( int i=0; i!=10; ++i ) | |
109 | leaf::try_handle_all( | |
110 | [&]() -> leaf::result<void> | |
111 | { | |
112 | std::cout << "Run # " << i << ": "; | |
113 | BOOST_LEAF_CHECK(f5()); | |
114 | std::cout << "Success!" << std::endl; | |
115 | return { }; | |
116 | }, | |
117 | #if ENABLE_ERROR_LOG // This single #if enables or disables the printing of the error log. | |
118 | []( e_error_log const & ) | |
119 | { | |
120 | }, | |
121 | #endif | |
122 | [] | |
123 | { | |
124 | std::cerr << "Error!" << std::endl; | |
125 | } ); | |
126 | return 0; | |
127 | } | |
128 | ||
129 | //////////////////////////////////////// | |
130 | ||
131 | #ifdef BOOST_LEAF_NO_EXCEPTIONS | |
132 | ||
133 | namespace boost | |
134 | { | |
135 | BOOST_LEAF_NORETURN void throw_exception( std::exception const & e ) | |
136 | { | |
137 | std::cerr << "Terminating due to a C++ exception under BOOST_LEAF_NO_EXCEPTIONS: " << e.what(); | |
138 | std::terminate(); | |
139 | } | |
140 | ||
141 | struct source_location; | |
142 | BOOST_LEAF_NORETURN void throw_exception( std::exception const & e, boost::source_location const & ) | |
143 | { | |
144 | throw_exception(e); | |
145 | } | |
146 | } | |
147 | ||
148 | #endif |