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