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<_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 { 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  // Create a basic_string by reading until a null character.
421  template<typename _InputIterator,
422  typename _Traits = std::iterator_traits<_InputIterator>,
423  typename _CharT
426  _S_string_from_iter(_InputIterator __source)
427  {
429  for (_CharT __ch = *__source; __ch != _CharT(); __ch = *++__source)
430  __str.push_back(__ch);
431  return __str;
432  }
433 
434  private:
435  enum class _Type : unsigned char {
436  _Multi = 0, _Root_name, _Root_dir, _Filename
437  };
438 
439  path(basic_string_view<value_type> __str, _Type __type)
440  : _M_pathname(__str)
441  {
442  __glibcxx_assert(__type != _Type::_Multi);
443  _M_cmpts.type(__type);
444  }
445 
446  enum class _Split { _Stem, _Extension };
447 
448  void _M_append(basic_string_view<value_type>);
449  void _M_concat(basic_string_view<value_type>);
450 
451  pair<const string_type*, size_t> _M_find_extension() const noexcept;
452 
453  template<typename _CharT>
454  struct _Cvt;
455 
456  static basic_string_view<value_type>
457  _S_convert(value_type* __src, __null_terminated)
458  { return __src; }
459 
460  static basic_string_view<value_type>
461  _S_convert(const value_type* __src, __null_terminated)
462  { return __src; }
463 
464  static basic_string_view<value_type>
465  _S_convert(value_type* __first, value_type* __last)
466  { return {__first, __last - __first}; }
467 
468  static basic_string_view<value_type>
469  _S_convert(const value_type* __first, const value_type* __last)
470  { return {__first, __last - __first}; }
471 
472  template<typename _Iter>
473  static string_type
474  _S_convert(_Iter __first, _Iter __last)
475  {
476  using __value_type = typename std::iterator_traits<_Iter>::value_type;
477  return _Cvt<typename remove_cv<__value_type>::type>::
478  _S_convert(__first, __last);
479  }
480 
481  template<typename _InputIterator>
482  static string_type
483  _S_convert(_InputIterator __src, __null_terminated)
484  {
485  // Read from iterator into basic_string until a null value is seen:
486  auto __s = _S_string_from_iter(__src);
487  // Convert (if needed) from iterator's value type to path::value_type:
488  return string_type(_S_convert(__s.data(), __s.data() + __s.size()));
489  }
490 
491  static string_type
492  _S_convert_loc(const char* __first, const char* __last,
493  const std::locale& __loc);
494 
495  template<typename _Iter>
496  static string_type
497  _S_convert_loc(_Iter __first, _Iter __last, const std::locale& __loc)
498  {
499  const std::string __str(__first, __last);
500  return _S_convert_loc(__str.data(), __str.data()+__str.size(), __loc);
501  }
502 
503  template<typename _InputIterator>
504  static string_type
505  _S_convert_loc(_InputIterator __src, __null_terminated,
506  const std::locale& __loc)
507  {
508  std::string __s = _S_string_from_iter(__src);
509  return _S_convert_loc(__s.data(), __s.data() + __s.size(), __loc);
510  }
511 
512  template<typename _CharT, typename _Traits, typename _Allocator>
513  static basic_string<_CharT, _Traits, _Allocator>
514  _S_str_convert(const string_type&, const _Allocator& __a);
515 
516  void _M_split_cmpts();
517 
518  _Type _M_type() const noexcept { return _M_cmpts.type(); }
519 
520  string_type _M_pathname;
521 
522  struct _Cmpt;
523 
524  struct _List
525  {
526  using value_type = _Cmpt;
527  using iterator = value_type*;
528  using const_iterator = const value_type*;
529 
530  _List();
531  _List(const _List&);
532  _List(_List&&) = default;
533  _List& operator=(const _List&);
534  _List& operator=(_List&&) = default;
535  ~_List() = default;
536 
537  _Type type() const noexcept
538  { return _Type{reinterpret_cast<uintptr_t>(_M_impl.get()) & 0x3}; }
539 
540  void type(_Type) noexcept;
541 
542  int size() const noexcept; // zero unless type() == _Type::_Multi
543  bool empty() const noexcept; // true unless type() == _Type::_Multi
544  void clear();
545  void swap(_List& __l) noexcept { _M_impl.swap(__l._M_impl); }
546  int capacity() const noexcept;
547  void reserve(int, bool); ///< @pre type() == _Type::_Multi
548 
549  // All the member functions below here have a precondition !empty()
550  // (and they should only be called from within the library).
551 
552  iterator begin();
553  iterator end();
554  const_iterator begin() const;
555  const_iterator end() const;
556 
557  value_type& front() noexcept;
558  value_type& back() noexcept;
559  const value_type& front() const noexcept;
560  const value_type& back() const noexcept;
561 
562  void pop_back();
563  void _M_erase_from(const_iterator __pos); // erases [__pos,end())
564 
565  struct _Impl;
566  struct _Impl_deleter
567  {
568  void operator()(_Impl*) const noexcept;
569  };
570  unique_ptr<_Impl, _Impl_deleter> _M_impl;
571  };
572  _List _M_cmpts;
573 
574  struct _Parser;
575  };
576 
577  inline void swap(path& __lhs, path& __rhs) noexcept { __lhs.swap(__rhs); }
578 
579  size_t hash_value(const path& __p) noexcept;
580 
581  /// Compare paths
582  inline bool operator<(const path& __lhs, const path& __rhs) noexcept
583  { return __lhs.compare(__rhs) < 0; }
584 
585  /// Compare paths
586  inline bool operator<=(const path& __lhs, const path& __rhs) noexcept
587  { return !(__rhs < __lhs); }
588 
589  /// Compare paths
590  inline bool operator>(const path& __lhs, const path& __rhs) noexcept
591  { return __rhs < __lhs; }
592 
593  /// Compare paths
594  inline bool operator>=(const path& __lhs, const path& __rhs) noexcept
595  { return !(__lhs < __rhs); }
596 
597  /// Compare paths
598  inline bool operator==(const path& __lhs, const path& __rhs) noexcept
599  { return __lhs.compare(__rhs) == 0; }
600 
601  /// Compare paths
602  inline bool operator!=(const path& __lhs, const path& __rhs) noexcept
603  { return !(__lhs == __rhs); }
604 
605  /// Append one path to another
606  inline path operator/(const path& __lhs, const path& __rhs)
607  {
608  path __result(__lhs);
609  __result /= __rhs;
610  return __result;
611  }
612 
613  template<typename _InputIterator>
614  inline auto
615  u8path(_InputIterator __first, _InputIterator __last)
616  -> decltype(filesystem::path(__first, __last, std::locale::classic()))
617  {
618 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
619  codecvt_utf8<path::value_type> __cvt;
620  path::string_type __tmp;
621  if constexpr (is_pointer_v<_InputIterator>)
622  {
623  if (__str_codecvt_in(__first, __last, __tmp, __cvt))
624  return path{ __tmp };
625  }
626  else
627  {
628  const std::string __u8str{__first, __last};
629  const char* const __ptr = __u8str.data();
630  if (__str_codecvt_in(__ptr, __ptr + __u8str.size(), __tmp, __cvt))
631  return path{ __tmp };
632  }
633  return {};
634 #else
635  return path{ __first, __last };
636 #endif
637  }
638 
639  template<typename _Source>
640  inline auto
641  u8path(const _Source& __source)
642  -> decltype(filesystem::path(__source, std::locale::classic()))
643  {
644 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
645  if constexpr (is_convertible_v<const _Source&, std::string_view>)
646  {
647  const std::string_view __s = __source;
648  return filesystem::u8path(__s.data(), __s.data() + __s.size());
649  }
650  else
651  {
652  std::string __s = path::_S_string_from_iter(__source);
653  return filesystem::u8path(__s.data(), __s.data() + __s.size());
654  }
655 #else
656  return path{ __source };
657 #endif
658  }
659 
660  class filesystem_error : public std::system_error
661  {
662  public:
663  filesystem_error(const string& __what_arg, error_code __ec);
664 
665  filesystem_error(const string& __what_arg, const path& __p1,
666  error_code __ec);
667 
668  filesystem_error(const string& __what_arg, const path& __p1,
669  const path& __p2, error_code __ec);
670 
671  filesystem_error(const filesystem_error&) = default;
672  filesystem_error& operator=(const filesystem_error&) = default;
673 
674  // No move constructor or assignment operator.
675  // Copy rvalues instead, so that _M_impl is not left empty.
676 
677  ~filesystem_error();
678 
679  const path& path1() const noexcept;
680  const path& path2() const noexcept;
681  const char* what() const noexcept;
682 
683  private:
684  struct _Impl;
685  std::__shared_ptr<const _Impl> _M_impl;
686  };
687 
688  struct path::_Cmpt : path
689  {
690  _Cmpt(basic_string_view<value_type> __s, _Type __t, size_t __pos)
691  : path(__s, __t), _M_pos(__pos) { }
692 
693  _Cmpt() : _M_pos(-1) { }
694 
695  size_t _M_pos;
696  };
697 
698  // specialize _Cvt for degenerate 'noconv' case
699  template<>
700  struct path::_Cvt<path::value_type>
701  {
702  template<typename _Iter>
703  static string_type
704  _S_convert(_Iter __first, _Iter __last)
705  { return string_type{__first, __last}; }
706  };
707 
708  template<typename _CharT>
709  struct path::_Cvt
710  {
711 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
712  static string_type
713  _S_wconvert(const char* __f, const char* __l, true_type)
714  {
716  const auto& __cvt = std::use_facet<_Cvt>(std::locale{});
717  std::wstring __wstr;
718  if (__str_codecvt_in(__f, __l, __wstr, __cvt))
719  return __wstr;
720  _GLIBCXX_THROW_OR_ABORT(filesystem_error(
721  "Cannot convert character sequence",
722  std::make_error_code(errc::illegal_byte_sequence)));
723  }
724 
725  static string_type
726  _S_wconvert(const _CharT* __f, const _CharT* __l, false_type)
727  {
728  std::codecvt_utf8<_CharT> __cvt;
729  std::string __str;
730  if (__str_codecvt_out(__f, __l, __str, __cvt))
731  {
732  const char* __f2 = __str.data();
733  const char* __l2 = __f2 + __str.size();
734  std::codecvt_utf8<wchar_t> __wcvt;
735  std::wstring __wstr;
736  if (__str_codecvt_in(__f2, __l2, __wstr, __wcvt))
737  return __wstr;
738  }
739  _GLIBCXX_THROW_OR_ABORT(filesystem_error(
740  "Cannot convert character sequence",
741  std::make_error_code(errc::illegal_byte_sequence)));
742  }
743 
744  static string_type
745  _S_convert(const _CharT* __f, const _CharT* __l)
746  {
747  return _S_wconvert(__f, __l, is_same<_CharT, char>{});
748  }
749 #else
750  static string_type
751  _S_convert(const _CharT* __f, const _CharT* __l)
752  {
753 #ifdef _GLIBCXX_USE_CHAR8_T
754  if constexpr (is_same_v<_CharT, char8_t>)
755  {
756  string_type __str(__f, __l);
757  return __str;
758  }
759  else
760  {
761 #endif
762  std::codecvt_utf8<_CharT> __cvt;
763  std::string __str;
764  if (__str_codecvt_out(__f, __l, __str, __cvt))
765  return __str;
766 #ifdef _GLIBCXX_USE_CHAR8_T
767  }
768 #endif
769  _GLIBCXX_THROW_OR_ABORT(filesystem_error(
770  "Cannot convert character sequence",
771  std::make_error_code(errc::illegal_byte_sequence)));
772  }
773 #endif
774 
775  static string_type
776  _S_convert(_CharT* __f, _CharT* __l)
777  {
778  return _S_convert(const_cast<const _CharT*>(__f),
779  const_cast<const _CharT*>(__l));
780  }
781 
782  template<typename _Iter>
783  static string_type
784  _S_convert(_Iter __first, _Iter __last)
785  {
786  const std::basic_string<_CharT> __str(__first, __last);
787  return _S_convert(__str.data(), __str.data() + __str.size());
788  }
789 
790  template<typename _Iter, typename _Cont>
791  static string_type
792  _S_convert(__gnu_cxx::__normal_iterator<_Iter, _Cont> __first,
793  __gnu_cxx::__normal_iterator<_Iter, _Cont> __last)
794  { return _S_convert(__first.base(), __last.base()); }
795  };
796 
797  /// An iterator for the components of a path
798  class path::iterator
799  {
800  public:
801  using difference_type = std::ptrdiff_t;
802  using value_type = path;
803  using reference = const path&;
804  using pointer = const path*;
805  using iterator_category = std::bidirectional_iterator_tag;
806 
807  iterator() : _M_path(nullptr), _M_cur(), _M_at_end() { }
808 
809  iterator(const iterator&) = default;
810  iterator& operator=(const iterator&) = default;
811 
812  reference operator*() const;
813  pointer operator->() const { return std::__addressof(**this); }
814 
815  iterator& operator++();
816  iterator operator++(int) { auto __tmp = *this; ++*this; return __tmp; }
817 
818  iterator& operator--();
819  iterator operator--(int) { auto __tmp = *this; --*this; return __tmp; }
820 
821  friend bool operator==(const iterator& __lhs, const iterator& __rhs)
822  { return __lhs._M_equals(__rhs); }
823 
824  friend bool operator!=(const iterator& __lhs, const iterator& __rhs)
825  { return !__lhs._M_equals(__rhs); }
826 
827  private:
828  friend class path;
829 
830  bool _M_is_multi() const { return _M_path->_M_type() == _Type::_Multi; }
831 
832  friend difference_type
833  __path_iter_distance(const iterator& __first, const iterator& __last)
834  {
835  __glibcxx_assert(__first._M_path != nullptr);
836  __glibcxx_assert(__first._M_path == __last._M_path);
837  if (__first._M_is_multi())
838  return std::distance(__first._M_cur, __last._M_cur);
839  else if (__first._M_at_end == __last._M_at_end)
840  return 0;
841  else
842  return __first._M_at_end ? -1 : 1;
843  }
844 
845  friend void
846  __path_iter_advance(iterator& __i, difference_type __n)
847  {
848  if (__n == 1)
849  ++__i;
850  else if (__n == -1)
851  --__i;
852  else if (__n != 0)
853  {
854  __glibcxx_assert(__i._M_path != nullptr);
855  __glibcxx_assert(__i._M_is_multi());
856  // __glibcxx_assert(__i._M_path->_M_cmpts.end() - __i._M_cur >= __n);
857  __i._M_cur += __n;
858  }
859  }
860 
861  iterator(const path* __path, path::_List::const_iterator __iter)
862  : _M_path(__path), _M_cur(__iter), _M_at_end()
863  { }
864 
865  iterator(const path* __path, bool __at_end)
866  : _M_path(__path), _M_cur(), _M_at_end(__at_end)
867  { }
868 
869  bool _M_equals(iterator) const;
870 
871  const path* _M_path;
872  path::_List::const_iterator _M_cur;
873  bool _M_at_end; // only used when type != _Multi
874  };
875 
876 
877  inline path&
878  path::operator=(path&& __p) noexcept
879  {
880  _M_pathname = std::move(__p._M_pathname);
881  _M_cmpts = std::move(__p._M_cmpts);
882  __p.clear();
883  return *this;
884  }
885 
886  inline path&
887  path::operator=(string_type&& __source)
888  { return *this = path(std::move(__source)); }
889 
890  inline path&
891  path::assign(string_type&& __source)
892  { return *this = path(std::move(__source)); }
893 
894  inline path&
895  path::operator+=(const string_type& __x)
896  {
897  _M_concat(__x);
898  return *this;
899  }
900 
901  inline path&
902  path::operator+=(const value_type* __x)
903  {
904  _M_concat(__x);
905  return *this;
906  }
907 
908  inline path&
909  path::operator+=(value_type __x)
910  {
911  _M_concat(basic_string_view<value_type>(&__x, 1));
912  return *this;
913  }
914 
915  inline path&
916  path::operator+=(basic_string_view<value_type> __x)
917  {
918  _M_concat(__x);
919  return *this;
920  }
921 
922  template<typename _CharT>
923  inline path::_Path<_CharT*, _CharT*>&
924  path::operator+=(_CharT __x)
925  {
926  auto* __addr = std::__addressof(__x);
927  return concat(__addr, __addr + 1);
928  }
929 
930  inline path&
931  path::make_preferred()
932  {
933 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
934  std::replace(_M_pathname.begin(), _M_pathname.end(), L'/',
935  preferred_separator);
936 #endif
937  return *this;
938  }
939 
940  inline void path::swap(path& __rhs) noexcept
941  {
942  _M_pathname.swap(__rhs._M_pathname);
943  _M_cmpts.swap(__rhs._M_cmpts);
944  }
945 
946  template<typename _CharT, typename _Traits, typename _Allocator>
948  path::_S_str_convert(const string_type& __str, const _Allocator& __a)
949  {
950  if (__str.size() == 0)
952 
953  const value_type* __first = __str.data();
954  const value_type* __last = __first + __str.size();
955 
956 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
957  using _CharAlloc = __alloc_rebind<_Allocator, char>;
958  using _String = basic_string<char, char_traits<char>, _CharAlloc>;
959  using _WString = basic_string<_CharT, _Traits, _Allocator>;
960 
961  // use codecvt_utf8<wchar_t> to convert native string to UTF-8
962  codecvt_utf8<value_type> __cvt;
963  _String __u8str{_CharAlloc{__a}};
964  if (__str_codecvt_out(__first, __last, __u8str, __cvt))
965  {
966  if constexpr (is_same_v<_CharT, char>)
967  return __u8str;
968 #ifdef _GLIBCXX_USE_CHAR8_T
969  else if constexpr (is_same_v<_CharT, char8_t>)
970  {
971  const char* __f = __u8str.data();
972  const char* __l = __f + __u8str.size();
973  _WString __wstr(__f, __l);
974  return __wstr;
975  }
976 #endif
977  else
978  {
979  _WString __wstr;
980  // use codecvt_utf8<_CharT> to convert UTF-8 to wide string
981  codecvt_utf8<_CharT> __cvt;
982  const char* __f = __u8str.data();
983  const char* __l = __f + __u8str.size();
984  if (__str_codecvt_in(__f, __l, __wstr, __cvt))
985  return __wstr;
986  }
987  }
988 #else
989 #ifdef _GLIBCXX_USE_CHAR8_T
990  if constexpr (is_same_v<_CharT, char8_t>)
991  {
992  basic_string<_CharT, _Traits, _Allocator> __wstr{__first, __last, __a};
993  return __wstr;
994  }
995  else
996  {
997 #endif
998  codecvt_utf8<_CharT> __cvt;
999  basic_string<_CharT, _Traits, _Allocator> __wstr{__a};
1000  if (__str_codecvt_in(__first, __last, __wstr, __cvt))
1001  return __wstr;
1002 #ifdef _GLIBCXX_USE_CHAR8_T
1003  }
1004 #endif
1005 #endif
1006  _GLIBCXX_THROW_OR_ABORT(filesystem_error(
1007  "Cannot convert character sequence",
1008  std::make_error_code(errc::illegal_byte_sequence)));
1009  }
1010 
1011  template<typename _CharT, typename _Traits, typename _Allocator>
1012  inline basic_string<_CharT, _Traits, _Allocator>
1013  path::string(const _Allocator& __a) const
1014  {
1015  if constexpr (is_same_v<_CharT, value_type>)
1016  return { _M_pathname, __a };
1017  else
1018  return _S_str_convert<_CharT, _Traits>(_M_pathname, __a);
1019  }
1020 
1021  inline std::string
1022  path::string() const { return string<char>(); }
1023 
1024 #if _GLIBCXX_USE_WCHAR_T
1025  inline std::wstring
1026  path::wstring() const { return string<wchar_t>(); }
1027 #endif
1028 
1029 #ifdef _GLIBCXX_USE_CHAR8_T
1030  inline std::u8string
1031  path::u8string() const { return string<char8_t>(); }
1032 #else
1033  inline std::string
1034  path::u8string() const
1035  {
1036 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
1037  std::string __str;
1038  // convert from native encoding to UTF-8
1039  codecvt_utf8<value_type> __cvt;
1040  const value_type* __first = _M_pathname.data();
1041  const value_type* __last = __first + _M_pathname.size();
1042  if (__str_codecvt_out(__first, __last, __str, __cvt))
1043  return __str;
1044  _GLIBCXX_THROW_OR_ABORT(filesystem_error(
1045  "Cannot convert character sequence",
1046  std::make_error_code(errc::illegal_byte_sequence)));
1047 #else
1048  return _M_pathname;
1049 #endif
1050  }
1051 #endif // _GLIBCXX_USE_CHAR8_T
1052 
1053  inline std::u16string
1054  path::u16string() const { return string<char16_t>(); }
1055 
1056  inline std::u32string
1057  path::u32string() const { return string<char32_t>(); }
1058 
1059  template<typename _CharT, typename _Traits, typename _Allocator>
1061  path::generic_string(const _Allocator& __a) const
1062  {
1063 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
1064  const value_type __slash = L'/';
1065 #else
1066  const value_type __slash = '/';
1067 #endif
1068  string_type __str(__a);
1069 
1070  if (_M_type() == _Type::_Root_dir)
1071  __str.assign(1, __slash);
1072  else
1073  {
1074  __str.reserve(_M_pathname.size());
1075  bool __add_slash = false;
1076  for (auto& __elem : *this)
1077  {
1078  if (__add_slash)
1079  __str += __slash;
1080  __str += __elem._M_pathname;
1081  __add_slash = __elem._M_type() == _Type::_Filename;
1082  }
1083  }
1084 
1085  if constexpr (is_same_v<_CharT, value_type>)
1086  return __str;
1087  else
1088  return _S_str_convert<_CharT, _Traits>(__str, __a);
1089  }
1090 
1091  inline std::string
1092  path::generic_string() const
1093  { return generic_string<char>(); }
1094 
1095 #if _GLIBCXX_USE_WCHAR_T
1096  inline std::wstring
1097  path::generic_wstring() const
1098  { return generic_string<wchar_t>(); }
1099 #endif
1100 
1101 #ifdef _GLIBCXX_USE_CHAR8_T
1102  inline std::u8string
1103  path::generic_u8string() const
1104  { return generic_string<char8_t>(); }
1105 #else
1106  inline std::string
1107  path::generic_u8string() const
1108  { return generic_string(); }
1109 #endif
1110 
1111  inline std::u16string
1112  path::generic_u16string() const
1113  { return generic_string<char16_t>(); }
1114 
1115  inline std::u32string
1116  path::generic_u32string() const
1117  { return generic_string<char32_t>(); }
1118 
1119  inline int
1120  path::compare(const string_type& __s) const noexcept
1121  { return compare(basic_string_view<value_type>(__s)); }
1122 
1123  inline int
1124  path::compare(const value_type* __s) const noexcept
1125  { return compare(basic_string_view<value_type>(__s)); }
1126 
1127  inline path
1128  path::filename() const
1129  {
1130  if (empty())
1131  return {};
1132  else if (_M_type() == _Type::_Filename)
1133  return *this;
1134  else if (_M_type() == _Type::_Multi)
1135  {
1136  if (_M_pathname.back() == preferred_separator)
1137  return {};
1138  auto& __last = *--end();
1139  if (__last._M_type() == _Type::_Filename)
1140  return __last;
1141  }
1142  return {};
1143  }
1144 
1145  inline path
1146  path::stem() const
1147  {
1148  auto ext = _M_find_extension();
1149  if (ext.first && ext.second != 0)
1150  return path{ext.first->substr(0, ext.second)};
1151  return {};
1152  }
1153 
1154  inline path
1155  path::extension() const
1156  {
1157  auto ext = _M_find_extension();
1158  if (ext.first && ext.second != string_type::npos)
1159  return path{ext.first->substr(ext.second)};
1160  return {};
1161  }
1162 
1163  inline bool
1164  path::has_stem() const noexcept
1165  {
1166  auto ext = _M_find_extension();
1167  return ext.first && ext.second != 0;
1168  }
1169 
1170  inline bool
1171  path::has_extension() const noexcept
1172  {
1173  auto ext = _M_find_extension();
1174  return ext.first && ext.second != string_type::npos;
1175  }
1176 
1177  inline bool
1178  path::is_absolute() const noexcept
1179  {
1180 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
1181  return has_root_name() && has_root_directory();
1182 #else
1183  return has_root_directory();
1184 #endif
1185  }
1186 
1187  inline path::iterator
1188  path::begin() const
1189  {
1190  if (_M_type() == _Type::_Multi)
1191  return iterator(this, _M_cmpts.begin());
1192  return iterator(this, empty());
1193  }
1194 
1195  inline path::iterator
1196  path::end() const
1197  {
1198  if (_M_type() == _Type::_Multi)
1199  return iterator(this, _M_cmpts.end());
1200  return iterator(this, true);
1201  }
1202 
1203  inline path::iterator&
1204  path::iterator::operator++()
1205  {
1206  __glibcxx_assert(_M_path != nullptr);
1207  if (_M_path->_M_type() == _Type::_Multi)
1208  {
1209  __glibcxx_assert(_M_cur != _M_path->_M_cmpts.end());
1210  ++_M_cur;
1211  }
1212  else
1213  {
1214  __glibcxx_assert(!_M_at_end);
1215  _M_at_end = true;
1216  }
1217  return *this;
1218  }
1219 
1220  inline path::iterator&
1221  path::iterator::operator--()
1222  {
1223  __glibcxx_assert(_M_path != nullptr);
1224  if (_M_path->_M_type() == _Type::_Multi)
1225  {
1226  __glibcxx_assert(_M_cur != _M_path->_M_cmpts.begin());
1227  --_M_cur;
1228  }
1229  else
1230  {
1231  __glibcxx_assert(_M_at_end);
1232  _M_at_end = false;
1233  }
1234  return *this;
1235  }
1236 
1237  inline path::iterator::reference
1238  path::iterator::operator*() const
1239  {
1240  __glibcxx_assert(_M_path != nullptr);
1241  if (_M_path->_M_type() == _Type::_Multi)
1242  {
1243  __glibcxx_assert(_M_cur != _M_path->_M_cmpts.end());
1244  return *_M_cur;
1245  }
1246  return *_M_path;
1247  }
1248 
1249  inline bool
1250  path::iterator::_M_equals(iterator __rhs) const
1251  {
1252  if (_M_path != __rhs._M_path)
1253  return false;
1254  if (_M_path == nullptr)
1255  return true;
1256  if (_M_path->_M_type() == path::_Type::_Multi)
1257  return _M_cur == __rhs._M_cur;
1258  return _M_at_end == __rhs._M_at_end;
1259  }
1260 
1261  // @} group filesystem
1262 _GLIBCXX_END_NAMESPACE_CXX11
1263 } // namespace filesystem
1264 
1265 inline ptrdiff_t
1266 distance(filesystem::path::iterator __first, filesystem::path::iterator __last)
1267 { return __path_iter_distance(__first, __last); }
1268 
1269 template<typename _InputIterator, typename _Distance>
1270  void
1271  advance(filesystem::path::iterator& __i, _Distance __n)
1272  { __path_iter_advance(__i, static_cast<ptrdiff_t>(__n)); }
1273 
1274 extern template class __shared_ptr<const filesystem::filesystem_error::_Impl>;
1275 
1276 _GLIBCXX_END_NAMESPACE_VERSION
1277 } // namespace std
1278 
1279 #endif // C++17
1280 
1281 #endif // _GLIBCXX_FS_PATH_H
size_t hash_value(const path &__p) noexcept
Compare paths.
typename enable_if< _Cond, _Tp >::type enable_if_t
Alias template for enable_if.
Definition: type_traits:2418
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:2087
_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.
path u8path(const _Source &__source)
Compare paths.
constexpr _Tp * __addressof(_Tp &__r) noexcept
Same as C++11 std::addressof.
Definition: move.h:47
constexpr const _Tp * begin(initializer_list< _Tp > __ils) noexcept
Return an iterator pointing to the first element of the initializer_list.
ISO C++ entities toplevel namespace is std.
basic_string< char16_t > u16string
A string of char16_t.
Definition: stringfwd.h:93
Marking input iterators.
basic_string< wchar_t > wstring
A string of wchar_t.
Definition: stringfwd.h:83
auto quoted(const _CharT *__string, _CharT __delim=_CharT('"'), _CharT __escape = _CharT('\\'))
Manipulator for quoted strings.
Definition: iomanip:461
_GLIBCXX_END_NAMESPACE_CXX11 typedef basic_string< char > string
A string of char.
Definition: stringfwd.h:74
is_base_of
Definition: type_traits:1343
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...
_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:1479
const _CharT * data() const noexcept
Return const pointer to contents.
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
Class codecvt<wchar_t, char, mbstate_t> specialization.
Definition: codecvt.h:401
std::basic_istream< _CharT, _Traits > & operator>>(std::basic_istream< _CharT, _Traits > &__is, bitset< _Nb > &__x)
Global I/O operators for bitsets.
Definition: bitset:1470
basic_string< char32_t > u32string
A string of char32_t.
Definition: stringfwd.h:96
_GLIBCXX17_CONSTEXPR void advance(_InputIterator &__i, _Distance __n)
A generalization of pointer arithmetic.
std::basic_ostream< _CharT, _Traits > & operator<<(std::basic_ostream< _CharT, _Traits > &__os, const bitset< _Nb > &__x)
Global I/O operators for bitsets.
Definition: bitset:1538
Bidirectional iterators support a superset of forward iterator operations.
void push_back(_CharT __c)
Append a single character.
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