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