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 43namespace std _GLIBCXX_VISIBILITY(default) 44{ 45_GLIBCXX_BEGIN_NAMESPACE_VERSION 46 47namespace experimental 48{ 49inline 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