1// <experimental/propagate_const> -*- C++ -*-
2
3// Copyright (C) 2015-2018 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