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  /// Exception type thrown by the Filesystem library
616  class filesystem_error : public std::system_error
617  {
618  public:
619  filesystem_error(const string& __what_arg, error_code __ec);
620 
621  filesystem_error(const string& __what_arg, const path& __p1,
622  error_code __ec);
623 
624  filesystem_error(const string& __what_arg, const path& __p1,
625  const path& __p2, error_code __ec);
626 
627  filesystem_error(const filesystem_error&) = default;
628  filesystem_error& operator=(const filesystem_error&) = default;
629 
630  // No move constructor or assignment operator.
631  // Copy rvalues instead, so that _M_impl is not left empty.
632 
633  ~filesystem_error();
634 
635  const path& path1() const noexcept;
636  const path& path2() const noexcept;
637  const char* what() const noexcept;
638 
639  private:
640  struct _Impl;
641  std::__shared_ptr<const _Impl> _M_impl;
642  };
643 
644  /// Create a path from a UTF-8-encoded sequence of char
645  template<typename _InputIterator>
646  inline auto
647  u8path(_InputIterator __first, _InputIterator __last)
648  -> decltype(filesystem::path(__first, __last, std::locale::classic()))
649  {
650 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
651  // XXX This assumes native wide encoding is UTF-16.
652  std::codecvt_utf8_utf16<path::value_type> __cvt;
653  path::string_type __tmp;
654  if constexpr (is_pointer_v<_InputIterator>)
655  {
656  if (__str_codecvt_in_all(__first, __last, __tmp, __cvt))
657  return path{ __tmp };
658  }
659  else
660  {
661  const std::string __u8str{__first, __last};
662  const char* const __ptr = __u8str.data();
663  if (__str_codecvt_in_all(__ptr, __ptr + __u8str.size(), __tmp, __cvt))
664  return path{ __tmp };
665  }
666  _GLIBCXX_THROW_OR_ABORT(filesystem_error(
667  "Cannot convert character sequence",
668  std::make_error_code(errc::illegal_byte_sequence)));
669 #else
670  // This assumes native normal encoding is UTF-8.
671  return path{ __first, __last };
672 #endif
673  }
674 
675  /// Create a path from a UTF-8-encoded sequence of char
676  template<typename _Source>
677  inline auto
678  u8path(const _Source& __source)
679  -> decltype(filesystem::path(__source, std::locale::classic()))
680  {
681 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
682  if constexpr (is_convertible_v<const _Source&, std::string_view>)
683  {
684  const std::string_view __s = __source;
685  return filesystem::u8path(__s.data(), __s.data() + __s.size());
686  }
687  else
688  {
689  std::string __s = path::_S_string_from_iter(__source);
690  return filesystem::u8path(__s.data(), __s.data() + __s.size());
691  }
692 #else
693  return path{ __source };
694 #endif
695  }
696 
697  struct path::_Cmpt : path
698  {
699  _Cmpt(basic_string_view<value_type> __s, _Type __t, size_t __pos)
700  : path(__s, __t), _M_pos(__pos) { }
701 
702  _Cmpt() : _M_pos(-1) { }
703 
704  size_t _M_pos;
705  };
706 
707  // specialize _Cvt for degenerate 'noconv' case
708  template<>
709  struct path::_Cvt<path::value_type>
710  {
711  template<typename _Iter>
712  static string_type
713  _S_convert(_Iter __first, _Iter __last)
714  { return string_type{__first, __last}; }
715  };
716 
717 #if !defined _GLIBCXX_FILESYSTEM_IS_WINDOWS && defined _GLIBCXX_USE_CHAR8_T
718  // For POSIX converting from char8_t to char is also 'noconv'
719  template<>
720  struct path::_Cvt<char8_t>
721  {
722  template<typename _Iter>
723  static string_type
724  _S_convert(_Iter __first, _Iter __last)
725  { return string_type(__first, __last); }
726  };
727 #endif
728 
729  template<typename _CharT>
730  struct path::_Cvt
731  {
732  static string_type
733  _S_convert(const _CharT* __f, const _CharT* __l)
734  {
735 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
736  std::wstring __wstr;
737  if constexpr (is_same_v<_CharT, char>)
738  {
739  struct _UCvt : std::codecvt<wchar_t, char, std::mbstate_t>
740  { } __cvt;
741  if (__str_codecvt_in_all(__f, __l, __wstr, __cvt))
742  return __wstr;
743  }
744 #ifdef _GLIBCXX_USE_CHAR8_T
745  else if constexpr (is_same_v<_CharT, char8_t>)
746  {
747  const char* __f2 = (const char*)__f;
748  const char* __l2 = (const char*)__l;
749  std::codecvt_utf8_utf16<wchar_t> __wcvt;
750  if (__str_codecvt_in_all(__f2, __l2, __wstr, __wcvt))
751  return __wstr;
752  }
753 #endif
754  else // char16_t or char32_t
755  {
756  struct _UCvt : std::codecvt<_CharT, char, std::mbstate_t>
757  { } __cvt;
758  std::string __str;
759  if (__str_codecvt_out_all(__f, __l, __str, __cvt))
760  {
761  const char* __f2 = __str.data();
762  const char* __l2 = __f2 + __str.size();
763  std::codecvt_utf8_utf16<wchar_t> __wcvt;
764  if (__str_codecvt_in_all(__f2, __l2, __wstr, __wcvt))
765  return __wstr;
766  }
767  }
768 #else // ! windows
769  struct _UCvt : std::codecvt<_CharT, char, std::mbstate_t>
770  { } __cvt;
771  std::string __str;
772  if (__str_codecvt_out_all(__f, __l, __str, __cvt))
773  return __str;
774 #endif
775  _GLIBCXX_THROW_OR_ABORT(filesystem_error(
776  "Cannot convert character sequence",
777  std::make_error_code(errc::illegal_byte_sequence)));
778  }
779 
780  static string_type
781  _S_convert(_CharT* __f, _CharT* __l)
782  {
783  return _S_convert(const_cast<const _CharT*>(__f),
784  const_cast<const _CharT*>(__l));
785  }
786 
787  template<typename _Iter>
788  static string_type
789  _S_convert(_Iter __first, _Iter __last)
790  {
791  const std::basic_string<_CharT> __str(__first, __last);
792  return _S_convert(__str.data(), __str.data() + __str.size());
793  }
794 
795  template<typename _Iter, typename _Cont>
796  static string_type
797  _S_convert(__gnu_cxx::__normal_iterator<_Iter, _Cont> __first,
798  __gnu_cxx::__normal_iterator<_Iter, _Cont> __last)
799  { return _S_convert(__first.base(), __last.base()); }
800  };
801 
802  /// An iterator for the components of a path
803  class path::iterator
804  {
805  public:
806  using difference_type = std::ptrdiff_t;
807  using value_type = path;
808  using reference = const path&;
809  using pointer = const path*;
810  using iterator_category = std::bidirectional_iterator_tag;
811 
812  iterator() : _M_path(nullptr), _M_cur(), _M_at_end() { }
813 
814  iterator(const iterator&) = default;
815  iterator& operator=(const iterator&) = default;
816 
817  reference operator*() const;
818  pointer operator->() const { return std::__addressof(**this); }
819 
820  iterator& operator++();
821  iterator operator++(int) { auto __tmp = *this; ++*this; return __tmp; }
822 
823  iterator& operator--();
824  iterator operator--(int) { auto __tmp = *this; --*this; return __tmp; }
825 
826  friend bool operator==(const iterator& __lhs, const iterator& __rhs)
827  { return __lhs._M_equals(__rhs); }
828 
829  friend bool operator!=(const iterator& __lhs, const iterator& __rhs)
830  { return !__lhs._M_equals(__rhs); }
831 
832  private:
833  friend class path;
834 
835  bool _M_is_multi() const { return _M_path->_M_type() == _Type::_Multi; }
836 
837  friend difference_type
838  __path_iter_distance(const iterator& __first, const iterator& __last)
839  {
840  __glibcxx_assert(__first._M_path != nullptr);
841  __glibcxx_assert(__first._M_path == __last._M_path);
842  if (__first._M_is_multi())
843  return std::distance(__first._M_cur, __last._M_cur);
844  else if (__first._M_at_end == __last._M_at_end)
845  return 0;
846  else
847  return __first._M_at_end ? -1 : 1;
848  }
849 
850  friend void
851  __path_iter_advance(iterator& __i, difference_type __n)
852  {
853  if (__n == 1)
854  ++__i;
855  else if (__n == -1)
856  --__i;
857  else if (__n != 0)
858  {
859  __glibcxx_assert(__i._M_path != nullptr);
860  __glibcxx_assert(__i._M_is_multi());
861  // __glibcxx_assert(__i._M_path->_M_cmpts.end() - __i._M_cur >= __n);
862  __i._M_cur += __n;
863  }
864  }
865 
866  iterator(const path* __path, path::_List::const_iterator __iter)
867  : _M_path(__path), _M_cur(__iter), _M_at_end()
868  { }
869 
870  iterator(const path* __path, bool __at_end)
871  : _M_path(__path), _M_cur(), _M_at_end(__at_end)
872  { }
873 
874  bool _M_equals(iterator) const;
875 
876  const path* _M_path;
877  path::_List::const_iterator _M_cur;
878  bool _M_at_end; // only used when type != _Multi
879  };
880 
881 
882  inline path&
883  path::operator=(path&& __p) noexcept
884  {
885  if (&__p == this) [[__unlikely__]]
886  return *this;
887 
888  _M_pathname = std::move(__p._M_pathname);
889  _M_cmpts = std::move(__p._M_cmpts);
890  __p.clear();
891  return *this;
892  }
893 
894  inline path&
895  path::operator=(string_type&& __source)
896  { return *this = path(std::move(__source)); }
897 
898  inline path&
899  path::assign(string_type&& __source)
900  { return *this = path(std::move(__source)); }
901 
902  inline path&
903  path::operator+=(const string_type& __x)
904  {
905  _M_concat(__x);
906  return *this;
907  }
908 
909  inline path&
910  path::operator+=(const value_type* __x)
911  {
912  _M_concat(__x);
913  return *this;
914  }
915 
916  inline path&
917  path::operator+=(value_type __x)
918  {
919  _M_concat(basic_string_view<value_type>(&__x, 1));
920  return *this;
921  }
922 
923  inline path&
924  path::operator+=(basic_string_view<value_type> __x)
925  {
926  _M_concat(__x);
927  return *this;
928  }
929 
930  template<typename _CharT>
931  inline path::_Path<_CharT*, _CharT*>&
932  path::operator+=(_CharT __x)
933  {
934  auto* __addr = std::__addressof(__x);
935  return concat(__addr, __addr + 1);
936  }
937 
938  inline path&
939  path::make_preferred()
940  {
941 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
942  std::replace(_M_pathname.begin(), _M_pathname.end(), L'/',
943  preferred_separator);
944 #endif
945  return *this;
946  }
947 
948  inline void path::swap(path& __rhs) noexcept
949  {
950  _M_pathname.swap(__rhs._M_pathname);
951  _M_cmpts.swap(__rhs._M_cmpts);
952  }
953 
954  template<typename _CharT, typename _Traits, typename _Allocator>
956  path::_S_str_convert(const string_type& __str, const _Allocator& __a)
957  {
958  static_assert(!is_same_v<_CharT, value_type>);
959 
960  using _WString = basic_string<_CharT, _Traits, _Allocator>;
961 
962  if (__str.size() == 0)
963  return _WString(__a);
964 
965 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
966  // First convert native string from UTF-16 to to UTF-8.
967  // XXX This assumes that the execution wide-character set is UTF-16.
968  std::codecvt_utf8_utf16<value_type> __cvt;
969 
970  using _CharAlloc = __alloc_rebind<_Allocator, char>;
971  using _String = basic_string<char, char_traits<char>, _CharAlloc>;
972  _String __u8str{_CharAlloc{__a}};
973  const value_type* __wfirst = __str.data();
974  const value_type* __wlast = __wfirst + __str.size();
975  if (__str_codecvt_out_all(__wfirst, __wlast, __u8str, __cvt)) {
976  if constexpr (is_same_v<_CharT, char>)
977  return __u8str; // XXX assumes native ordinary encoding is UTF-8.
978  else {
979 
980  const char* __first = __u8str.data();
981  const char* __last = __first + __u8str.size();
982 #else
983  const value_type* __first = __str.data();
984  const value_type* __last = __first + __str.size();
985 #endif
986 
987  // Convert UTF-8 string to requested format.
988 #ifdef _GLIBCXX_USE_CHAR8_T
989  if constexpr (is_same_v<_CharT, char8_t>)
990  return _WString(__first, __last, __a);
991  else
992 #endif
993  {
994  // Convert UTF-8 to wide string.
995  _WString __wstr(__a);
996  struct _UCvt : std::codecvt<_CharT, char, std::mbstate_t> { } __cvt;
997  if (__str_codecvt_in_all(__first, __last, __wstr, __cvt))
998  return __wstr;
999  }
1000 
1001 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
1002  } }
1003 #endif
1004  _GLIBCXX_THROW_OR_ABORT(filesystem_error(
1005  "Cannot convert character sequence",
1006  std::make_error_code(errc::illegal_byte_sequence)));
1007  }
1008 
1009  template<typename _CharT, typename _Traits, typename _Allocator>
1010  inline basic_string<_CharT, _Traits, _Allocator>
1011  path::string(const _Allocator& __a) const
1012  {
1013  if constexpr (is_same_v<_CharT, value_type>)
1014  return { _M_pathname.c_str(), _M_pathname.length(), __a };
1015  else
1016  return _S_str_convert<_CharT, _Traits>(_M_pathname, __a);
1017  }
1018 
1019  inline std::string
1020  path::string() const { return string<char>(); }
1021 
1022 #if _GLIBCXX_USE_WCHAR_T
1023  inline std::wstring
1024  path::wstring() const { return string<wchar_t>(); }
1025 #endif
1026 
1027 #ifdef _GLIBCXX_USE_CHAR8_T
1028  inline std::u8string
1029  path::u8string() const { return string<char8_t>(); }
1030 #else
1031  inline std::string
1032  path::u8string() const
1033  {
1034 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
1035  std::string __str;
1036  // convert from native wide encoding (assumed to be UTF-16) to UTF-8
1037  std::codecvt_utf8_utf16<value_type> __cvt;
1038  const value_type* __first = _M_pathname.data();
1039  const value_type* __last = __first + _M_pathname.size();
1040  if (__str_codecvt_out_all(__first, __last, __str, __cvt))
1041  return __str;
1042  _GLIBCXX_THROW_OR_ABORT(filesystem_error(
1043  "Cannot convert character sequence",
1044  std::make_error_code(errc::illegal_byte_sequence)));
1045 #else
1046  return _M_pathname;
1047 #endif
1048  }
1049 #endif // _GLIBCXX_USE_CHAR8_T
1050 
1051  inline std::u16string
1052  path::u16string() const { return string<char16_t>(); }
1053 
1054  inline std::u32string
1055  path::u32string() const { return string<char32_t>(); }
1056 
1057  template<typename _CharT, typename _Traits, typename _Allocator>
1059  path::generic_string(const _Allocator& __a) const
1060  {
1061 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
1062  const value_type __slash = L'/';
1063 #else
1064  const value_type __slash = '/';
1065 #endif
1066  string_type __str(__a);
1067 
1068  if (_M_type() == _Type::_Root_dir)
1069  __str.assign(1, __slash);
1070  else
1071  {
1072  __str.reserve(_M_pathname.size());
1073  bool __add_slash = false;
1074  for (auto& __elem : *this)
1075  {
1076  if (__add_slash)
1077  __str += __slash;
1078  __str += __elem._M_pathname;
1079  __add_slash = __elem._M_type() == _Type::_Filename;
1080  }
1081  }
1082 
1083  if constexpr (is_same_v<_CharT, value_type>)
1084  return __str;
1085  else
1086  return _S_str_convert<_CharT, _Traits>(__str, __a);
1087  }
1088 
1089  inline std::string
1090  path::generic_string() const
1091  { return generic_string<char>(); }
1092 
1093 #if _GLIBCXX_USE_WCHAR_T
1094  inline std::wstring
1095  path::generic_wstring() const
1096  { return generic_string<wchar_t>(); }
1097 #endif
1098 
1099 #ifdef _GLIBCXX_USE_CHAR8_T
1100  inline std::u8string
1101  path::generic_u8string() const
1102  { return generic_string<char8_t>(); }
1103 #else
1104  inline std::string
1105  path::generic_u8string() const
1106  { return generic_string(); }
1107 #endif
1108 
1109  inline std::u16string
1110  path::generic_u16string() const
1111  { return generic_string<char16_t>(); }
1112 
1113  inline std::u32string
1114  path::generic_u32string() const
1115  { return generic_string<char32_t>(); }
1116 
1117  inline int
1118  path::compare(const string_type& __s) const noexcept
1119  { return compare(basic_string_view<value_type>(__s)); }
1120 
1121  inline int
1122  path::compare(const value_type* __s) const noexcept
1123  { return compare(basic_string_view<value_type>(__s)); }
1124 
1125  inline path
1126  path::filename() const
1127  {
1128  if (empty())
1129  return {};
1130  else if (_M_type() == _Type::_Filename)
1131  return *this;
1132  else if (_M_type() == _Type::_Multi)
1133  {
1134  if (_M_pathname.back() == preferred_separator)
1135  return {};
1136  auto& __last = *--end();
1137  if (__last._M_type() == _Type::_Filename)
1138  return __last;
1139  }
1140  return {};
1141  }
1142 
1143  inline path
1144  path::stem() const
1145  {
1146  auto ext = _M_find_extension();
1147  if (ext.first && ext.second != 0)
1148  return path{ext.first->substr(0, ext.second)};
1149  return {};
1150  }
1151 
1152  inline path
1153  path::extension() const
1154  {
1155  auto ext = _M_find_extension();
1156  if (ext.first && ext.second != string_type::npos)
1157  return path{ext.first->substr(ext.second)};
1158  return {};
1159  }
1160 
1161  inline bool
1162  path::has_stem() const noexcept
1163  {
1164  auto ext = _M_find_extension();
1165  return ext.first && ext.second != 0;
1166  }
1167 
1168  inline bool
1169  path::has_extension() const noexcept
1170  {
1171  auto ext = _M_find_extension();
1172  return ext.first && ext.second != string_type::npos;
1173  }
1174 
1175  inline bool
1176  path::is_absolute() const noexcept
1177  {
1178 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
1179  return has_root_name() && has_root_directory();
1180 #else
1181  return has_root_directory();
1182 #endif
1183  }
1184 
1185  inline path::iterator
1186  path::begin() const
1187  {
1188  if (_M_type() == _Type::_Multi)
1189  return iterator(this, _M_cmpts.begin());
1190  return iterator(this, empty());
1191  }
1192 
1193  inline path::iterator
1194  path::end() const
1195  {
1196  if (_M_type() == _Type::_Multi)
1197  return iterator(this, _M_cmpts.end());
1198  return iterator(this, true);
1199  }
1200 
1201  inline path::iterator&
1202  path::iterator::operator++()
1203  {
1204  __glibcxx_assert(_M_path != nullptr);
1205  if (_M_path->_M_type() == _Type::_Multi)
1206  {
1207  __glibcxx_assert(_M_cur != _M_path->_M_cmpts.end());
1208  ++_M_cur;
1209  }
1210  else
1211  {
1212  __glibcxx_assert(!_M_at_end);
1213  _M_at_end = true;
1214  }
1215  return *this;
1216  }
1217 
1218  inline path::iterator&
1219  path::iterator::operator--()
1220  {
1221  __glibcxx_assert(_M_path != nullptr);
1222  if (_M_path->_M_type() == _Type::_Multi)
1223  {
1224  __glibcxx_assert(_M_cur != _M_path->_M_cmpts.begin());
1225  --_M_cur;
1226  }
1227  else
1228  {
1229  __glibcxx_assert(_M_at_end);
1230  _M_at_end = false;
1231  }
1232  return *this;
1233  }
1234 
1235  inline path::iterator::reference
1236  path::iterator::operator*() const
1237  {
1238  __glibcxx_assert(_M_path != nullptr);
1239  if (_M_path->_M_type() == _Type::_Multi)
1240  {
1241  __glibcxx_assert(_M_cur != _M_path->_M_cmpts.end());
1242  return *_M_cur;
1243  }
1244  return *_M_path;
1245  }
1246 
1247  inline bool
1248  path::iterator::_M_equals(iterator __rhs) const
1249  {
1250  if (_M_path != __rhs._M_path)
1251  return false;
1252  if (_M_path == nullptr)
1253  return true;
1254  if (_M_path->_M_type() == path::_Type::_Multi)
1255  return _M_cur == __rhs._M_cur;
1256  return _M_at_end == __rhs._M_at_end;
1257  }
1258 
1259  // @} group filesystem
1260 _GLIBCXX_END_NAMESPACE_CXX11
1261 } // namespace filesystem
1262 
1263 inline ptrdiff_t
1264 distance(filesystem::path::iterator __first, filesystem::path::iterator __last)
1265 { return __path_iter_distance(__first, __last); }
1266 
1267 template<typename _InputIterator, typename _Distance>
1268  void
1269  advance(filesystem::path::iterator& __i, _Distance __n)
1270  { __path_iter_advance(__i, static_cast<ptrdiff_t>(__n)); }
1271 
1272 extern template class __shared_ptr<const filesystem::filesystem_error::_Impl>;
1273 
1274 _GLIBCXX_END_NAMESPACE_VERSION
1275 } // namespace std
1276 
1277 #endif // C++17
1278 
1279 #endif // _GLIBCXX_FS_PATH_H
constexpr const _Tp * end(initializer_list< _Tp > __ils) noexcept
Return an iterator pointing to one past the last element of the initializer_list. ...
_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
basic_string< char16_t > u16string
A string of char16_t.
Definition: stringfwd.h:93
Container class for localization functionality.The locale class is first a class wrapper for C librar...
ISO C++ entities toplevel namespace is std.
_GLIBCXX_END_NAMESPACE_CXX11 typedef basic_string< char > string
A string of char.
Definition: stringfwd.h:74
Primary class template codecvt.NB: Generic, mostly useless implementation.
Definition: codecvt.h:274
is_base_of
Definition: type_traits:1301
const _CharT * data() const noexcept
Return const pointer to contents.
Template class basic_ostream.
Definition: iosfwd:86
constexpr const _Tp * begin(initializer_list< _Tp > __ils) noexcept
Return an iterator pointing to the first element of the initializer_list.
integral_constant
Definition: type_traits:57
typename remove_cv< _Tp >::type remove_cv_t
Alias template for remove_cv.
Definition: type_traits:1437
void push_back(_CharT __c)
Append a single character.
Template class basic_istream.
Definition: iosfwd:83
Thrown to indicate error code of underlying system.
Definition: system_error:341
static const locale & classic()
Return reference to the C locale.
std::basic_istream< _CharT, _Traits > & operator>>(std::basic_istream< _CharT, _Traits > &__is, bitset< _Nb > &__x)
Global I/O operators for bitsets.
Definition: bitset:1470
const _CharT * c_str() const noexcept
Return const pointer to null-terminated contents.
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:4395
_GLIBCXX20_CONSTEXPR complex< _Tp > operator/(const complex< _Tp > &__x, const complex< _Tp > &__y)
Return new complex value x divided by y.
Definition: complex:417
basic_string< wchar_t > wstring
A string of wchar_t.
Definition: stringfwd.h:83
size_t hash_value(const path &__p) noexcept
Compare paths.
constexpr _Tp * __addressof(_Tp &__r) noexcept
Same as C++11 std::addressof.
Definition: move.h:47
typename enable_if< _Cond, _Tp >::type enable_if_t
Alias template for enable_if.
Definition: type_traits:2384
_GLIBCXX17_CONSTEXPR iterator_traits< _InputIterator >::difference_type distance(_InputIterator __first, _InputIterator __last)
A generalization of pointer arithmetic.
Marking input iterators.
path u8path(_InputIterator __first, _InputIterator __last)
Create a path from a UTF-8-encoded sequence of char.
Bidirectional iterators support a superset of forward iterator operations.
_GLIBCXX17_CONSTEXPR void advance(_InputIterator &__i, _Distance __n)
A generalization of pointer arithmetic.
basic_string< char32_t > u32string
A string of char32_t.
Definition: stringfwd.h:96
Define a member typedef type only if a boolean constant is true.
Definition: type_traits:2045