Subversion Repositories Kolibri OS

Rev

Details | Last modification | View Log | RSS feed

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