Home | History | Annotate | Line # | Download | only in experimental
      1 // <experimental/propagate_const> -*- C++ -*-
      2 
      3 // Copyright (C) 2015-2022 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