Implement filesystem NB comments, relative paths, and related issues.

This is a fairly large patch that implements all of the filesystem NB comments
and the relative paths changes (ex. adding weakly_canonical). These issues
and papers are all interrelated so their implementation couldn't be split up
nicely.

This patch upgrades <experimental/filesystem> to match the C++17 spec and not
the published experimental TS spec. Some of the changes in this patch are both
API and ABI breaking, however libc++ makes no guarantee about stability for
experimental implementations.

The major changes in this patch are:

* Implement NB comments for filesystem (P0492R2), including:
  * Implement `perm_options` enum as part of NB comments, and update the
    `permissions` function to match.
  * Implement changes to `remove_filename` and `replace_filename`
  * Implement changes to `path::stem()` and `path::extension()` which support
    splitting examples like `.profile`.
  * Change path iteration to return an empty path instead of '.' for trailing
    separators.
  * Change `operator/=` to handle absolute paths on the RHS.
  * Change `absolute` to no longer accept a current path argument.

* Implement relative paths according to NB comments (P0219r1)

* Combine `path.cpp` and `operations.cpp` since some path functions require
  access to the operations internals, and some fs operations require access
  to the path parser.

git-svn-id: https://llvm.org/svn/llvm-project/libcxx/trunk@329028 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/experimental/filesystem b/include/experimental/filesystem
index 47cc0c5..411b981 100644
--- a/include/experimental/filesystem
+++ b/include/experimental/filesystem
@@ -76,11 +76,11 @@
 
     // operational functions
 
-    path absolute(const path& p, const path& base=current_path());
+    path absolute(const path& p);
+    path absolute(const path& p, error_code &ec);
 
-    path canonical(const path& p, const path& base = current_path());
+    path canonical(const path& p);
     path canonical(const path& p, error_code& ec);
-    path canonical(const path& p, const path& base, error_code& ec);
 
     void copy(const path& from, const path& to);
     void copy(const path& from, const path& to, error_code& ec);
@@ -185,9 +185,17 @@
     void permissions(const path& p, perms prms, perm_options opts,
                      error_code& ec);
 
+    path proximate(const path& p, error_code& ec);
+    path proximate(const path& p, const path& base = current_path());
+    path proximate(const path& p, const path& base, error_code &ec);
+
     path read_symlink(const path& p);
     path read_symlink(const path& p, error_code& ec);
 
+    path relative(const path& p, error_code& ec);
+    path relative(const path& p, const path& base=current_path());
+    path relative(const path& p, const path& base, error_code& ec);
+
     bool remove(const path& p);
     bool remove(const path& p, error_code& ec) _NOEXCEPT;
 
@@ -211,12 +219,13 @@
     file_status  symlink_status(const path& p);
     file_status  symlink_status(const path& p, error_code& ec) _NOEXCEPT;
 
-    path system_complete(const path& p);
-    path system_complete(const path& p, error_code& ec);
-
     path temp_directory_path();
     path temp_directory_path(error_code& ec);
 
+    path weakly_canonical(path const& p);
+    path weakly_canonical(path const& p, error_code& ec);
+
+
 } } } }  // namespaces std::experimental::filesystem::v1
 
 */
@@ -796,26 +805,26 @@
 
 private:
     template <class _ECharT>
