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