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