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 
is_dir_sep(path::value_type ch)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 
validpath::_Parser::cmpt59     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 
_Parserpath::_Parser67   _Parser(string_view_type s, size_t o = 0) : input(s), origin(o) { }
68 
root_pathpath::_Parser69   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 (len && 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 
nextpath::_Parser142   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
offsetpath::_Parser178   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 
_Implpath::_List::_Impl186   _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 
beginpath::_List::_Impl194   iterator begin() { return reinterpret_cast<value_type*>(this + 1); }
endpath::_List::_Impl195   iterator end() { return begin() + size(); }
196 
beginpath::_List::_Impl197   const_iterator begin() const
198   { return reinterpret_cast<const value_type*>(this + 1); }
endpath::_List::_Impl199   const_iterator end() const { return begin() + size(); }
200 
frontpath::_List::_Impl201   const value_type& front() const { return *begin(); }
backpath::_List::_Impl202   const value_type& back() const { return end()[-1]; }
203 
sizepath::_List::_Impl204   int size() const { return _M_size; }
capacitypath::_List::_Impl205   int capacity() const { return _M_capacity; }
emptypath::_List::_Impl206   bool empty() const { return _M_size == 0; }
207 
clearpath::_List::_Impl208   void clear() { std::destroy_n(begin(), _M_size); _M_size = 0; }
209 
pop_backpath::_List::_Impl210   void pop_back()
211   {
212     back().~_Cmpt();
213     --_M_size;
214   }
215 
_M_erase_frompath::_List::_Impl216   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 
copypath::_List::_Impl224   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)
notypepath::_List::_Impl235   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 
operator ()(_Impl * p) const242 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 
_List()253 path::_List::_List() : _M_impl(reinterpret_cast<_Impl*>(_Type::_Filename)) { }
254 
_List(const _List & other)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&
operator =(const _List & other)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
type(_Type t)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
size() const309 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
capacity() const317 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
empty() const325 path::_List::empty() const noexcept
326 {
327   return size() == 0;
328 }
329 
330 inline auto
begin()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
end()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
begin() const351 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
end() const361 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
front()371 path::_List::front() noexcept
372 -> value_type&
373 {
374   return *_M_impl->begin();
375 }
376 
377 inline auto
back()378 path::_List::back() noexcept
379 -> value_type&
380 {
381   return _M_impl->begin()[_M_impl->size() - 1];
382 }
383 
384 inline auto
front() const385 path::_List::front() const noexcept
386 -> const value_type&
387 {
388   return *_M_impl->begin();
389 }
390 
391 inline auto
back() const392 path::_List::back() const noexcept
393 -> const value_type&
394 {
395   return _M_impl->begin()[_M_impl->size() - 1];
396 }
397 
398 inline void
pop_back()399 path::_List::pop_back()
400 {
401   __glibcxx_assert(size() > 0);
402   _M_impl->pop_back();
403 }
404 
405 inline void
_M_erase_from(const_iterator pos)406 path::_List::_M_erase_from(const_iterator pos)
407 {
408   _M_impl->_M_erase_from(pos);
409 }
410 
411 inline void
clear()412 path::_List::clear()
413 {
414   if (auto ptr = _Impl::notype(_M_impl.get()))
415     ptr->clear();
416 }
417 
418 void
reserve(int newcap,bool exact=false)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&
operator =(const path & p)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&
operator /=(const path & __p)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
_M_append(basic_string_view<value_type> s)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&
operator +=(const path & p)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 #if _GLIBCXX_FILESYSTEM_IS_WINDOWS
849   if (_M_type() == _Type::_Root_name
850       || (_M_type() == _Type::_Filename && _M_pathname.size() == 1))
851     {
852       // Handle path("C") += path(":") and path("C:") += path("/x")
853       // FIXME: do this more efficiently
854       *this = path(_M_pathname + p._M_pathname);
855       return *this;
856     }
857 #endif
858 #if SLASHSLASH_IS_ROOTNAME
859   if (_M_type() == _Type::_Root_dir)
860     {
861       // Handle path("/") += path("/x") and path("//") += path("x")
862       // FIXME: do this more efficiently
863       *this = path(_M_pathname + p._M_pathname);
864       return *this;
865     }
866 #endif
867 
868   const auto orig_pathlen = _M_pathname.length();
869   const auto orig_type = _M_type();
870   const auto orig_size = _M_cmpts.size();
871   int orig_filenamelen = -1;
872   basic_string_view<value_type> extra;
873 
874   // Ensure that '_M_pathname += p._M_pathname' won't throw:
875   _M_pathname.reserve(orig_pathlen + p._M_pathname.length());
876 
877   _Cmpt c;
878   _Cmpt* it = nullptr;
879   _Cmpt* last = nullptr;
880   if (p._M_type() == _Type::_Multi)
881     {
882       it = p._M_cmpts._M_impl->begin();
883       last = p._M_cmpts._M_impl->end();
884     }
885   else
886     {
887       c = _Cmpt(p._M_pathname, p._M_type(), 0);
888       it = &c;
889       last = it + 1;
890     }
891 
892   if (it->_M_type() == _Type::_Filename)
893     {
894       // See if there's a filename or root-name at the end of the original path
895       // that we can add to.
896       if (_M_type() == _Type::_Filename
897 #if SLASHSLASH_IS_ROOTNAME
898 	  || _M_type() == _Type::_Root_name
899 #endif
900 	  )
901 	{
902 	  if (p._M_type() == _Type::_Filename)
903 	    {
904 	      // Simplest case where we just add the whole of p to the
905 	      // original path.
906 	      _M_pathname += p._M_pathname;
907 	      return *this;
908 	    }
909 	  // Only the first component of s should be appended, do so below:
910 	  extra = it->_M_pathname;
911 	  ++it;
912 	}
913       else if (_M_type() == _Type::_Multi
914 	  && _M_cmpts.back()._M_type() == _Type::_Filename)
915 	{
916 	  auto& back = _M_cmpts.back();
917 	  if (p._M_type() == _Type::_Filename)
918 	    {
919 	      basic_string_view<value_type> s = p._M_pathname;
920 	      back._M_pathname += s;
921 	      _M_pathname += s;
922 	      return *this;
923 	    }
924 
925 	  orig_filenamelen = back._M_pathname.length();
926 	  back._M_pathname += it->_M_pathname;
927 	  extra = it->_M_pathname;
928 	  ++it;
929 	}
930     }
931   else if (is_dir_sep(_M_pathname.back()) && _M_type() == _Type::_Multi
932       && _M_cmpts.back()._M_type() == _Type::_Filename)
933     orig_filenamelen = 0; // current path has empty filename at end
934 
935   int capacity = 0;
936   if (_M_type() == _Type::_Multi)
937     capacity += _M_cmpts.size();
938   else
939     capacity += 1;
940   if (p._M_type() == _Type::_Multi)
941     capacity += p._M_cmpts.size();
942   else
943     capacity += 1;
944 
945   __try
946     {
947       _M_cmpts.type(_Type::_Multi);
948       _M_cmpts.reserve(capacity);
949       _Cmpt* output = _M_cmpts._M_impl->end();
950 
951       if (orig_type != _Type::_Multi)
952 	{
953 	  // Create single component from original path
954 	  auto ptr = ::new(output++) _Cmpt({}, orig_type, 0);
955 	  ++_M_cmpts._M_impl->_M_size;
956 	  ptr->_M_pathname.reserve(_M_pathname.length() + extra.length());
957 	  ptr->_M_pathname = _M_pathname;
958 	  ptr->_M_pathname += extra;
959 
960 #if SLASHSLASH_IS_ROOTNAME
961 	  if (orig_type == _Type::_Root_name)
962 	    {
963 	      basic_string_view<value_type> s(p._M_pathname);
964 	      ::new(output++) _Cmpt(s.substr(extra.length(), 1),
965 		  _Type::_Root_dir, orig_pathlen + extra.length());
966 	      ++_M_cmpts._M_impl->_M_size;
967 	    }
968 #endif
969 	}
970       else if (orig_filenamelen == 0 && it != last)
971 	{
972 	  // Remove empty filename at end of original path.
973 	  _M_cmpts.pop_back();
974 	  --output;
975 	}
976 
977       if (it != last && it->_M_type() == _Type::_Root_name)
978 	{
979 	  basic_string_view<value_type> s = it->_M_pathname;
980 	  auto pos = orig_pathlen;
981 #if SLASHSLASH_IS_ROOTNAME
982 	  s.remove_prefix(2);
983 	  pos += 2;
984 #endif
985 	  ::new(output++) _Cmpt(s, _Type::_Filename, pos);
986 	  ++_M_cmpts._M_impl->_M_size;
987 	  ++it;
988 	}
989 
990       if (it != last && it->_M_type() == _Type::_Root_dir)
991 	++it;
992 
993       while (it != last)
994 	{
995 	  auto pos = it->_M_pos + orig_pathlen;
996 	  ::new(output++) _Cmpt(it->_M_pathname, _Type::_Filename, pos);
997 	  ++_M_cmpts._M_impl->_M_size;
998 	  ++it;
999 	}
1000 
1001       _M_pathname += p._M_pathname;
1002 
1003       if (is_dir_sep(_M_pathname.back()))
1004 	{
1005 	  ::new(output++) _Cmpt({}, _Type::_Filename, _M_pathname.length());
1006 	  ++_M_cmpts._M_impl->_M_size;
1007 	}
1008       }
1009   __catch (...)
1010     {
1011       _M_pathname.resize(orig_pathlen);
1012       if (orig_type == _Type::_Multi)
1013 	{
1014 	  if (_M_cmpts.size() > orig_size)
1015 	    _M_cmpts._M_erase_from(_M_cmpts.begin() + orig_size);
1016 	  if (orig_filenamelen != -1)
1017 	    {
1018 	      if (_M_cmpts.size() == orig_size)
1019 		{
1020 		  auto& back = _M_cmpts.back();
1021 		  back._M_pathname.resize(orig_filenamelen);
1022 		  if (orig_filenamelen == 0)
1023 		    back._M_pos = orig_pathlen;
1024 		}
1025 	      else
1026 		{
1027 		  auto output = _M_cmpts._M_impl->end();
1028 		  ::new(output) _Cmpt({}, _Type::_Filename, orig_pathlen);
1029 		  ++_M_cmpts._M_impl->_M_size;
1030 		}
1031 	    }
1032 	}
1033       else
1034 	_M_cmpts.clear();
1035       _M_cmpts.type(orig_type);
1036       __throw_exception_again;
1037     }
1038   return *this;
1039 }
1040 
1041 // [fs.path.concat]
1042 void
_M_concat(basic_string_view<value_type> s)1043 path::_M_concat(basic_string_view<value_type> s)
1044 {
1045   if (s.empty())
1046     return;
1047 
1048   if (this->empty())
1049     {
1050       operator=(s);
1051       return;
1052     }
1053 
1054 #if _GLIBCXX_FILESYSTEM_IS_WINDOWS
1055   if (_M_type() == _Type::_Root_name
1056       || (_M_type() == _Type::_Filename && _M_pathname.size() == 1))
1057     {
1058       // Handle path("C") += ":" and path("C:") += "/x"
1059       // FIXME: do this more efficiently
1060       *this = path(_M_pathname + string_type(s));
1061       return;
1062     }
1063 #endif
1064 #if SLASHSLASH_IS_ROOTNAME
1065   if (_M_type() == _Type::_Root_dir)
1066     {
1067       // Handle path("/") += "/x" and path("//") += "x"
1068       // FIXME: do this more efficiently
1069       *this = path(_M_pathname + string_type(s));
1070       return;
1071     }
1072 #endif
1073 
1074   const auto orig_pathlen = _M_pathname.length();
1075   const auto orig_type = _M_type();
1076   const auto orig_size = _M_cmpts.size();
1077   int orig_filenamelen = -1;
1078   basic_string_view<value_type> extra;
1079 
1080   // Copy the input into _M_pathname:
1081   _M_pathname += s;
1082   // Update s to refer to the new copy (this ensures s is not a dangling
1083   // reference to deallocated characters, in the case where it was referring
1084   // into _M_pathname or a member of _M_cmpts).
1085   s = _M_pathname;
1086   const auto orig_pathname = s.substr(0, orig_pathlen);
1087   s.remove_prefix(orig_pathlen);
1088 
1089   _Parser parser(s, orig_pathlen);
1090   auto cmpt = parser.next();
1091 
1092   if (cmpt.str.data() == s.data())
1093     {
1094       // See if there's a filename or root-name at the end of the original path
1095       // that we can add to.
1096       if (_M_type() == _Type::_Filename
1097 #if SLASHSLASH_IS_ROOTNAME
1098 	  || _M_type() == _Type::_Root_name
1099 #endif
1100 	  )
1101 	{
1102 	  if (cmpt.str.length() == s.length())
1103 	    {
1104 	      // Simplest case where we just need to add the whole of s
1105 	      // to the original path, which was already done above.
1106 	      return;
1107 	    }
1108 	  // Only the first component of s should be appended, do so below:
1109 	  extra = cmpt.str;
1110 	  cmpt = {}; // so we don't process it again
1111 	}
1112       else if (_M_type() == _Type::_Multi
1113 	  && _M_cmpts.back()._M_type() == _Type::_Filename)
1114 	{
1115 	  auto& back = _M_cmpts.back();
1116 	  if (cmpt.str.length() == s.length())
1117 	    {
1118 	      back._M_pathname += s;
1119 	      return;
1120 	    }
1121 
1122 	  orig_filenamelen = back._M_pathname.length();
1123 	  back._M_pathname += cmpt.str;
1124 	  extra = cmpt.str;
1125 	  cmpt = {};
1126 	}
1127     }
1128   else if (is_dir_sep(orig_pathname.back()) && _M_type() == _Type::_Multi
1129       && _M_cmpts.back()._M_type() == _Type::_Filename)
1130     orig_filenamelen = 0; // original path had empty filename at end
1131 
1132   std::array<_Parser::cmpt, 64> buf;
1133   auto next = buf.begin();
1134 
1135   if (cmpt.valid())
1136     *next++ = cmpt;
1137 
1138   cmpt = parser.next();
1139   while (cmpt.valid() && next != buf.end())
1140     {
1141       *next++ = cmpt;
1142       cmpt = parser.next();
1143     }
1144 
1145   int capacity = 0;
1146   if (_M_type() == _Type::_Multi)
1147     capacity += _M_cmpts.size();
1148   else
1149     capacity += 1;
1150 
1151   capacity += next - buf.begin();
1152 
1153   if (cmpt.valid()) // filled buffer before parsing whole input
1154     {
1155       ++capacity;
1156       _Parser parser2(parser);
1157       while (parser2.next().valid())
1158 	++capacity;
1159     }
1160 
1161 #if SLASHSLASH_IS_ROOTNAME
1162   if (orig_type == _Type::_Root_name)
1163     ++capacity; // Need to insert root-directory after root-name
1164 #endif
1165 
1166   __try
1167     {
1168       _M_cmpts.type(_Type::_Multi);
1169       _M_cmpts.reserve(capacity);
1170       _Cmpt* output = _M_cmpts._M_impl->end();
1171       auto it = buf.begin();
1172 
1173       if (orig_type != _Type::_Multi)
1174 	{
1175 	  // Create single component from original path
1176 	  auto p = ::new(output++) _Cmpt({}, orig_type, 0);
1177 	  ++_M_cmpts._M_impl->_M_size;
1178 	  p->_M_pathname.reserve(orig_pathname.length() + extra.length());
1179 	  p->_M_pathname = orig_pathname;
1180 	  p->_M_pathname += extra;
1181 
1182 #if SLASHSLASH_IS_ROOTNAME
1183 	  if (orig_type == _Type::_Root_name)
1184 	    {
1185 	      ::new(output++) _Cmpt(s.substr(extra.length(), 1),
1186 		  _Type::_Root_dir, orig_pathlen + extra.length());
1187 	      ++_M_cmpts._M_impl->_M_size;
1188 	    }
1189 #endif
1190 	}
1191       else if (orig_filenamelen == 0 && extra.empty())
1192 	{
1193 	  // Replace empty filename at end of original path.
1194 	  std::prev(output)->_M_pathname = it->str;
1195 	  std::prev(output)->_M_pos = parser.offset(*it);
1196 	  ++it;
1197 	}
1198 
1199       while (it != next)
1200 	{
1201 	  ::new(output++) _Cmpt(it->str, _Type::_Filename, parser.offset(*it));
1202 	  ++_M_cmpts._M_impl->_M_size;
1203 	  ++it;
1204 	}
1205 
1206       if (next == buf.end())
1207 	{
1208 	  while (cmpt.valid())
1209 	    {
1210 	      auto pos = parser.offset(cmpt);
1211 	      ::new(output++) _Cmpt(cmpt.str, _Type::_Filename, pos);
1212 	      ++_M_cmpts._M_impl->_M_size;
1213 	      cmpt = parser.next();
1214 	    }
1215 	}
1216     }
1217   __catch (...)
1218     {
1219       _M_pathname.resize(orig_pathlen);
1220       if (orig_type == _Type::_Multi)
1221 	{
1222 	  _M_cmpts._M_erase_from(_M_cmpts.begin() + orig_size);
1223 	  if (orig_filenamelen != -1)
1224 	    {
1225 	      auto& back = _M_cmpts.back();
1226 	      back._M_pathname.resize(orig_filenamelen);
1227 	      if (orig_filenamelen == 0)
1228 		back._M_pos = orig_pathlen;
1229 	    }
1230 	}
1231       else
1232 	_M_cmpts.clear();
1233       _M_cmpts.type(orig_type);
1234       __throw_exception_again;
1235     }
1236 }
1237 
1238 path&
remove_filename()1239 path::remove_filename()
1240 {
1241   if (_M_type() == _Type::_Multi)
1242     {
1243       if (!_M_cmpts.empty())
1244 	{
1245 	  auto cmpt = std::prev(_M_cmpts.end());
1246 	  if (cmpt->_M_type() == _Type::_Filename && !cmpt->empty())
1247 	    {
1248 	      _M_pathname.erase(cmpt->_M_pos);
1249 	      auto prev = std::prev(cmpt);
1250 	      if (prev->_M_type() == _Type::_Root_dir
1251 		  || prev->_M_type() == _Type::_Root_name)
1252 		{
1253 		  _M_cmpts.pop_back();
1254 		  if (_M_cmpts.size() == 1)
1255 		    {
1256 		      _M_cmpts.type(_M_cmpts.front()._M_type());
1257 		      _M_cmpts.clear();
1258 		    }
1259 		}
1260 	      else
1261 		cmpt->clear();
1262 	    }
1263 	}
1264     }
1265   else if (_M_type() == _Type::_Filename)
1266     clear();
1267   return *this;
1268 }
1269 
1270 path&
replace_filename(const path & replacement)1271 path::replace_filename(const path& replacement)
1272 {
1273   remove_filename();
1274   operator/=(replacement);
1275   return *this;
1276 }
1277 
1278 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
1279 const fs::path::value_type dot = L'.';
1280 #else
1281 const fs::path::value_type dot = '.';
1282 #endif
1283 
1284 path&
replace_extension(const path & replacement)1285 path::replace_extension(const path& replacement)
1286 {
1287   auto ext = _M_find_extension();
1288   // Any existing extension() is removed
1289   if (ext.first && ext.second != string_type::npos)
1290     {
1291       if (ext.first == &_M_pathname)
1292 	_M_pathname.erase(ext.second);
1293       else
1294 	{
1295 	  auto& back = _M_cmpts.back();
1296 	  __glibcxx_assert( ext.first == &back._M_pathname );
1297 	  back._M_pathname.erase(ext.second);
1298 	  _M_pathname.erase(back._M_pos + ext.second);
1299 	}
1300     }
1301    // If replacement is not empty and does not begin with a dot character,
1302    // a dot character is appended
1303   if (!replacement.empty() && replacement.native()[0] != dot)
1304     operator+=(".");
1305   operator+=(replacement);
1306   return *this;
1307 }
1308 
1309 int
compare(const path & p) const1310 path::compare(const path& p) const noexcept
1311 {
1312   if (_M_pathname == p._M_pathname)
1313     return 0;
1314 
1315   basic_string_view<value_type> lroot, rroot;
1316   if (_M_type() == _Type::_Root_name)
1317     lroot = _M_pathname;
1318   else if (_M_type() == _Type::_Multi
1319       && _M_cmpts.front()._M_type() == _Type::_Root_name)
1320     lroot = _M_cmpts.front()._M_pathname;
1321   if (p._M_type() == _Type::_Root_name)
1322     rroot = p._M_pathname;
1323   else if (p._M_type() == _Type::_Multi
1324       && p._M_cmpts.front()._M_type() == _Type::_Root_name)
1325     rroot = p._M_cmpts.front()._M_pathname;
1326   if (int rootNameComparison = lroot.compare(rroot))
1327     return rootNameComparison;
1328 
1329   if (!this->has_root_directory() && p.has_root_directory())
1330     return -1;
1331   else if (this->has_root_directory() && !p.has_root_directory())
1332     return +1;
1333 
1334   using Iterator = const _Cmpt*;
1335   Iterator begin1, end1, begin2, end2;
1336   if (_M_type() == _Type::_Multi)
1337     {
1338       begin1 = _M_cmpts.begin();
1339       end1 = _M_cmpts.end();
1340       // Find start of this->relative_path()
1341       while (begin1 != end1 && begin1->_M_type() != _Type::_Filename)
1342 	++begin1;
1343     }
1344   else
1345     begin1 = end1 = nullptr;
1346 
1347   if (p._M_type() == _Type::_Multi)
1348     {
1349       begin2 = p._M_cmpts.begin();
1350       end2 = p._M_cmpts.end();
1351       // Find start of p.relative_path()
1352       while (begin2 != end2 && begin2->_M_type() != _Type::_Filename)
1353 	++begin2;
1354     }
1355   else
1356     begin2 = end2 = nullptr;
1357 
1358   if (_M_type() == _Type::_Filename)
1359     {
1360       if (p._M_type() == _Type::_Filename)
1361 	return native().compare(p.native());
1362       else if (begin2 != end2)
1363 	{
1364 	  if (int ret = native().compare(begin2->native()))
1365 	    return ret;
1366 	  else
1367 	    return ++begin2 == end2 ? 0 : -1;
1368 	}
1369       else
1370 	return +1;
1371     }
1372   else if (p._M_type() == _Type::_Filename)
1373     {
1374       if (begin1 != end1)
1375 	{
1376 	  if (int ret = begin1->native().compare(p.native()))
1377 	    return ret;
1378 	  else
1379 	    return ++begin1 == end1 ? 0 : +1;
1380 	}
1381       else
1382 	return -1;
1383     }
1384 
1385   int count = 1;
1386   while (begin1 != end1 && begin2 != end2)
1387     {
1388       if (int i = begin1->native().compare(begin2->native()))
1389 	return i;
1390       ++begin1;
1391       ++begin2;
1392       ++count;
1393     }
1394   if (begin1 == end1)
1395     {
1396       if (begin2 == end2)
1397 	return 0;
1398       return -count;
1399     }
1400   return count;
1401 }
1402 
1403 int
compare(basic_string_view<value_type> s) const1404 path::compare(basic_string_view<value_type> s) const noexcept
1405 {
1406   if (_M_pathname == s)
1407     return 0;
1408 
1409   _Parser parser(s);
1410 
1411   basic_string_view<value_type> lroot, rroot;
1412   if (_M_type() == _Type::_Root_name)
1413     lroot = _M_pathname;
1414   else if (_M_type() == _Type::_Multi
1415       && _M_cmpts.front()._M_type() == _Type::_Root_name)
1416     lroot = _M_cmpts.front()._M_pathname;
1417   auto root_path = parser.root_path();
1418   if (root_path.first.type == _Type::_Root_name)
1419     rroot = root_path.first.str;
1420   if (int rootNameComparison = lroot.compare(rroot))
1421     return rootNameComparison;
1422 
1423   const bool has_root_dir = root_path.first.type == _Type::_Root_dir
1424     || root_path.second.type == _Type::_Root_dir;
1425   if (!this->has_root_directory() && has_root_dir)
1426     return -1;
1427   else if (this->has_root_directory() && !has_root_dir)
1428     return +1;
1429 
1430   using Iterator = const _Cmpt*;
1431   Iterator begin1, end1;
1432   if (_M_type() == _Type::_Filename)
1433     {
1434       auto cmpt = parser.next();
1435       if (cmpt.valid())
1436 	{
1437 	  if (int ret = this->native().compare(cmpt.str))
1438 	    return ret;
1439 	  return parser.next().valid() ? -1 : 0;
1440 	}
1441       else
1442 	return +1;
1443     }
1444   else if (_M_type() == _Type::_Multi)
1445     {
1446       begin1 = _M_cmpts.begin();
1447       end1 = _M_cmpts.end();
1448       while (begin1 != end1 && begin1->_M_type() != _Type::_Filename)
1449 	++begin1;
1450     }
1451   else
1452     begin1 = end1 = nullptr;
1453 
1454   int count = 1;
1455   auto cmpt = parser.next();
1456   while (begin1 != end1 && cmpt.valid())
1457     {
1458       if (int i = begin1->native().compare(cmpt.str))
1459 	return i;
1460       ++begin1;
1461       cmpt = parser.next();
1462       ++count;
1463     }
1464   if (begin1 == end1)
1465     {
1466       if (!cmpt.valid())
1467 	return 0;
1468       return -count;
1469     }
1470   return +count;
1471 }
1472 
1473 path
root_name() const1474 path::root_name() const
1475 {
1476   path __ret;
1477   if (_M_type() == _Type::_Root_name)
1478     __ret = *this;
1479   else if (_M_cmpts.size() && _M_cmpts.begin()->_M_type() == _Type::_Root_name)
1480     __ret = *_M_cmpts.begin();
1481   return __ret;
1482 }
1483 
1484 path
root_directory() const1485 path::root_directory() const
1486 {
1487   path __ret;
1488   if (_M_type() == _Type::_Root_dir)
1489     {
1490       __ret._M_cmpts.type(_Type::_Root_dir);
1491       __ret._M_pathname.assign(1, preferred_separator);
1492     }
1493   else if (!_M_cmpts.empty())
1494     {
1495       auto __it = _M_cmpts.begin();
1496       if (__it->_M_type() == _Type::_Root_name)
1497         ++__it;
1498       if (__it != _M_cmpts.end() && __it->_M_type() == _Type::_Root_dir)
1499         __ret = *__it;
1500     }
1501   return __ret;
1502 }
1503 
1504 path
root_path() const1505 path::root_path() const
1506 {
1507   path __ret;
1508   if (_M_type() == _Type::_Root_name)
1509     __ret = *this;
1510   else if (_M_type() == _Type::_Root_dir)
1511     {
1512       __ret._M_pathname.assign(1, preferred_separator);
1513       __ret._M_cmpts.type(_Type::_Root_dir);
1514     }
1515   else if (!_M_cmpts.empty())
1516     {
1517       auto __it = _M_cmpts.begin();
1518       if (__it->_M_type() == _Type::_Root_name)
1519         {
1520           __ret = *__it++;
1521           if (__it != _M_cmpts.end() && __it->_M_type() == _Type::_Root_dir)
1522 	    __ret /= *__it;
1523         }
1524       else if (__it->_M_type() == _Type::_Root_dir)
1525         __ret = *__it;
1526     }
1527   return __ret;
1528 }
1529 
1530 path
relative_path() const1531 path::relative_path() const
1532 {
1533   path __ret;
1534   if (_M_type() == _Type::_Filename)
1535     __ret = *this;
1536   else if (!_M_cmpts.empty())
1537     {
1538       auto __it = _M_cmpts.begin();
1539       if (__it->_M_type() == _Type::_Root_name)
1540         ++__it;
1541       if (__it != _M_cmpts.end() && __it->_M_type() == _Type::_Root_dir)
1542         ++__it;
1543       if (__it != _M_cmpts.end())
1544         __ret.assign(_M_pathname.substr(__it->_M_pos));
1545     }
1546   return __ret;
1547 }
1548 
1549 path
parent_path() const1550 path::parent_path() const
1551 {
1552   path __ret;
1553   if (!has_relative_path())
1554     __ret = *this;
1555   else if (_M_cmpts.size() >= 2)
1556     {
1557       const auto parent = std::prev(_M_cmpts.end(), 2);
1558       const auto len = parent->_M_pos + parent->_M_pathname.length();
1559       __ret.assign(_M_pathname.substr(0, len));
1560     }
1561   return __ret;
1562 }
1563 
1564 bool
has_root_name() const1565 path::has_root_name() const noexcept
1566 {
1567   if (_M_type() == _Type::_Root_name)
1568     return true;
1569   if (!_M_cmpts.empty() && _M_cmpts.begin()->_M_type() == _Type::_Root_name)
1570     return true;
1571   return false;
1572 }
1573 
1574 bool
has_root_directory() const1575 path::has_root_directory() const noexcept
1576 {
1577   if (_M_type() == _Type::_Root_dir)
1578     return true;
1579   if (!_M_cmpts.empty())
1580     {
1581       auto __it = _M_cmpts.begin();
1582       if (__it->_M_type() == _Type::_Root_name)
1583         ++__it;
1584       if (__it != _M_cmpts.end() && __it->_M_type() == _Type::_Root_dir)
1585         return true;
1586     }
1587   return false;
1588 }
1589 
1590 bool
has_root_path() const1591 path::has_root_path() const noexcept
1592 {
1593   if (_M_type() == _Type::_Root_name || _M_type() == _Type::_Root_dir)
1594     return true;
1595   if (!_M_cmpts.empty())
1596     {
1597       auto __type = _M_cmpts.front()._M_type();
1598       if (__type == _Type::_Root_name || __type == _Type::_Root_dir)
1599         return true;
1600     }
1601   return false;
1602 }
1603 
1604 bool
has_relative_path() const1605 path::has_relative_path() const noexcept
1606 {
1607   if (_M_type() == _Type::_Filename && !_M_pathname.empty())
1608     return true;
1609   if (!_M_cmpts.empty())
1610     {
1611       auto __it = _M_cmpts.begin();
1612       if (__it->_M_type() == _Type::_Root_name)
1613         ++__it;
1614       if (__it != _M_cmpts.end() && __it->_M_type() == _Type::_Root_dir)
1615         ++__it;
1616       if (__it != _M_cmpts.end() && !__it->_M_pathname.empty())
1617         return true;
1618     }
1619   return false;
1620 }
1621 
1622 
1623 bool
has_parent_path() const1624 path::has_parent_path() const noexcept
1625 {
1626   if (!has_relative_path())
1627     return !empty();
1628   return _M_cmpts.size() >= 2;
1629 }
1630 
1631 bool
has_filename() const1632 path::has_filename() const noexcept
1633 {
1634   if (empty())
1635     return false;
1636   if (_M_type() == _Type::_Filename)
1637     return !_M_pathname.empty();
1638   if (_M_type() == _Type::_Multi)
1639     {
1640       if (_M_pathname.back() == preferred_separator)
1641 	return false;
1642       return _M_cmpts.back().has_filename();
1643     }
1644   return false;
1645 }
1646 
1647 namespace
1648 {
is_dot(fs::path::value_type c)1649   inline bool is_dot(fs::path::value_type c) { return c == dot; }
1650 
is_dot(const fs::path & path)1651   inline bool is_dot(const fs::path& path)
1652   {
1653     const auto& filename = path.native();
1654     return filename.size() == 1 && is_dot(filename[0]);
1655   }
1656 
is_dotdot(const fs::path & path)1657   inline bool is_dotdot(const fs::path& path)
1658   {
1659     const auto& filename = path.native();
1660     return filename.size() == 2 && is_dot(filename[0]) && is_dot(filename[1]);
1661   }
1662 } // namespace
1663 
1664 path
lexically_normal() const1665 path::lexically_normal() const
1666 {
1667   /*
1668   C++17 [fs.path.generic] p6
1669   - If the path is empty, stop.
1670   - Replace each slash character in the root-name with a preferred-separator.
1671   - Replace each directory-separator with a preferred-separator.
1672   - Remove each dot filename and any immediately following directory-separator.
1673   - As long as any appear, remove a non-dot-dot filename immediately followed
1674     by a directory-separator and a dot-dot filename, along with any immediately
1675     following directory-separator.
1676   - If there is a root-directory, remove all dot-dot filenames and any
1677     directory-separators immediately following them.
1678   - If the last filename is dot-dot, remove any trailing directory-separator.
1679   - If the path is empty, add a dot.
1680   */
1681   path ret;
1682   // If the path is empty, stop.
1683   if (empty())
1684     return ret;
1685   for (auto& p : *this)
1686     {
1687 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
1688       // Replace each slash character in the root-name
1689       if (p._M_type() == _Type::_Root_name || p._M_type() == _Type::_Root_dir)
1690 	{
1691 	  string_type s = p.native();
1692 	  std::replace(s.begin(), s.end(), L'/', L'\\');
1693 	  ret /= s;
1694 	  continue;
1695 	}
1696 #endif
1697       if (is_dotdot(p))
1698 	{
1699 	  if (ret.has_filename())
1700 	    {
1701 	      // remove a non-dot-dot filename immediately followed by /..
1702 	      if (!is_dotdot(ret.filename()))
1703 		ret.remove_filename();
1704 	      else
1705 		ret /= p;
1706 	    }
1707 	  else if (!ret.has_relative_path())
1708 	    {
1709 	      // remove a dot-dot filename immediately after root-directory
1710 	      if (!ret.has_root_directory())
1711 		ret /= p;
1712 	    }
1713 	  else
1714 	    {
1715 	      // Got a path with a relative path (i.e. at least one non-root
1716 	      // element) and no filename at the end (i.e. empty last element),
1717 	      // so must have a trailing slash. See what is before it.
1718 	      auto elem = ret._M_cmpts.end() - 2;
1719 	      if (elem->has_filename() && !is_dotdot(*elem))
1720 		{
1721 		  // Remove the filename before the trailing slash
1722 		  // (equiv. to ret = ret.parent_path().remove_filename())
1723 
1724 		  if (elem == ret._M_cmpts.begin())
1725 		    ret.clear();
1726 		  else
1727 		    {
1728 		      ret._M_pathname.erase(elem->_M_pos);
1729 		      // Remove empty filename at the end:
1730 		      ret._M_cmpts.pop_back();
1731 		      // If we still have a trailing non-root dir separator
1732 		      // then leave an empty filename at the end:
1733 		      if (std::prev(elem)->_M_type() == _Type::_Filename)
1734 			elem->clear();
1735 		      else // remove the component completely:
1736 			ret._M_cmpts.pop_back();
1737 		    }
1738 		}
1739 	      else
1740 		// Append the ".." to something ending in "../" which happens
1741 		// when normalising paths like ".././.." and "../a/../.."
1742 		ret /= p;
1743 	    }
1744 	}
1745       else if (is_dot(p))
1746 	ret /= path();
1747 #if SLASHSLASH_IS_ROOTNAME
1748       else if (p._M_type() == _Type::_Root_dir)
1749 	ret += '/'; // using operator/=('/') would replace whole of ret
1750 #endif
1751       else
1752 	ret /= p;
1753     }
1754 
1755   if (ret._M_cmpts.size() >= 2)
1756     {
1757       auto back = std::prev(ret.end());
1758       // If the last filename is dot-dot, ...
1759       if (back->empty() && is_dotdot(*std::prev(back)))
1760 	// ... remove any trailing directory-separator.
1761 	ret = ret.parent_path();
1762     }
1763   // If the path is empty, add a dot.
1764   else if (ret.empty())
1765     ret = ".";
1766 
1767   return ret;
1768 }
1769 
1770 path
lexically_relative(const path & base) const1771 path::lexically_relative(const path& base) const
1772 {
1773   path ret;
1774   if (root_name() != base.root_name())
1775     return ret;
1776   if (is_absolute() != base.is_absolute())
1777     return ret;
1778   if (!has_root_directory() && base.has_root_directory())
1779     return ret;
1780   auto [a, b] = std::mismatch(begin(), end(), base.begin(), base.end());
1781   if (a == end() && b == base.end())
1782     ret = ".";
1783   else
1784   {
1785     int n = 0;
1786     for (; b != base.end(); ++b)
1787     {
1788       const path& p = *b;
1789       if (is_dotdot(p))
1790 	--n;
1791       else if (!p.empty() && !is_dot(p))
1792 	++n;
1793     }
1794     if (n == 0 && (a == end() || a->empty()))
1795       ret = ".";
1796     else if (n >= 0)
1797     {
1798       const path dotdot("..");
1799       while (n--)
1800 	ret /= dotdot;
1801       for (; a != end(); ++a)
1802 	ret /= *a;
1803     }
1804   }
1805   return ret;
1806 }
1807 
1808 path
lexically_proximate(const path & base) const1809 path::lexically_proximate(const path& base) const
1810 {
1811   path rel = lexically_relative(base);
1812   if (rel.empty())
1813     rel = *this;
1814   return rel;
1815 }
1816 
1817 std::pair<const path::string_type*, std::size_t>
_M_find_extension() const1818 path::_M_find_extension() const noexcept
1819 {
1820   const string_type* s = nullptr;
1821 
1822   if (_M_type() == _Type::_Filename)
1823     s = &_M_pathname;
1824   else if (_M_type() == _Type::_Multi && !_M_cmpts.empty())
1825     {
1826       const auto& c = _M_cmpts.back();
1827       if (c._M_type() == _Type::_Filename)
1828 	s = &c._M_pathname;
1829     }
1830 
1831   if (s)
1832     {
1833       if (auto sz = s->size())
1834 	{
1835 	  if (sz <= 2 && (*s)[0] == dot)
1836 	    return { s, string_type::npos };
1837 	  if (const auto pos = s->rfind(dot))
1838 	    return { s , pos };
1839 	  return { s, string_type::npos };
1840 	}
1841     }
1842   return {};
1843 }
1844 
1845 void
_M_split_cmpts()1846 path::_M_split_cmpts()
1847 {
1848   _M_cmpts.clear();
1849 
1850   if (_M_pathname.empty())
1851     {
1852       _M_cmpts.type(_Type::_Filename);
1853       return;
1854     }
1855   if (_M_pathname.length() == 1 && _M_pathname[0] == preferred_separator)
1856     {
1857       _M_cmpts.type(_Type::_Root_dir);
1858       return;
1859     }
1860 
1861   _Parser parser(_M_pathname);
1862 
1863   std::array<_Parser::cmpt, 64> buf;
1864   auto next = buf.begin();
1865 
1866   // look for root name or root directory
1867   auto root_path = parser.root_path();
1868   if (root_path.first.valid())
1869     {
1870       *next++ = root_path.first;
1871       if (root_path.second.valid())
1872 	*next++ = root_path.second;
1873     }
1874 
1875   auto cmpt = parser.next();
1876   while (cmpt.valid())
1877     {
1878       do
1879 	{
1880 	  *next++ = cmpt;
1881 	  cmpt = parser.next();
1882 	}
1883       while (cmpt.valid() && next != buf.end());
1884 
1885       if (next == buf.end())
1886 	{
1887 	  _M_cmpts.type(_Type::_Multi);
1888 	  _M_cmpts.reserve(_M_cmpts.size() + buf.size());
1889 	  auto output = _M_cmpts._M_impl->end();
1890 	  for (const auto& c : buf)
1891 	    {
1892 	      ::new(output++) _Cmpt(c.str, c.type, parser.offset(c));
1893 	      ++_M_cmpts._M_impl->_M_size;
1894 	    }
1895 	  next = buf.begin();
1896 	}
1897     }
1898 
1899   if (auto n = next - buf.begin())
1900     {
1901       if (n == 1 && _M_cmpts.empty())
1902 	{
1903 	  _M_cmpts.type(buf.front().type);
1904 	  return;
1905 	}
1906 
1907       _M_cmpts.type(_Type::_Multi);
1908       _M_cmpts.reserve(_M_cmpts.size() + n, true);
1909       auto output = _M_cmpts._M_impl->end();
1910       for (int i = 0; i < n; ++i)
1911 	{
1912 	  const auto& c = buf[i];
1913 	  ::new(output++) _Cmpt(c.str, c.type, parser.offset(c));
1914 	  ++_M_cmpts._M_impl->_M_size;
1915 	}
1916     }
1917 }
1918 
1919 path::string_type
_S_convert_loc(const char * __first,const char * __last,const std::locale & __loc)1920 path::_S_convert_loc(const char* __first, const char* __last,
1921 		     const std::locale& __loc)
1922 {
1923 #if _GLIBCXX_USE_WCHAR_T
1924   auto& __cvt = std::use_facet<codecvt<wchar_t, char, mbstate_t>>(__loc);
1925   basic_string<wchar_t> __ws;
1926   if (!__str_codecvt_in_all(__first, __last, __ws, __cvt))
1927     _GLIBCXX_THROW_OR_ABORT(filesystem_error(
1928 	  "Cannot convert character sequence",
1929 	  std::make_error_code(errc::illegal_byte_sequence)));
1930 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
1931   return __ws;
1932 #else
1933   return _Cvt<wchar_t>::_S_convert(__ws.data(), __ws.data() + __ws.size());
1934 #endif
1935 #else
1936   return {__first, __last};
1937 #endif
1938 }
1939 
1940 std::size_t
hash_value(const path & p)1941 fs::hash_value(const path& p) noexcept
1942 {
1943   // [path.non-member]
1944   // "If for two paths, p1 == p2 then hash_value(p1) == hash_value(p2)."
1945   // Equality works as if by traversing the range [begin(), end()), meaning
1946   // e.g. path("a//b") == path("a/b"), so we cannot simply hash _M_pathname
1947   // but need to iterate over individual elements. Use the hash_combine from
1948   // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3876.pdf
1949   size_t seed = 0;
1950   for (const auto& x : p)
1951     {
1952       seed ^= std::hash<path::string_type>()(x.native()) + 0x9e3779b9
1953 	+ (seed<<6) + (seed>>2);
1954     }
1955   return seed;
1956 }
1957 
1958 struct fs::filesystem_error::_Impl
1959 {
_Implfs::filesystem_error::_Impl1960   _Impl(string_view what_arg, const path& p1, const path& p2)
1961   : path1(p1), path2(p2), what(make_what(what_arg, &p1, &p2))
1962   { }
1963 
_Implfs::filesystem_error::_Impl1964   _Impl(string_view what_arg, const path& p1)
1965   : path1(p1), path2(), what(make_what(what_arg, &p1, nullptr))
1966   { }
1967 
_Implfs::filesystem_error::_Impl1968   _Impl(string_view what_arg)
1969   : what(make_what(what_arg, nullptr, nullptr))
1970   { }
1971 
1972   static std::string
make_whatfs::filesystem_error::_Impl1973   make_what(string_view s, const path* p1, const path* p2)
1974   {
1975     const std::string pstr1 = p1 ? p1->u8string() : std::string{};
1976     const std::string pstr2 = p2 ? p2->u8string() : std::string{};
1977     const size_t len = 18 + s.length()
1978       + (pstr1.length() ? pstr1.length() + 3 : 0)
1979       + (pstr2.length() ? pstr2.length() + 3 : 0);
1980     std::string w;
1981     w.reserve(len);
1982     w = "filesystem error: ";
1983     w += s;
1984     if (p1)
1985       {
1986 	w += " [";
1987 	w += pstr1;
1988 	w += ']';
1989 	if (p2)
1990 	  {
1991 	    w += " [";
1992 	    w += pstr2;
1993 	    w += ']';
1994 	  }
1995       }
1996     return w;
1997   }
1998 
1999   path path1;
2000   path path2;
2001   std::string what;
2002 };
2003 
2004 template class std::__shared_ptr<const fs::filesystem_error::_Impl>;
2005 
2006 fs::filesystem_error::
filesystem_error(const string & what_arg,error_code ec)2007 filesystem_error(const string& what_arg, error_code ec)
2008 : system_error(ec, what_arg),
2009   _M_impl(std::__make_shared<_Impl>(system_error::what()))
2010 { }
2011 
2012 fs::filesystem_error::
filesystem_error(const string & what_arg,const path & p1,error_code ec)2013 filesystem_error(const string& what_arg, const path& p1, error_code ec)
2014 : system_error(ec, what_arg),
2015   _M_impl(std::__make_shared<_Impl>(system_error::what(), p1))
2016 { }
2017 
2018 fs::filesystem_error::
filesystem_error(const string & what_arg,const path & p1,const path & p2,error_code ec)2019 filesystem_error(const string& what_arg, const path& p1, const path& p2,
2020 		 error_code ec)
2021 : system_error(ec, what_arg),
2022   _M_impl(std::__make_shared<_Impl>(system_error::what(), p1, p2))
2023 { }
2024 
2025 fs::filesystem_error::~filesystem_error() = default;
2026 
2027 const fs::path&
path1() const2028 fs::filesystem_error::path1() const noexcept
2029 { return _M_impl->path1; }
2030 
2031 const fs::path&
path2() const2032 fs::filesystem_error::path2() const noexcept
2033 { return _M_impl->path2; }
2034 
2035 const char*
what() const2036 fs::filesystem_error::what() const noexcept
2037 { return _M_impl->what.c_str(); }
2038