-    void __append_sep_if_needed(_ECharT __first_or_null) {
-        const _ECharT __null_val = {};
-        bool __append_sep = !empty()                       &&
-                            !__is_separator(__pn_.back())  &&
-                            __first_or_null != __null_val  && // non-empty
-                            !__is_separator(__first_or_null);
-        if (__append_sep)
-            __pn_ += preferred_separator;
+    static bool __source_is_absolute(_ECharT __first_or_null) {
+        return __is_separator(__first_or_null);
     }
 
 public:
     // appends
     path& operator/=(const path& __p) {
-        _LIBCPP_ASSERT(!__p.has_root_name(),
-                      "cannot append to a path with a root name");
-        __append_sep_if_needed(__p.empty() ? char{} : __p.__pn_[0]);
+        if (__p.is_absolute()) {
+          __pn_ = __p.__pn_;
+          return *this;
+        }
+        if (has_filename())
+          __pn_ += preferred_separator;
         __pn_ += __p.native();
         return *this;
     }
 
+    // FIXME: Use _LIBCPP_DIAGNOSE_WARNING to produce a diagnostic when __src
+    // is known at compile time to be "/' since the user almost certainly intended
+    // to append a separator instead of overwriting the path with "/"
     template <class _Source>
     _LIBCPP_INLINE_VISIBILITY
     _EnableIfPathable<_Source>
@@ -828,7 +837,10 @@
     append(const _Source& __src) {
         using _Traits = __is_pathable<_Source>;
         using _CVT = _PathCVT<_SourceChar<_Source>>;
-        __append_sep_if_needed(_Traits::__first_or_null(__src));
+        if (__source_is_absolute(_Traits::__first_or_null(__src)))
+          __pn_.clear();
+        else if (has_filename())
+          __pn_ += preferred_separator;
         _CVT::__append_source(__pn_, __src);
         return *this;
     }
@@ -838,10 +850,11 @@
         typedef typename iterator_traits<_InputIt>::value_type _ItVal;
         static_assert(__can_convert_char<_ItVal>::value, "Must convertible");
         using _CVT = _PathCVT<_ItVal>;
-        if (__first != __last) {
-            __append_sep_if_needed(*__first);
-            _CVT::__append_range(__pn_, __first, __last);
-        }
+        if (__first != __last && __source_is_absolute(*__first))
+          __pn_.clear();
+        else if (has_filename())
+          __pn_ += preferred_separator;
+        _CVT::__append_range(__pn_, __first, __last);
         return *this;
     }
 
@@ -916,10 +929,9 @@
 
     _LIBCPP_INLINE_VISIBILITY
     path& remove_filename() {
-      if (__pn_.size() == __root_path_raw().size())
-        clear();
-      else
-        __pn_ = __parent_path();
+      auto __fname = __filename();
+      if (!__fname.empty())
+        __pn_.erase(__fname.data() - __pn_.data());
       return *this;
     }
 
@@ -935,6 +947,10 @@
         __pn_.swap(__rhs.__pn_);
     }
 
