Imported Upstream version 1.72.0
[platform/upstream/boost.git] / libs / contract / example / features / throw_on_failure.cpp
1
2 // Copyright (C) 2008-2018 Lorenzo Caminiti
3 // Distributed under the Boost Software License, Version 1.0 (see accompanying
4 // file LICENSE_1_0.txt or a copy at http://www.boost.org/LICENSE_1_0.txt).
5 // See: http://www.boost.org/doc/libs/release/libs/contract/doc/html/index.html
6
7 #include <boost/contract.hpp>
8 #include <iostream>
9 #include <cstring>
10 #include <cassert>
11
12 //[throw_on_failure_class_begin
13 struct too_large_error {};
14
15 template<unsigned MaxSize>
16 class cstring
17     #define BASES private boost::contract::constructor_precondition<cstring< \
18             MaxSize> >
19     : BASES
20 {
21 //]
22 public:
23     typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types;
24     #undef BASES
25
26 //[throw_on_failure_ctor
27 public:
28     /* implicit */ cstring(char const* chars) :
29         boost::contract::constructor_precondition<cstring>([&] {
30             BOOST_CONTRACT_ASSERT(chars); // Throw `assertion_failure`.
31             // Or, throw user-defined exception.
32             if(std::strlen(chars) > MaxSize) throw too_large_error();
33         })
34     {
35 //]
36         boost::contract::check c = boost::contract::constructor(this)
37             .postcondition([&] {
38                 BOOST_CONTRACT_ASSERT(size() == std::strlen(chars));
39             })
40         ;
41
42         size_ = std::strlen(chars);
43         for(unsigned i = 0; i < size_; ++i) chars_[i] = chars[i];
44         chars_[size_] = '\0';
45     }
46     
47 //[throw_on_failure_dtor
48 public:
49     void invariant() const {
50         if(size() > MaxSize) throw too_large_error(); // Throw user-defined ex.
51         BOOST_CONTRACT_ASSERT(chars_); // Or, throw `assertion_failure`.
52         BOOST_CONTRACT_ASSERT(chars_[size()] == '\0');
53     }
54
55     ~cstring() noexcept { // Exception specifiers apply to contract code.
56         // Check invariants.
57         boost::contract::check c = boost::contract::destructor(this);
58     }
59 //]
60
61     unsigned size() const {
62         // Check invariants.
63         boost::contract::check c = boost::contract::public_function(this);
64         return size_;
65     }
66     
67 private:
68     char chars_[MaxSize + 1];
69     unsigned size_;
70 //[throw_on_failure_class_end
71     /* ... */
72 };
73 //]
74
75 void bad_throwing_handler() { // For docs only (not actually used here).
76     //[throw_on_failure_bad_handler
77     /* ... */
78
79     // Warning... might cause destructors to throw (unless declared noexcept).
80     boost::contract::set_invariant_failure(
81         [] (boost::contract::from) {
82             throw; // Throw no matter if from destructor, etc.
83         }
84     );
85
86     /* ... */
87     //]
88 }
89
90 //[throw_on_failure_handlers
91 int main() {
92     boost::contract::set_precondition_failure(
93     boost::contract::set_postcondition_failure(
94     boost::contract::set_invariant_failure(
95     boost::contract::set_old_failure(
96         [] (boost::contract::from where) {
97             if(where == boost::contract::from_destructor) {
98                 // Shall not throw from C++ destructors.
99                 std::clog << "ignored destructor contract failure" << std::endl;
100             } else throw; // Re-throw (assertion_failure, user-defined, etc.).
101         }
102     ))));
103     boost::contract::set_except_failure(
104         [] (boost::contract::from) {
105             // Already an active exception so shall not throw another...
106             std::clog << "ignored exception guarantee failure" << std::endl;
107         }
108     );
109     boost::contract::set_check_failure(
110         [] {
111             // But now CHECK shall not be used in destructor implementations.
112             throw; // Re-throw (assertion_failure, user-defined, etc.).
113         }
114     );
115
116     /* ... */
117 //]
118
119     {
120         cstring<3> s("abc");
121         assert(s.size() == 3);
122     }
123
124     #ifndef BOOST_CONTRACT_NO_PRECONDITIONS
125         // These failures properly handled only when preconditions checked.
126
127         try {
128             char* c = 0;
129             cstring<3> s(c);
130             assert(false);
131         } catch(boost::contract::assertion_failure const& error) {
132             // OK (expected).
133             std::clog << "ignored: " << error.what() << std::endl;
134         } catch(...) { assert(false); }
135         
136         try {
137             cstring<3> s("abcd");
138             assert(false);
139         } catch(too_large_error const&) {} // OK (expected).
140         catch(...) { assert(false); }
141     #endif
142
143     return 0;
144 }
145