1 /*
2 * RESTinio
3 */
4
5 /*!
6 * @file
7 * @brief Detection of compiler version and absence of various features.
8 *
9 * @since v.0.6.0
10 */
11
12 #pragma once
13
14 #include <utility>
15
16 // Try to use __has_cpp_attribute if it is supported.
17 #if defined(__has_cpp_attribute)
18 // clang-4 and clang-5 produce warnings when [[nodiscard]]
19 // is used with -std=c++11 and -std=c++14.
20 #if __has_cpp_attribute(nodiscard) && \
21 !(defined(__clang__) && __cplusplus < 201703L)
22 #define RESTINIO_NODISCARD [[nodiscard]]
23 #endif
24
25 #if __has_cpp_attribute(fallthrough) && \
26 !(defined(__clang__) && __cplusplus < 201703L)
27 #define RESTINIO_FALLTHROUGH [[fallthrough]]
28 #endif
29 #endif
30
31 // Handle the result of __has_cpp_attribute.
32 #if !defined( RESTINIO_NODISCARD )
33 #define RESTINIO_NODISCARD
34 #endif
35
36 #if !defined( RESTINIO_FALLTHROUGH )
37 #define RESTINIO_FALLTHROUGH
38 #endif
39
40 /*!
41 * @brief A wrapper around static_assert for checking that an expression
42 * is noexcept and execution of that expression
43 *
44 * Usage example:
45 * @code
46 * some_class::~some_class() noexcept {
47 * // We should have a guarantee that this call doesn't throw.
48 * RESTINIO_ENSURE_NOEXCEPT_CALL(m_some_resouce.release());
49 * ...
50 * }
51 * @endcode
52 *
53 * @attention
54 * This macro is a part of RESTinio and is not intended to be uses as
55 * a part of public API. It can be changed or remove in some future version
56 * without any prior notice.
57 *
58 * @since v.0.6.0
59 */
60 #define RESTINIO_ENSURE_NOEXCEPT_CALL(expr) \
61 static_assert(noexcept(expr), "this call is expected to be noexcept: " #expr); \
62 expr
63
64 /*!
65 * @brief A wrapper around static_assert for checking that an expression is
66 * noexcept
67 *
68 * Usage example:
69 * @code
70 * void remove_appropriate_items_at_front(some_container_t & cnt) noexcept {
71 * RESTINIO_STATIC_ASSERT_NOEXCEPT(cnt.empty());
72 * RESTINIO_STATIC_ASSERT_NOEXCEPT(cnt.front());
73 * RESTINIO_STATIC_ASSERT_NOEXCEPT(cnt.pop_front());
74 *
75 * while(!cnt.empty() && some_confitions(cnt.front()) {
76 * // We don't expect exceptions here.
77 * cnt.pop_front();
78 * }
79 * }
80 * @endcode
81 *
82 * @attention
83 * This macro is a part of RESTinio and is not intended to be uses as
84 * a part of public API. It can be changed or remove in some future version
85 * without any prior notice.
86 *
87 * @since v.0.6.0
88 */
89 #define RESTINIO_STATIC_ASSERT_NOEXCEPT(expr) \
90 static_assert(noexcept(expr), #expr " is expected to be noexcept" )
91
92 /*!
93 * @brief A wrapper around static_assert for checking that an expression is
94 * not noexcept.
95 *
96 * Usage example:
97 * @code
98 * some_class::~some_class() noexcept {
99 * // If that call throws then we have to use try-catch block.
100 * RESTINIO_STATIC_ASSERT_NOT_NOEXCEPT(m_some_resouce.release());
101 * try {
102 * m_some_resouce.release();
103 * }
104 * catch(...) {}
105 * ...
106 * }
107 * @endcode
108 *
109 * @attention
110 * This macro is a part of RESTinio and is not intended to be uses as
111 * a part of public API. It can be changed or remove in some future version
112 * without any prior notice.
113 *
114 * @since v.0.6.0
115 */
116 #define RESTINIO_STATIC_ASSERT_NOT_NOEXCEPT(expr) \
117 static_assert(!noexcept(expr), #expr " is not expected to be noexcept" )
118
119 namespace restinio
120 {
121
122 namespace static_if_details
123 {
124
125 template< bool Condition >
126 struct static_if_impl;
127
128 template<>
129 struct static_if_impl<true>
130 {
131 template<typename If_Part, typename Else_Part>
132 static decltype(auto)
callrestinio::static_if_details::static_if_impl133 call( If_Part && if_part, Else_Part && )
134 {
135 return if_part();
136 }
137 };
138
139 template<>
140 struct static_if_impl<false>
141 {
142 template<typename If_Part, typename Else_Part>
143 static decltype(auto)
callrestinio::static_if_details::static_if_impl144 call( If_Part &&, Else_Part && else_part )
145 {
146 return else_part();
147 }
148 };
149
150 } /* namespace static_if_details */
151
152 //
153 // static_if_else
154 //
155 /*!
156 * @brief An emulation of if constexpr for C++14.
157 *
158 * Usage example:
159 * @code
160 * static_if_else< noexcept(some-expression) >(
161 * []() noexcept {
162 * ... // Some action that doesn't throw.
163 * },
164 * [] {
165 * try {
166 * ... // Some action that throws.
167 * }
168 * catch(...) {}
169 * });
170 * @endcode
171 *
172 * @since v.0.6.1.1
173 */
174 template< bool Condition, typename If_Part, typename Else_Part >
175 decltype(auto)
static_if_else(If_Part && if_part,Else_Part && else_part)176 static_if_else( If_Part && if_part, Else_Part && else_part )
177 {
178 return static_if_details::static_if_impl<Condition>::call(
179 std::forward<If_Part>(if_part),
180 std::forward<Else_Part>(else_part) );
181 }
182
183 } /* namespace restinio */
184
185