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