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  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  codecvt_utf8<path::value_type> __cvt;
622  path::string_type __tmp;
623  if constexpr (is_pointer_v<_InputIterator>)
624  {
625  if (__str_codecvt_in(__first, __last, __tmp, __cvt))
626  return path{ __tmp };
627  }
628  else
629  {
630  const std::string __u8str{__first, __last};
631  const char* const __ptr = __u8str.data();
632  if (__str_codecvt_in(__ptr, __ptr + __u8str.size(), __tmp, __cvt))
633  return path{ __tmp };
634  }
635  return {};
636 #else
637  return path{ __first, __last };
638 #endif
639  }
640 
641  template<typename _Source>
642  inline auto
643  u8path(const _Source& __source)
644  -> decltype(filesystem::path(__source, std::locale::classic()))
645  {
646 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
647  if constexpr (is_convertible_v<const _Source&, std::string_view>)
648  {
649  const std::string_view __s = __source;
650  return filesystem::u8path(__s.data(), __s.data() + __s.size());
651  }
652  else
653  {
654  std::string __s = path::_S_string_from_iter(__source);
655  return filesystem::u8path(__s.data(), __s.data() + __s.size());
656  }
657 #else
658  return path{ __source };
659 #endif
660  }
661 
662  class filesystem_error : public std::system_error
663  {
664  public:
665  filesystem_error(const string& __what_arg, error_code __ec);
666 
667  filesystem_error(const string& __what_arg, const path& __p1,
668  error_code __ec);
669 
670  filesystem_error(const string& __what_arg, const path& __p1,
671  const path& __p2, error_code __ec);
672 
673  filesystem_error(const filesystem_error&) = default;
674  filesystem_error& operator=(const filesystem_error&) = default;
675 
676  // No move constructor or assignment operator.
677  // Copy rvalues instead, so that _M_impl is not left empty.
678 
679  ~filesystem_error();
680 
681  const path& path1() const noexcept;
682  const path& path2() const noexcept;
683  const char* what() const noexcept;
684 
685  private:
686  struct _Impl;
687  std::__shared_ptr<const _Impl> _M_impl;
688  };
689 
690  struct path::_Cmpt : path
691  {
692  _Cmpt(basic_string_view<value_type> __s, _Type __t, size_t __pos)
693  : path(__s, __t), _M_pos(__pos) { }
694 
695  _Cmpt() : _M_pos(-1) { }
696 
697  size_t _M_pos;
698  };
699 
700  // specialize _Cvt for degenerate 'noconv' case
701  template<>
702  struct path::_Cvt<path::value_type>
703  {
704  template<typename _Iter>
705  static string_type
706  _S_convert(_Iter __first, _Iter __last)
707  { return string_type{__first, __last}; }
708  };
709 
710  template<typename _CharT>
711  struct path::_Cvt
712  {
713 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
714  static string_type
715  _S_wconvert(const char* __f, const char* __l, true_type)
716  {
718  const auto& __cvt = std::use_facet<_Cvt>(std::locale{});
719  std::wstring __wstr;
720  if (__str_codecvt_in(__f, __l, __wstr, __cvt))
721  return __wstr;
722  _GLIBCXX_THROW_OR_ABORT(filesystem_error(
723  "Cannot convert character sequence",
724  std::make_error_code(errc::illegal_byte_sequence)));
725  }
726 
727  static string_type
728  _S_wconvert(const _CharT* __f, const _CharT* __l, false_type)
729  {
730  std::codecvt_utf8<_CharT> __cvt;
731  std::string __str;
732  if (__str_codecvt_out(__f, __l, __str, __cvt))
733  {
734  const char* __f2 = __str.data();
735  const char* __l2 = __f2 + __str.size();
736  std::codecvt_utf8<wchar_t> __wcvt;
737  std::wstring __wstr;
738  if (__str_codecvt_in(__f2, __l2, __wstr, __wcvt))
739  return __wstr;
740  }
741  _GLIBCXX_THROW_OR_ABORT(filesystem_error(
742  "Cannot convert character sequence",
743  std::make_error_code(errc::illegal_byte_sequence)));
744  }
745 
746  static string_type
747  _S_convert(const _CharT* __f, const _CharT* __l)
748  {
749  return _S_wconvert(__f, __l, is_same<_CharT, char>{});
750  }
751 #else
752  static string_type
753  _S_convert(const _CharT* __f, const _CharT* __l)
754  {
755 #ifdef _GLIBCXX_USE_CHAR8_T
756  if constexpr (is_same_v<_CharT, char8_t>)
757  {
758  string_type __str(__f, __l);
759  return __str;
760  }
761  else
762  {
763 #endif
764  std::codecvt_utf8<_CharT> __cvt;
765  std::string __str;
766  if (__str_codecvt_out(__f, __l, __str, __cvt))
767  return __str;
768 #ifdef _GLIBCXX_USE_CHAR8_T
769  }
770 #endif
771  _GLIBCXX_THROW_OR_ABORT(filesystem_error(
772  "Cannot convert character sequence",
773  std::make_error_code(errc::illegal_byte_sequence)));
774  }
775 #endif
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  if (__str.size() == 0)
957 
958  const value_type* __first = __str.data();
959  const value_type* __last = __first + __str.size();
960 
961 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
962  using _CharAlloc = __alloc_rebind<_Allocator, char>;
963  using _String = basic_string<char, char_traits<char>, _CharAlloc>;
964  using _WString = basic_string<_CharT, _Traits, _Allocator>;
965 
966  // use codecvt_utf8<wchar_t> to convert native string to UTF-8
967  codecvt_utf8<value_type> __cvt;
968  _String __u8str{_CharAlloc{__a}};
969  if (__str_codecvt_out(__first, __last, __u8str, __cvt))
970  {
971  if constexpr (is_same_v<_CharT, char>)
972  return __u8str;
973 #ifdef _GLIBCXX_USE_CHAR8_T
974  else if constexpr (is_same_v<_CharT, char8_t>)
975  {
976  const char* __f = __u8str.data();
977  const char* __l = __f + __u8str.size();
978  _WString __wstr(__f, __l);
979  return __wstr;
980  }
981 #endif
982  else
983  {
984  _WString __wstr;
985  // use codecvt_utf8<_CharT> to convert UTF-8 to wide string
986  codecvt_utf8<_CharT> __cvt;
987  const char* __f = __u8str.data();
988  const char* __l = __f + __u8str.size();
989  if (__str_codecvt_in(__f, __l, __wstr, __cvt))
990  return __wstr;
991  }
992  }
993 #else
994 #ifdef _GLIBCXX_USE_CHAR8_T
995  if constexpr (is_same_v<_CharT, char8_t>)
996  {
997  basic_string<_CharT, _Traits, _Allocator> __wstr{__first, __last, __a};
998  return __wstr;
999  }
1000  else
1001  {
1002 #endif
1003  codecvt_utf8<_CharT> __cvt;
1004  basic_string<_CharT, _Traits, _Allocator> __wstr{__a};
1005  if (__str_codecvt_in(__first, __last, __wstr, __cvt))
1006  return __wstr;
1007 #ifdef _GLIBCXX_USE_CHAR8_T
1008  }
1009 #endif
1010 #endif
1011  _GLIBCXX_THROW_OR_ABORT(filesystem_error(
1012  "Cannot convert character sequence",
1013  std::make_error_code(errc::illegal_byte_sequence)));
1014  }
1015 
1016  template<typename _CharT, typename _Traits, typename _Allocator>
1017  inline basic_string<_CharT, _Traits, _Allocator>
1018  path::string(const _Allocator& __a) const
1019  {
1020  if constexpr (is_same_v<_CharT, value_type>)
1021  return { _M_pathname, __a };
1022  else
1023  return _S_str_convert<_CharT, _Traits>(_M_pathname, __a);
1024  }
1025 
1026  inline std::string
1027  path::string() const { return string<char>(); }
1028 
1029 #if _GLIBCXX_USE_WCHAR_T
1030  inline std::wstring
1031  path::wstring() const { return string<wchar_t>(); }
1032 #endif
1033 
1034 #ifdef _GLIBCXX_USE_CHAR8_T
1035  inline std::u8string
1036  path::u8string() const { return string<char8_t>(); }
1037 #else
1038  inline std::string
1039  path::u8string() const
1040  {
1041 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
1042  std::string __str;
1043  // convert from native encoding to UTF-8
1044  codecvt_utf8<value_type> __cvt;
1045  const value_type* __first = _M_pathname.data();
1046  const value_type* __last = __first + _M_pathname.size();
1047  if (__str_codecvt_out(__first, __last, __str, __cvt))
1048  return __str;
1049  _GLIBCXX_THROW_OR_ABORT(filesystem_error(
1050  "Cannot convert character sequence",
1051  std::make_error_code(errc::illegal_byte_sequence)));
1052 #else
1053  return _M_pathname;
1054 #endif
1055  }
1056 #endif // _GLIBCXX_USE_CHAR8_T
1057 
1058  inline std::u16string
1059  path::u16string() const { return string<char16_t>(); }
1060 
1061  inline std::u32string
1062  path::u32string() const { return string<char32_t>(); }
1063 
1064  template<typename _CharT, typename _Traits, typename _Allocator>
1066  path::generic_string(const _Allocator& __a) const
1067  {
1068 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
1069  const value_type __slash = L'/';
1070 #else
1071  const value_type __slash = '/';
1072 #endif
1073  string_type __str(__a);
1074 
1075  if (_M_type() == _Type::_Root_dir)
1076  __str.assign(1, __slash);
1077  else
1078  {
1079  __str.reserve(_M_pathname.size());
1080  bool __add_slash = false;
1081  for (auto& __elem : *this)
1082  {
1083  if (__add_slash)
1084  __str += __slash;
1085  __str += __elem._M_pathname;
1086  __add_slash = __elem._M_type() == _Type::_Filename;
1087  }
1088  }
1089 
1090  if constexpr (is_same_v<_CharT, value_type>)
1091  return __str;
1092  else
1093  return _S_str_convert<_CharT, _Traits>(__str, __a);
1094  }
1095 
1096  inline std::string
1097  path::generic_string() const
1098  { return generic_string<char>(); }
1099 
1100 #if _GLIBCXX_USE_WCHAR_T
1101  inline std::wstring
1102  path::generic_wstring() const
1103  { return generic_string<wchar_t>(); }
1104 #endif
1105 
1106 #ifdef _GLIBCXX_USE_CHAR8_T
1107  inline std::u8string
1108  path::generic_u8string() const
1109  { return generic_string<char8_t>(); }
1110 #else
1111  inline std::string
1112  path::generic_u8string() const
1113  { return generic_string(); }
1114 #endif
1115 
1116  inline std::u16string
1117  path::generic_u16string() const
1118  { return generic_string<char16_t>(); }
1119 
1120  inline std::u32string
1121  path::generic_u32string() const
1122  { return generic_string<char32_t>(); }
1123 
1124  inline int
1125  path::compare(const string_type& __s) const noexcept
1126  { return compare(basic_string_view<value_type>(__s)); }
1127 
1128  inline int
1129  path::compare(const value_type* __s) const noexcept
1130  { return compare(basic_string_view<value_type>(__s)); }
1131 
1132  inline path
1133  path::filename() const
1134  {
1135  if (empty())
1136  return {};
1137  else if (_M_type() == _Type::_Filename)
1138  return *this;
1139  else if (_M_type() == _Type::_Multi)
1140  {
1141  if (_M_pathname.back() == preferred_separator)
1142  return {};
1143  auto& __last = *--end();
1144  if (__last._M_type() == _Type::_Filename)
1145  return __last;
1146  }
1147  return {};
1148  }
1149 
1150  inline path
1151  path::stem() const
1152  {
1153  auto ext = _M_find_extension();
1154  if (ext.first && ext.second != 0)
1155  return path{ext.first->substr(0, ext.second)};
1156  return {};
1157  }
1158 
1159  inline path
1160  path::extension() const
1161  {
1162  auto ext = _M_find_extension();
1163  if (ext.first && ext.second != string_type::npos)
1164  return path{ext.first->substr(ext.second)};
1165  return {};
1166  }
1167 
1168  inline bool
1169  path::has_stem() const noexcept
1170  {
1171  auto ext = _M_find_extension();
1172  return ext.first && ext.second != 0;
1173  }
1174 
1175  inline bool
1176  path::has_extension() const noexcept
1177  {
1178  auto ext = _M_find_extension();
1179  return ext.first && ext.second != string_type::npos;
1180  }
1181 
1182  inline bool
1183  path::is_absolute() const noexcept
1184  {
1185 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
1186  return has_root_name() && has_root_directory();
1187 #else
1188  return has_root_directory();
1189 #endif
1190  }
1191 
1192  inline path::iterator
1193  path::begin() const
1194  {
1195  if (_M_type() == _Type::_Multi)
1196  return iterator(this, _M_cmpts.begin());
1197  return iterator(this, empty());
1198  }
1199 
1200  inline path::iterator
1201  path::end() const
1202  {
1203  if (_M_type() == _Type::_Multi)
1204  return iterator(this, _M_cmpts.end());
1205  return iterator(this, true);
1206  }
1207 
1208  inline path::iterator&
1209  path::iterator::operator++()
1210  {
1211  __glibcxx_assert(_M_path != nullptr);
1212  if (_M_path->_M_type() == _Type::_Multi)
1213  {
1214  __glibcxx_assert(_M_cur != _M_path->_M_cmpts.end());
1215  ++_M_cur;
1216  }
1217  else
1218  {
1219  __glibcxx_assert(!_M_at_end);
1220  _M_at_end = true;
1221  }
1222  return *this;
1223  }
1224 
1225  inline path::iterator&
1226  path::iterator::operator--()
1227  {
1228  __glibcxx_assert(_M_path != nullptr);
1229  if (_M_path->_M_type() == _Type::_Multi)
1230  {
1231  __glibcxx_assert(_M_cur != _M_path->_M_cmpts.begin());
1232  --_M_cur;
1233  }
1234  else
1235  {
1236  __glibcxx_assert(_M_at_end);
1237  _M_at_end = false;
1238  }
1239  return *this;
1240  }
1241 
1242  inline path::iterator::reference
1243  path::iterator::operator*() const
1244  {
1245  __glibcxx_assert(_M_path != nullptr);
1246  if (_M_path->_M_type() == _Type::_Multi)
1247  {
1248  __glibcxx_assert(_M_cur != _M_path->_M_cmpts.end());
1249  return *_M_cur;
1250  }
1251  return *_M_path;
1252  }
1253 
1254  inline bool
1255  path::iterator::_M_equals(iterator __rhs) const
1256  {
1257  if (_M_path != __rhs._M_path)
1258  return false;
1259  if (_M_path == nullptr)
1260  return true;
1261  if (_M_path->_M_type() == path::_Type::_Multi)
1262  return _M_cur == __rhs._M_cur;
1263  return _M_at_end == __rhs._M_at_end;
1264  }
1265 
1266  // @} group filesystem
1267 _GLIBCXX_END_NAMESPACE_CXX11
1268 } // namespace filesystem
1269 
1270 inline ptrdiff_t
1271 distance(filesystem::path::iterator __first, filesystem::path::iterator __last)
1272 { return __path_iter_distance(__first, __last); }
1273 
1274 template<typename _InputIterator, typename _Distance>
1275  void
1276  advance(filesystem::path::iterator& __i, _Distance __n)
1277  { __path_iter_advance(__i, static_cast<ptrdiff_t>(__n)); }
1278 
1279 extern template class __shared_ptr<const filesystem::filesystem_error::_Impl>;
1280 
1281 _GLIBCXX_END_NAMESPACE_VERSION
1282 } // namespace std
1283 
1284 #endif // C++17
1285 
1286 #endif // _GLIBCXX_FS_PATH_H
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.
Class codecvt&lt;wchar_t, char, mbstate_t&gt; specialization.
Definition: codecvt.h:401
_GLIBCXX17_CONSTEXPR iterator_traits< _InputIterator >::difference_type distance(_InputIterator __first, _InputIterator __last)
A generalization of pointer arithmetic.
Container class for localization functionality.The locale class is first a class wrapper for C librar...
integral_constant< bool, false > false_type
The type used as a compile-time boolean with false value.
Definition: type_traits:78
constexpr const _Tp * end(initializer_list< _Tp > __ils) noexcept
Return an iterator pointing to one past the last element of the initializer_list. ...
std::basic_istream< _CharT, _Traits > & operator>>(std::basic_istream< _CharT, _Traits > &__is, bitset< _Nb > &__x)
Global I/O operators for bitsets.
Definition: bitset:1470
Template class basic_ostream.
Definition: iosfwd:86
static const locale & classic()
Return reference to the C locale.
Bidirectional iterators support a superset of forward iterator operations.
typename enable_if< _Cond, _Tp >::type enable_if_t
Alias template for enable_if.
Definition: type_traits:2384
basic_string< wchar_t > wstring
A string of wchar_t.
Definition: stringfwd.h:83
const _CharT * data() const noexcept
Return const pointer to contents.
enable_if< ::__array_traits< _Tp, _Nm >::_Is_swappable::value >::type noexcept(noexcept(__one.swap(__two)))
swap
Definition: array:295
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
Define a member typedef type only if a boolean constant is true.
Definition: type_traits:2045
_GLIBCXX_END_NAMESPACE_CXX11 typedef basic_string< char > string
A string of char.
Definition: stringfwd.h:74
is_base_of
Definition: type_traits:1301
Thrown to indicate error code of underlying system.
Definition: system_error:341
Marking input iterators.
Template class basic_istream.
Definition: iosfwd:83
basic_string< char16_t > u16string
A string of char16_t.
Definition: stringfwd.h:93
auto quoted(const _CharT *__string, _CharT __delim=_CharT('"'), _CharT __escape = _CharT('\\'))
Manipulator for quoted strings.
Definition: iomanip:461
constexpr const _Tp * begin(initializer_list< _Tp > __ils) noexcept
Return an iterator pointing to the first element of the initializer_list.
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 divided by y.
Definition: complex:417
integral_constant
Definition: type_traits:57
constexpr _Tp * __addressof(_Tp &__r) noexcept
Same as C++11 std::addressof.
Definition: move.h:47
_GLIBCXX20_CONSTEXPR complex< _Tp > operator*(const complex< _Tp > &__x, const complex< _Tp > &__y)
Return new complex value x times y.
Definition: complex:387
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.