]>
Commit | Line | Data |
---|---|---|
1e59de90 | 1 | // Copyright 2018-2022 Emil Dotchevski and Reverge Studios, Inc. |
20effc67 TL |
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 | ||
1e59de90 TL |
6 | // This program demonstrates the use of leaf::on_error to capture the path an |
7 | // error takes as is bubbles up the call stack. The error path-capturing code | |
8 | // only runs if: | |
20effc67 | 9 | // - An error occurs, and |
1e59de90 TL |
10 | // - A handler that takes e_error_trace argument is present. Otherwise none of |
11 | // the error trace machinery will be invoked by LEAF. | |
20effc67 | 12 | |
1e59de90 TL |
13 | // This example is similar to error_log, except the path the error takes is |
14 | // recorded in a std::deque, rather than just printed in-place. | |
20effc67 | 15 | |
1e59de90 | 16 | #include <boost/leaf.hpp> |
20effc67 TL |
17 | #include <iostream> |
18 | #include <deque> | |
19 | #include <cstdlib> | |
20 | ||
21 | #define ENABLE_ERROR_TRACE 1 | |
22 | ||
23 | namespace leaf = boost::leaf; | |
24 | ||
1e59de90 TL |
25 | // The error trace is activated only if an error handling scope provides a |
26 | // handler for e_error_trace. | |
20effc67 TL |
27 | struct e_error_trace |
28 | { | |
29 | struct rec | |
30 | { | |
31 | char const * file; | |
32 | int line; | |
33 | friend std::ostream & operator<<( std::ostream & os, rec const & x ) | |
34 | { | |
35 | return os << x.file << '(' << x.line << ')' << std::endl; | |
36 | } | |
37 | }; | |
38 | ||
39 | std::deque<rec> value; | |
40 | ||
41 | friend std::ostream & operator<<( std::ostream & os, e_error_trace const & tr ) | |
42 | { | |
43 | for( auto & i : tr.value ) | |
44 | os << i; | |
45 | return os; | |
46 | } | |
47 | }; | |
48 | ||
1e59de90 TL |
49 | // The ERROR_TRACE macro is designed for use in functions that detect or forward |
50 | // errors up the call stack. If an error occurs, and if an error handling scope | |
51 | // provides a handler for e_error_trace, the supplied lambda is executed as the | |
52 | // error bubbles up. | |
20effc67 TL |
53 | #define ERROR_TRACE auto _trace = leaf::on_error( []( e_error_trace & tr ) { tr.value.emplace_front(e_error_trace::rec{__FILE__, __LINE__}); } ) |
54 | ||
1e59de90 TL |
55 | // Each function in the sequence below calls the previous function, and each |
56 | // function has failure_percent chance of failing. If a failure occurs, the | |
57 | // ERROR_TRACE macro will cause the path the error takes to be captured in an | |
58 | // e_error_trace. | |
20effc67 TL |
59 | int const failure_percent = 25; |
60 | ||
61 | leaf::result<void> f1() | |
62 | { | |
63 | ERROR_TRACE; | |
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_TRACE; | |
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_TRACE; | |
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_TRACE; | |
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_TRACE; | |
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_TRACE // This single #if enables or disables the capturing of the error trace. | |
118 | []( e_error_trace const & tr ) | |
119 | { | |
120 | std::cerr << "Error! Trace:" << std::endl << tr; | |
121 | }, | |
122 | #endif | |
123 | [] | |
124 | { | |
125 | std::cerr << "Error!" << std::endl; | |
126 | } ); | |
127 | return 0; | |
128 | } | |
129 | ||
130 | //////////////////////////////////////// | |
131 | ||
132 | #ifdef BOOST_LEAF_NO_EXCEPTIONS | |
133 | ||
134 | namespace boost | |
135 | { | |
136 | BOOST_LEAF_NORETURN void throw_exception( std::exception const & e ) | |
137 | { | |
138 | std::cerr << "Terminating due to a C++ exception under BOOST_LEAF_NO_EXCEPTIONS: " << e.what(); | |
139 | std::terminate(); | |
140 | } | |
141 | ||
142 | struct source_location; | |
143 | BOOST_LEAF_NORETURN void throw_exception( std::exception const & e, boost::source_location const & ) | |
144 | { | |
145 | throw_exception(e); | |
146 | } | |
147 | } | |
148 | ||
149 | #endif |