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