1// <experimental/propagate_const> -*- C++ -*- 2 3// Copyright (C) 2015-2020 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 template <typename _Up, typename 117 enable_if<__and_<is_constructible<_Tp, _Up&&>, 118 is_convertible<_Up&&, _Tp>>::value, bool 119 >::type=true> 120 constexpr propagate_const(propagate_const<_Up>&& __pu) 121 : _M_t(std::move(get_underlying(__pu))) 122 {} 123 template <typename _Up, typename 124 enable_if<__and_<is_constructible<_Tp, _Up&&>, 125 __not_<is_convertible<_Up&&, _Tp>>>::value, 126 bool>::type=false> 127 constexpr explicit propagate_const(propagate_const<_Up>&& __pu) 128 : _M_t(std::move(get_underlying(__pu))) 129 {} 130 template <typename _Up, typename 131 enable_if<__and_<is_constructible<_Tp, _Up&&>, 132 is_convertible<_Up&&, _Tp>, 133 __not_<__is_propagate_const< 134 typename decay<_Up>::type>> 135 >::value, bool>::type=true> 136 constexpr propagate_const(_Up&& __u) 137 : _M_t(std::forward<_Up>(__u)) 138 {} 139 template <typename _Up, typename 140 enable_if<__and_<is_constructible<_Tp, _Up&&>, 141 __not_<is_convertible<_Up&&, _Tp>>, 142 __not_<__is_propagate_const< 143 typename decay<_Up>::type>> 144 >::value, bool>::type=false> 145 constexpr explicit propagate_const(_Up&& __u) 146 : _M_t(std::forward<_Up>(__u)) 147 {} 148 149 // [propagate_const.assignment], assignment 150 propagate_const& operator=(const propagate_const& __p) = delete; 151 constexpr propagate_const& operator=(propagate_const&& __p) = default; 152 153 template <typename _Up, typename = 154 typename enable_if<is_convertible<_Up&&, _Tp>::value>::type> 155 constexpr propagate_const& operator=(propagate_const<_Up>&& __pu) 156 { 157 _M_t = std::move(get_underlying(__pu)); 158 return *this; 159 } 160 161 template <typename _Up, typename = 162 typename enable_if<__and_<is_convertible<_Up&&, _Tp>, 163 __not_<__is_propagate_const< 164 typename decay<_Up>::type>> 165 >::value>::type> 166 constexpr propagate_const& operator=(_Up&& __u) 167 { 168 _M_t = std::forward<_Up>(__u); 169 return *this; 170 } 171 172 // [propagate_const.const_observers], const observers 173 explicit constexpr operator bool() const 174 { 175 return bool(_M_t); 176 } 177 178 constexpr const element_type* operator->() const 179 { 180 return get(); 181 } 182 183 template <typename _Up = _Tp, 184 typename enable_if<__or_<is_pointer<_Up>, 185 is_convertible<_Up, 186 const element_type*> 187 >::value, bool>::type = true> 188 constexpr operator const element_type*() const 189 { 190 return get(); 191 } 192 193 constexpr const element_type& operator*() const 194 { 195 return *get(); 196 } 197 198 constexpr const element_type* get() const 199 { 200 return __to_raw_pointer(_M_t); 201 } 202 203 // [propagate_const.non_const_observers], non-const observers 204 constexpr element_type* operator->() 205 { 206 return get(); 207 } 208 209 template <typename _Up = _Tp, 210 typename enable_if<__or_<is_pointer<_Up>, 211 is_convertible<_Up, 212 const element_type*> 213 >::value, bool>::type = true> 214 constexpr operator element_type*() 215 { 216 return get(); 217 } 218 219 constexpr element_type& operator*() 220 { 221 return *get(); 222 } 223 224 constexpr element_type* get() 225 { 226 return __to_raw_pointer(_M_t); 227 } 228 229 // [propagate_const.modifiers], modifiers 230 constexpr void 231 swap(propagate_const& __pt) noexcept(__is_nothrow_swappable<_Tp>::value) 232 { 233 using std::swap; 234 swap(_M_t, get_underlying(__pt)); 235 } 236 237 private: 238 _Tp _M_t; 239 }; 240 241 // [propagate_const.relational], relational operators 242 template <typename _Tp> 243 constexpr bool 244 operator==(const propagate_const<_Tp>& __pt, nullptr_t) 245 { 246 return get_underlying(__pt) == nullptr; 247 } 248 249 template <typename _Tp> 250 constexpr bool 251 operator==(nullptr_t, const propagate_const<_Tp>& __pu) 252 { 253 return nullptr == get_underlying(__pu); 254 } 255 256 template <typename _Tp> 257 constexpr bool 258 operator!=(const propagate_const<_Tp>& __pt, nullptr_t) 259 { 260 return get_underlying(__pt) != nullptr; 261 } 262 263 template <typename _Tp> 264 constexpr bool operator!=(nullptr_t, const propagate_const<_Tp>& __pu) 265 { 266 return nullptr != get_underlying(__pu); 267 } 268 269 template <typename _Tp, typename _Up> 270 constexpr bool 271 operator==(const propagate_const<_Tp>& __pt, 272 const propagate_const<_Up>& __pu) 273 { 274 return get_underlying(__pt) == get_underlying(__pu); 275 } 276 277 template <typename _Tp, typename _Up> 278 constexpr bool 279 operator!=(const propagate_const<_Tp>& __pt, 280 const propagate_const<_Up>& __pu) 281 { 282 return get_underlying(__pt) != get_underlying(__pu); 283 } 284 285 template <typename _Tp, typename _Up> 286 constexpr bool 287 operator<(const propagate_const<_Tp>& __pt, 288 const propagate_const<_Up>& __pu) 289 { 290 return get_underlying(__pt) < get_underlying(__pu); 291 } 292 293 template <typename _Tp, typename _Up> 294 constexpr bool 295 operator>(const propagate_const<_Tp>& __pt, 296 const propagate_const<_Up>& __pu) 297 { 298 return get_underlying(__pt) > get_underlying(__pu); 299 } 300 301 template <typename _Tp, typename _Up> 302 constexpr bool 303 operator<=(const propagate_const<_Tp>& __pt, 304 const propagate_const<_Up>& __pu) 305 { 306 return get_underlying(__pt) <= get_underlying(__pu); 307 } 308 309 template <typename _Tp, typename _Up> 310 constexpr bool 311 operator>=(const propagate_const<_Tp>& __pt, 312 const propagate_const<_Up>& __pu) 313 { 314 return get_underlying(__pt) >= get_underlying(__pu); 315 } 316 317 template <typename _Tp, typename _Up> 318 constexpr bool 319 operator==(const propagate_const<_Tp>& __pt, const _Up& __u) 320 { 321 return get_underlying(__pt) == __u; 322 } 323 324 template <typename _Tp, typename _Up> 325 constexpr bool 326 operator!=(const propagate_const<_Tp>& __pt, const _Up& __u) 327 { 328 return get_underlying(__pt) != __u; 329 } 330 331 template <typename _Tp, typename _Up> 332 constexpr bool 333 operator<(const propagate_const<_Tp>& __pt, const _Up& __u) 334 { 335 return get_underlying(__pt) < __u; 336 } 337 338 template <typename _Tp, typename _Up> 339 constexpr bool 340 operator>(const propagate_const<_Tp>& __pt, const _Up& __u) 341 { 342 return get_underlying(__pt) > __u; 343 } 344 345 template <typename _Tp, typename _Up> 346 constexpr bool 347 operator<=(const propagate_const<_Tp>& __pt, const _Up& __u) 348 { 349 return get_underlying(__pt) <= __u; 350 } 351 352 template <typename _Tp, typename _Up> 353 constexpr bool 354 operator>=(const propagate_const<_Tp>& __pt, const _Up& __u) 355 { 356 return get_underlying(__pt) >= __u; 357 } 358 359 template <typename _Tp, typename _Up> 360 constexpr bool 361 operator==(const _Tp& __t, const propagate_const<_Up>& __pu) 362 { 363 return __t == get_underlying(__pu); 364 } 365 366 template <typename _Tp, typename _Up> 367 constexpr bool 368 operator!=(const _Tp& __t, const propagate_const<_Up>& __pu) 369 { 370 return __t != get_underlying(__pu); 371 } 372 373 template <typename _Tp, typename _Up> 374 constexpr bool 375 operator<(const _Tp& __t, const propagate_const<_Up>& __pu) 376 { 377 return __t < get_underlying(__pu); 378 } 379 380 template <typename _Tp, typename _Up> 381 constexpr bool 382 operator>(const _Tp& __t, const propagate_const<_Up>& __pu) 383 { 384 return __t > get_underlying(__pu); 385 } 386 387 template <typename _Tp, typename _Up> 388 constexpr bool 389 operator<=(const _Tp& __t, const propagate_const<_Up>& __pu) 390 { 391 return __t <= get_underlying(__pu); 392 } 393 394 template <typename _Tp, typename _Up> 395 constexpr bool 396 operator>=(const _Tp& __t, const propagate_const<_Up>& __pu) 397 { 398 return __t >= get_underlying(__pu); 399 } 400 401 // [propagate_const.algorithms], specialized algorithms 402 template <typename _Tp> 403 constexpr void 404 swap(propagate_const<_Tp>& __pt, propagate_const<_Tp>& __pt2) 405 noexcept(__is_nothrow_swappable<_Tp>::value) 406 { 407 __pt.swap(__pt2); 408 } 409 410 // [propagate_const.underlying], underlying pointer access 411 template <typename _Tp> 412 constexpr const _Tp& 413 get_underlying(const propagate_const<_Tp>& __pt) noexcept 414 { 415 return __pt._M_t; 416 } 417 418 template <typename _Tp> 419 constexpr _Tp& 420 get_underlying(propagate_const<_Tp>& __pt) noexcept 421 { 422 return __pt._M_t; 423 } 424 425 /// @} group propagate_const 426} // namespace fundamentals_v2 427} // namespace experimental 428 429// [propagate_const.hash], hash support 430 template <typename _Tp> 431 struct hash<experimental::propagate_const<_Tp>> 432 { 433 using result_type = size_t; 434 using argument_type = experimental::propagate_const<_Tp>; 435 436 size_t 437 operator()(const experimental::propagate_const<_Tp>& __t) const 438 noexcept(noexcept(hash<_Tp>{}(get_underlying(__t)))) 439 { 440 return hash<_Tp>{}(get_underlying(__t)); 441 } 442 }; 443 444 // [propagate_const.comparison_function_objects], comparison function objects 445 template <typename _Tp> 446 struct equal_to<experimental::propagate_const<_Tp>> 447 { 448 constexpr bool 449 operator()(const experimental::propagate_const<_Tp>& __x, 450 const experimental::propagate_const<_Tp>& __y) const 451 { 452 return equal_to<_Tp>{}(get_underlying(__x), get_underlying(__y)); 453 } 454 455 typedef experimental::propagate_const<_Tp> first_argument_type; 456 typedef experimental::propagate_const<_Tp> second_argument_type; 457 typedef bool result_type; 458 }; 459 460 template <typename _Tp> 461 struct not_equal_to<experimental::propagate_const<_Tp>> 462 { 463 constexpr bool 464 operator()(const experimental::propagate_const<_Tp>& __x, 465 const experimental::propagate_const<_Tp>& __y) const 466 { 467 return not_equal_to<_Tp>{}(get_underlying(__x), get_underlying(__y)); 468 } 469 470 typedef experimental::propagate_const<_Tp> first_argument_type; 471 typedef experimental::propagate_const<_Tp> second_argument_type; 472 typedef bool result_type; 473 }; 474 475 template <typename _Tp> 476 struct less<experimental::propagate_const<_Tp>> 477 { 478 constexpr bool 479 operator()(const experimental::propagate_const<_Tp>& __x, 480 const experimental::propagate_const<_Tp>& __y) const 481 { 482 return less<_Tp>{}(get_underlying(__x), get_underlying(__y)); 483 } 484 485 typedef experimental::propagate_const<_Tp> first_argument_type; 486 typedef experimental::propagate_const<_Tp> second_argument_type; 487 typedef bool result_type; 488 }; 489 490 template <typename _Tp> 491 struct greater<experimental::propagate_const<_Tp>> 492 { 493 constexpr bool 494 operator()(const experimental::propagate_const<_Tp>& __x, 495 const experimental::propagate_const<_Tp>& __y) const 496 { 497 return greater<_Tp>{}(get_underlying(__x), get_underlying(__y)); 498 } 499 500 typedef experimental::propagate_const<_Tp> first_argument_type; 501 typedef experimental::propagate_const<_Tp> second_argument_type; 502 typedef bool result_type; 503 }; 504 505 template <typename _Tp> 506 struct less_equal<experimental::propagate_const<_Tp>> 507 { 508 constexpr bool 509 operator()(const experimental::propagate_const<_Tp>& __x, 510 const experimental::propagate_const<_Tp>& __y) const 511 { 512 return less_equal<_Tp>{}(get_underlying(__x), get_underlying(__y)); 513 } 514 515 typedef experimental::propagate_const<_Tp> first_argument_type; 516 typedef experimental::propagate_const<_Tp> second_argument_type; 517 typedef bool result_type; 518 }; 519 520 template <typename _Tp> 521 struct greater_equal<experimental::propagate_const<_Tp>> 522 { 523 constexpr bool 524 operator()(const experimental::propagate_const<_Tp>& __x, 525 const experimental::propagate_const<_Tp>& __y) const 526 { 527 return greater_equal<_Tp>{}(get_underlying(__x), get_underlying(__y)); 528 } 529 530 typedef experimental::propagate_const<_Tp> first_argument_type; 531 typedef experimental::propagate_const<_Tp> second_argument_type; 532 typedef bool result_type; 533 }; 534 535_GLIBCXX_END_NAMESPACE_VERSION 536} // namespace std 537 538#endif // C++14 539 540#endif // _GLIBCXX_EXPERIMENTAL_PROPAGATE_CONST 541