+    // private helper to allow reserving memory in the path
+    _LIBCPP_INLINE_VISIBILITY
+    void __reserve(size_t __s) { __pn_.reserve(__s); }
+
     // native format observers
     _LIBCPP_INLINE_VISIBILITY
     const string_type& native() const _NOEXCEPT {
@@ -1023,6 +1039,17 @@
     _LIBCPP_INLINE_VISIBILITY bool is_absolute()        const { return has_root_directory(); }
     _LIBCPP_INLINE_VISIBILITY bool is_relative()        const { return !is_absolute(); }
 
+    // relative paths
+    path lexically_normal() const;
+    path lexically_relative(const path& __base) const;
+
+    _LIBCPP_INLINE_VISIBILITY path lexically_proximate(const path& __base) const {
+      path __result = this->lexically_relative(__base);
+      if (__result.native().empty())
+        return *this;
+      return __result;
+    }
+
     // iterators
     class _LIBCPP_TYPE_VIS iterator;
     typedef iterator const_iterator;
@@ -1277,7 +1304,9 @@
 // operational functions
 
 _LIBCPP_FUNC_VIS
-path __canonical(const path&, const path&, error_code *__ec=nullptr);
+path __absolute(const path&, error_code *__ec=nullptr);
+_LIBCPP_FUNC_VIS
+path __canonical(const path&, error_code *__ec=nullptr);
 _LIBCPP_FUNC_VIS
 void __copy(const path& __from, const path& __to, copy_options __opt,
         error_code *__ec=nullptr);
@@ -1342,6 +1371,8 @@
 path __system_complete(const path&, error_code *__ec=nullptr);
 _LIBCPP_FUNC_VIS
 path __temp_directory_path(error_code *__ec=nullptr);
+_LIBCPP_FUNC_VIS
+path __weakly_canonical(path const& __p, error_code *__ec=nullptr);
 
 inline _LIBCPP_INLINE_VISIBILITY
 path current_path() {
@@ -1363,24 +1394,24 @@
     __current_path(__p, &__ec);
 }
 
-_LIBCPP_FUNC_VIS
-path absolute(const path&, const path& __p2 = current_path());
+inline _LIBCPP_INLINE_VISIBILITY
+path absolute(const path& __p) {
+  return __absolute(__p);
+}
 
 inline _LIBCPP_INLINE_VISIBILITY
-path canonical(const path& __p, const path& __base = current_path()) {
-    return __canonical(__p, __base);
+path absolute(const path& __p, error_code &__ec) {
+  return __absolute(__p, &__ec);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY
+path canonical(const path& __p) {
+    return __canonical(__p);
 }
 
 inline _LIBCPP_INLINE_VISIBILITY
 path canonical(const path& __p, error_code& __ec) {
-    path __base = __current_path(&__ec);
-    if (__ec) return {};
-    return __canonical(__p, __base, &__ec);
-}
-
-inline _LIBCPP_INLINE_VISIBILITY
-path canonical(const path& __p, const path& __base, error_code& __ec) {
-    return __canonical(__p, __base, &__ec);
+    return __canonical(__p, &__ec);
 }
 
 inline _LIBCPP_INLINE_VISIBILITY
@@ -1492,7 +1523,8 @@
 }
 
 inline _LIBCPP_INLINE_VISIBILITY
-void create_symlink(const path& __to, const path& __new, error_code& __ec) _NOEXCEPT {
+void create_symlink(const path& __to, const path& __new,
+                    error_code& __ec) _NOEXCEPT {
     return __create_symlink(__to, __new, &__ec);
 }
 
@@ -1716,6 +1748,27 @@
 }
 
 inline _LIBCPP_INLINE_VISIBILITY
+path proximate(const path& __p, const path& __base, error_code& __ec) {
+   path __tmp = __weakly_canonical(__p, &__ec);
+  if (__ec)
+    return {};
+  path __tmp_base = __weakly_canonical(__base, &__ec);
+  if (__ec)
+    return {};
+  return __tmp.lexically_proximate(__tmp_base);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY
+path proximate(const path& __p, error_code& __ec) {
+  return proximate(__p, current_path(), __ec);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY
+path proximate(const path& __p, const path& __base = current_path()) {
+  return __weakly_canonical(__p).lexically_proximate(__weakly_canonical(__base));
+}
+
+inline _LIBCPP_INLINE_VISIBILITY
 path read_symlink(const path& __p) {
     return __read_symlink(__p);
 }
@@ -1725,6 +1778,29 @@
     return __read_symlink(__p, &__ec);
 }
 
+
+inline _LIBCPP_INLINE_VISIBILITY
+path relative(const path& __p, const path& __base, error_code& __ec) {
+  path __tmp = __weakly_canonical(__p, &__ec);
+  if (__ec)
+    return path();
+  path __tmpbase = __weakly_canonical(__base, &__ec);
+  if (__ec)
+    return path();
+  return __tmp.lexically_relative(__tmpbase);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY
+path relative(const path& __p, error_code& __ec) {
+  return relative(__p, current_path(), __ec);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY
+path relative(const path& __p, const path& __base=current_path()) {
+  return __weakly_canonical(__p).lexically_relative(__weakly_canonical(__base));
+}
+
+
 inline _LIBCPP_INLINE_VISIBILITY
 bool remove(const path& __p) {
     return __remove(__p);
@@ -1796,16 +1872,6 @@
 }
 
 inline _LIBCPP_INLINE_VISIBILITY
-path system_complete(const path& __p) {
-    return __system_complete(__p);
-}
-
-inline _LIBCPP_INLINE_VISIBILITY
-path system_complete(const path& __p, error_code& __ec) {
-    return __system_complete(__p, &__ec);
-}
-
-inline _LIBCPP_INLINE_VISIBILITY
 path temp_directory_path() {
     return __temp_directory_path();
 }
@@ -1815,6 +1881,16 @@
     return __temp_directory_path(&__ec);
 }
 
+inline _LIBCPP_INLINE_VISIBILITY
+path weakly_canonical(path const& __p) {
+  return __weakly_canonical(__p);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY
+path weakly_canonical(path const& __p, error_code& __ec) {
+  return __weakly_canonical(__p, &__ec);
+}
+
 
 class directory_entry
 {