1 | // <experimental/propagate_const> -*- C++ -*- |
2 | |
3 | // Copyright (C) 2015-2021 Free Software Foundation, Inc. |
4 | // |
5 | // This file is part of the GNU ISO C++ Library. This library is free |
6 | // software; you can redistribute it and/or modify it under the |
7 | // terms of the GNU General Public License as published by the |
8 | // Free Software Foundation; either version 3, or (at your option) |
9 | // any later version. |
10 | |
11 | // This library is distributed in the hope that it will be useful, |
12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | // GNU General Public License for more details. |
15 | |
16 | // Under Section 7 of GPL version 3, you are granted additional |
17 | // permissions described in the GCC Runtime Library Exception, version |
18 | // 3.1, as published by the Free Software Foundation. |
19 | |
20 | // You should have received a copy of the GNU General Public License and |
21 | // a copy of the GCC Runtime Library Exception along with this program; |
22 | // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see |
23 | // <http://www.gnu.org/licenses/>. |
24 | |
25 | /** @file experimental/propagate_const |
26 | * This is a TS C++ Library header. |
27 | * @ingroup libfund-ts |
28 | */ |
29 | |
30 | #ifndef _GLIBCXX_EXPERIMENTAL_PROPAGATE_CONST |
31 | #define _GLIBCXX_EXPERIMENTAL_PROPAGATE_CONST 1 |
32 | |
33 | #pragma GCC system_header |
34 | |
35 | #if __cplusplus >= 201402L |
36 | |
37 | #include <type_traits> |
38 | #include <bits/functional_hash.h> |
39 | #include <bits/move.h> |
40 | #include <bits/stl_function.h> |
41 | #include <experimental/bits/lfts_config.h> |
42 | |
43 | namespace std _GLIBCXX_VISIBILITY(default) |
44 | { |
45 | _GLIBCXX_BEGIN_NAMESPACE_VERSION |
46 | |
47 | namespace experimental |
48 | { |
49 | inline namespace fundamentals_v2 |
50 | { |
51 | /** |
52 | * @defgroup propagate_const Const-propagating wrapper |
53 | * @ingroup libfund-ts |
54 | * |
55 | * A const-propagating wrapper that propagates const to pointer-like members, |
56 | * as described in n4388 "A Proposal to Add a Const-Propagating Wrapper |
57 | * to the Standard Library". |
58 | * |
59 | * @{ |
60 | */ |
61 | |
62 | /// Const-propagating wrapper. |
63 | template <typename _Tp> |
64 | class propagate_const |
65 | { |
66 | public: |
67 | typedef remove_reference_t<decltype(*std::declval<_Tp&>())> element_type; |
68 | |
69 | private: |
70 | template <typename _Up> |
71 | struct __is_propagate_const : false_type |
72 | { }; |
73 | |
74 | template <typename _Up> |
75 | struct __is_propagate_const<propagate_const<_Up>> : true_type |
76 | { }; |
77 | |
78 | template <typename _Up> |
79 | friend constexpr const _Up& |
80 | get_underlying(const propagate_const<_Up>& __pt) noexcept; |
81 | template <typename _Up> |
82 | friend constexpr _Up& |
83 | get_underlying(propagate_const<_Up>& __pt) noexcept; |
84 | |
85 | template <typename _Up> |
86 | static constexpr element_type* |
87 | __to_raw_pointer(_Up* __u) |
88 | { return __u; } |
89 | |
90 | template <typename _Up> |
91 | static constexpr element_type* |
92 | __to_raw_pointer(_Up& __u) |
93 | { return __u.get(); } |
94 | |
95 | template <typename _Up> |
96 | static constexpr const element_type* |
97 | __to_raw_pointer(const _Up* __u) |
98 | { return __u; } |
99 | |
100 | template <typename _Up> |
101 | static constexpr const element_type* |
102 | __to_raw_pointer(const _Up& __u) |
103 | { return __u.get(); } |
104 | |
105 | public: |
106 | static_assert(__and_<is_object<typename remove_pointer<_Tp>::type>, |
107 | __not_<is_array<_Tp>>, |
108 | __or_<is_class<_Tp>, is_pointer<_Tp>>>::value, |
109 | "propagate_const requires a class or a pointer to an" |
110 | " object type" ); |
111 | |
112 | // [propagate_const.ctor], constructors |
113 | constexpr propagate_const() = default; |
114 | propagate_const(const propagate_const& __p) = delete; |
115 | constexpr propagate_const(propagate_const&& __p) = default; |
116 | |
117 | template <typename _Up, typename |
118 | enable_if<__and_<is_constructible<_Tp, _Up&&>, |
119 | is_convertible<_Up&&, _Tp>>::value, bool |
120 | >::type=true> |
121 | constexpr propagate_const(propagate_const<_Up>&& __pu) |
122 | : _M_t(std::move(get_underlying(__pu))) |
123 | {} |
124 | |
125 | template <typename _Up, typename |
126 | enable_if<__and_<is_constructible<_Tp, _Up&&>, |
127 | __not_<is_convertible<_Up&&, _Tp>>>::value, |
128 | bool>::type=false> |
129 | constexpr explicit propagate_const(propagate_const<_Up>&& __pu) |
130 | : _M_t(std::move(get_underlying(__pu))) |
131 | {} |
132 | |
133 | template <typename _Up, typename |
134 | enable_if<__and_<is_constructible<_Tp, _Up&&>, |
135 | is_convertible<_Up&&, _Tp>, |
136 | __not_<__is_propagate_const< |
137 | typename decay<_Up>::type>> |
138 | >::value, bool>::type=true> |
139 | constexpr propagate_const(_Up&& __u) |
140 | : _M_t(std::forward<_Up>(__u)) |
141 | {} |
142 | |
143 | template <typename _Up, typename |
144 | enable_if<__and_<is_constructible<_Tp, _Up&&>, |
145 | __not_<is_convertible<_Up&&, _Tp>>, |
146 | __not_<__is_propagate_const< |
147 | typename decay<_Up>::type>> |
148 | >::value, bool>::type=false> |
149 | constexpr explicit propagate_const(_Up&& __u) |
150 | : _M_t(std::forward<_Up>(__u)) |
151 | {} |
152 | |
153 | // [propagate_const.assignment], assignment |
154 | propagate_const& operator=(const propagate_const& __p) = delete; |
155 | constexpr propagate_const& operator=(propagate_const&& __p) = default; |
156 | |
157 | template <typename _Up, typename = |
158 | typename enable_if<is_convertible<_Up&&, _Tp>::value>::type> |
159 | constexpr propagate_const& operator=(propagate_const<_Up>&& __pu) |
160 | { |
161 | _M_t = std::move(get_underlying(__pu)); |
162 | return *this; |
163 | } |
164 | |
165 | template <typename _Up, typename = |
166 | typename enable_if<__and_<is_convertible<_Up&&, _Tp>, |
167 | __not_<__is_propagate_const< |
168 | typename decay<_Up>::type>> |
169 | >::value>::type> |
170 | constexpr propagate_const& operator=(_Up&& __u) |
171 | { |
172 | _M_t = std::forward<_Up>(__u); |
173 | return *this; |
174 | } |
175 | |
176 | // [propagate_const.const_observers], const observers |
177 | explicit constexpr operator bool() const |
178 | { |
179 | return bool(_M_t); |
180 | } |
181 | |
182 | constexpr const element_type* operator->() const |
183 | { |
184 | return get(); |
185 | } |
186 | |
187 | template <typename _Up = _Tp, |
188 | typename enable_if<__or_<is_pointer<_Up>, |
189 | is_convertible<_Up, |
190 | const element_type*> |
191 | >::value, bool>::type = true> |
192 | constexpr operator const element_type*() const |
193 | { |
194 | return get(); |
195 | } |
196 | |
197 | constexpr const element_type& operator*() const |
198 | { |
199 | return *get(); |
200 | } |
201 | |
202 | constexpr const element_type* get() const |
203 | { |
204 | return __to_raw_pointer(_M_t); |
205 | } |
206 | |
207 | // [propagate_const.non_const_observers], non-const observers |
208 | constexpr element_type* operator->() |
209 | { |
210 | return get(); |
211 | } |
212 | |
213 | template <typename _Up = _Tp, |
214 | typename enable_if<__or_<is_pointer<_Up>, |
215 | is_convertible<_Up, |
216 | const element_type*> |
217 | >::value, bool>::type = true> |
218 | constexpr operator element_type*() |
219 | { |
220 | return get(); |
221 | } |
222 | |
223 | constexpr element_type& operator*() |
224 | { |
225 | return *get(); |
226 | } |
227 | |
228 | constexpr element_type* get() |
229 | { |
230 | return __to_raw_pointer(_M_t); |
231 | } |
232 | |
233 | // [propagate_const.modifiers], modifiers |
234 | constexpr void |
235 | swap(propagate_const& __pt) noexcept(__is_nothrow_swappable<_Tp>::value) |
236 | { |
237 | using std::swap; |
238 | swap(_M_t, get_underlying(__pt)); |
239 | } |
240 | |
241 | private: |
242 | _Tp _M_t; |
243 | }; |
244 | |
245 | // [propagate_const.relational], relational operators |
246 | template <typename _Tp> |
247 | constexpr bool |
248 | operator==(const propagate_const<_Tp>& __pt, nullptr_t) |
249 | { |
250 | return get_underlying(__pt) == nullptr; |
251 | } |
252 | |
253 | template <typename _Tp> |
254 | constexpr bool |
255 | operator==(nullptr_t, const propagate_const<_Tp>& __pu) |
256 | { |
257 | return nullptr == get_underlying(__pu); |
258 | } |
259 | |
260 | template <typename _Tp> |
261 | constexpr bool |
262 | operator!=(const propagate_const<_Tp>& __pt, nullptr_t) |
263 | { |
264 | return get_underlying(__pt) != nullptr; |
265 | } |
266 | |
267 | template <typename _Tp> |
268 | constexpr bool operator!=(nullptr_t, const propagate_const<_Tp>& __pu) |
269 | { |
270 | return nullptr != get_underlying(__pu); |
271 | } |
272 | |
273 | template <typename _Tp, typename _Up> |
274 | constexpr bool |
275 | operator==(const propagate_const<_Tp>& __pt, |
276 | const propagate_const<_Up>& __pu) |
277 | { |
278 | return get_underlying(__pt) == get_underlying(__pu); |
279 | } |
280 | |
281 | template <typename _Tp, typename _Up> |
282 | constexpr bool |
283 | operator!=(const propagate_const<_Tp>& __pt, |
284 | const propagate_const<_Up>& __pu) |
285 | { |
286 | return get_underlying(__pt) != get_underlying(__pu); |
287 | } |
288 | |
289 | template <typename _Tp, typename _Up> |
290 | constexpr bool |
291 | operator<(const propagate_const<_Tp>& __pt, |
292 | const propagate_const<_Up>& __pu) |
293 | { |
294 | return get_underlying(__pt) < get_underlying(__pu); |
295 | } |
296 | |
297 | template <typename _Tp, typename _Up> |
298 | constexpr bool |
299 | operator>(const propagate_const<_Tp>& __pt, |
300 | const propagate_const<_Up>& __pu) |
301 | { |
302 | return get_underlying(__pt) > get_underlying(__pu); |
303 | } |
304 | |
305 | template <typename _Tp, typename _Up> |
306 | constexpr bool |
307 | operator<=(const propagate_const<_Tp>& __pt, |
308 | const propagate_const<_Up>& __pu) |
309 | { |
310 | return get_underlying(__pt) <= get_underlying(__pu); |
311 | } |
312 | |
313 | template <typename _Tp, typename _Up> |
314 | constexpr bool |
315 | operator>=(const propagate_const<_Tp>& __pt, |
316 | const propagate_const<_Up>& __pu) |
317 | { |
318 | return get_underlying(__pt) >= get_underlying(__pu); |
319 | } |
320 | |
321 | template <typename _Tp, typename _Up> |
322 | constexpr bool |
323 | operator==(const propagate_const<_Tp>& __pt, const _Up& __u) |
324 | { |
325 | return get_underlying(__pt) == __u; |
326 | } |
327 | |
328 | template <typename _Tp, typename _Up> |
329 | constexpr bool |
330 | operator!=(const propagate_const<_Tp>& __pt, const _Up& __u) |
331 | { |
332 | return get_underlying(__pt) != __u; |
333 | } |
334 | |
335 | template <typename _Tp, typename _Up> |
336 | constexpr bool |
337 | operator<(const propagate_const<_Tp>& __pt, const _Up& __u) |
338 | { |
339 | return get_underlying(__pt) < __u; |
340 | } |
341 | |
342 | template <typename _Tp, typename _Up> |
343 | constexpr bool |
344 | operator>(const propagate_const<_Tp>& __pt, const _Up& __u) |
345 | { |
346 | return get_underlying(__pt) > __u; |
347 | } |
348 | |
349 | template <typename _Tp, typename _Up> |
350 | constexpr bool |
351 | operator<=(const propagate_const<_Tp>& __pt, const _Up& __u) |
352 | { |
353 | return get_underlying(__pt) <= __u; |
354 | } |
355 | |
356 | template <typename _Tp, typename _Up> |
357 | constexpr bool |
358 | operator>=(const propagate_const<_Tp>& __pt, const _Up& __u) |
359 | { |
360 | return get_underlying(__pt) >= __u; |
361 | } |
362 | |
363 | template <typename _Tp, typename _Up> |
364 | constexpr bool |
365 | operator==(const _Tp& __t, const propagate_const<_Up>& __pu) |
366 | { |
367 | return __t == get_underlying(__pu); |
368 | } |
369 | |
370 | template <typename _Tp, typename _Up> |
371 | constexpr bool |
372 | operator!=(const _Tp& __t, const propagate_const<_Up>& __pu) |
373 | { |
374 | return __t != get_underlying(__pu); |
375 | } |
376 | |
377 | template <typename _Tp, typename _Up> |
378 | constexpr bool |
379 | operator<(const _Tp& __t, const propagate_const<_Up>& __pu) |
380 | { |
381 | return __t < get_underlying(__pu); |
382 | } |
383 | |
384 | template <typename _Tp, typename _Up> |
385 | constexpr bool |
386 | operator>(const _Tp& __t, const propagate_const<_Up>& __pu) |
387 | { |
388 | return __t > get_underlying(__pu); |
389 | } |
390 | |
391 | template <typename _Tp, typename _Up> |
392 | constexpr bool |
393 | operator<=(const _Tp& __t, const propagate_const<_Up>& __pu) |
394 | { |
395 | return __t <= get_underlying(__pu); |
396 | } |
397 | |
398 | template <typename _Tp, typename _Up> |
399 | constexpr bool |
400 | operator>=(const _Tp& __t, const propagate_const<_Up>& __pu) |
401 | { |
402 | return __t >= get_underlying(__pu); |
403 | } |
404 | |
405 | // [propagate_const.algorithms], specialized algorithms |
406 | // _GLIBCXX_RESOLVE_LIB_DEFECTS |
407 | // 3413. propagate_const's swap [...] needs to be constrained and use a trait |
408 | template <typename _Tp> |
409 | constexpr enable_if_t<__is_swappable<_Tp>::value, void> |
410 | swap(propagate_const<_Tp>& __pt, propagate_const<_Tp>& __pt2) |
411 | noexcept(__is_nothrow_swappable<_Tp>::value) |
412 | { |
413 | __pt.swap(__pt2); |
414 | } |
415 | |
416 | // [propagate_const.underlying], underlying pointer access |
417 | template <typename _Tp> |
418 | constexpr const _Tp& |
419 | get_underlying(const propagate_const<_Tp>& __pt) noexcept |
420 | { |
421 | return __pt._M_t; |
422 | } |
423 | |
424 | template <typename _Tp> |
425 | constexpr _Tp& |
426 | get_underlying(propagate_const<_Tp>& __pt) noexcept |
427 | { |
428 | return __pt._M_t; |
429 | } |
430 | |
431 | /// @} group propagate_const |
432 | } // namespace fundamentals_v2 |
433 | } // namespace experimental |
434 | |
435 | // [propagate_const.hash], hash support |
436 | template <typename _Tp> |
437 | struct hash<experimental::propagate_const<_Tp>> |
438 | { |
439 | using result_type = size_t; |
440 | using argument_type = experimental::propagate_const<_Tp>; |
441 | |
442 | size_t |
443 | operator()(const experimental::propagate_const<_Tp>& __t) const |
444 | noexcept(noexcept(hash<_Tp>{}(get_underlying(__t)))) |
445 | { |
446 | return hash<_Tp>{}(get_underlying(__t)); |
447 | } |
448 | }; |
449 | |
450 | // [propagate_const.comparison_function_objects], comparison function objects |
451 | template <typename _Tp> |
452 | struct equal_to<experimental::propagate_const<_Tp>> |
453 | { |
454 | constexpr bool |
455 | operator()(const experimental::propagate_const<_Tp>& __x, |
456 | const experimental::propagate_const<_Tp>& __y) const |
457 | { |
458 | return equal_to<_Tp>{}(get_underlying(__x), get_underlying(__y)); |
459 | } |
460 | |
461 | typedef experimental::propagate_const<_Tp> first_argument_type; |
462 | typedef experimental::propagate_const<_Tp> second_argument_type; |
463 | typedef bool result_type; |
464 | }; |
465 | |
466 | template <typename _Tp> |
467 | struct not_equal_to<experimental::propagate_const<_Tp>> |
468 | { |
469 | constexpr bool |
470 | operator()(const experimental::propagate_const<_Tp>& __x, |
471 | const experimental::propagate_const<_Tp>& __y) const |
472 | { |
473 | return not_equal_to<_Tp>{}(get_underlying(__x), get_underlying(__y)); |
474 | } |
475 | |
476 | typedef experimental::propagate_const<_Tp> first_argument_type; |
477 | typedef experimental::propagate_const<_Tp> second_argument_type; |
478 | typedef bool result_type; |
479 | }; |
480 | |
481 | template <typename _Tp> |
482 | struct less<experimental::propagate_const<_Tp>> |
483 | { |
484 | constexpr bool |
485 | operator()(const experimental::propagate_const<_Tp>& __x, |
486 | const experimental::propagate_const<_Tp>& __y) const |
487 | { |
488 | return less<_Tp>{}(get_underlying(__x), get_underlying(__y)); |
489 | } |
490 | |
491 | typedef experimental::propagate_const<_Tp> first_argument_type; |
492 | typedef experimental::propagate_const<_Tp> second_argument_type; |
493 | typedef bool result_type; |
494 | }; |
495 | |
496 | template <typename _Tp> |
497 | struct greater<experimental::propagate_const<_Tp>> |
498 | { |
499 | constexpr bool |
500 | operator()(const experimental::propagate_const<_Tp>& __x, |
501 | const experimental::propagate_const<_Tp>& __y) const |
502 | { |
503 | return greater<_Tp>{}(get_underlying(__x), get_underlying(__y)); |
504 | } |
505 | |
506 | typedef experimental::propagate_const<_Tp> first_argument_type; |
507 | typedef experimental::propagate_const<_Tp> second_argument_type; |
508 | typedef bool result_type; |
509 | }; |
510 | |
511 | template <typename _Tp> |
512 | struct less_equal<experimental::propagate_const<_Tp>> |
513 | { |
514 | constexpr bool |
515 | operator()(const experimental::propagate_const<_Tp>& __x, |
516 | const experimental::propagate_const<_Tp>& __y) const |
517 | { |
518 | return less_equal<_Tp>{}(get_underlying(__x), get_underlying(__y)); |
519 | } |
520 | |
521 | typedef experimental::propagate_const<_Tp> first_argument_type; |
522 | typedef experimental::propagate_const<_Tp> second_argument_type; |
523 | typedef bool result_type; |
524 | }; |
525 | |
526 | template <typename _Tp> |
527 | struct greater_equal<experimental::propagate_const<_Tp>> |
528 | { |
529 | constexpr bool |
530 | operator()(const experimental::propagate_const<_Tp>& __x, |
531 | const experimental::propagate_const<_Tp>& __y) const |
532 | { |
533 | return greater_equal<_Tp>{}(get_underlying(__x), get_underlying(__y)); |
534 | } |
535 | |
536 | typedef experimental::propagate_const<_Tp> first_argument_type; |
537 | typedef experimental::propagate_const<_Tp> second_argument_type; |
538 | typedef bool result_type; |
539 | }; |
540 | |
541 | _GLIBCXX_END_NAMESPACE_VERSION |
542 | } // namespace std |
543 | |
544 | #endif // C++14 |
545 | |
546 | #endif // _GLIBCXX_EXPERIMENTAL_PROPAGATE_CONST |
547 | |