xref: /netbsd-src/external/gpl3/gcc/dist/libstdc++-v3/src/c++17/fs_path.cc (revision d16b7486a53dcb8072b60ec6fcb4373a2d0c27b7)
1 // Class filesystem::path -*- C++ -*-
2 
3 // Copyright (C) 2014-2022 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 #ifndef _GLIBCXX_USE_CXX11_ABI
26 # define _GLIBCXX_USE_CXX11_ABI 1
27 #endif
28 
29 #ifdef __CYGWIN__
30 // Interpret "//x" as a root-name, not root-dir + filename
31 # define SLASHSLASH_IS_ROOTNAME 1
32 #endif
33 
34 #include <filesystem>
35 #include <algorithm>
36 #include <array>
37 #include <bits/stl_uninitialized.h>
38 
39 namespace fs = std::filesystem;
40 using fs::path;
41 
42 static inline bool is_dir_sep(path::value_type ch)
43 {
44 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
45     return ch == L'/' || ch == path::preferred_separator;
46 #else
47     return ch == '/';
48 #endif
49 }
50 
51 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
52 static inline bool is_disk_designator(std::wstring_view s)
53 {
54   return s.length() == 2 && s[1] == L':';
55 }
56 #endif
57 
58 struct path::_Parser
59 {
60   using string_view_type = std::basic_string_view<value_type>;
61 
62   struct cmpt
63   {
64     string_view_type str;
65     _Type type = _Type::_Multi;
66 
67     bool valid() const { return type != _Type::_Multi; }
68   };
69 
70   string_view_type input;
71   string_view_type::size_type pos = 0;
72   size_t origin;
73   _Type last_type = _Type::_Multi;
74 
75   _Parser(string_view_type s, size_t o = 0) : input(s), origin(o) { }
76 
77   pair<cmpt, cmpt> root_path() noexcept
78   {
79     pos = 0;
80     pair<cmpt, cmpt> root;
81 
82     const size_t len = input.size();
83 
84     // look for root name or root directory
85     if (len && is_dir_sep(input[0]))
86       {
87 #if SLASHSLASH_IS_ROOTNAME
88 	// look for root name, such as "//foo"
89 	if (len > 2 && input[1] == input[0])
90 	  {
91 	    if (!is_dir_sep(input[2]))
92 	      {
93 		// got root name, find its end
94 		pos = 3;
95 		while (pos < len && !is_dir_sep(input[pos]))
96 		  ++pos;
97 		root.first.str = input.substr(0, pos);
98 		root.first.type = _Type::_Root_name;
99 
100 		if (pos < len) // also got root directory
101 		  {
102 		    root.second.str = input.substr(pos, 1);
103 		    root.second.type = _Type::_Root_dir;
104 		    ++pos;
105 		  }
106 	      }
107 	    else
108 	      {
109 		// got something like "///foo" which is just a root directory
110 		// composed of multiple redundant directory separators
111 		root.first.str = input.substr(0, 1);
112 		root.first.type = _Type::_Root_dir;
113 		pos += 2;
114 	      }
115 	  }
116 	else
117 #endif
118 	  {
119 	    root.first.str = input.substr(0, 1);
120 	    root.first.type = _Type::_Root_dir;
121 	    ++pos;
122 	  }
123 	// Find the start of the first filename
124 	while (pos < len && is_dir_sep(input[pos]))
125 	  ++pos;
126       }
127 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
128     else if (is_disk_designator(input.substr(0, 2)))
129       {
130 	// got disk designator
131 	root.first.str = input.substr(0, 2);
132 	root.first.type = _Type::_Root_name;
133 	if (len > 2 && is_dir_sep(input[2]))
134 	  {
135 	    root.second.str = input.substr(2, 1);
136 	    root.second.type = _Type::_Root_dir;
137 	  }
138 	pos = input.find_first_not_of(L"/\\", 2);
139       }
140 #endif
141 
142     if (root.second.valid())
143       last_type = root.second.type;
144     else
145       last_type = root.first.type;
146 
147     return root;
148   }
149 
150   cmpt next() noexcept
151   {
152 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
153     string_view_type sep = L"/\\";
154 #else
155     char sep = '/';
156 #endif
157 
158     const int last_pos = pos;
159 
160     cmpt f;
161     if (pos != input.npos)
162       {
163 	pos = input.find_first_not_of(sep, pos);
164 	if (pos != input.npos)
165 	  {
166 	    const auto end = input.find_first_of(sep, pos);
167 	    f.str = input.substr(pos, end - pos);
168 	    f.type = _Type::_Filename;
169 	    pos = end;
170 	  }
171 	else if (last_type == _Type::_Filename
172 	    || (last_pos == 0 && !input.empty()))
173 	  {
174 	    // [fs.path.itr]/4 An empty element, if trailing non-root
175 	    // directory-separator present.
176 	    __glibcxx_assert(is_dir_sep(input.back()));
177 	    f.str = input.substr(input.length(), 0);
178 	    f.type = _Type::_Filename;
179 	  }
180       }
181     last_type = f.type;
182     return f;
183   }
184 
185   string_view_type::size_type
186   offset(const cmpt& c) const noexcept
187   { return origin + c.str.data() - input.data(); }
188 };
189 
190 inline
191 path::path(basic_string_view<value_type> __str, _Type __type)
192 : _M_pathname(__str)
193 {
194   __glibcxx_assert(__type != _Type::_Multi);
195   _M_cmpts.type(__type);
196 }
197 
198 inline
199 path::_Cmpt::_Cmpt(basic_string_view<value_type> __s, _Type __t, size_t __pos)
200 : path(__s, __t), _M_pos(__pos)
201 { }
202 
203 struct path::_List::_Impl
204 {
205   using value_type = _Cmpt;
206 
207   _Impl(int cap) : _M_size(0), _M_capacity(cap) { }
208 
209   alignas(value_type) int _M_size;
210   int _M_capacity;
211 
212   using iterator = value_type*;
213   using const_iterator = const value_type*;
214 
215   iterator begin() { return reinterpret_cast<value_type*>(this + 1); }
216   iterator end() { return begin() + size(); }
217 
218   const_iterator begin() const
219   { return reinterpret_cast<const value_type*>(this + 1); }
220   const_iterator end() const { return begin() + size(); }
221 
222   const value_type& front() const { return *begin(); }
223   const value_type& back() const { return end()[-1]; }
224 
225   int size() const { return _M_size; }
226   int capacity() const { return _M_capacity; }
227   bool empty() const { return _M_size == 0; }
228 
229   void clear() { std::destroy_n(begin(), _M_size); _M_size = 0; }
230 
231   void pop_back()
232   {
233     back().~_Cmpt();
234     --_M_size;
235   }
236 
237   void _M_erase_from(const_iterator pos)
238   {
239     iterator first = begin() + (pos - begin());
240     iterator last = end();
241     std::destroy(first, last);
242     _M_size -= last - first;
243   }
244 
245   unique_ptr<_Impl, _Impl_deleter> copy() const
246   {
247     const auto n = size();
248     void* p = ::operator new(sizeof(_Impl) + n * sizeof(value_type));
249     unique_ptr<_Impl, _Impl_deleter> newptr(::new (p) _Impl{n});
250     std::uninitialized_copy_n(begin(), n, newptr->begin());
251     newptr->_M_size = n;
252     return newptr;
253   }
254 
255   // Clear the lowest two bits from the pointer (i.e. remove the _Type value)
256   static _Impl* notype(_Impl* p)
257   {
258     constexpr uintptr_t mask = ~(uintptr_t)0x3;
259     return reinterpret_cast<_Impl*>(reinterpret_cast<uintptr_t>(p) & mask);
260   }
261 };
262 
263 void path::_List::_Impl_deleter::operator()(_Impl* p) const noexcept
264 {
265   p = _Impl::notype(p);
266   if (p)
267     {
268       __glibcxx_assert(p->_M_size <= p->_M_capacity);
269       p->clear();
270       ::operator delete(p, sizeof(*p) + p->_M_capacity * sizeof(value_type));
271     }
272 }
273 
274 path::_List::_List() : _M_impl(reinterpret_cast<_Impl*>(_Type::_Filename)) { }
275 
276 path::_List::_List(const _List& other)
277 {
278   if (!other.empty())
279     _M_impl = other._M_impl->copy();
280   else
281     type(other.type());
282 }
283 
284 path::_List&
285 path::_List::operator=(const _List& other)
286 {
287   if (!other.empty())
288     {
289       // copy in-place if there is capacity
290       const int newsize = other._M_impl->size();
291       auto impl = _Impl::notype(_M_impl.get());
292       if (impl && impl->capacity() >= newsize)
293 	{
294 	  const int oldsize = impl->_M_size;
295 	  auto to = impl->begin();
296 	  auto from = other._M_impl->begin();
297 	  const int minsize = std::min(newsize, oldsize);
298 	  for (int i = 0; i < minsize; ++i)
299 	    to[i]._M_pathname.reserve(from[i]._M_pathname.length());
300 	  if (newsize > oldsize)
301 	    {
302 	      std::uninitialized_copy_n(from + oldsize, newsize - oldsize,
303 					to + oldsize);
304 	      impl->_M_size = newsize;
305 	    }
306 	  else if (newsize < oldsize)
307 	    impl->_M_erase_from(impl->begin() + newsize);
308 	  std::copy_n(from, minsize, to);
309 	  type(_Type::_Multi);
310 	}
311       else
312 	_M_impl = other._M_impl->copy();
313     }
314   else
315     {
316       clear();
317       type(other.type());
318     }
319   return *this;
320 }
321 
322 inline void
323 path::_List::type(_Type t) noexcept
324 {
325   auto val = reinterpret_cast<uintptr_t>(_Impl::notype(_M_impl.release()));
326   _M_impl.reset(reinterpret_cast<_Impl*>(val | (unsigned char)t));
327 }
328 
329 inline int
330 path::_List::size() const noexcept
331 {
332   if (auto* ptr = _Impl::notype(_M_impl.get()))
333     return ptr->size();
334   return 0;
335 }
336 
337 inline int
338 path::_List::capacity() const noexcept
339 {
340   if (auto* ptr = _Impl::notype(_M_impl.get()))
341     return ptr->capacity();
342   return 0;
343 }
344 
345 inline bool
346 path::_List::empty() const noexcept
347 {
348   return size() == 0;
349 }
350 
351 inline auto
352 path::_List::begin() noexcept
353 -> iterator
354 {
355   __glibcxx_assert(!empty());
356   if (auto* ptr = _Impl::notype(_M_impl.get()))
357     return ptr->begin();
358   return nullptr;
359 }
360 
361 inline auto
362 path::_List::end() noexcept
363 -> iterator
364 {
365   __glibcxx_assert(!empty());
366   if (auto* ptr = _Impl::notype(_M_impl.get()))
367     return ptr->end();
368   return nullptr;
369 }
370 
371 auto
372 path::_List::begin() const noexcept
373 -> const_iterator
374 {
375   __glibcxx_assert(!empty());
376   if (auto* ptr = _Impl::notype(_M_impl.get()))
377     return ptr->begin();
378   return nullptr;
379 }
380 
381 auto
382 path::_List::end() const noexcept
383 -> const_iterator
384 {
385   __glibcxx_assert(!empty());
386   if (auto* ptr = _Impl::notype(_M_impl.get()))
387     return ptr->end();
388   return nullptr;
389 }
390 
391 inline auto
392 path::_List::front() noexcept
393 -> value_type&
394 {
395   return *_M_impl->begin();
396 }
397 
398 inline auto
399 path::_List::back() noexcept
400 -> value_type&
401 {
402   return _M_impl->begin()[_M_impl->size() - 1];
403 }
404 
405 inline auto
406 path::_List::front() const noexcept
407 -> const value_type&
408 {
409   return *_M_impl->begin();
410 }
411 
412 inline auto
413 path::_List::back() const noexcept
414 -> const value_type&
415 {
416   return _M_impl->begin()[_M_impl->size() - 1];
417 }
418 
419 inline void
420 path::_List::pop_back()
421 {
422   __glibcxx_assert(size() > 0);
423   _M_impl->pop_back();
424 }
425 
426 inline void
427 path::_List::_M_erase_from(const_iterator pos)
428 {
429   _M_impl->_M_erase_from(pos);
430 }
431 
432 inline void
433 path::_List::clear()
434 {
435   if (auto ptr = _Impl::notype(_M_impl.get()))
436     ptr->clear();
437 }
438 
439 void
440 path::_List::reserve(int newcap, bool exact = false)
441 {
442   // __glibcxx_assert(type() == _Type::_Multi);
443 
444   _Impl* curptr = _Impl::notype(_M_impl.get());
445 
446   int curcap = curptr ? curptr->capacity() : 0;
447 
448   if (curcap < newcap)
449     {
450       if (!exact && newcap < int(1.5 * curcap))
451 	newcap = 1.5 * curcap;
452 
453       void* p = ::operator new(sizeof(_Impl) + newcap * sizeof(value_type));
454       std::unique_ptr<_Impl, _Impl_deleter> newptr(::new(p) _Impl{newcap});
455       const int cursize = curptr ? curptr->size() : 0;
456       if (cursize)
457 	{
458 	  std::uninitialized_move_n(curptr->begin(), cursize, newptr->begin());
459 	  newptr->_M_size = cursize;
460 	}
461       std::swap(newptr, _M_impl);
462     }
463 }
464 
465 path&
466 path::operator=(const path& p)
467 {
468   if (&p == this) [[__unlikely__]]
469     return *this;
470 
471   _M_pathname.reserve(p._M_pathname.length());
472   _M_cmpts = p._M_cmpts;	// might throw
473   _M_pathname = p._M_pathname;	// won't throw because we reserved enough space
474   return *this;
475 }
476 
477 path&
478 path::operator/=(const path& __p)
479 {
480 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
481   if (__p.is_absolute()
482       || (__p.has_root_name() && __p.root_name() != root_name()))
483     return operator=(__p);
484 
485   basic_string_view<value_type> __lhs = _M_pathname;
486   bool __add_sep = false;
487 
488   if (__p.has_root_directory())
489     {
490       // Remove any root directory and relative path
491       if (_M_type() != _Type::_Root_name)
492 	{
493 	  if (!_M_cmpts.empty()
494 	      && _M_cmpts.front()._M_type() == _Type::_Root_name)
495 	    __lhs = _M_cmpts.front()._M_pathname;
496 	  else
497 	    __lhs = {};
498 	}
499     }
500   else if (has_filename() || (!has_root_directory() && is_absolute()))
501     __add_sep = true;
502 
503   basic_string_view<value_type> __rhs = __p._M_pathname;
504   // Omit any root-name from the generic format pathname:
505   if (__p._M_type() == _Type::_Root_name)
506     __rhs = {};
507   else if (!__p._M_cmpts.empty()
508       && __p._M_cmpts.front()._M_type() == _Type::_Root_name)
509     __rhs.remove_prefix(__p._M_cmpts.front()._M_pathname.size());
510 
511   const size_t __len = __lhs.size() + (int)__add_sep + __rhs.size();
512   const int __maxcmpts = _M_cmpts.size() + __p._M_cmpts.size();
513   if (_M_pathname.capacity() < __len || _M_cmpts.capacity() < __maxcmpts)
514     {
515       // Construct new path and swap (strong exception-safety guarantee).
516       string_type __tmp;
517       __tmp.reserve(__len);
518       __tmp = __lhs;
519       if (__add_sep)
520 	__tmp += preferred_separator;
521       __tmp += __rhs;
522       path __newp = std::move(__tmp);
523       swap(__newp);
524     }
525   else
526     {
527       _M_pathname = __lhs;
528       if (__add_sep)
529 	_M_pathname += preferred_separator;
530       _M_pathname += __rhs;
531       __try
532 	{
533 	  _M_split_cmpts();
534 	}
535       __catch (...)
536 	{
537 	  __try
538 	    {
539 	      // try to restore original state
540 	      _M_pathname.resize(__lhs.length());
541 	      _M_split_cmpts();
542 	    }
543 	  __catch (...)
544 	    {
545 	      // give up, basic exception safety guarantee only:
546 	      clear();
547 	      __throw_exception_again;
548 	    }
549 	}
550     }
551 #else
552   // POSIX version is simpler than the specification in the standard,
553   // as any path with root-name or root-dir is absolute.
554 
555   if (__p.is_absolute() || this->empty())
556     {
557       return operator=(__p);
558     }
559 
560   using string_view_type = basic_string_view<value_type>;
561 
562   string_view_type sep;
563   if (has_filename())
564     sep = { &preferred_separator, 1 };  // need to add a separator
565 #if SLASHSLASH_IS_ROOTNAME
566   else if (_M_type() == _Type::_Root_name) // root-name with no root-dir
567     sep = { &preferred_separator, 1 };  // need to add a separator
568 #endif
569   else if (__p.empty())
570     return *this;			    // nothing to do
571 
572   const auto orig_pathlen = _M_pathname.length();
573   const auto orig_size = _M_cmpts.size();
574   const auto orig_type = _M_type();
575 
576   int capacity = 0;
577   if (_M_type() == _Type::_Multi)
578     capacity += _M_cmpts.size();
579   else if (!empty())
580     capacity += 1;
581   if (__p._M_type() == _Type::_Multi)
582     capacity += __p._M_cmpts.size();
583   else if (!__p.empty() || !sep.empty())
584     capacity += 1;
585 #if SLASHSLASH_IS_ROOTNAME
586   if (orig_type == _Type::_Root_name)
587     ++capacity; // Need to insert root-directory after root-name
588 #endif
589 
590   if (orig_type == _Type::_Multi)
591     {
592       const int curcap = _M_cmpts._M_impl->capacity();
593       if (capacity > curcap)
594 	capacity = std::max(capacity, (int) (curcap * 1.5));
595     }
596 
597   _M_pathname.reserve(_M_pathname.length() + sep.length()
598 		      + __p._M_pathname.length());
599 
600   __try
601     {
602       _M_pathname += sep;
603       const auto basepos = _M_pathname.length();
604       _M_pathname += __p.native();
605 
606       _M_cmpts.type(_Type::_Multi);
607       _M_cmpts.reserve(capacity);
608       _Cmpt* output = _M_cmpts._M_impl->end();
609 
610       if (orig_type == _Type::_Multi)
611 	{
612 	  // Remove empty final component
613 	  if (_M_cmpts._M_impl->back().empty())
614 	    {
615 	      _M_cmpts.pop_back();
616 	      --output;
617 	    }
618 	}
619       else if (orig_pathlen != 0)
620 	{
621 	  // Create single component from original path
622 	  string_view_type s(_M_pathname.data(), orig_pathlen);
623 	  ::new(output++) _Cmpt(s, orig_type, 0);
624 	  ++_M_cmpts._M_impl->_M_size;
625 #if SLASHSLASH_IS_ROOTNAME
626 	  if (orig_type == _Type::_Root_name)
627 	    {
628 	      ::new(output++) _Cmpt(sep, _Type::_Root_dir,
629 				    orig_pathlen + sep.length());
630 	      ++_M_cmpts._M_impl->_M_size;
631 	    }
632 #endif
633 	}
634 
635       if (__p._M_type() == _Type::_Multi)
636 	{
637 	  for (auto& c : *__p._M_cmpts._M_impl)
638 	    {
639 	      ::new(output++) _Cmpt(c._M_pathname, _Type::_Filename,
640 				    c._M_pos + basepos);
641 	      ++_M_cmpts._M_impl->_M_size;
642 	    }
643 	}
644       else if (!__p.empty() || !sep.empty())
645 	{
646 	  __glibcxx_assert(__p._M_type() == _Type::_Filename);
647 	  ::new(output) _Cmpt(__p._M_pathname, __p._M_type(), basepos);
648 	  ++_M_cmpts._M_impl->_M_size;
649 	}
650     }
651   __catch (...)
652     {
653       _M_pathname.resize(orig_pathlen);
654       if (orig_type == _Type::_Multi)
655 	_M_cmpts._M_erase_from(_M_cmpts.begin() + orig_size);
656       else
657 	_M_cmpts.clear();
658       _M_cmpts.type(orig_type);
659       __throw_exception_again;
660     }
661 #endif
662   return *this;
663 }
664 
665 // [fs.path.append]
666 void
667 path::_M_append(basic_string_view<value_type> s)
668 {
669   _Parser parser(s);
670   auto root_path = parser.root_path();
671 
672 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
673   bool is_absolute = root_path.second.type == _Type::_Root_dir;
674   bool has_root_name = root_path.first.type == _Type::_Root_name;
675   if (is_absolute || (has_root_name && root_path.first.str != root_name()))
676     {
677       operator=(s);
678       return;
679     }
680 
681   basic_string_view<value_type> lhs = _M_pathname;
682   bool add_sep = false;
683 
684   bool has_root_directory = root_path.first.type == _Type::_Root_dir
685     || root_path.second.type == _Type::_Root_dir;
686 
687   if (has_root_directory)
688     {
689       // Remove any root directory and relative path
690       if (_M_type() != _Type::_Root_name)
691 	{
692 	  if (!_M_cmpts.empty()
693 	      && _M_cmpts.front()._M_type() == _Type::_Root_name)
694 	    lhs = _M_cmpts.front()._M_pathname;
695 	  else
696 	    lhs = {};
697 	}
698     }
699   else if (has_filename() || (!has_root_directory && is_absolute))
700     add_sep = true;
701 
702   basic_string_view<value_type> rhs = s;
703   // Omit any root-name from the generic format pathname:
704   if (has_root_name)
705     rhs.remove_prefix(root_path.first.str.length());
706 
707   // Construct new path and swap (strong exception-safety guarantee).
708   string_type tmp;
709   tmp.reserve(lhs.size() + (int)add_sep + rhs.size());
710   tmp = lhs;
711   if (add_sep)
712     tmp += preferred_separator;
713   tmp += rhs;
714   path newp = std::move(tmp);
715   swap(newp);
716 #else
717 
718   bool is_absolute = root_path.first.type == _Type::_Root_dir
719     || root_path.second.type == _Type::_Root_dir;
720   if (is_absolute || this->empty())
721     {
722       operator=(s);
723       return;
724     }
725 
726   const auto orig_pathlen = _M_pathname.length();
727   const auto orig_size = _M_cmpts.size();
728   const auto orig_type = _M_type();
729 
730   basic_string_view<value_type> sep;
731   if (has_filename())
732     sep = { &preferred_separator, 1 };  // need to add a separator
733 #if SLASHSLASH_IS_ROOTNAME
734   else if (_M_type() == _Type::_Root_name) // root-name with no root-dir
735     sep = { &preferred_separator, 1 };  // need to add a separator
736 #endif
737   else if (s.empty())
738     return;			    // nothing to do
739 
740   // Copy the input into _M_pathname:
741   _M_pathname += s;
742   _M_pathname.insert(orig_pathlen, sep);
743   // Update s to refer to the new copy (this ensures s is not a dangling
744   // reference to deallocated characters, in the case where it was referring
745   // into _M_pathname or a member of _M_cmpts).
746   s = _M_pathname;
747   const auto orig_pathname = s.substr(0, orig_pathlen);
748   s.remove_prefix(orig_pathlen + sep.length());
749 
750   parser.input = s; // reset parser to use updated string view
751   const auto basepos = orig_pathname.length() + sep.length();
752   parser.origin = basepos;
753 
754   std::array<_Parser::cmpt, 64> buf;
755   auto next = buf.begin();
756 
757   int capacity = 0;
758   if (_M_type() == _Type::_Multi)
759     capacity += _M_cmpts.size();
760   else if (!empty())
761     capacity += 1;
762 
763   auto cmpt = parser.next();
764   if (cmpt.valid())
765     {
766       do
767 	{
768 	  *next++ = cmpt;
769 	  cmpt = parser.next();
770 	}
771       while (cmpt.valid() && next != buf.end());
772 
773       capacity += next - buf.begin();
774       if (cmpt.valid()) // filled buffer before parsing whole input
775 	{
776 	  ++capacity;
777 	  _Parser parser2(parser);
778 	  while (parser2.next().valid())
779 	    ++capacity;
780 	}
781     }
782   else if (!sep.empty())
783     ++capacity;
784 
785 #if SLASHSLASH_IS_ROOTNAME
786   if (orig_type == _Type::_Root_name)
787     ++capacity; // Need to insert root-directory after root-name
788 #endif
789 
790   __try
791     {
792       _M_cmpts.type(_Type::_Multi);
793       _M_cmpts.reserve(capacity);
794       _Cmpt* output = _M_cmpts._M_impl->end();
795 
796       if (orig_type == _Type::_Multi)
797 	{
798 	  // Remove empty final component
799 	  if (_M_cmpts._M_impl->back().empty())
800 	    {
801 	      _M_cmpts.pop_back();
802 	      --output;
803 	    }
804 	}
805       else if (orig_pathlen != 0)
806 	{
807 	  // Create single component from original path
808 	  ::new(output++) _Cmpt(orig_pathname, orig_type, 0);
809 	  ++_M_cmpts._M_impl->_M_size;
810 
811 #if SLASHSLASH_IS_ROOTNAME
812 	  if (!sep.empty() && orig_type == _Type::_Root_name)
813 	    {
814 	      ::new(output++) _Cmpt(sep, _Type::_Root_dir,
815 				    orig_pathlen + sep.length());
816 	      ++_M_cmpts._M_impl->_M_size;
817 	    }
818 #endif
819 	}
820 
821       if (next != buf.begin())
822 	{
823 	  for (auto it = buf.begin(); it != next; ++it)
824 	    {
825 	      auto c = *it;
826 	      ::new(output++) _Cmpt(c.str, c.type, parser.offset(c));
827 	      ++_M_cmpts._M_impl->_M_size;
828 	    }
829 	  while (cmpt.valid())
830 	    {
831 	      ::new(output++) _Cmpt(cmpt.str, cmpt.type, parser.offset(cmpt));
832 	      ++_M_cmpts._M_impl->_M_size;
833 	      cmpt = parser.next();
834 	    }
835 	}
836       else if (!sep.empty())
837 	{
838 	  // Empty filename at the end:
839 	  ::new(output) _Cmpt({}, _Type::_Filename, basepos);
840 	  ++_M_cmpts._M_impl->_M_size;
841 	}
842     }
843   __catch (...)
844     {
845       _M_pathname.resize(orig_pathlen);
846       if (orig_type == _Type::_Multi)
847 	_M_cmpts._M_erase_from(_M_cmpts.begin() + orig_size);
848       else
849 	_M_cmpts.clear();
850       _M_cmpts.type(orig_type);
851       __throw_exception_again;
852     }
853 #endif
854 }
855 
856 // [fs.path.concat]
857 path&
858 path::operator+=(const path& p)
859 {
860   if (p.empty())
861     return *this;
862 
863   if (this->empty())
864     {
865       operator=(p);
866       return *this;
867     }
868 
869 #if _GLIBCXX_FILESYSTEM_IS_WINDOWS
870   if (_M_type() == _Type::_Root_name
871       || (_M_type() == _Type::_Filename && _M_pathname.size() == 1))
872     {
873       // Handle path("C") += path(":") and path("C:") += path("/x")
874       // FIXME: do this more efficiently
875       *this = path(_M_pathname + p._M_pathname);
876       return *this;
877     }
878 #endif
879 #if SLASHSLASH_IS_ROOTNAME
880   if (_M_type() == _Type::_Root_dir)
881     {
882       // Handle path("/") += path("/x") and path("//") += path("x")
883       // FIXME: do this more efficiently
884       *this = path(_M_pathname + p._M_pathname);
885       return *this;
886     }
887 #endif
888 
889   const auto orig_pathlen = _M_pathname.length();
890   const auto orig_type = _M_type();
891   const auto orig_size = _M_cmpts.size();
892   int orig_filenamelen = -1;
893   basic_string_view<value_type> extra;
894 
895   // Ensure that '_M_pathname += p._M_pathname' won't throw:
896   _M_pathname.reserve(orig_pathlen + p._M_pathname.length());
897 
898   _Cmpt c;
899   _Cmpt* it = nullptr;
900   _Cmpt* last = nullptr;
901   if (p._M_type() == _Type::_Multi)
902     {
903       it = p._M_cmpts._M_impl->begin();
904       last = p._M_cmpts._M_impl->end();
905     }
906   else
907     {
908       c = _Cmpt(p._M_pathname, p._M_type(), 0);
909       it = &c;
910       last = it + 1;
911     }
912 
913   if (it->_M_type() == _Type::_Filename)
914     {
915       // See if there's a filename or root-name at the end of the original path
916       // that we can add to.
917       if (_M_type() == _Type::_Filename
918 #if SLASHSLASH_IS_ROOTNAME
919 	  || _M_type() == _Type::_Root_name
920 #endif
921 	  )
922 	{
923 	  if (p._M_type() == _Type::_Filename)
924 	    {
925 	      // Simplest case where we just add the whole of p to the
926 	      // original path.
927 	      _M_pathname += p._M_pathname;
928 	      return *this;
929 	    }
930 	  // Only the first component of s should be appended, do so below:
931 	  extra = it->_M_pathname;
932 	  ++it;
933 	}
934       else if (_M_type() == _Type::_Multi
935 	  && _M_cmpts.back()._M_type() == _Type::_Filename)
936 	{
937 	  auto& back = _M_cmpts.back();
938 	  if (p._M_type() == _Type::_Filename)
939 	    {
940 	      basic_string_view<value_type> s = p._M_pathname;
941 	      back._M_pathname += s;
942 	      _M_pathname += s;
943 	      return *this;
944 	    }
945 
946 	  orig_filenamelen = back._M_pathname.length();
947 	  back._M_pathname += it->_M_pathname;
948 	  extra = it->_M_pathname;
949 	  ++it;
950 	}
951     }
952   else if (is_dir_sep(_M_pathname.back()) && _M_type() == _Type::_Multi
953       && _M_cmpts.back()._M_type() == _Type::_Filename)
954     orig_filenamelen = 0; // current path has empty filename at end
955 
956   int capacity = 0;
957   if (_M_type() == _Type::_Multi)
958     capacity += _M_cmpts.size();
959   else
960     capacity += 1;
961   if (p._M_type() == _Type::_Multi)
962     capacity += p._M_cmpts.size();
963   else
964     capacity += 1;
965 
966   __try
967     {
968       _M_cmpts.type(_Type::_Multi);
969       _M_cmpts.reserve(capacity);
970       _Cmpt* output = _M_cmpts._M_impl->end();
971 
972       if (orig_type != _Type::_Multi)
973 	{
974 	  // Create single component from original path
975 	  auto ptr = ::new(output++) _Cmpt({}, orig_type, 0);
976 	  ++_M_cmpts._M_impl->_M_size;
977 	  ptr->_M_pathname.reserve(_M_pathname.length() + extra.length());
978 	  ptr->_M_pathname = _M_pathname;
979 	  ptr->_M_pathname += extra;
980 
981 #if SLASHSLASH_IS_ROOTNAME
982 	  if (orig_type == _Type::_Root_name)
983 	    {
984 	      basic_string_view<value_type> s(p._M_pathname);
985 	      ::new(output++) _Cmpt(s.substr(extra.length(), 1),
986 		  _Type::_Root_dir, orig_pathlen + extra.length());
987 	      ++_M_cmpts._M_impl->_M_size;
988 	    }
989 #endif
990 	}
991       else if (orig_filenamelen == 0 && it != last)
992 	{
993 	  // Remove empty filename at end of original path.
994 	  _M_cmpts.pop_back();
995 	  --output;
996 	}
997 
998       if (it != last && it->_M_type() == _Type::_Root_name)
999 	{
1000 	  basic_string_view<value_type> s = it->_M_pathname;
1001 	  auto pos = orig_pathlen;
1002 #if SLASHSLASH_IS_ROOTNAME
1003 	  s.remove_prefix(2);
1004 	  pos += 2;
1005 #endif
1006 	  ::new(output++) _Cmpt(s, _Type::_Filename, pos);
1007 	  ++_M_cmpts._M_impl->_M_size;
1008 	  ++it;
1009 	}
1010 
1011       if (it != last && it->_M_type() == _Type::_Root_dir)
1012 	++it;
1013 
1014       while (it != last)
1015 	{
1016 	  auto pos = it->_M_pos + orig_pathlen;
1017 	  ::new(output++) _Cmpt(it->_M_pathname, _Type::_Filename, pos);
1018 	  ++_M_cmpts._M_impl->_M_size;
1019 	  ++it;
1020 	}
1021 
1022       _M_pathname += p._M_pathname;
1023 
1024       if (is_dir_sep(_M_pathname.back()))
1025 	{
1026 	  ::new(output++) _Cmpt({}, _Type::_Filename, _M_pathname.length());
1027 	  ++_M_cmpts._M_impl->_M_size;
1028 	}
1029       }
1030   __catch (...)
1031     {
1032       _M_pathname.resize(orig_pathlen);
1033       if (orig_type == _Type::_Multi)
1034 	{
1035 	  if (_M_cmpts.size() > orig_size)
1036 	    _M_cmpts._M_erase_from(_M_cmpts.begin() + orig_size);
1037 	  if (orig_filenamelen != -1)
1038 	    {
1039 	      if (_M_cmpts.size() == orig_size)
1040 		{
1041 		  auto& back = _M_cmpts.back();
1042 		  back._M_pathname.resize(orig_filenamelen);
1043 		  if (orig_filenamelen == 0)
1044 		    back._M_pos = orig_pathlen;
1045 		}
1046 	      else
1047 		{
1048 		  auto output = _M_cmpts._M_impl->end();
1049 		  ::new(output) _Cmpt({}, _Type::_Filename, orig_pathlen);
1050 		  ++_M_cmpts._M_impl->_M_size;
1051 		}
1052 	    }
1053 	}
1054       else
1055 	_M_cmpts.clear();
1056       _M_cmpts.type(orig_type);
1057       __throw_exception_again;
1058     }
1059   return *this;
1060 }
1061 
1062 // [fs.path.concat]
1063 void
1064 path::_M_concat(basic_string_view<value_type> s)
1065 {
1066   if (s.empty())
1067     return;
1068 
1069   if (this->empty())
1070     {
1071       operator=(s);
1072       return;
1073     }
1074 
1075 #if _GLIBCXX_FILESYSTEM_IS_WINDOWS
1076   if (_M_type() == _Type::_Root_name
1077       || (_M_type() == _Type::_Filename && _M_pathname.size() == 1))
1078     {
1079       // Handle path("C") += ":" and path("C:") += "/x"
1080       // FIXME: do this more efficiently
1081       *this = path(_M_pathname + string_type(s));
1082       return;
1083     }
1084 #endif
1085 #if SLASHSLASH_IS_ROOTNAME
1086   if (_M_type() == _Type::_Root_dir)
1087     {
1088       // Handle path("/") += "/x" and path("//") += "x"
1089       // FIXME: do this more efficiently
1090       *this = path(_M_pathname + string_type(s));
1091       return;
1092     }
1093 #endif
1094 
1095   const auto orig_pathlen = _M_pathname.length();
1096   const auto orig_type = _M_type();
1097   const auto orig_size = _M_cmpts.size();
1098   int orig_filenamelen = -1;
1099   basic_string_view<value_type> extra;
1100 
1101   // Copy the input into _M_pathname:
1102   _M_pathname += s;
1103   // Update s to refer to the new copy (this ensures s is not a dangling
1104   // reference to deallocated characters, in the case where it was referring
1105   // into _M_pathname or a member of _M_cmpts).
1106   s = _M_pathname;
1107   const auto orig_pathname = s.substr(0, orig_pathlen);
1108   s.remove_prefix(orig_pathlen);
1109 
1110   _Parser parser(s, orig_pathlen);
1111   auto cmpt = parser.next();
1112 
1113   if (cmpt.str.data() == s.data())
1114     {
1115       // See if there's a filename or root-name at the end of the original path
1116       // that we can add to.
1117       if (_M_type() == _Type::_Filename
1118 #if SLASHSLASH_IS_ROOTNAME
1119 	  || _M_type() == _Type::_Root_name
1120 #endif
1121 	  )
1122 	{
1123 	  if (cmpt.str.length() == s.length())
1124 	    {
1125 	      // Simplest case where we just need to add the whole of s
1126 	      // to the original path, which was already done above.
1127 	      return;
1128 	    }
1129 	  // Only the first component of s should be appended, do so below:
1130 	  extra = cmpt.str;
1131 	  cmpt = {}; // so we don't process it again
1132 	}
1133       else if (_M_type() == _Type::_Multi
1134 	  && _M_cmpts.back()._M_type() == _Type::_Filename)
1135 	{
1136 	  auto& back = _M_cmpts.back();
1137 	  if (cmpt.str.length() == s.length())
1138 	    {
1139 	      back._M_pathname += s;
1140 	      return;
1141 	    }
1142 
1143 	  orig_filenamelen = back._M_pathname.length();
1144 	  back._M_pathname += cmpt.str;
1145 	  extra = cmpt.str;
1146 	  cmpt = {};
1147 	}
1148     }
1149   else if (is_dir_sep(orig_pathname.back()) && _M_type() == _Type::_Multi
1150       && _M_cmpts.back()._M_type() == _Type::_Filename)
1151     orig_filenamelen = 0; // original path had empty filename at end
1152 
1153   std::array<_Parser::cmpt, 64> buf;
1154   auto next = buf.begin();
1155 
1156   if (cmpt.valid())
1157     *next++ = cmpt;
1158 
1159   cmpt = parser.next();
1160   while (cmpt.valid() && next != buf.end())
1161     {
1162       *next++ = cmpt;
1163       cmpt = parser.next();
1164     }
1165 
1166   int capacity = 0;
1167   if (_M_type() == _Type::_Multi)
1168     capacity += _M_cmpts.size();
1169   else
1170     capacity += 1;
1171 
1172   capacity += next - buf.begin();
1173 
1174   if (cmpt.valid()) // filled buffer before parsing whole input
1175     {
1176       ++capacity;
1177       _Parser parser2(parser);
1178       while (parser2.next().valid())
1179 	++capacity;
1180     }
1181 
1182 #if SLASHSLASH_IS_ROOTNAME
1183   if (orig_type == _Type::_Root_name)
1184     ++capacity; // Need to insert root-directory after root-name
1185 #endif
1186 
1187   __try
1188     {
1189       _M_cmpts.type(_Type::_Multi);
1190       _M_cmpts.reserve(capacity);
1191       _Cmpt* output = _M_cmpts._M_impl->end();
1192       auto it = buf.begin();
1193 
1194       if (orig_type != _Type::_Multi)
1195 	{
1196 	  // Create single component from original path
1197 	  auto p = ::new(output++) _Cmpt({}, orig_type, 0);
1198 	  ++_M_cmpts._M_impl->_M_size;
1199 	  p->_M_pathname.reserve(orig_pathname.length() + extra.length());
1200 	  p->_M_pathname = orig_pathname;
1201 	  p->_M_pathname += extra;
1202 
1203 #if SLASHSLASH_IS_ROOTNAME
1204 	  if (orig_type == _Type::_Root_name)
1205 	    {
1206 	      ::new(output++) _Cmpt(s.substr(extra.length(), 1),
1207 		  _Type::_Root_dir, orig_pathlen + extra.length());
1208 	      ++_M_cmpts._M_impl->_M_size;
1209 	    }
1210 #endif
1211 	}
1212       else if (orig_filenamelen == 0 && extra.empty())
1213 	{
1214 	  // Replace empty filename at end of original path.
1215 	  std::prev(output)->_M_pathname = it->str;
1216 	  std::prev(output)->_M_pos = parser.offset(*it);
1217 	  ++it;
1218 	}
1219 
1220       while (it != next)
1221 	{
1222 	  ::new(output++) _Cmpt(it->str, _Type::_Filename, parser.offset(*it));
1223 	  ++_M_cmpts._M_impl->_M_size;
1224 	  ++it;
1225 	}
1226 
1227       if (next == buf.end())
1228 	{
1229 	  while (cmpt.valid())
1230 	    {
1231 	      auto pos = parser.offset(cmpt);
1232 	      ::new(output++) _Cmpt(cmpt.str, _Type::_Filename, pos);
1233 	      ++_M_cmpts._M_impl->_M_size;
1234 	      cmpt = parser.next();
1235 	    }
1236 	}
1237     }
1238   __catch (...)
1239     {
1240       _M_pathname.resize(orig_pathlen);
1241       if (orig_type == _Type::_Multi)
1242 	{
1243 	  _M_cmpts._M_erase_from(_M_cmpts.begin() + orig_size);
1244 	  if (orig_filenamelen != -1)
1245 	    {
1246 	      auto& back = _M_cmpts.back();
1247 	      back._M_pathname.resize(orig_filenamelen);
1248 	      if (orig_filenamelen == 0)
1249 		back._M_pos = orig_pathlen;
1250 	    }
1251 	}
1252       else
1253 	_M_cmpts.clear();
1254       _M_cmpts.type(orig_type);
1255       __throw_exception_again;
1256     }
1257 }
1258 
1259 path&
1260 path::remove_filename()
1261 {
1262   if (_M_type() == _Type::_Multi)
1263     {
1264       if (!_M_cmpts.empty())
1265 	{
1266 	  auto cmpt = std::prev(_M_cmpts.end());
1267 	  if (cmpt->_M_type() == _Type::_Filename && !cmpt->empty())
1268 	    {
1269 	      _M_pathname.erase(cmpt->_M_pos);
1270 	      auto prev = std::prev(cmpt);
1271 	      if (prev->_M_type() == _Type::_Root_dir
1272 		  || prev->_M_type() == _Type::_Root_name)
1273 		{
1274 		  _M_cmpts.pop_back();
1275 		  if (_M_cmpts.size() == 1)
1276 		    {
1277 		      _M_cmpts.type(_M_cmpts.front()._M_type());
1278 		      _M_cmpts.clear();
1279 		    }
1280 		}
1281 	      else
1282 		cmpt->clear();
1283 	    }
1284 	}
1285     }
1286   else if (_M_type() == _Type::_Filename)
1287     clear();
1288   return *this;
1289 }
1290 
1291 path&
1292 path::replace_filename(const path& replacement)
1293 {
1294   remove_filename();
1295   operator/=(replacement);
1296   return *this;
1297 }
1298 
1299 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
1300 const fs::path::value_type dot = L'.';
1301 #else
1302 const fs::path::value_type dot = '.';
1303 #endif
1304 
1305 path&
1306 path::replace_extension(const path& replacement)
1307 {
1308   auto ext = _M_find_extension();
1309   // Any existing extension() is removed
1310   if (ext.first && ext.second != string_type::npos)
1311     {
1312       if (ext.first == &_M_pathname)
1313 	_M_pathname.erase(ext.second);
1314       else
1315 	{
1316 	  auto& back = _M_cmpts.back();
1317 	  __glibcxx_assert( ext.first == &back._M_pathname );
1318 	  back._M_pathname.erase(ext.second);
1319 	  _M_pathname.erase(back._M_pos + ext.second);
1320 	}
1321     }
1322    // If replacement is not empty and does not begin with a dot character,
1323    // a dot character is appended
1324   if (!replacement.empty() && replacement.native()[0] != dot)
1325     operator+=(".");
1326   operator+=(replacement);
1327   return *this;
1328 }
1329 
1330 int
1331 path::compare(const path& p) const noexcept
1332 {
1333   if (_M_pathname == p._M_pathname)
1334     return 0;
1335 
1336   basic_string_view<value_type> lroot, rroot;
1337   if (_M_type() == _Type::_Root_name)
1338     lroot = _M_pathname;
1339   else if (_M_type() == _Type::_Multi
1340       && _M_cmpts.front()._M_type() == _Type::_Root_name)
1341     lroot = _M_cmpts.front()._M_pathname;
1342   if (p._M_type() == _Type::_Root_name)
1343     rroot = p._M_pathname;
1344   else if (p._M_type() == _Type::_Multi
1345       && p._M_cmpts.front()._M_type() == _Type::_Root_name)
1346     rroot = p._M_cmpts.front()._M_pathname;
1347   if (int rootNameComparison = lroot.compare(rroot))
1348     return rootNameComparison;
1349 
1350   if (!this->has_root_directory() && p.has_root_directory())
1351     return -1;
1352   else if (this->has_root_directory() && !p.has_root_directory())
1353     return +1;
1354 
1355   using Iterator = const _Cmpt*;
1356   Iterator begin1, end1, begin2, end2;
1357   if (_M_type() == _Type::_Multi)
1358     {
1359       begin1 = _M_cmpts.begin();
1360       end1 = _M_cmpts.end();
1361       // Find start of this->relative_path()
1362       while (begin1 != end1 && begin1->_M_type() != _Type::_Filename)
1363 	++begin1;
1364     }
1365   else
1366     begin1 = end1 = nullptr;
1367 
1368   if (p._M_type() == _Type::_Multi)
1369     {
1370       begin2 = p._M_cmpts.begin();
1371       end2 = p._M_cmpts.end();
1372       // Find start of p.relative_path()
1373       while (begin2 != end2 && begin2->_M_type() != _Type::_Filename)
1374 	++begin2;
1375     }
1376   else
1377     begin2 = end2 = nullptr;
1378 
1379   if (_M_type() == _Type::_Filename)
1380     {
1381       if (p._M_type() == _Type::_Filename)
1382 	return native().compare(p.native());
1383       else if (begin2 != end2)
1384 	{
1385 	  if (int ret = native().compare(begin2->native()))
1386 	    return ret;
1387 	  else
1388 	    return ++begin2 == end2 ? 0 : -1;
1389 	}
1390       else
1391 	return +1;
1392     }
1393   else if (p._M_type() == _Type::_Filename)
1394     {
1395       if (begin1 != end1)
1396 	{
1397 	  if (int ret = begin1->native().compare(p.native()))
1398 	    return ret;
1399 	  else
1400 	    return ++begin1 == end1 ? 0 : +1;
1401 	}
1402       else
1403 	return -1;
1404     }
1405 
1406   int count = 1;
1407   while (begin1 != end1 && begin2 != end2)
1408     {
1409       if (int i = begin1->native().compare(begin2->native()))
1410 	return i;
1411       ++begin1;
1412       ++begin2;
1413       ++count;
1414     }
1415   if (begin1 == end1)
1416     {
1417       if (begin2 == end2)
1418 	return 0;
1419       return -count;
1420     }
1421   return count;
1422 }
1423 
1424 int
1425 path::compare(basic_string_view<value_type> s) const noexcept
1426 {
1427   if (_M_pathname == s)
1428     return 0;
1429 
1430   _Parser parser(s);
1431 
1432   basic_string_view<value_type> lroot, rroot;
1433   if (_M_type() == _Type::_Root_name)
1434     lroot = _M_pathname;
1435   else if (_M_type() == _Type::_Multi
1436       && _M_cmpts.front()._M_type() == _Type::_Root_name)
1437     lroot = _M_cmpts.front()._M_pathname;
1438   auto root_path = parser.root_path();
1439   if (root_path.first.type == _Type::_Root_name)
1440     rroot = root_path.first.str;
1441   if (int rootNameComparison = lroot.compare(rroot))
1442     return rootNameComparison;
1443 
1444   const bool has_root_dir = root_path.first.type == _Type::_Root_dir
1445     || root_path.second.type == _Type::_Root_dir;
1446   if (!this->has_root_directory() && has_root_dir)
1447     return -1;
1448   else if (this->has_root_directory() && !has_root_dir)
1449     return +1;
1450 
1451   using Iterator = const _Cmpt*;
1452   Iterator begin1, end1;
1453   if (_M_type() == _Type::_Filename)
1454     {
1455       auto cmpt = parser.next();
1456       if (cmpt.valid())
1457 	{
1458 	  if (int ret = this->native().compare(cmpt.str))
1459 	    return ret;
1460 	  return parser.next().valid() ? -1 : 0;
1461 	}
1462       else
1463 	return +1;
1464     }
1465   else if (_M_type() == _Type::_Multi)
1466     {
1467       begin1 = _M_cmpts.begin();
1468       end1 = _M_cmpts.end();
1469       while (begin1 != end1 && begin1->_M_type() != _Type::_Filename)
1470 	++begin1;
1471     }
1472   else
1473     begin1 = end1 = nullptr;
1474 
1475   int count = 1;
1476   auto cmpt = parser.next();
1477   while (begin1 != end1 && cmpt.valid())
1478     {
1479       if (int i = begin1->native().compare(cmpt.str))
1480 	return i;
1481       ++begin1;
1482       cmpt = parser.next();
1483       ++count;
1484     }
1485   if (begin1 == end1)
1486     {
1487       if (!cmpt.valid())
1488 	return 0;
1489       return -count;
1490     }
1491   return +count;
1492 }
1493 
1494 path
1495 path::root_name() const
1496 {
1497   path __ret;
1498   if (_M_type() == _Type::_Root_name)
1499     __ret = *this;
1500   else if (_M_cmpts.size() && _M_cmpts.begin()->_M_type() == _Type::_Root_name)
1501     __ret = *_M_cmpts.begin();
1502   return __ret;
1503 }
1504 
1505 path
1506 path::root_directory() const
1507 {
1508   path __ret;
1509   if (_M_type() == _Type::_Root_dir)
1510     {
1511       __ret._M_cmpts.type(_Type::_Root_dir);
1512       __ret._M_pathname.assign(1, preferred_separator);
1513     }
1514   else if (!_M_cmpts.empty())
1515     {
1516       auto __it = _M_cmpts.begin();
1517       if (__it->_M_type() == _Type::_Root_name)
1518         ++__it;
1519       if (__it != _M_cmpts.end() && __it->_M_type() == _Type::_Root_dir)
1520         __ret = *__it;
1521     }
1522   return __ret;
1523 }
1524 
1525 path
1526 path::root_path() const
1527 {
1528   path __ret;
1529   if (_M_type() == _Type::_Root_name)
1530     __ret = *this;
1531   else if (_M_type() == _Type::_Root_dir)
1532     {
1533       __ret._M_pathname.assign(1, preferred_separator);
1534       __ret._M_cmpts.type(_Type::_Root_dir);
1535     }
1536   else if (!_M_cmpts.empty())
1537     {
1538       auto __it = _M_cmpts.begin();
1539       if (__it->_M_type() == _Type::_Root_name)
1540         {
1541           __ret = *__it++;
1542           if (__it != _M_cmpts.end() && __it->_M_type() == _Type::_Root_dir)
1543 	    __ret /= *__it;
1544         }
1545       else if (__it->_M_type() == _Type::_Root_dir)
1546         __ret = *__it;
1547     }
1548   return __ret;
1549 }
1550 
1551 path
1552 path::relative_path() const
1553 {
1554   path __ret;
1555   if (_M_type() == _Type::_Filename)
1556     __ret = *this;
1557   else if (!_M_cmpts.empty())
1558     {
1559       auto __it = _M_cmpts.begin();
1560       if (__it->_M_type() == _Type::_Root_name)
1561         ++__it;
1562       if (__it != _M_cmpts.end() && __it->_M_type() == _Type::_Root_dir)
1563         ++__it;
1564       if (__it != _M_cmpts.end())
1565         __ret.assign(_M_pathname.substr(__it->_M_pos));
1566     }
1567   return __ret;
1568 }
1569 
1570 path
1571 path::parent_path() const
1572 {
1573   path __ret;
1574   if (!has_relative_path())
1575     __ret = *this;
1576   else if (_M_cmpts.size() >= 2)
1577     {
1578       const auto parent = std::prev(_M_cmpts.end(), 2);
1579       const auto len = parent->_M_pos + parent->_M_pathname.length();
1580       __ret.assign(_M_pathname.substr(0, len));
1581     }
1582   return __ret;
1583 }
1584 
1585 bool
1586 path::has_root_name() const noexcept
1587 {
1588   if (_M_type() == _Type::_Root_name)
1589     return true;
1590   if (!_M_cmpts.empty() && _M_cmpts.begin()->_M_type() == _Type::_Root_name)
1591     return true;
1592   return false;
1593 }
1594 
1595 bool
1596 path::has_root_directory() const noexcept
1597 {
1598   if (_M_type() == _Type::_Root_dir)
1599     return true;
1600   if (!_M_cmpts.empty())
1601     {
1602       auto __it = _M_cmpts.begin();
1603       if (__it->_M_type() == _Type::_Root_name)
1604         ++__it;
1605       if (__it != _M_cmpts.end() && __it->_M_type() == _Type::_Root_dir)
1606         return true;
1607     }
1608   return false;
1609 }
1610 
1611 bool
1612 path::has_root_path() const noexcept
1613 {
1614   if (_M_type() == _Type::_Root_name || _M_type() == _Type::_Root_dir)
1615     return true;
1616   if (!_M_cmpts.empty())
1617     {
1618       auto __type = _M_cmpts.front()._M_type();
1619       if (__type == _Type::_Root_name || __type == _Type::_Root_dir)
1620         return true;
1621     }
1622   return false;
1623 }
1624 
1625 bool
1626 path::has_relative_path() const noexcept
1627 {
1628   if (_M_type() == _Type::_Filename && !_M_pathname.empty())
1629     return true;
1630   if (!_M_cmpts.empty())
1631     {
1632       auto __it = _M_cmpts.begin();
1633       if (__it->_M_type() == _Type::_Root_name)
1634         ++__it;
1635       if (__it != _M_cmpts.end() && __it->_M_type() == _Type::_Root_dir)
1636         ++__it;
1637       if (__it != _M_cmpts.end() && !__it->_M_pathname.empty())
1638         return true;
1639     }
1640   return false;
1641 }
1642 
1643 
1644 bool
1645 path::has_parent_path() const noexcept
1646 {
1647   if (!has_relative_path())
1648     return !empty();
1649   return _M_cmpts.size() >= 2;
1650 }
1651 
1652 bool
1653 path::has_filename() const noexcept
1654 {
1655   if (empty())
1656     return false;
1657   if (_M_type() == _Type::_Filename)
1658     return !_M_pathname.empty();
1659   if (_M_type() == _Type::_Multi)
1660     {
1661       if (_M_pathname.back() == preferred_separator)
1662 	return false;
1663       return _M_cmpts.back().has_filename();
1664     }
1665   return false;
1666 }
1667 
1668 namespace
1669 {
1670   inline bool is_dot(fs::path::value_type c) { return c == dot; }
1671 
1672   inline bool is_dot(const fs::path& path)
1673   {
1674     const auto& filename = path.native();
1675     return filename.size() == 1 && is_dot(filename[0]);
1676   }
1677 
1678   inline bool is_dotdot(const fs::path& path)
1679   {
1680     const auto& filename = path.native();
1681     return filename.size() == 2 && is_dot(filename[0]) && is_dot(filename[1]);
1682   }
1683 } // namespace
1684 
1685 path
1686 path::lexically_normal() const
1687 {
1688   /*
1689   C++17 [fs.path.generic] p6
1690   - If the path is empty, stop.
1691   - Replace each slash character in the root-name with a preferred-separator.
1692   - Replace each directory-separator with a preferred-separator.
1693   - Remove each dot filename and any immediately following directory-separator.
1694   - As long as any appear, remove a non-dot-dot filename immediately followed
1695     by a directory-separator and a dot-dot filename, along with any immediately
1696     following directory-separator.
1697   - If there is a root-directory, remove all dot-dot filenames and any
1698     directory-separators immediately following them.
1699   - If the last filename is dot-dot, remove any trailing directory-separator.
1700   - If the path is empty, add a dot.
1701   */
1702   path ret;
1703   // If the path is empty, stop.
1704   if (empty())
1705     return ret;
1706   for (auto& p : *this)
1707     {
1708 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
1709       // Replace each slash character in the root-name
1710       if (p._M_type() == _Type::_Root_name || p._M_type() == _Type::_Root_dir)
1711 	{
1712 	  string_type s = p.native();
1713 	  std::replace(s.begin(), s.end(), L'/', L'\\');
1714 	  ret /= s;
1715 	  continue;
1716 	}
1717 #endif
1718       if (is_dotdot(p))
1719 	{
1720 	  if (ret.has_filename())
1721 	    {
1722 	      // remove a non-dot-dot filename immediately followed by /..
1723 	      if (!is_dotdot(ret.filename()))
1724 		ret.remove_filename();
1725 	      else
1726 		ret /= p;
1727 	    }
1728 	  else if (!ret.has_relative_path())
1729 	    {
1730 	      // remove a dot-dot filename immediately after root-directory
1731 	      if (!ret.has_root_directory())
1732 		ret /= p;
1733 	    }
1734 	  else
1735 	    {
1736 	      // Got a path with a relative path (i.e. at least one non-root
1737 	      // element) and no filename at the end (i.e. empty last element),
1738 	      // so must have a trailing slash. See what is before it.
1739 	      auto elem = ret._M_cmpts.end() - 2;
1740 	      if (elem->has_filename() && !is_dotdot(*elem))
1741 		{
1742 		  // Remove the filename before the trailing slash
1743 		  // (equiv. to ret = ret.parent_path().remove_filename())
1744 
1745 		  if (elem == ret._M_cmpts.begin())
1746 		    ret.clear();
1747 		  else
1748 		    {
1749 		      ret._M_pathname.erase(elem->_M_pos);
1750 		      // Remove empty filename at the end:
1751 		      ret._M_cmpts.pop_back();
1752 		      // If we still have a trailing non-root dir separator
1753 		      // then leave an empty filename at the end:
1754 		      if (std::prev(elem)->_M_type() == _Type::_Filename)
1755 			elem->clear();
1756 		      else // remove the component completely:
1757 			ret._M_cmpts.pop_back();
1758 		    }
1759 		}
1760 	      else
1761 		// Append the ".." to something ending in "../" which happens
1762 		// when normalising paths like ".././.." and "../a/../.."
1763 		ret /= p;
1764 	    }
1765 	}
1766       else if (is_dot(p))
1767 	ret /= path();
1768 #if SLASHSLASH_IS_ROOTNAME
1769       else if (p._M_type() == _Type::_Root_dir)
1770 	ret += '/'; // using operator/=('/') would replace whole of ret
1771 #endif
1772       else
1773 	ret /= p;
1774     }
1775 
1776   if (ret._M_cmpts.size() >= 2)
1777     {
1778       auto back = std::prev(ret.end());
1779       // If the last filename is dot-dot, ...
1780       if (back->empty() && is_dotdot(*std::prev(back)))
1781 	// ... remove any trailing directory-separator.
1782 	ret = ret.parent_path();
1783     }
1784   // If the path is empty, add a dot.
1785   else if (ret.empty())
1786     ret = ".";
1787 
1788   return ret;
1789 }
1790 
1791 path
1792 path::lexically_relative(const path& base) const
1793 {
1794   path ret;
1795   if (root_name() != base.root_name())
1796     return ret;
1797   if (is_absolute() != base.is_absolute())
1798     return ret;
1799   if (!has_root_directory() && base.has_root_directory())
1800     return ret;
1801   auto [a, b] = std::mismatch(begin(), end(), base.begin(), base.end());
1802 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
1803   // _GLIBCXX_RESOLVE_LIB_DEFECTS
1804   // 3070. path::lexically_relative causes surprising results if a filename
1805   // can also be a root-name
1806   if (!empty())
1807     for (auto& p : _M_cmpts)
1808       if (p._M_type() == _Type::_Filename && is_disk_designator(p.native()))
1809 	return ret;
1810   if (!base.empty())
1811     for (auto i = b, end = base.end(); i != end; ++i)
1812       if (i->_M_type() == _Type::_Filename && is_disk_designator(i->native()))
1813 	return ret;
1814 #endif
1815   if (a == end() && b == base.end())
1816     ret = ".";
1817   else
1818   {
1819     int n = 0;
1820     for (; b != base.end(); ++b)
1821     {
1822       const path& p = *b;
1823       if (is_dotdot(p))
1824 	--n;
1825       else if (!p.empty() && !is_dot(p))
1826 	++n;
1827     }
1828     if (n == 0 && (a == end() || a->empty()))
1829       ret = ".";
1830     else if (n >= 0)
1831     {
1832       const path dotdot("..");
1833       while (n--)
1834 	ret /= dotdot;
1835       for (; a != end(); ++a)
1836 	ret /= *a;
1837     }
1838   }
1839   return ret;
1840 }
1841 
1842 path
1843 path::lexically_proximate(const path& base) const
1844 {
1845   path rel = lexically_relative(base);
1846   if (rel.empty())
1847     rel = *this;
1848   return rel;
1849 }
1850 
1851 std::pair<const path::string_type*, std::size_t>
1852 path::_M_find_extension() const noexcept
1853 {
1854   const string_type* s = nullptr;
1855 
1856   if (_M_type() == _Type::_Filename)
1857     s = &_M_pathname;
1858   else if (_M_type() == _Type::_Multi && !_M_cmpts.empty())
1859     {
1860       const auto& c = _M_cmpts.back();
1861       if (c._M_type() == _Type::_Filename)
1862 	s = &c._M_pathname;
1863     }
1864 
1865   if (s)
1866     {
1867       if (auto sz = s->size())
1868 	{
1869 	  if (sz <= 2 && (*s)[0] == dot)
1870 	    return { s, string_type::npos };
1871 	  if (const auto pos = s->rfind(dot))
1872 	    return { s , pos };
1873 	  return { s, string_type::npos };
1874 	}
1875     }
1876   return {};
1877 }
1878 
1879 void
1880 path::_M_split_cmpts()
1881 {
1882   _M_cmpts.clear();
1883 
1884   if (_M_pathname.empty())
1885     {
1886       _M_cmpts.type(_Type::_Filename);
1887       return;
1888     }
1889 
1890   _Parser parser(_M_pathname);
1891 
1892   std::array<_Parser::cmpt, 64> buf;
1893   auto next = buf.begin();
1894 
1895   // look for root name or root directory
1896   auto root_path = parser.root_path();
1897   if (root_path.first.valid())
1898     {
1899       *next++ = root_path.first;
1900       if (root_path.second.valid())
1901 	*next++ = root_path.second;
1902     }
1903 
1904   auto cmpt = parser.next();
1905   while (cmpt.valid())
1906     {
1907       do
1908 	{
1909 	  *next++ = cmpt;
1910 	  cmpt = parser.next();
1911 	}
1912       while (cmpt.valid() && next != buf.end());
1913 
1914       if (next == buf.end())
1915 	{
1916 	  _M_cmpts.type(_Type::_Multi);
1917 	  _M_cmpts.reserve(_M_cmpts.size() + buf.size());
1918 	  auto output = _M_cmpts._M_impl->end();
1919 	  for (const auto& c : buf)
1920 	    {
1921 	      ::new(output++) _Cmpt(c.str, c.type, parser.offset(c));
1922 	      ++_M_cmpts._M_impl->_M_size;
1923 	    }
1924 	  next = buf.begin();
1925 	}
1926     }
1927 
1928   if (auto n = next - buf.begin())
1929     {
1930       if (n == 1 && _M_cmpts.empty())
1931 	{
1932 	  _M_cmpts.type(buf.front().type);
1933 	  return;
1934 	}
1935 
1936       _M_cmpts.type(_Type::_Multi);
1937       _M_cmpts.reserve(_M_cmpts.size() + n, true);
1938       auto output = _M_cmpts._M_impl->end();
1939       for (int i = 0; i < n; ++i)
1940 	{
1941 	  const auto& c = buf[i];
1942 	  ::new(output++) _Cmpt(c.str, c.type, parser.offset(c));
1943 	  ++_M_cmpts._M_impl->_M_size;
1944 	}
1945     }
1946 }
1947 
1948 path::string_type
1949 path::_S_convert_loc(const char* __first, const char* __last,
1950 		     const std::locale& __loc)
1951 {
1952 #if _GLIBCXX_USE_WCHAR_T
1953   auto& __cvt = std::use_facet<codecvt<wchar_t, char, mbstate_t>>(__loc);
1954   basic_string<wchar_t> __ws;
1955   if (!__str_codecvt_in_all(__first, __last, __ws, __cvt))
1956     _GLIBCXX_THROW_OR_ABORT(filesystem_error(
1957 	  "Cannot convert character sequence",
1958 	  std::make_error_code(errc::illegal_byte_sequence)));
1959   return _S_convert(std::move(__ws));
1960 #else
1961   return {__first, __last};
1962 #endif
1963 }
1964 
1965 std::size_t
1966 fs::hash_value(const path& p) noexcept
1967 {
1968   // [path.non-member]
1969   // "If for two paths, p1 == p2 then hash_value(p1) == hash_value(p2)."
1970   // Equality works as if by traversing the range [begin(), end()), meaning
1971   // e.g. path("a//b") == path("a/b"), so we cannot simply hash _M_pathname
1972   // but need to iterate over individual elements. Use the hash_combine from
1973   // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3876.pdf
1974   size_t seed = 0;
1975   for (const auto& x : p)
1976     {
1977       seed ^= std::hash<path::string_type>()(x.native()) + 0x9e3779b9
1978 	+ (seed<<6) + (seed>>2);
1979     }
1980   return seed;
1981 }
1982 
1983 struct fs::filesystem_error::_Impl
1984 {
1985   _Impl(string_view what_arg, const path& p1, const path& p2)
1986   : path1(p1), path2(p2), what(make_what(what_arg, &p1, &p2))
1987   { }
1988 
1989   _Impl(string_view what_arg, const path& p1)
1990   : path1(p1), path2(), what(make_what(what_arg, &p1, nullptr))
1991   { }
1992 
1993   _Impl(string_view what_arg)
1994   : what(make_what(what_arg, nullptr, nullptr))
1995   { }
1996 
1997   static std::string
1998   make_what(string_view s, const path* p1, const path* p2)
1999   {
2000     const std::string pstr1 = p1 ? p1->u8string() : std::string{};
2001     const std::string pstr2 = p2 ? p2->u8string() : std::string{};
2002     const size_t len = 18 + s.length()
2003       + (pstr1.length() ? pstr1.length() + 3 : 0)
2004       + (pstr2.length() ? pstr2.length() + 3 : 0);
2005     std::string w;
2006     w.reserve(len);
2007     w = "filesystem error: ";
2008     w += s;
2009     if (p1)
2010       {
2011 	w += " [";
2012 	w += pstr1;
2013 	w += ']';
2014 	if (p2)
2015 	  {
2016 	    w += " [";
2017 	    w += pstr2;
2018 	    w += ']';
2019 	  }
2020       }
2021     return w;
2022   }
2023 
2024   path path1;
2025   path path2;
2026   std::string what;
2027 };
2028 
2029 template class std::__shared_ptr<const fs::filesystem_error::_Impl>;
2030 
2031 fs::filesystem_error::
2032 filesystem_error(const string& what_arg, error_code ec)
2033 : system_error(ec, what_arg),
2034   _M_impl(std::__make_shared<_Impl>(system_error::what()))
2035 { }
2036 
2037 fs::filesystem_error::
2038 filesystem_error(const string& what_arg, const path& p1, error_code ec)
2039 : system_error(ec, what_arg),
2040   _M_impl(std::__make_shared<_Impl>(system_error::what(), p1))
2041 { }
2042 
2043 fs::filesystem_error::
2044 filesystem_error(const string& what_arg, const path& p1, const path& p2,
2045 		 error_code ec)
2046 : system_error(ec, what_arg),
2047   _M_impl(std::__make_shared<_Impl>(system_error::what(), p1, p2))
2048 { }
2049 
2050 fs::filesystem_error::~filesystem_error() = default;
2051 
2052 const fs::path&
2053 fs::filesystem_error::path1() const noexcept
2054 { return _M_impl->path1; }
2055 
2056 const fs::path&
2057 fs::filesystem_error::path2() const noexcept
2058 { return _M_impl->path2; }
2059 
2060 const char*
2061 fs::filesystem_error::what() const noexcept
2062 { return _M_impl->what.c_str(); }
2063