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