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