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