1 | // Copyright (C) 2015-2018 Andrzej Krzemienski. |
2 | // |
3 | // Use, modification, and distribution is subject to the Boost Software |
4 | // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at |
5 | // http://www.boost.org/LICENSE_1_0.txt) |
6 | // |
7 | // See http://www.boost.org/libs/optional for documentation. |
8 | // |
9 | // You are welcome to contact the author at: |
10 | // akrzemi1@gmail.com |
11 | |
12 | #ifndef BOOST_OPTIONAL_DETAIL_OPTIONAL_REFERENCE_SPEC_AJK_03OCT2015_HPP |
13 | #define BOOST_OPTIONAL_DETAIL_OPTIONAL_REFERENCE_SPEC_AJK_03OCT2015_HPP |
14 | |
15 | #ifdef BOOST_OPTIONAL_CONFIG_NO_PROPER_ASSIGN_FROM_CONST_INT |
16 | #include <boost/type_traits/is_integral.hpp> |
17 | #include <boost/type_traits/is_const.hpp> |
18 | #endif |
19 | |
20 | # if 1 |
21 | |
22 | namespace boost { |
23 | |
24 | namespace detail { |
25 | |
26 | #ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES |
27 | |
28 | template <class From> |
29 | void prevent_binding_rvalue() |
30 | { |
31 | #ifndef BOOST_OPTIONAL_CONFIG_ALLOW_BINDING_TO_RVALUES |
32 | BOOST_STATIC_ASSERT_MSG(boost::is_lvalue_reference<From>::value, |
33 | "binding rvalue references to optional lvalue references is disallowed" ); |
34 | #endif |
35 | } |
36 | |
37 | template <class T> |
38 | BOOST_DEDUCED_TYPENAME boost::remove_reference<T>::type& forward_reference(T&& r) |
39 | { |
40 | BOOST_STATIC_ASSERT_MSG(boost::is_lvalue_reference<T>::value, |
41 | "binding rvalue references to optional lvalue references is disallowed" ); |
42 | return boost::forward<T>(r); |
43 | } |
44 | |
45 | #endif // BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES |
46 | |
47 | |
48 | template <class T> |
49 | struct is_const_integral |
50 | { |
51 | static const bool value = boost::is_const<T>::value && boost::is_integral<T>::value; |
52 | }; |
53 | |
54 | template <class T> |
55 | struct is_const_integral_bad_for_conversion |
56 | { |
57 | #if (!defined BOOST_OPTIONAL_CONFIG_ALLOW_BINDING_TO_RVALUES) && (defined BOOST_OPTIONAL_CONFIG_NO_PROPER_CONVERT_FROM_CONST_INT) |
58 | static const bool value = boost::is_const<T>::value && boost::is_integral<T>::value; |
59 | #else |
60 | static const bool value = false; |
61 | #endif |
62 | }; |
63 | |
64 | template <class From> |
65 | void prevent_assignment_from_false_const_integral() |
66 | { |
67 | #ifndef BOOST_OPTIONAL_CONFIG_ALLOW_BINDING_TO_RVALUES |
68 | #ifdef BOOST_OPTIONAL_CONFIG_NO_PROPER_ASSIGN_FROM_CONST_INT |
69 | // MSVC compiler without rvalue refernces: we need to disable the asignment from |
70 | // const integral lvalue reference, as it may be an invalid temporary |
71 | BOOST_STATIC_ASSERT_MSG(!is_const_integral<From>::value, |
72 | "binding const lvalue references to integral types is disabled in this compiler" ); |
73 | #endif |
74 | #endif |
75 | } |
76 | |
77 | |
78 | template <class T> |
79 | struct is_optional_ |
80 | { |
81 | static const bool value = false; |
82 | }; |
83 | |
84 | template <class U> |
85 | struct is_optional_< ::boost::optional<U> > |
86 | { |
87 | static const bool value = true; |
88 | }; |
89 | |
90 | template <class T> |
91 | struct is_no_optional |
92 | { |
93 | static const bool value = !is_optional_<BOOST_DEDUCED_TYPENAME boost::decay<T>::type>::value; |
94 | }; |
95 | |
96 | |
97 | template <class T, class U> |
98 | struct is_same_decayed |
99 | { |
100 | static const bool value = ::boost::is_same<T, BOOST_DEDUCED_TYPENAME ::boost::remove_reference<U>::type>::value |
101 | || ::boost::is_same<T, const BOOST_DEDUCED_TYPENAME ::boost::remove_reference<U>::type>::value; |
102 | }; |
103 | |
104 | template <class T, class U> |
105 | struct no_unboxing_cond |
106 | { |
107 | static const bool value = is_no_optional<U>::value && !is_same_decayed<T, U>::value; |
108 | }; |
109 | |
110 | |
111 | } // namespace detail |
112 | |
113 | template <class T> |
114 | class optional<T&> : public optional_detail::optional_tag |
115 | { |
116 | T* ptr_; |
117 | |
118 | public: |
119 | typedef T& value_type; |
120 | typedef T& reference_type; |
121 | typedef T& reference_const_type; |
122 | typedef T& rval_reference_type; |
123 | typedef T* pointer_type; |
124 | typedef T* pointer_const_type; |
125 | |
126 | optional() BOOST_NOEXCEPT : ptr_() {} |
127 | optional(none_t) BOOST_NOEXCEPT : ptr_() {} |
128 | |
129 | template <class U> |
130 | explicit optional(const optional<U&>& rhs) BOOST_NOEXCEPT : ptr_(rhs.get_ptr()) {} |
131 | optional(const optional& rhs) BOOST_NOEXCEPT : ptr_(rhs.get_ptr()) {} |
132 | |
133 | // the following two implement a 'conditionally explicit' constructor: condition is a hack for buggy compilers with srewed conversion construction from const int |
134 | template <class U> |
135 | explicit optional(U& rhs, BOOST_DEDUCED_TYPENAME boost::enable_if_c<detail::is_same_decayed<T, U>::value && detail::is_const_integral_bad_for_conversion<U>::value, bool>::type = true) BOOST_NOEXCEPT |
136 | : ptr_(boost::addressof(rhs)) {} |
137 | |
138 | template <class U> |
139 | optional(U& rhs, BOOST_DEDUCED_TYPENAME boost::enable_if_c<detail::is_same_decayed<T, U>::value && !detail::is_const_integral_bad_for_conversion<U>::value, bool>::type = true) BOOST_NOEXCEPT |
140 | : ptr_(boost::addressof(rhs)) {} |
141 | |
142 | optional& operator=(const optional& rhs) BOOST_NOEXCEPT { ptr_ = rhs.get_ptr(); return *this; } |
143 | template <class U> |
144 | optional& operator=(const optional<U&>& rhs) BOOST_NOEXCEPT { ptr_ = rhs.get_ptr(); return *this; } |
145 | optional& operator=(none_t) BOOST_NOEXCEPT { ptr_ = 0; return *this; } |
146 | |
147 | |
148 | void swap(optional& rhs) BOOST_NOEXCEPT { std::swap(ptr_, rhs.ptr_); } |
149 | T& get() const { BOOST_ASSERT(ptr_); return *ptr_; } |
150 | |
151 | T* get_ptr() const BOOST_NOEXCEPT { return ptr_; } |
152 | T* operator->() const { BOOST_ASSERT(ptr_); return ptr_; } |
153 | T& operator*() const { BOOST_ASSERT(ptr_); return *ptr_; } |
154 | T& value() const { return ptr_ ? *ptr_ : (throw_exception(e: bad_optional_access()), *ptr_); } |
155 | |
156 | bool operator!() const BOOST_NOEXCEPT { return ptr_ == 0; } |
157 | BOOST_EXPLICIT_OPERATOR_BOOL_NOEXCEPT() |
158 | |
159 | void reset() BOOST_NOEXCEPT { ptr_ = 0; } |
160 | |
161 | bool is_initialized() const BOOST_NOEXCEPT { return ptr_ != 0; } |
162 | bool has_value() const BOOST_NOEXCEPT { return ptr_ != 0; } |
163 | |
164 | template <typename F> |
165 | optional<typename boost::result_of<F(T&)>::type> map(F f) const |
166 | { |
167 | if (this->has_value()) |
168 | return f(this->get()); |
169 | else |
170 | return none; |
171 | } |
172 | |
173 | template <typename F> |
174 | optional<typename optional_detail::optional_value_type<typename boost::result_of<F(T&)>::type>::type> flat_map(F f) const |
175 | { |
176 | if (this->has_value()) |
177 | return f(get()); |
178 | else |
179 | return none; |
180 | } |
181 | |
182 | #ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES |
183 | |
184 | optional(T&& /* rhs */) BOOST_NOEXCEPT { detail::prevent_binding_rvalue<T&&>(); } |
185 | |
186 | template <class R> |
187 | optional(R&& r, BOOST_DEDUCED_TYPENAME boost::enable_if<detail::no_unboxing_cond<T, R>, bool>::type = true) BOOST_NOEXCEPT |
188 | : ptr_(boost::addressof(r)) { detail::prevent_binding_rvalue<R>(); } |
189 | |
190 | template <class R> |
191 | optional(bool cond, R&& r, BOOST_DEDUCED_TYPENAME boost::enable_if<detail::is_no_optional<R>, bool>::type = true) BOOST_NOEXCEPT |
192 | : ptr_(cond ? boost::addressof(r) : 0) { detail::prevent_binding_rvalue<R>(); } |
193 | |
194 | template <class R> |
195 | BOOST_DEDUCED_TYPENAME boost::enable_if<detail::is_no_optional<R>, optional<T&>&>::type |
196 | operator=(R&& r) BOOST_NOEXCEPT { detail::prevent_binding_rvalue<R>(); ptr_ = boost::addressof(r); return *this; } |
197 | |
198 | template <class R> |
199 | void emplace(R&& r, BOOST_DEDUCED_TYPENAME boost::enable_if<detail::is_no_optional<R>, bool>::type = true) BOOST_NOEXCEPT |
200 | { detail::prevent_binding_rvalue<R>(); ptr_ = boost::addressof(r); } |
201 | |
202 | template <class R> |
203 | T& get_value_or(R&& r, BOOST_DEDUCED_TYPENAME boost::enable_if<detail::is_no_optional<R>, bool>::type = true) const BOOST_NOEXCEPT |
204 | { detail::prevent_binding_rvalue<R>(); return ptr_ ? *ptr_ : r; } |
205 | |
206 | template <class R> |
207 | T& value_or(R&& r, BOOST_DEDUCED_TYPENAME boost::enable_if<detail::is_no_optional<R>, bool>::type = true) const BOOST_NOEXCEPT |
208 | { detail::prevent_binding_rvalue<R>(); return ptr_ ? *ptr_ : r; } |
209 | |
210 | template <class R> |
211 | void reset(R&& r, BOOST_DEDUCED_TYPENAME boost::enable_if<detail::is_no_optional<R>, bool>::type = true) BOOST_NOEXCEPT |
212 | { detail::prevent_binding_rvalue<R>(); ptr_ = boost::addressof(r); } |
213 | |
214 | template <class F> |
215 | T& value_or_eval(F f) const { return ptr_ ? *ptr_ : detail::forward_reference(f()); } |
216 | |
217 | #else // BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES |
218 | |
219 | |
220 | // the following two implement a 'conditionally explicit' constructor |
221 | template <class U> |
222 | explicit optional(U& v, BOOST_DEDUCED_TYPENAME boost::enable_if_c<detail::no_unboxing_cond<T, U>::value && detail::is_const_integral_bad_for_conversion<U>::value, bool>::type = true) BOOST_NOEXCEPT |
223 | : ptr_(boost::addressof(v)) { } |
224 | |
225 | template <class U> |
226 | optional(U& v, BOOST_DEDUCED_TYPENAME boost::enable_if_c<detail::no_unboxing_cond<T, U>::value && !detail::is_const_integral_bad_for_conversion<U>::value, bool>::type = true) BOOST_NOEXCEPT |
227 | : ptr_(boost::addressof(v)) { } |
228 | |
229 | template <class U> |
230 | optional(bool cond, U& v, BOOST_DEDUCED_TYPENAME boost::enable_if<detail::is_no_optional<U>, bool>::type = true) BOOST_NOEXCEPT : ptr_(cond ? boost::addressof(v) : 0) {} |
231 | |
232 | template <class U> |
233 | BOOST_DEDUCED_TYPENAME boost::enable_if<detail::is_no_optional<U>, optional<T&>&>::type |
234 | operator=(U& v) BOOST_NOEXCEPT |
235 | { |
236 | detail::prevent_assignment_from_false_const_integral<U>(); |
237 | ptr_ = boost::addressof(v); return *this; |
238 | } |
239 | |
240 | template <class U> |
241 | void emplace(U& v, BOOST_DEDUCED_TYPENAME boost::enable_if<detail::is_no_optional<U>, bool>::type = true) BOOST_NOEXCEPT |
242 | { ptr_ = boost::addressof(v); } |
243 | |
244 | template <class U> |
245 | T& get_value_or(U& v, BOOST_DEDUCED_TYPENAME boost::enable_if<detail::is_no_optional<U>, bool>::type = true) const BOOST_NOEXCEPT |
246 | { return ptr_ ? *ptr_ : v; } |
247 | |
248 | template <class U> |
249 | T& value_or(U& v, BOOST_DEDUCED_TYPENAME boost::enable_if<detail::is_no_optional<U>, bool>::type = true) const BOOST_NOEXCEPT |
250 | { return ptr_ ? *ptr_ : v; } |
251 | |
252 | template <class U> |
253 | void reset(U& v, BOOST_DEDUCED_TYPENAME boost::enable_if<detail::is_no_optional<U>, bool>::type = true) BOOST_NOEXCEPT |
254 | { ptr_ = boost::addressof(v); } |
255 | |
256 | template <class F> |
257 | T& value_or_eval(F f) const { return ptr_ ? *ptr_ : f(); } |
258 | |
259 | #endif // BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES |
260 | }; |
261 | |
262 | template <class T> |
263 | void swap ( optional<T&>& x, optional<T&>& y) BOOST_NOEXCEPT |
264 | { |
265 | x.swap(y); |
266 | } |
267 | |
268 | } // namespace boost |
269 | |
270 | #endif // 1/0 |
271 | |
272 | #endif // header guard |
273 | |