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