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