libstdc++
bits/fs_path.h
Go to the documentation of this file.
1 // Class filesystem::path -*- C++ -*-
2 
3 // Copyright (C) 2014-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 include/bits/fs_path.h
26  * This is an internal header file, included by other library headers.
27  * Do not attempt to use it directly. @headername{filesystem}
28  */
29 
30 #ifndef _GLIBCXX_FS_PATH_H
31 #define _GLIBCXX_FS_PATH_H 1
32 
33 #if __cplusplus >= 201703L
34 
35 #include <utility>
36 #include <type_traits>
37 #include <locale>
38 #include <iosfwd>
39 #include <iomanip>
40 #include <codecvt>
41 #include <string_view>
42 #include <system_error>
43 #include <bits/stl_algobase.h>
44 #include <bits/locale_conv.h>
45 #include <ext/concurrence.h>
46 #include <bits/shared_ptr.h>
47 #include <bits/unique_ptr.h>
48 
49 #if defined(_WIN32) && !defined(__CYGWIN__)
50 # define _GLIBCXX_FILESYSTEM_IS_WINDOWS 1
51 # include <algorithm>
52 #endif
53 
54 namespace std _GLIBCXX_VISIBILITY(default)
55 {
56 _GLIBCXX_BEGIN_NAMESPACE_VERSION
57 
58 namespace filesystem
59 {
60 _GLIBCXX_BEGIN_NAMESPACE_CXX11
61 
62  /** @addtogroup filesystem
63  * @{
64  */
65 
66  class path;
67 
68  /// @cond undocumented
69 namespace __detail
70 {
71  template<typename _CharT>
72  using __is_encoded_char = __is_one_of<remove_const_t<_CharT>,
73  char,
74 #ifdef _GLIBCXX_USE_CHAR8_T
75  char8_t,
76 #endif
77 #if _GLIBCXX_USE_WCHAR_T
78  wchar_t,
79 #endif
80  char16_t, char32_t>;
81 
82  template<typename _Iter,
83  typename _Iter_traits = std::iterator_traits<_Iter>>
84  using __is_path_iter_src
85  = __and_<__is_encoded_char<typename _Iter_traits::value_type>,
87  typename _Iter_traits::iterator_category>>;
88 
89  template<typename _Iter>
90  static __is_path_iter_src<_Iter>
91  __is_path_src(_Iter, int);
92 
93  template<typename _CharT, typename _Traits, typename _Alloc>
94  static __is_encoded_char<_CharT>
95  __is_path_src(const basic_string<_CharT, _Traits, _Alloc>&, int);
96 
97  template<typename _CharT, typename _Traits>
98  static __is_encoded_char<_CharT>
99  __is_path_src(const basic_string_view<_CharT, _Traits>&, int);
100 
101  template<typename _Unknown>
102  static std::false_type
103  __is_path_src(const _Unknown&, ...);
104 
105  template<typename _Tp1, typename _Tp2>
106  struct __constructible_from;
107 
108  template<typename _Iter>
109  struct __constructible_from<_Iter, _Iter>
110  : __is_path_iter_src<_Iter>
111  { };
112 
113  template<typename _Source>
114  struct __constructible_from<_Source, void>
115  : decltype(__is_path_src(std::declval<_Source>(), 0))
116  { };
117 
118  template<typename _Tp1, typename _Tp2 = void>
119  using _Path = typename
121  __not_<is_void<remove_pointer_t<_Tp1>>>,
122  __constructible_from<_Tp1, _Tp2>>::value,
123  path>::type;
124 
125  template<typename _Source>
126  static _Source
127  _S_range_begin(_Source __begin) { return __begin; }
128 
129  struct __null_terminated { };
130 
131  template<typename _Source>
132  static __null_terminated
133  _S_range_end(_Source) { return {}; }
134 
135  template<typename _CharT, typename _Traits, typename _Alloc>
136  static const _CharT*
137  _S_range_begin(const basic_string<_CharT, _Traits, _Alloc>& __str)
138  { return __str.data(); }
139 
140  template<typename _CharT, typename _Traits, typename _Alloc>
141  static const _CharT*
142  _S_range_end(const basic_string<_CharT, _Traits, _Alloc>& __str)
143  { return __str.data() + __str.size(); }
144 
145  template<typename _CharT, typename _Traits>
146  static const _CharT*
147  _S_range_begin(const basic_string_view<_CharT, _Traits>& __str)
148  { return __str.data(); }
149 
150  template<typename _CharT, typename _Traits>
151  static const _CharT*
152  _S_range_end(const basic_string_view<_CharT, _Traits>& __str)
153  { return __str.data() + __str.size(); }
154 
155  template<typename _Tp,
156  typename _Iter = decltype(_S_range_begin(std::declval<_Tp>())),
157  typename _Val = typename std::iterator_traits<_Iter>::value_type,
158  typename _UnqualVal = std::remove_const_t<_Val>>
159  using __value_type_is_char
161  _UnqualVal>;
162 
163  template<typename _Tp,
164  typename _Iter = decltype(_S_range_begin(std::declval<_Tp>())),
165  typename _Val = typename std::iterator_traits<_Iter>::value_type,
166  typename _UnqualVal = std::remove_const_t<_Val>>
167  using __value_type_is_char_or_char8_t
168  = std::enable_if_t<__or_v<
170 #ifdef _GLIBCXX_USE_CHAR8_T
172 #endif
173  >,
174  _UnqualVal>;
175 
176 } // namespace __detail
177  /// @endcond
178 
179  /// A filesystem path.
180  class path
181  {
182  public:
183 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
184  using value_type = wchar_t;
185  static constexpr value_type preferred_separator = L'\\';
186 #else
187 # ifdef _GLIBCXX_DOXYGEN
188  /// Windows uses wchar_t for path::value_type, POSIX uses char.
189  using value_type = __os_dependent__;
190 # else
191  using value_type = char;
192 # endif
193  static constexpr value_type preferred_separator = '/';
194 #endif
195  using string_type = std::basic_string<value_type>;
196 
197  /// path::format is ignored in this implementation
198  enum format : unsigned char { native_format, generic_format, auto_format };
199 
200  // constructors and destructor
201 
202  path() noexcept { }
203 
204  path(const path& __p) = default;
205 
206  path(path&& __p)
207 #if _GLIBCXX_USE_CXX11_ABI || _GLIBCXX_FULLY_DYNAMIC_STRING == 0
208  noexcept
209 #endif
210  : _M_pathname(std::move(__p._M_pathname)),
211  _M_cmpts(std::move(__p._M_cmpts))
212  { __p.clear(); }
213 
214  path(string_type&& __source, format = auto_format)
215  : _M_pathname(std::move(__source))
216  { _M_split_cmpts(); }
217 
218  template<typename _Source,
219  typename _Require = __detail::_Path<_Source>>
220  path(_Source const& __source, format = auto_format)
221  : _M_pathname(_S_convert(__detail::_S_range_begin(__source),
222  __detail::_S_range_end(__source)))
223  { _M_split_cmpts(); }
224 
225  template<typename _InputIterator,
226  typename _Require = __detail::_Path<_InputIterator, _InputIterator>>
227  path(_InputIterator __first, _InputIterator __last, format = auto_format)
228  : _M_pathname(_S_convert(__first, __last))
229  { _M_split_cmpts(); }
230 
231  template<typename _Source,
232  typename _Require = __detail::_Path<_Source>,
233  typename _Require2 = __detail::__value_type_is_char<_Source>>
234  path(_Source const& __source, const locale& __loc, format = auto_format)
235  : _M_pathname(_S_convert_loc(__detail::_S_range_begin(__source),
236  __detail::_S_range_end(__source), __loc))
237  { _M_split_cmpts(); }
238 
239  template<typename _InputIterator,
240  typename _Require = __detail::_Path<_InputIterator, _InputIterator>,
241  typename _Require2 = __detail::__value_type_is_char<_InputIterator>>
242  path(_InputIterator __first, _InputIterator __last, const locale& __loc,
243  format = auto_format)
244  : _M_pathname(_S_convert_loc(__first, __last, __loc))
245  { _M_split_cmpts(); }
246 
247  ~path() = default;
248 
249  // assignments
250 
251  path& operator=(const path&);
252  path& operator=(path&&) noexcept;
253  path& operator=(string_type&& __source);
254  path& assign(string_type&& __source);
255 
256  template<typename _Source>
257  __detail::_Path<_Source>&
258  operator=(_Source const& __source)
259  { return *this = path(__source); }
260 
261  template<typename _Source>
262  __detail::_Path<_Source>&
263  assign(_Source const& __source)
264  { return *this = path(__source); }
265 
266  template<typename _InputIterator>
267  __detail::_Path<_InputIterator, _InputIterator>&
268  assign(_InputIterator __first, _InputIterator __last)
269  { return *this = path(__first, __last); }
270 
271  // appends
272 
273  path& operator/=(const path& __p);
274 
275  template<typename _Source>
276  __detail::_Path<_Source>&
277  operator/=(_Source const& __source)
278  {
279  _M_append(_S_convert(__detail::_S_range_begin(__source),
280  __detail::_S_range_end(__source)));
281  return *this;
282  }
283 
284  template<typename _Source>
285  __detail::_Path<_Source>&
286  append(_Source const& __source)
287  {
288  _M_append(_S_convert(__detail::_S_range_begin(__source),
289  __detail::_S_range_end(__source)));
290  return *this;
291  }
292 
293  template<typename _InputIterator>
294  __detail::_Path<_InputIterator, _InputIterator>&
295  append(_InputIterator __first, _InputIterator __last)
296  {
297  _M_append(_S_convert(__first, __last));
298  return *this;
299  }
300 
301  // concatenation
302 
303  path& operator+=(const path& __x);
304  path& operator+=(const string_type& __x);
305  path& operator+=(const value_type* __x);
306  path& operator+=(value_type __x);
307  path& operator+=(basic_string_view<value_type> __x);
308 
309  template<typename _Source>
310  __detail::_Path<_Source>&
311  operator+=(_Source const& __x) { return concat(__x); }
312 
313  template<typename _CharT>
314  __detail::_Path<_CharT*, _CharT*>&
315  operator+=(_CharT __x);
316 
317  template<typename _Source>
318  __detail::_Path<_Source>&
319  concat(_Source const& __x)
320  {
321  _M_concat(_S_convert(__detail::_S_range_begin(__x),
322  __detail::_S_range_end(__x)));
323  return *this;
324  }
325 
326  template<typename _InputIterator>
327  __detail::_Path<_InputIterator, _InputIterator>&
328  concat(_InputIterator __first, _InputIterator __last)
329  {
330  _M_concat(_S_convert(__first, __last));
331  return *this;
332  }
333 
334  // modifiers
335 
336  void clear() noexcept { _M_pathname.clear(); _M_split_cmpts(); }
337 
338  path& make_preferred();
339  path& remove_filename();
340  path& replace_filename(const path& __replacement);
341  path& replace_extension(const path& __replacement = path());
342 
343  void swap(path& __rhs) noexcept;
344 
345  // native format observers
346 
347  const string_type& native() const noexcept { return _M_pathname; }
348  const value_type* c_str() const noexcept { return _M_pathname.c_str(); }
349  operator string_type() const { return _M_pathname; }
350 
351  template<typename _CharT, typename _Traits = std::char_traits<_CharT>,
352  typename _Allocator = std::allocator<_CharT>>
354  string(const _Allocator& __a = _Allocator()) const;
355 
356  std::string string() const;
357 #if _GLIBCXX_USE_WCHAR_T
358  std::wstring wstring() const;
359 #endif
360 #ifdef _GLIBCXX_USE_CHAR8_T
361  __attribute__((__abi_tag__("__u8")))
362  std::u8string u8string() const;
363 #else
364  std::string u8string() const;
365 #endif // _GLIBCXX_USE_CHAR8_T
366  std::u16string u16string() const;
367  std::u32string u32string() const;
368 
369  // generic format observers
370  template<typename _CharT, typename _Traits = std::char_traits<_CharT>,
371  typename _Allocator = std::allocator<_CharT>>
373  generic_string(const _Allocator& __a = _Allocator()) const;
374 
375  std::string generic_string() const;
376 #if _GLIBCXX_USE_WCHAR_T
377  std::wstring generic_wstring() const;
378 #endif
379 #ifdef _GLIBCXX_USE_CHAR8_T
380  __attribute__((__abi_tag__("__u8")))
381  std::u8string generic_u8string() const;
382 #else
383  std::string generic_u8string() const;
384 #endif // _GLIBCXX_USE_CHAR8_T
385  std::u16string generic_u16string() const;
386  std::u32string generic_u32string() const;
387 
388  // compare
389 
390  int compare(const path& __p) const noexcept;
391  int compare(const string_type& __s) const noexcept;
392  int compare(const value_type* __s) const noexcept;
393  int compare(basic_string_view<value_type> __s) const noexcept;
394 
395  // decomposition
396 
397  path root_name() const;
398  path root_directory() const;
399  path root_path() const;
400  path relative_path() const;
401  path parent_path() const;
402  path filename() const;
403  path stem() const;
404  path extension() const;
405 
406  // query
407 
408  [[nodiscard]] bool empty() const noexcept { return _M_pathname.empty(); }
409  bool has_root_name() const noexcept;
410  bool has_root_directory() const noexcept;
411  bool has_root_path() const noexcept;
412  bool has_relative_path() const noexcept;
413  bool has_parent_path() const noexcept;
414  bool has_filename() const noexcept;
415  bool has_stem() const noexcept;
416  bool has_extension() const noexcept;
417  bool is_absolute() const noexcept;
418  bool is_relative() const noexcept { return !is_absolute(); }
419 
420  // generation
421  path lexically_normal() const;
422  path lexically_relative(const path& base) const;
423  path lexically_proximate(const path& base) const;
424 
425  // iterators
426  class iterator;
427  using const_iterator = iterator;
428 
429  iterator begin() const;
430  iterator end() const;
431 
432  /// Write a path to a stream
433  template<typename _CharT, typename _Traits>
435  operator<<(std::basic_ostream<_CharT, _Traits>& __os, const path& __p)
436  {
437  __os << std::quoted(__p.string<_CharT, _Traits>());
438  return __os;
439  }
440 
441  /// Read a path from a stream
442  template<typename _CharT, typename _Traits>
445  {
447  if (__is >> std::quoted(__tmp))
448  __p = std::move(__tmp);
449  return __is;
450  }
451 
452  // non-member operators
453 
454  /// Compare paths
455  friend bool operator<(const path& __lhs, const path& __rhs) noexcept
456  { return __lhs.compare(__rhs) < 0; }
457 
458  /// Compare paths
459  friend bool operator<=(const path& __lhs, const path& __rhs) noexcept
460  { return !(__rhs < __lhs); }
461 
462  /// Compare paths
463  friend bool operator>(const path& __lhs, const path& __rhs) noexcept
464  { return __rhs < __lhs; }
465 
466  /// Compare paths
467  friend bool operator>=(const path& __lhs, const path& __rhs) noexcept
468  { return !(__lhs < __rhs); }
469 
470  /// Compare paths
471  friend bool operator==(const path& __lhs, const path& __rhs) noexcept
472  { return __lhs.compare(__rhs) == 0; }
473 
474  /// Compare paths
475  friend bool operator!=(const path& __lhs, const path& __rhs) noexcept
476  { return !(__lhs == __rhs); }
477 
478  /// Append one path to another
479  friend path operator/(const path& __lhs, const path& __rhs)
480  {
481  path __result(__lhs);
482  __result /= __rhs;
483  return __result;
484  }
485 
486  /// @cond undocumented
487  // Create a basic_string by reading until a null character.
488  template<typename _InputIterator,
489  typename _Traits = std::iterator_traits<_InputIterator>,
490  typename _CharT
493  _S_string_from_iter(_InputIterator __source)
494  {
496  for (_CharT __ch = *__source; __ch != _CharT(); __ch = *++__source)
497  __str.push_back(__ch);
498  return __str;
499  }
500  /// @endcond
501 
502  private:
503  enum class _Type : unsigned char {
504  _Multi = 0, _Root_name, _Root_dir, _Filename
505  };
506 
507  path(basic_string_view<value_type> __str, _Type __type)
508  : _M_pathname(__str)
509  {
510  __glibcxx_assert(__type != _Type::_Multi);
511  _M_cmpts.type(__type);
512  }
513 
514  enum class _Split { _Stem, _Extension };
515 
516  void _M_append(basic_string_view<value_type>);
517  void _M_concat(basic_string_view<value_type>);
518 
519  pair<const string_type*, size_t> _M_find_extension() const noexcept;
520 
521  template<typename _CharT>
522  struct _Cvt;
523 
524  static basic_string_view<value_type>
525  _S_convert(value_type* __src, __detail::__null_terminated)
526  { return __src; }
527 
528  static basic_string_view<value_type>
529  _S_convert(const value_type* __src, __detail::__null_terminated)
530  { return __src; }
531 
532  static basic_string_view<value_type>
533  _S_convert(value_type* __first, value_type* __last)
534  { return {__first, __last - __first}; }
535 
536  static basic_string_view<value_type>
537  _S_convert(const value_type* __first, const value_type* __last)
538  { return {__first, __last - __first}; }
539 
540  template<typename _Iter>
541  static string_type
542  _S_convert(_Iter __first, _Iter __last)
543  {
544  using __value_type = typename std::iterator_traits<_Iter>::value_type;
545  return _Cvt<typename remove_cv<__value_type>::type>::
546  _S_convert(__first, __last);
547  }
548 
549  template<typename _InputIterator>
550  static string_type
551  _S_convert(_InputIterator __src, __detail::__null_terminated)
552  {
553  // Read from iterator into basic_string until a null value is seen:
554  auto __s = _S_string_from_iter(__src);
555  // Convert (if needed) from iterator's value type to path::value_type:
556  return string_type(_S_convert(__s.data(), __s.data() + __s.size()));
557  }
558 
559  static string_type
560  _S_convert_loc(const char* __first, const char* __last,
561  const std::locale& __loc);
562 
563  template<typename _Iter>
564  static string_type
565  _S_convert_loc(_Iter __first, _Iter __last, const std::locale& __loc)
566  {
567  const std::string __str(__first, __last);
568  return _S_convert_loc(__str.data(), __str.data()+__str.size(), __loc);
569  }
570 
571  template<typename _InputIterator>
572  static string_type
573  _S_convert_loc(_InputIterator __src, __detail::__null_terminated,
574  const std::locale& __loc)
575  {
576  const std::string __s = _S_string_from_iter(__src);
577  return _S_convert_loc(__s.data(), __s.data() + __s.size(), __loc);
578  }
579 
580  template<typename _CharT, typename _Traits, typename _Allocator>
581  static basic_string<_CharT, _Traits, _Allocator>
582  _S_str_convert(basic_string_view<value_type>, const _Allocator&);
583 
584  void _M_split_cmpts();
585 
586  _Type _M_type() const noexcept { return _M_cmpts.type(); }
587 
588  string_type _M_pathname;
589 
590  struct _Cmpt;
591 
592  struct _List
593  {
594  using value_type = _Cmpt;
595  using iterator = value_type*;
596  using const_iterator = const value_type*;
597 
598  _List();
599  _List(const _List&);
600  _List(_List&&) = default;
601  _List& operator=(const _List&);
602  _List& operator=(_List&&) = default;
603  ~_List() = default;
604 
605  _Type type() const noexcept
606  { return _Type{reinterpret_cast<uintptr_t>(_M_impl.get()) & 0x3}; }
607 
608  void type(_Type) noexcept;
609 
610  int size() const noexcept; // zero unless type() == _Type::_Multi
611  bool empty() const noexcept; // true unless type() == _Type::_Multi
612  void clear();
613  void swap(_List& __l) noexcept { _M_impl.swap(__l._M_impl); }
614  int capacity() const noexcept;
615  void reserve(int, bool); ///< @pre type() == _Type::_Multi
616 
617  // All the member functions below here have a precondition !empty()
618  // (and they should only be called from within the library).
619 
620  iterator begin();
621  iterator end();
622  const_iterator begin() const;
623  const_iterator end() const;
624 
625  value_type& front() noexcept;
626  value_type& back() noexcept;
627  const value_type& front() const noexcept;
628  const value_type& back() const noexcept;
629 
630  void pop_back();
631  void _M_erase_from(const_iterator __pos); // erases [__pos,end())
632 
633  struct _Impl;
634  struct _Impl_deleter
635  {
636  void operator()(_Impl*) const noexcept;
637  };
638  unique_ptr<_Impl, _Impl_deleter> _M_impl;
639  };
640  _List _M_cmpts;
641 
642  struct _Parser;
643  };
644 
645  /// @relates std::filesystem::path @{
646 
647  inline void swap(path& __lhs, path& __rhs) noexcept { __lhs.swap(__rhs); }
648 
649  size_t hash_value(const path& __p) noexcept;
650 
651  /// @}
652 
653  /// Exception type thrown by the Filesystem library
654  class filesystem_error : public std::system_error
655  {
656  public:
657  filesystem_error(const string& __what_arg, error_code __ec);
658 
659  filesystem_error(const string& __what_arg, const path& __p1,
660  error_code __ec);
661 
662  filesystem_error(const string& __what_arg, const path& __p1,
663  const path& __p2, error_code __ec);
664 
665  filesystem_error(const filesystem_error&) = default;
666  filesystem_error& operator=(const filesystem_error&) = default;
667 
668  // No move constructor or assignment operator.
669  // Copy rvalues instead, so that _M_impl is not left empty.
670 
671  ~filesystem_error();
672 
673  const path& path1() const noexcept;
674  const path& path2() const noexcept;
675  const char* what() const noexcept;
676 
677  private:
678  struct _Impl;
679  std::__shared_ptr<const _Impl> _M_impl;
680  };
681 
682  /** Create a path from a UTF-8-encoded sequence of char
683  *
684  * @relates std::filesystem::path
685  */
686  template<typename _InputIterator,
687  typename _Require = __detail::_Path<_InputIterator, _InputIterator>,
688  typename _CharT
689  = __detail::__value_type_is_char_or_char8_t<_InputIterator>>
690  inline path
691  u8path(_InputIterator __first, _InputIterator __last)
692  {
693 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
694  if constexpr (is_same_v<_CharT, char>)
695  {
696  // XXX This assumes native wide encoding is UTF-16.
697  std::codecvt_utf8_utf16<path::value_type> __cvt;
698  path::string_type __tmp;
699  if constexpr (is_pointer_v<_InputIterator>)
700  {
701  if (__str_codecvt_in_all(__first, __last, __tmp, __cvt))
702  return path{ __tmp };
703  }
704  else
705  {
706  const std::string __u8str{__first, __last};
707  const char* const __p = __u8str.data();
708  if (__str_codecvt_in_all(__p, __p + __u8str.size(), __tmp, __cvt))
709  return path{ __tmp };
710  }
711  _GLIBCXX_THROW_OR_ABORT(filesystem_error(
712  "Cannot convert character sequence",
713  std::make_error_code(errc::illegal_byte_sequence)));
714  }
715  else
716  return path{ __first, __last };
717 #else
718  // This assumes native normal encoding is UTF-8.
719  return path{ __first, __last };
720 #endif
721  }
722 
723  /** Create a path from a UTF-8-encoded sequence of char
724  *
725  * @relates std::filesystem::path
726  */
727  template<typename _Source,
728  typename _Require = __detail::_Path<_Source>,
729  typename _CharT = __detail::__value_type_is_char_or_char8_t<_Source>>
730  inline path
731  u8path(const _Source& __source)
732  {
733 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
734  if constexpr (is_same_v<_CharT, char>)
735  {
736  if constexpr (is_convertible_v<const _Source&, std::string_view>)
737  {
738  const std::string_view __s = __source;
739  return filesystem::u8path(__s.data(), __s.data() + __s.size());
740  }
741  else
742  {
743  std::string __s = path::_S_string_from_iter(__source);
744  return filesystem::u8path(__s.data(), __s.data() + __s.size());
745  }
746  }
747  else
748  return path{ __source };
749 #else
750  return path{ __source };
751 #endif
752  }
753 
754  /// @cond undocumented
755 
756  struct path::_Cmpt : path
757  {
758  _Cmpt(basic_string_view<value_type> __s, _Type __t, size_t __pos)
759  : path(__s, __t), _M_pos(__pos) { }
760 
761  _Cmpt() : _M_pos(-1) { }
762 
763  size_t _M_pos;
764  };
765 
766  // specialize _Cvt for degenerate 'noconv' case
767  template<>
768  struct path::_Cvt<path::value_type>
769  {
770  template<typename _Iter>
771  static string_type
772  _S_convert(_Iter __first, _Iter __last)
773  { return string_type{__first, __last}; }
774  };
775 
776 #if !defined _GLIBCXX_FILESYSTEM_IS_WINDOWS && defined _GLIBCXX_USE_CHAR8_T
777  // For POSIX converting from char8_t to char is also 'noconv'
778  template<>
779  struct path::_Cvt<char8_t>
780  {
781  template<typename _Iter>
782  static string_type
783  _S_convert(_Iter __first, _Iter __last)
784  { return string_type(__first, __last); }
785  };
786 #endif
787 
788  template<typename _CharT>
789  struct path::_Cvt
790  {
791  static string_type
792  _S_convert(const _CharT* __f, const _CharT* __l)
793  {
794 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
795  std::wstring __wstr;
796  if constexpr (is_same_v<_CharT, char>)
797  {
798  struct _UCvt : std::codecvt<wchar_t, char, std::mbstate_t>
799  { } __cvt;
800  if (__str_codecvt_in_all(__f, __l, __wstr, __cvt))
801  return __wstr;
802  }
803 #ifdef _GLIBCXX_USE_CHAR8_T
804  else if constexpr (is_same_v<_CharT, char8_t>)
805  {
806  const char* __f2 = (const char*)__f;
807  const char* __l2 = (const char*)__l;
808  std::codecvt_utf8_utf16<wchar_t> __wcvt;
809  if (__str_codecvt_in_all(__f2, __l2, __wstr, __wcvt))
810  return __wstr;
811  }
812 #endif
813  else // char16_t or char32_t
814  {
815  struct _UCvt : std::codecvt<_CharT, char, std::mbstate_t>
816  { } __cvt;
817  std::string __str;
818  if (__str_codecvt_out_all(__f, __l, __str, __cvt))
819  {
820  const char* __f2 = __str.data();
821  const char* __l2 = __f2 + __str.size();
822  std::codecvt_utf8_utf16<wchar_t> __wcvt;
823  if (__str_codecvt_in_all(__f2, __l2, __wstr, __wcvt))
824  return __wstr;
825  }
826  }
827 #else // ! windows
828  struct _UCvt : std::codecvt<_CharT, char, std::mbstate_t>
829  { } __cvt;
830  std::string __str;
831  if (__str_codecvt_out_all(__f, __l, __str, __cvt))
832  return __str;
833 #endif
834  _GLIBCXX_THROW_OR_ABORT(filesystem_error(
835  "Cannot convert character sequence",
836  std::make_error_code(errc::illegal_byte_sequence)));
837  }
838 
839  static string_type
840  _S_convert(_CharT* __f, _CharT* __l)
841  {
842  return _S_convert(const_cast<const _CharT*>(__f),
843  const_cast<const _CharT*>(__l));
844  }
845 
846  template<typename _Iter>
847  static string_type
848  _S_convert(_Iter __first, _Iter __last)
849  {
850  const std::basic_string<_CharT> __str(__first, __last);
851  return _S_convert(__str.data(), __str.data() + __str.size());
852  }
853 
854  template<typename _Iter, typename _Cont>
855  static string_type
856  _S_convert(__gnu_cxx::__normal_iterator<_Iter, _Cont> __first,
857  __gnu_cxx::__normal_iterator<_Iter, _Cont> __last)
858  { return _S_convert(__first.base(), __last.base()); }
859  };
860 
861  /// @endcond
862 
863  /// An iterator for the components of a path
864  class path::iterator
865  {
866  public:
867  using difference_type = std::ptrdiff_t;
868  using value_type = path;
869  using reference = const path&;
870  using pointer = const path*;
871  using iterator_category = std::bidirectional_iterator_tag;
872 
873  iterator() : _M_path(nullptr), _M_cur(), _M_at_end() { }
874 
875  iterator(const iterator&) = default;
876  iterator& operator=(const iterator&) = default;
877 
878  reference operator*() const;
879  pointer operator->() const { return std::__addressof(**this); }
880 
881  iterator& operator++();
882  iterator operator++(int) { auto __tmp = *this; ++*this; return __tmp; }
883 
884  iterator& operator--();
885  iterator operator--(int) { auto __tmp = *this; --*this; return __tmp; }
886 
887  friend bool operator==(const iterator& __lhs, const iterator& __rhs)
888  { return __lhs._M_equals(__rhs); }
889 
890  friend bool operator!=(const iterator& __lhs, const iterator& __rhs)
891  { return !__lhs._M_equals(__rhs); }
892 
893  private:
894  friend class path;
895 
896  bool _M_is_multi() const { return _M_path->_M_type() == _Type::_Multi; }
897 
898  friend difference_type
899  __path_iter_distance(const iterator& __first, const iterator& __last)
900  {
901  __glibcxx_assert(__first._M_path != nullptr);
902  __glibcxx_assert(__first._M_path == __last._M_path);
903  if (__first._M_is_multi())
904  return std::distance(__first._M_cur, __last._M_cur);
905  else if (__first._M_at_end == __last._M_at_end)
906  return 0;
907  else
908  return __first._M_at_end ? -1 : 1;
909  }
910 
911  friend void
912  __path_iter_advance(iterator& __i, difference_type __n)
913  {
914  if (__n == 1)
915  ++__i;
916  else if (__n == -1)
917  --__i;
918  else if (__n != 0)
919  {
920  __glibcxx_assert(__i._M_path != nullptr);
921  __glibcxx_assert(__i._M_is_multi());
922  // __glibcxx_assert(__i._M_path->_M_cmpts.end() - __i._M_cur >= __n);
923  __i._M_cur += __n;
924  }
925  }
926 
927  iterator(const path* __path, path::_List::const_iterator __iter)
928  : _M_path(__path), _M_cur(__iter), _M_at_end()
929  { }
930 
931  iterator(const path* __path, bool __at_end)
932  : _M_path(__path), _M_cur(), _M_at_end(__at_end)
933  { }
934 
935  bool _M_equals(iterator) const;
936 
937  const path* _M_path;
938  path::_List::const_iterator _M_cur;
939  bool _M_at_end; // only used when type != _Multi
940  };
941 
942 
943  inline path&
944  path::operator=(path&& __p) noexcept
945  {
946  if (&__p == this) [[__unlikely__]]
947  return *this;
948 
949  _M_pathname = std::move(__p._M_pathname);
950  _M_cmpts = std::move(__p._M_cmpts);
951  __p.clear();
952  return *this;
953  }
954 
955  inline path&
956  path::operator=(string_type&& __source)
957  { return *this = path(std::move(__source)); }
958 
959  inline path&
960  path::assign(string_type&& __source)
961  { return *this = path(std::move(__source)); }
962 
963  inline path&
964  path::operator+=(const string_type& __x)
965  {
966  _M_concat(__x);
967  return *this;
968  }
969 
970  inline path&
971  path::operator+=(const value_type* __x)
972  {
973  _M_concat(__x);
974  return *this;
975  }
976 
977  inline path&
978  path::operator+=(value_type __x)
979  {
980  _M_concat(basic_string_view<value_type>(&__x, 1));
981  return *this;
982  }
983 
984  inline path&
985  path::operator+=(basic_string_view<value_type> __x)
986  {
987  _M_concat(__x);
988  return *this;
989  }
990 
991  template<typename _CharT>
992  inline __detail::_Path<_CharT*, _CharT*>&
993  path::operator+=(_CharT __x)
994  {
995  auto* __addr = std::__addressof(__x);
996  return concat(__addr, __addr + 1);
997  }
998 
999  inline path&
1000  path::make_preferred()
1001  {
1002 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
1003  std::replace(_M_pathname.begin(), _M_pathname.end(), L'/',
1004  preferred_separator);
1005 #endif
1006  return *this;
1007  }
1008 
1009  inline void path::swap(path& __rhs) noexcept
1010  {
1011  _M_pathname.swap(__rhs._M_pathname);
1012  _M_cmpts.swap(__rhs._M_cmpts);
1013  }
1014 
1015  /// @cond undocumented
1016  template<typename _CharT, typename _Traits, typename _Allocator>
1018  path::_S_str_convert(basic_string_view<value_type> __str,
1019  const _Allocator& __a)
1020  {
1021  static_assert(!is_same_v<_CharT, value_type>);
1022 
1023  using _WString = basic_string<_CharT, _Traits, _Allocator>;
1024 
1025  if (__str.size() == 0)
1026  return _WString(__a);
1027 
1028 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
1029  // First convert native string from UTF-16 to to UTF-8.
1030  // XXX This assumes that the execution wide-character set is UTF-16.
1031  std::codecvt_utf8_utf16<value_type> __cvt;
1032 
1033  using _CharAlloc = __alloc_rebind<_Allocator, char>;
1034  using _String = basic_string<char, char_traits<char>, _CharAlloc>;
1035  _String __u8str{_CharAlloc{__a}};
1036  const value_type* __wfirst = __str.data();
1037  const value_type* __wlast = __wfirst + __str.size();
1038  if (__str_codecvt_out_all(__wfirst, __wlast, __u8str, __cvt)) {
1039  if constexpr (is_same_v<_CharT, char>)
1040  return __u8str; // XXX assumes native ordinary encoding is UTF-8.
1041  else {
1042 
1043  const char* __first = __u8str.data();
1044  const char* __last = __first + __u8str.size();
1045 #else
1046  const value_type* __first = __str.data();
1047  const value_type* __last = __first + __str.size();
1048 #endif
1049 
1050  // Convert UTF-8 string to requested format.
1051 #ifdef _GLIBCXX_USE_CHAR8_T
1052  if constexpr (is_same_v<_CharT, char8_t>)
1053  return _WString(__first, __last, __a);
1054  else
1055 #endif
1056  {
1057  // Convert UTF-8 to wide string.
1058  _WString __wstr(__a);
1059  struct _UCvt : std::codecvt<_CharT, char, std::mbstate_t> { } __cvt;
1060  if (__str_codecvt_in_all(__first, __last, __wstr, __cvt))
1061  return __wstr;
1062  }
1063 
1064 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
1065  } }
1066 #endif
1067  _GLIBCXX_THROW_OR_ABORT(filesystem_error(
1068  "Cannot convert character sequence",
1069  std::make_error_code(errc::illegal_byte_sequence)));
1070  }
1071  /// @endcond
1072 
1073  template<typename _CharT, typename _Traits, typename _Allocator>
1074  inline basic_string<_CharT, _Traits, _Allocator>
1075  path::string(const _Allocator& __a) const
1076  {
1077  if constexpr (is_same_v<_CharT, value_type>)
1078  return { _M_pathname.c_str(), _M_pathname.length(), __a };
1079  else
1080  return _S_str_convert<_CharT, _Traits>(_M_pathname, __a);
1081  }
1082 
1083  inline std::string
1084  path::string() const { return string<char>(); }
1085 
1086 #if _GLIBCXX_USE_WCHAR_T
1087  inline std::wstring
1088  path::wstring() const { return string<wchar_t>(); }
1089 #endif
1090 
1091 #ifdef _GLIBCXX_USE_CHAR8_T
1092  inline std::u8string
1093  path::u8string() const { return string<char8_t>(); }
1094 #else
1095  inline std::string
1096  path::u8string() const
1097  {
1098 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
1099  std::string __str;
1100  // convert from native wide encoding (assumed to be UTF-16) to UTF-8
1101  std::codecvt_utf8_utf16<value_type> __cvt;
1102  const value_type* __first = _M_pathname.data();
1103  const value_type* __last = __first + _M_pathname.size();
1104  if (__str_codecvt_out_all(__first, __last, __str, __cvt))
1105  return __str;
1106  _GLIBCXX_THROW_OR_ABORT(filesystem_error(
1107  "Cannot convert character sequence",
1108  std::make_error_code(errc::illegal_byte_sequence)));
1109 #else
1110  return _M_pathname;
1111 #endif
1112  }
1113 #endif // _GLIBCXX_USE_CHAR8_T
1114 
1115  inline std::u16string
1116  path::u16string() const { return string<char16_t>(); }
1117 
1118  inline std::u32string
1119  path::u32string() const { return string<char32_t>(); }
1120 
1121  template<typename _CharT, typename _Traits, typename _Allocator>
1123  path::generic_string(const _Allocator& __a) const
1124  {
1125 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
1126  const value_type __slash = L'/';
1127 #else
1128  const value_type __slash = '/';
1129 #endif
1130  using _Alloc2 = typename allocator_traits<_Allocator>::template
1131  rebind_alloc<value_type>;
1132  basic_string<value_type, char_traits<value_type>, _Alloc2> __str(__a);
1133 
1134  if (_M_type() == _Type::_Root_dir)
1135  __str.assign(1, __slash);
1136  else
1137  {
1138  __str.reserve(_M_pathname.size());
1139  bool __add_slash = false;
1140  for (auto& __elem : *this)
1141  {
1142 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
1143  if (__elem._M_type() == _Type::_Root_dir)
1144  {
1145  __str += __slash;
1146  continue;
1147  }
1148 #endif
1149  if (__add_slash)
1150  __str += __slash;
1151  __str += basic_string_view<value_type>(__elem._M_pathname);
1152  __add_slash = __elem._M_type() == _Type::_Filename;
1153  }
1154  }
1155 
1156  if constexpr (is_same_v<_CharT, value_type>)
1157  return __str;
1158  else
1159  return _S_str_convert<_CharT, _Traits>(__str, __a);
1160  }
1161 
1162  inline std::string
1163  path::generic_string() const
1164  { return generic_string<char>(); }
1165 
1166 #if _GLIBCXX_USE_WCHAR_T
1167  inline std::wstring
1168  path::generic_wstring() const
1169  { return generic_string<wchar_t>(); }
1170 #endif
1171 
1172 #ifdef _GLIBCXX_USE_CHAR8_T
1173  inline std::u8string
1174  path::generic_u8string() const
1175  { return generic_string<char8_t>(); }
1176 #else
1177  inline std::string
1178  path::generic_u8string() const
1179  { return generic_string(); }
1180 #endif
1181 
1182  inline std::u16string
1183  path::generic_u16string() const
1184  { return generic_string<char16_t>(); }
1185 
1186  inline std::u32string
1187  path::generic_u32string() const
1188  { return generic_string<char32_t>(); }
1189 
1190  inline int
1191  path::compare(const string_type& __s) const noexcept
1192  { return compare(basic_string_view<value_type>(__s)); }
1193 
1194  inline int
1195  path::compare(const value_type* __s) const noexcept
1196  { return compare(basic_string_view<value_type>(__s)); }
1197 
1198  inline path
1199  path::filename() const
1200  {
1201  if (empty())
1202  return {};
1203  else if (_M_type() == _Type::_Filename)
1204  return *this;
1205  else if (_M_type() == _Type::_Multi)
1206  {
1207  if (_M_pathname.back() == preferred_separator)
1208  return {};
1209  auto& __last = *--end();
1210  if (__last._M_type() == _Type::_Filename)
1211  return __last;
1212  }
1213  return {};
1214  }
1215 
1216  inline path
1217  path::stem() const
1218  {
1219  auto ext = _M_find_extension();
1220  if (ext.first && ext.second != 0)
1221  return path{ext.first->substr(0, ext.second)};
1222  return {};
1223  }
1224 
1225  inline path
1226  path::extension() const
1227  {
1228  auto ext = _M_find_extension();
1229  if (ext.first && ext.second != string_type::npos)
1230  return path{ext.first->substr(ext.second)};
1231  return {};
1232  }
1233 
1234  inline bool
1235  path::has_stem() const noexcept
1236  {
1237  auto ext = _M_find_extension();
1238  return ext.first && ext.second != 0;
1239  }
1240 
1241  inline bool
1242  path::has_extension() const noexcept
1243  {
1244  auto ext = _M_find_extension();
1245  return ext.first && ext.second != string_type::npos;
1246  }
1247 
1248  inline bool
1249  path::is_absolute() const noexcept
1250  {
1251 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
1252  return has_root_name() && has_root_directory();
1253 #else
1254  return has_root_directory();
1255 #endif
1256  }
1257 
1258  inline path::iterator
1259  path::begin() const
1260  {
1261  if (_M_type() == _Type::_Multi)
1262  return iterator(this, _M_cmpts.begin());
1263  return iterator(this, empty());
1264  }
1265 
1266  inline path::iterator
1267  path::end() const
1268  {
1269  if (_M_type() == _Type::_Multi)
1270  return iterator(this, _M_cmpts.end());
1271  return iterator(this, true);
1272  }
1273 
1274  inline path::iterator&
1275  path::iterator::operator++()
1276  {
1277  __glibcxx_assert(_M_path != nullptr);
1278  if (_M_path->_M_type() == _Type::_Multi)
1279  {
1280  __glibcxx_assert(_M_cur != _M_path->_M_cmpts.end());
1281  ++_M_cur;
1282  }
1283  else
1284  {
1285  __glibcxx_assert(!_M_at_end);
1286  _M_at_end = true;
1287  }
1288  return *this;
1289  }
1290 
1291  inline path::iterator&
1292  path::iterator::operator--()
1293  {
1294  __glibcxx_assert(_M_path != nullptr);
1295  if (_M_path->_M_type() == _Type::_Multi)
1296  {
1297  __glibcxx_assert(_M_cur != _M_path->_M_cmpts.begin());
1298  --_M_cur;
1299  }
1300  else
1301  {
1302  __glibcxx_assert(_M_at_end);
1303  _M_at_end = false;
1304  }
1305  return *this;
1306  }
1307 
1308  inline path::iterator::reference
1310  {
1311  __glibcxx_assert(_M_path != nullptr);
1312  if (_M_path->_M_type() == _Type::_Multi)
1313  {
1314  __glibcxx_assert(_M_cur != _M_path->_M_cmpts.end());
1315  return *_M_cur;
1316  }
1317  return *_M_path;
1318  }
1319 
1320  inline bool
1321  path::iterator::_M_equals(iterator __rhs) const
1322  {
1323  if (_M_path != __rhs._M_path)
1324  return false;
1325  if (_M_path == nullptr)
1326  return true;
1327  if (_M_path->_M_type() == path::_Type::_Multi)
1328  return _M_cur == __rhs._M_cur;
1329  return _M_at_end == __rhs._M_at_end;
1330  }
1331 
1332  // @} group filesystem
1333 _GLIBCXX_END_NAMESPACE_CXX11
1334 } // namespace filesystem
1335 
1336 inline ptrdiff_t
1337 distance(filesystem::path::iterator __first, filesystem::path::iterator __last)
1338 { return __path_iter_distance(__first, __last); }
1339 
1340 template<typename _InputIterator, typename _Distance>
1341  void
1342  advance(filesystem::path::iterator& __i, _Distance __n)
1343  { __path_iter_advance(__i, static_cast<ptrdiff_t>(__n)); }
1344 
1345 extern template class __shared_ptr<const filesystem::filesystem_error::_Impl>;
1346 
1347 _GLIBCXX_END_NAMESPACE_VERSION
1348 } // namespace std
1349 
1350 #endif // C++17
1351 
1352 #endif // _GLIBCXX_FS_PATH_H
std::u32string
basic_string< char32_t > u32string
A string of char32_t.
Definition: stringfwd.h:96
iosfwd
std::distance
constexpr iterator_traits< _InputIterator >::difference_type distance(_InputIterator __first, _InputIterator __last)
A generalization of pointer arithmetic.
Definition: stl_iterator_base_funcs.h:138
std::string
basic_string< char > string
A string of char.
Definition: stringfwd.h:74
std::bidirectional_iterator_tag
Bidirectional iterators support a superset of forward iterator operations.
Definition: stl_iterator_base_types.h:103
std::codecvt
Primary class template codecvt.
Definition: codecvt.h:274
iomanip
locale_conv.h
std::u16string
basic_string< char16_t > u16string
A string of char16_t.
Definition: stringfwd.h:93
std::basic_string::reserve
void reserve(size_type __res_arg=0)
Attempt to preallocate enough memory for specified number of characters.
Definition: basic_string.tcc:954
std::remove_cv_t
typename remove_cv< _Tp >::type remove_cv_t
Alias template for remove_cv.
Definition: type_traits:1561
std::replace
constexpr void replace(_ForwardIterator __first, _ForwardIterator __last, const _Tp &__old_value, const _Tp &__new_value)
Replace each occurrence of one value in a sequence with another value.
Definition: stl_algo.h:4373
std
ISO C++ entities toplevel namespace is std.
std::basic_string::push_back
void push_back(_CharT __c)
Append a single character.
Definition: basic_string.h:4321
std::basic_ostream
Template class basic_ostream.
Definition: iosfwd:86
std::input_iterator_tag
Marking input iterators.
Definition: stl_iterator_base_types.h:93
std::basic_string::data
const _CharT * data() const noexcept
Return const pointer to contents.
Definition: basic_string.h:5209
stl_algobase.h
std::advance
constexpr void advance(_InputIterator &__i, _Distance __n)
A generalization of pointer arithmetic.
Definition: stl_iterator_base_funcs.h:202
std::basic_string::c_str
const _CharT * c_str() const noexcept
Return const pointer to null-terminated contents.
Definition: basic_string.h:5197
std::end
_Tp * end(valarray< _Tp > &__va)
Return an iterator pointing to one past the last element of the valarray.
Definition: valarray:1234
std::locale
Container class for localization functionality.
Definition: locale_classes.h:62
std::basic_istream
Template class basic_istream.
Definition: iosfwd:83
std::basic_string::assign
basic_string & assign(const basic_string &__str)
Set value to contents of another string.
Definition: basic_string.tcc:695
std::operator>>
std::basic_istream< _CharT, _Traits > & operator>>(std::basic_istream< _CharT, _Traits > &__is, bitset< _Nb > &__x)
Global I/O operators for bitsets.
Definition: bitset:1470
std::wstring
basic_string< wchar_t > wstring
A string of wchar_t.
Definition: stringfwd.h:83
std::integral_constant
integral_constant
Definition: type_traits:57
std::system_error
An exception type that includes an error_code value.
Definition: system_error:428
locale
std::begin
_Tp * begin(valarray< _Tp > &__va)
Return an iterator pointing to the first element of the valarray.
Definition: valarray:1214
std::__addressof
constexpr _Tp * __addressof(_Tp &__r) noexcept
Same as C++11 std::addressof.
Definition: move.h:49
std::quoted
auto quoted(const _CharT *__string, _CharT __delim=_CharT('"'), _CharT __escape = _CharT('\\'))
Manipulator for quoted strings.
Definition: iomanip:461
unique_ptr.h
std::enable_if
Define a member typedef type only if a boolean constant is true.
Definition: type_traits:2169
std::is_base_of
is_base_of
Definition: type_traits:1399
concurrence.h
std::basic_string< value_type >
std::is_same
is_same
Definition: type_traits:582
std::operator/
constexpr complex< _Tp > operator/(const complex< _Tp > &__x, const complex< _Tp > &__y)
Return new complex value x divided by y.
Definition: complex:421
std::operator*
constexpr complex< _Tp > operator*(const complex< _Tp > &__x, const complex< _Tp > &__y)
Return new complex value x times y.
Definition: complex:391
std::remove_const_t
typename remove_const< _Tp >::type remove_const_t
Alias template for remove_const.
Definition: type_traits:1553
std::basic_string::size
size_type size() const noexcept
Returns the number of characters in the string, not including any null-termination.
Definition: basic_string.h:3903
std::iterator_traits
Traits class for iterators.
Definition: cpp_type_traits.h:423
codecvt
std::enable_if_t
typename enable_if< _Cond, _Tp >::type enable_if_t
Alias template for enable_if.
Definition: type_traits:2541
std::move
constexpr std::remove_reference< _Tp >::type && move(_Tp &&__t) noexcept
Convert a value to an rvalue.
Definition: move.h:101