libstdc++
experimental/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 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  struct __is_encoded_char : std::false_type { };
84 
85  template<typename _Iter,
86  typename _Iter_traits = std::iterator_traits<_Iter>>
87  using __is_path_iter_src
88  = __and_<__is_encoded_char<typename _Iter_traits::value_type>,
90  typename _Iter_traits::iterator_category>>;
91 
92  template<typename _Iter>
93  static __is_path_iter_src<_Iter>
94  __is_path_src(_Iter, int);
95 
96  template<typename _CharT, typename _Traits, typename _Alloc>
97  static __is_encoded_char<_CharT>
98  __is_path_src(const basic_string<_CharT, _Traits, _Alloc>&, int);
99 
100 #if __cplusplus >= 201402L
101  template<typename _CharT, typename _Traits>
102  static __is_encoded_char<_CharT>
103  __is_path_src(const basic_string_view<_CharT, _Traits>&, int);
104 #endif
105 
106  template<typename _Unknown>
107  static std::false_type
108  __is_path_src(const _Unknown&, ...);
109 
110  template<typename _Tp1, typename _Tp2>
111  struct __constructible_from;
112 
113  template<typename _Iter>
114  struct __constructible_from<_Iter, _Iter>
115  : __is_path_iter_src<_Iter>
116  { };
117 
118  template<typename _Source>
119  struct __constructible_from<_Source, void>
120  : decltype(__is_path_src(std::declval<_Source>(), 0))
121  { };
122 
123  template<typename _Tp1, typename _Tp2 = void>
124  using _Path = typename
126  __constructible_from<_Tp1, _Tp2>>::value,
127  path>::type;
128 
129  template<typename _Source>
130  static _Source
131  _S_range_begin(_Source __begin) { return __begin; }
132 
133  struct __null_terminated { };
134 
135  template<typename _Source>
136  static __null_terminated
137  _S_range_end(_Source) { return {}; }
138 
139  template<typename _CharT, typename _Traits, typename _Alloc>
140  static const _CharT*
141  _S_range_begin(const basic_string<_CharT, _Traits, _Alloc>& __str)
142  { return __str.data(); }
143 
144  template<typename _CharT, typename _Traits, typename _Alloc>
145  static const _CharT*
146  _S_range_end(const basic_string<_CharT, _Traits, _Alloc>& __str)
147  { return __str.data() + __str.size(); }
148 
149 #if __cplusplus >= 201402L
150  template<typename _CharT, typename _Traits>
151  static const _CharT*
152  _S_range_begin(const basic_string_view<_CharT, _Traits>& __str)
153  { return __str.data(); }
154 
155  template<typename _CharT, typename _Traits>
156  static const _CharT*
157  _S_range_end(const basic_string_view<_CharT, _Traits>& __str)
158  { return __str.data() + __str.size(); }
159 #endif
160 
161  template<typename _Tp,
162  typename _Iter = decltype(_S_range_begin(std::declval<_Tp>())),
163  typename _Val = typename std::iterator_traits<_Iter>::value_type>
164  using __value_type_is_char
166 
167  public:
168 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
169  typedef wchar_t value_type;
170  static constexpr value_type preferred_separator = L'\\';
171 #else
172  typedef char value_type;
173  static constexpr value_type preferred_separator = '/';
174 #endif
176 
177  // constructors and destructor
178 
179  path() noexcept { }
180 
181  path(const path& __p) = default;
182 
183  path(path&& __p) noexcept
184  : _M_pathname(std::move(__p._M_pathname)), _M_type(__p._M_type)
185  {
186  _M_split_cmpts();
187  __p.clear();
188  }
189 
190  path(string_type&& __source)
191  : _M_pathname(std::move(__source))
192  { _M_split_cmpts(); }
193 
194  template<typename _Source,
195  typename _Require = _Path<_Source>>
196  path(_Source const& __source)
197  : _M_pathname(_S_convert(_S_range_begin(__source),
198  _S_range_end(__source)))
199  { _M_split_cmpts(); }
200 
201  template<typename _InputIterator,
202  typename _Require = _Path<_InputIterator, _InputIterator>>
203  path(_InputIterator __first, _InputIterator __last)
204  : _M_pathname(_S_convert(__first, __last))
205  { _M_split_cmpts(); }
206 
207  template<typename _Source,
208  typename _Require = _Path<_Source>,
209  typename _Require2 = __value_type_is_char<_Source>>
210  path(_Source const& __source, const locale& __loc)
211  : _M_pathname(_S_convert_loc(_S_range_begin(__source),
212  _S_range_end(__source), __loc))
213  { _M_split_cmpts(); }
214 
215  template<typename _InputIterator,
216  typename _Require = _Path<_InputIterator, _InputIterator>,
217  typename _Require2 = __value_type_is_char<_InputIterator>>
218  path(_InputIterator __first, _InputIterator __last, const locale& __loc)
219  : _M_pathname(_S_convert_loc(__first, __last, __loc))
220  { _M_split_cmpts(); }
221 
222  ~path() = default;
223 
224  // assignments
225 
226  path& operator=(const path& __p) = default;
227  path& operator=(path&& __p) noexcept;
228  path& operator=(string_type&& __source);
229  path& assign(string_type&& __source);
230 
231  template<typename _Source>
232  _Path<_Source>&
233  operator=(_Source const& __source)
234  { return *this = path(__source); }
235 
236  template<typename _Source>
237  _Path<_Source>&
238  assign(_Source const& __source)
239  { return *this = path(__source); }
240 
241  template<typename _InputIterator>
242  _Path<_InputIterator, _InputIterator>&
243  assign(_InputIterator __first, _InputIterator __last)
244  { return *this = path(__first, __last); }
245 
246  // appends
247 
248  path& operator/=(const path& __p) { return _M_append(__p._M_pathname); }
249 
250  template <class _Source>
251  _Path<_Source>&
252  operator/=(_Source const& __source)
253  { return append(__source); }
254 
255  template<typename _Source>
256  _Path<_Source>&
257  append(_Source const& __source)
258  {
259  return _M_append(_S_convert(_S_range_begin(__source),
260  _S_range_end(__source)));
261  }
262 
263  template<typename _InputIterator>
264  _Path<_InputIterator, _InputIterator>&
265  append(_InputIterator __first, _InputIterator __last)
266  { return _M_append(_S_convert(__first, __last)); }
267 
268  // concatenation
269 
270  path& operator+=(const path& __x);
271  path& operator+=(const string_type& __x);
272  path& operator+=(const value_type* __x);
273  path& operator+=(value_type __x);
274 #if __cplusplus >= 201402L
275  path& operator+=(basic_string_view<value_type> __x);
276 #endif
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  { return *this += _S_convert(_S_range_begin(__x), _S_range_end(__x)); }
290 
291  template<typename _InputIterator>
292  _Path<_InputIterator, _InputIterator>&
293  concat(_InputIterator __first, _InputIterator __last)
294  { return *this += _S_convert(__first, __last); }
295 
296  // modifiers
297 
298  void clear() noexcept { _M_pathname.clear(); _M_split_cmpts(); }
299 
300  path& make_preferred();
301  path& remove_filename();
302  path& replace_filename(const path& __replacement);
303  path& replace_extension(const path& __replacement = path());
304 
305  void swap(path& __rhs) noexcept;
306 
307  // native format observers
308 
309  const string_type& native() const noexcept { return _M_pathname; }
310  const value_type* c_str() const noexcept { return _M_pathname.c_str(); }
311  operator string_type() const { return _M_pathname; }
312 
313  template<typename _CharT, typename _Traits = std::char_traits<_CharT>,
314  typename _Allocator = std::allocator<_CharT>>
316  string(const _Allocator& __a = _Allocator()) const;
317 
318  std::string string() const;
319 #if _GLIBCXX_USE_WCHAR_T
320  std::wstring wstring() const;
321 #endif
322  std::string u8string() const;
323  std::u16string u16string() const;
324  std::u32string u32string() const;
325 
326  // generic format observers
327  template<typename _CharT, typename _Traits = std::char_traits<_CharT>,
328  typename _Allocator = std::allocator<_CharT>>
330  generic_string(const _Allocator& __a = _Allocator()) const;
331 
332  std::string generic_string() const;
333 #if _GLIBCXX_USE_WCHAR_T
334  std::wstring generic_wstring() const;
335 #endif
336  std::string generic_u8string() const;
337  std::u16string generic_u16string() const;
338  std::u32string generic_u32string() const;
339 
340  // compare
341 
342  int compare(const path& __p) const noexcept;
343  int compare(const string_type& __s) const;
344  int compare(const value_type* __s) const;
345 #if __cplusplus >= 201402L
346  int compare(const basic_string_view<value_type> __s) const;
347 #endif
348 
349  // decomposition
350 
351  path root_name() const;
352  path root_directory() const;
353  path root_path() const;
354  path relative_path() const;
355  path parent_path() const;
356  path filename() const;
357  path stem() const;
358  path extension() const;
359 
360  // query
361 
362  bool empty() const noexcept { return _M_pathname.empty(); }
363  bool has_root_name() const;
364  bool has_root_directory() const;
365  bool has_root_path() const;
366  bool has_relative_path() const;
367  bool has_parent_path() const;
368  bool has_filename() const;
369  bool has_stem() const;
370  bool has_extension() const;
371  bool is_absolute() const;
372  bool is_relative() const { return !is_absolute(); }
373 
374  // iterators
375  class iterator;
376  typedef iterator const_iterator;
377 
378  iterator begin() const;
379  iterator end() const;
380 
381  private:
382  enum class _Type : unsigned char {
383  _Multi, _Root_name, _Root_dir, _Filename
384  };
385 
386  path(string_type __str, _Type __type) : _M_pathname(__str), _M_type(__type)
387  {
388  __glibcxx_assert(!empty());
389  __glibcxx_assert(_M_type != _Type::_Multi);
390  }
391 
392  enum class _Split { _Stem, _Extension };
393 
394  path& _M_append(const string_type& __str)
395  {
396  if (!_M_pathname.empty() && !_S_is_dir_sep(_M_pathname.back())
397  && !__str.empty() && !_S_is_dir_sep(__str.front()))
398  _M_pathname += preferred_separator;
399  _M_pathname += __str;
400  _M_split_cmpts();
401  return *this;
402  }
403 
404  pair<const string_type*, size_t> _M_find_extension() const;
405 
406  template<typename _CharT>
407  struct _Cvt;
408 
409  static string_type
410  _S_convert(value_type* __src, __null_terminated)
411  { return string_type(__src); }
412 
413  static string_type
414  _S_convert(const value_type* __src, __null_terminated)
415  { return string_type(__src); }
416 
417  template<typename _Iter>
418  static string_type
419  _S_convert(_Iter __first, _Iter __last)
420  {
421  using __value_type = typename std::iterator_traits<_Iter>::value_type;
422  return _Cvt<typename remove_cv<__value_type>::type>::
423  _S_convert(__first, __last);
424  }
425 
426  template<typename _InputIterator>
427  static string_type
428  _S_convert(_InputIterator __src, __null_terminated)
429  {
430  using _Tp = typename std::iterator_traits<_InputIterator>::value_type;
432  for (; *__src != _Tp{}; ++__src)
433  __tmp.push_back(*__src);
434  return _S_convert(__tmp.c_str(), __tmp.c_str() + __tmp.size());
435  }
436 
437  static string_type
438  _S_convert_loc(const char* __first, const char* __last,
439  const std::locale& __loc);
440 
441  template<typename _Iter>
442  static string_type
443  _S_convert_loc(_Iter __first, _Iter __last, const std::locale& __loc)
444  {
445  const std::string __str(__first, __last);
446  return _S_convert_loc(__str.data(), __str.data()+__str.size(), __loc);
447  }
448 
449  template<typename _InputIterator>
450  static string_type
451  _S_convert_loc(_InputIterator __src, __null_terminated,
452  const std::locale& __loc)
453  {
454  std::string __tmp;
455  while (*__src != '\0')
456  __tmp.push_back(*__src++);
457  return _S_convert_loc(__tmp.data(), __tmp.data()+__tmp.size(), __loc);
458  }
459 
460  bool _S_is_dir_sep(value_type __ch)
461  {
462 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
463  return __ch == L'/' || __ch == preferred_separator;
464 #else
465  return __ch == '/';
466 #endif
467  }
468 
469  void _M_split_cmpts();
470  void _M_trim();
471  void _M_add_root_name(size_t __n);
472  void _M_add_root_dir(size_t __pos);
473  void _M_add_filename(size_t __pos, size_t __n);
474 
475  string_type _M_pathname;
476 
477  struct _Cmpt;
478  using _List = _GLIBCXX_STD_C::vector<_Cmpt>;
479  _List _M_cmpts; // empty unless _M_type == _Type::_Multi
480  _Type _M_type = _Type::_Multi;
481  };
482 
483  inline void swap(path& __lhs, path& __rhs) noexcept { __lhs.swap(__rhs); }
484 
485  size_t hash_value(const path& __p) noexcept;
486 
487  /// Compare paths
488  inline bool operator<(const path& __lhs, const path& __rhs) noexcept
489  { return __lhs.compare(__rhs) < 0; }
490 
491  /// Compare paths
492  inline bool operator<=(const path& __lhs, const path& __rhs) noexcept
493  { return !(__rhs < __lhs); }
494 
495  /// Compare paths
496  inline bool operator>(const path& __lhs, const path& __rhs) noexcept
497  { return __rhs < __lhs; }
498 
499  /// Compare paths
500  inline bool operator>=(const path& __lhs, const path& __rhs) noexcept
501  { return !(__lhs < __rhs); }
502 
503  /// Compare paths
504  inline bool operator==(const path& __lhs, const path& __rhs) noexcept
505  { return __lhs.compare(__rhs) == 0; }
506 
507  /// Compare paths
508  inline bool operator!=(const path& __lhs, const path& __rhs) noexcept
509  { return !(__lhs == __rhs); }
510 
511  /// Append one path to another
512  inline path operator/(const path& __lhs, const path& __rhs)
513  { return path(__lhs) /= __rhs; }
514 
515  /// Write a path to a stream
516  template<typename _CharT, typename _Traits>
518  operator<<(basic_ostream<_CharT, _Traits>& __os, const path& __p)
519  {
520  auto __tmp = __p.string<_CharT, _Traits>();
521  using __quoted_string
523  __os << __quoted_string{__tmp, '"', '\\'};
524  return __os;
525  }
526 
527  /// Read a path from a stream
528  template<typename _CharT, typename _Traits>
531  {
533  using __quoted_string
535  if (__is >> __quoted_string{ __tmp, '"', '\\' })
536  __p = std::move(__tmp);
537  return __is;
538  }
539 
540  // TODO constrain with _Path<Source> and __value_type_is_char
541  template<typename _Source>
542  inline path
543  u8path(const _Source& __source)
544  {
545 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
546  return path{ path::string_type{__source} };
547 #else
548  return path{ __source };
549 #endif
550  }
551 
552  // TODO constrain with _Path<InputIterator, InputIterator> and __value_type_is_char
553  template<typename _InputIterator>
554  inline path
555  u8path(_InputIterator __first, _InputIterator __last)
556  {
557 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
558  return path{ path::string_type{__first, __last} };
559 #else
560  return path{ __first, __last };
561 #endif
562  }
563 
564  class filesystem_error : public std::system_error
565  {
566  public:
567  filesystem_error(const string& __what_arg, error_code __ec)
568  : system_error(__ec, __what_arg) { }
569 
570  filesystem_error(const string& __what_arg, const path& __p1,
571  error_code __ec)
572  : system_error(__ec, __what_arg), _M_path1(__p1) { }
573 
574  filesystem_error(const string& __what_arg, const path& __p1,
575  const path& __p2, error_code __ec)
576  : system_error(__ec, __what_arg), _M_path1(__p1), _M_path2(__p2)
577  { }
578 
579  ~filesystem_error();
580 
581  const path& path1() const noexcept { return _M_path1; }
582  const path& path2() const noexcept { return _M_path2; }
583  const char* what() const noexcept { return _M_what.c_str(); }
584 
585  private:
586  std::string _M_gen_what();
587 
588  path _M_path1;
589  path _M_path2;
590  std::string _M_what = _M_gen_what();
591  };
592 
593  template<>
594  struct path::__is_encoded_char<char> : std::true_type
595  { using value_type = char; };
596 
597  template<>
598  struct path::__is_encoded_char<wchar_t> : std::true_type
599  { using value_type = wchar_t; };
600 
601  template<>
602  struct path::__is_encoded_char<char16_t> : std::true_type
603  { using value_type = char16_t; };
604 
605  template<>
606  struct path::__is_encoded_char<char32_t> : std::true_type
607  { using value_type = char32_t; };
608 
609  template<typename _Tp>
610  struct path::__is_encoded_char<const _Tp> : __is_encoded_char<_Tp> { };
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  {
845  if (is_same<_CharT, value_type>::value)
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>;
854  using _WString = basic_string<_CharT, _Traits, _Allocator>;
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;
885  basic_string<_CharT, _Traits, _Allocator> __wstr{__a};
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();
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 
1058  inline path::iterator::reference
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
basic_string & append(const basic_string &__str)
Append a string to this string.
An iterator for the components of a path.
iterator begin() noexcept
Definition: stl_vector.h:698
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
reference front()
constexpr const _Tp * begin(initializer_list< _Tp > __ils) noexcept
Return an iterator pointing to the first element of the initializer_list.
Template class basic_istream.
Definition: iosfwd:83
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
Managing sequences of characters and character-like objects.
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
ISO C++ entities toplevel namespace is std.
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
Marking input iterators.
integral_constant
Definition: type_traits:69
reference back()
basic_string< wchar_t > wstring
A string of wchar_t.
Definition: stringfwd.h:78
void clear() noexcept
Container class for localization functionality.The locale class is first a class wrapper for C librar...
error_code
Definition: system_error:146
Struct holding two objects of arbitrary type.
Definition: stl_pair.h:198
const _CharT * c_str() const noexcept
Return const pointer to null-terminated contents.
bool empty() const noexcept
static const size_type npos
Value returned by various member functions when they fail.
Template class basic_ostream.
Definition: iosfwd:86
iterator end() noexcept
Definition: stl_vector.h:716