[libcxx] r329028 - Implement filesystem NB comments, relative paths, and related issues.

Mike Edwards via cfe-commits cfe-commits at lists.llvm.org
Mon Apr 2 21:10:48 PDT 2018


Thank you very much!  Have a nice evening.

On Mon, Apr 2, 2018 at 7:48 PM, Eric Fiselier <eric at efcs.ca> wrote:

> Hi Mike,
>
> It should be fixed at this point.
>
> /Eric
>
> On Mon, Apr 2, 2018 at 6:05 PM, Mike Edwards <mike at sqlby.me> wrote:
>
>> Hi Eric,
>> Looks like this commit caused a test failure on Green Dragon in
>> libc++.std/experimental/filesystem/fs_op_funcs/fs_op_proximate.proximate.pass.cpp.
>> The test result from the build may be found here:
>> http://green.lab.llvm.org/green/job/libcxx_master_cmake_32/
>> 2643/testReport/junit/libc++/std_experimental_filesystem_fs
>> _op_funcs_fs_op_proximate/proximate_pass_cpp/
>>
>> Would you please have a look and either revert the commit or let me know
>> if a patch will be committed within the next hour?
>>
>> Respectfully,
>> Mike Edwards
>>
>> On Mon, Apr 2, 2018 at 4:03 PM, Eric Fiselier via cfe-commits <
>> cfe-commits at lists.llvm.org> wrote:
>>
>>> Author: ericwf
>>> Date: Mon Apr  2 16:03:41 2018
>>> New Revision: 329028
>>>
>>> URL: http://llvm.org/viewvc/llvm-project?rev=329028&view=rev
>>> Log:
>>> 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.
>>>
>>> Added:
>>>     libcxx/trunk/test/std/experimental/filesystem/class.path/pat
>>> h.member/path.gen/
>>>     libcxx/trunk/test/std/experimental/filesystem/class.path/pat
>>> h.member/path.gen/lexically_normal.pass.cpp
>>>     libcxx/trunk/test/std/experimental/filesystem/class.path/pat
>>> h.member/path.gen/lexically_relative_and_proximate.pass.cpp
>>>     libcxx/trunk/test/std/experimental/filesystem/fs.enum/enum.p
>>> erm_options.pass.cpp
>>>     libcxx/trunk/test/std/experimental/filesystem/fs.op.funcs/fs
>>> .op.proximate/
>>>     libcxx/trunk/test/std/experimental/filesystem/fs.op.funcs/fs
>>> .op.proximate/proximate.pass.cpp
>>>     libcxx/trunk/test/std/experimental/filesystem/fs.op.funcs/fs
>>> .op.relative/
>>>     libcxx/trunk/test/std/experimental/filesystem/fs.op.funcs/fs
>>> .op.relative/relative.pass.cpp
>>>     libcxx/trunk/test/std/experimental/filesystem/fs.op.funcs/fs
>>> .op.weakly_canonical/
>>>     libcxx/trunk/test/std/experimental/filesystem/fs.op.funcs/fs
>>> .op.weakly_canonical/weakly_canonical.pass.cpp
>>>     libcxx/trunk/test/support/verbose_assert.h
>>> Removed:
>>>     libcxx/trunk/src/experimental/filesystem/path.cpp
>>>     libcxx/trunk/test/libcxx/experimental/filesystem/class.path/
>>> path.member/path.append.pass.cpp
>>>     libcxx/trunk/test/std/experimental/filesystem/fs.op.funcs/fs
>>> .op.system_complete/system_complete.pass.cpp
>>> Modified:
>>>     libcxx/trunk/benchmarks/CMakeLists.txt
>>>     libcxx/trunk/benchmarks/GenerateInput.hpp
>>>     libcxx/trunk/benchmarks/filesystem.bench.cpp
>>>     libcxx/trunk/include/experimental/filesystem
>>>     libcxx/trunk/src/experimental/filesystem/operations.cpp
>>>     libcxx/trunk/test/std/experimental/filesystem/class.path/pat
>>> h.itr/iterator.pass.cpp
>>>     libcxx/trunk/test/std/experimental/filesystem/class.path/pat
>>> h.member/path.append.pass.cpp
>>>     libcxx/trunk/test/std/experimental/filesystem/class.path/pat
>>> h.member/path.compare.pass.cpp
>>>     libcxx/trunk/test/std/experimental/filesystem/class.path/pat
>>> h.member/path.decompose/empty.fail.cpp
>>>     libcxx/trunk/test/std/experimental/filesystem/class.path/pat
>>> h.member/path.decompose/path.decompose.pass.cpp
>>>     libcxx/trunk/test/std/experimental/filesystem/class.path/pat
>>> h.member/path.generic.obs/generic_string_alloc.pass.cpp
>>>     libcxx/trunk/test/std/experimental/filesystem/class.path/pat
>>> h.member/path.generic.obs/named_overloads.pass.cpp
>>>     libcxx/trunk/test/std/experimental/filesystem/class.path/pat
>>> h.member/path.modifiers/remove_filename.pass.cpp
>>>     libcxx/trunk/test/std/experimental/filesystem/class.path/pat
>>> h.member/path.modifiers/replace_filename.pass.cpp
>>>     libcxx/trunk/test/std/experimental/filesystem/fs.op.funcs/fs
>>> .op.absolute/absolute.pass.cpp
>>>     libcxx/trunk/test/std/experimental/filesystem/fs.op.funcs/fs
>>> .op.canonical/canonical.pass.cpp
>>>     libcxx/trunk/test/std/experimental/filesystem/fs.op.funcs/fs
>>> .op.last_write_time/last_write_time.pass.cpp
>>>     libcxx/trunk/test/support/filesystem_test_helper.hpp
>>>     libcxx/trunk/www/cxx1z_status.html
>>>     libcxx/trunk/www/cxx2a_status.html
>>>
>>> Modified: libcxx/trunk/benchmarks/CMakeLists.txt
>>> URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/benchmarks/
>>> CMakeLists.txt?rev=329028&r1=329027&r2=329028&view=diff
>>> ============================================================
>>> ==================
>>> --- libcxx/trunk/benchmarks/CMakeLists.txt (original)
>>> +++ libcxx/trunk/benchmarks/CMakeLists.txt Mon Apr  2 16:03:41 2018
>>> @@ -68,7 +68,7 @@ set(BENCHMARK_OUTPUT_DIR ${CMAKE_CURRENT
>>>  set(BENCHMARK_LIBCXX_INSTALL ${CMAKE_CURRENT_BINARY_DIR}/be
>>> nchmark-libcxx)
>>>  set(BENCHMARK_NATIVE_INSTALL ${CMAKE_CURRENT_BINARY_DIR}/be
>>> nchmark-native)
>>>  set(BENCHMARK_TEST_COMPILE_FLAGS
>>> -    -std=c++14 -O2
>>> +    -std=c++17 -O2
>>>      -I${BENCHMARK_LIBCXX_INSTALL}/include
>>>      -I${LIBCXX_SOURCE_DIR}/test/support
>>>  )
>>>
>>> Modified: libcxx/trunk/benchmarks/GenerateInput.hpp
>>> URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/benchmarks/
>>> GenerateInput.hpp?rev=329028&r1=329027&r2=329028&view=diff
>>> ============================================================
>>> ==================
>>> --- libcxx/trunk/benchmarks/GenerateInput.hpp (original)
>>> +++ libcxx/trunk/benchmarks/GenerateInput.hpp Mon Apr  2 16:03:41 2018
>>> @@ -29,14 +29,16 @@ inline std::default_random_engine& getRa
>>>      return RandEngine;
>>>  }
>>>
>>> +
>>>  inline char getRandomChar() {
>>>      std::uniform_int_distribution<> LettersDist(0, LettersSize-1);
>>>      return Letters[LettersDist(getRandomEngine())];
>>>  }
>>>
>>>  template <class IntT>
>>> -inline IntT getRandomInteger() {
>>> -    std::uniform_int_distribution<IntT> dist;
>>> +inline IntT getRandomInteger(IntT Min = 0,
>>> +                             IntT Max = std::numeric_limits<IntT>::max())
>>> {
>>> +    std::uniform_int_distribution<IntT> dist(Min, Max);
>>>      return dist(getRandomEngine());
>>>  }
>>>
>>>
>>> Modified: libcxx/trunk/benchmarks/filesystem.bench.cpp
>>> URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/benchmarks/
>>> filesystem.bench.cpp?rev=329028&r1=329027&r2=329028&view=diff
>>> ============================================================
>>> ==================
>>> --- libcxx/trunk/benchmarks/filesystem.bench.cpp (original)
>>> +++ libcxx/trunk/benchmarks/filesystem.bench.cpp Mon Apr  2 16:03:41
>>> 2018
>>> @@ -1,17 +1,14 @@
>>> -#include <experimental/filesystem>
>>> -
>>>  #include "benchmark/benchmark.h"
>>>  #include "GenerateInput.hpp"
>>>  #include "test_iterators.h"
>>> -
>>> -namespace fs = std::experimental::filesystem;
>>> +#include "filesystem_include.hpp"
>>>
>>>  static const size_t TestNumInputs = 1024;
>>>
>>>
>>>  template <class GenInputs>
>>>  void BM_PathConstructString(benchmark::State &st, GenInputs gen) {
>>> -  using namespace fs;
>>> +  using fs::path;
>>>    const auto in = gen(st.range(0));
>>>    path PP;
>>>    for (auto& Part : in)
>>> @@ -21,14 +18,15 @@ void BM_PathConstructString(benchmark::S
>>>      const path P(PP.native());
>>>      benchmark::DoNotOptimize(P.native().data());
>>>    }
>>> +  st.SetComplexityN(st.range(0));
>>>  }
>>>  BENCHMARK_CAPTURE(BM_PathConstructString, large_string,
>>> -  getRandomStringInputs)->Arg(TestNumInputs);
>>> +  getRandomStringInputs)->Range(8, TestNumInputs)->Complexity();
>>>
>>>
>>>  template <class GenInputs>
>>>  void BM_PathConstructCStr(benchmark::State &st, GenInputs gen) {
>>> -  using namespace fs;
>>> +  using fs::path;
>>>    const auto in = gen(st.range(0));
>>>    path PP;
>>>    for (auto& Part : in)
>>> @@ -45,7 +43,7 @@ BENCHMARK_CAPTURE(BM_PathConstructCStr,
>>>
>>>  template <template <class...> class ItType, class GenInputs>
>>>  void BM_PathConstructIter(benchmark::State &st, GenInputs gen) {
>>> -  using namespace fs;
>>> +  using fs::path;
>>>    using Iter = ItType<std::string::const_iterator>;
>>>    const auto in = gen(st.range(0));
>>>    path PP;
>>> @@ -60,6 +58,7 @@ void BM_PathConstructIter(benchmark::Sta
>>>      const path P(Start, End);
>>>      benchmark::DoNotOptimize(P.native().data());
>>>    }
>>> +  st.SetComplexityN(st.range(0));
>>>  }
>>>  template <class GenInputs>
>>>  void BM_PathConstructInputIter(benchmark::State &st, GenInputs gen) {
>>> @@ -70,14 +69,14 @@ void BM_PathConstructForwardIter(benchma
>>>    BM_PathConstructIter<forward_iterator>(st, gen);
>>>  }
>>>  BENCHMARK_CAPTURE(BM_PathConstructInputIter, large_string,
>>> -  getRandomStringInputs)->Arg(TestNumInputs);
>>> +  getRandomStringInputs)->Range(8, TestNumInputs)->Complexity();
>>>  BENCHMARK_CAPTURE(BM_PathConstructForwardIter, large_string,
>>> -  getRandomStringInputs)->Arg(TestNumInputs);
>>> +  getRandomStringInputs)->Range(8, TestNumInputs)->Complexity();
>>>
>>>
>>>  template <class GenInputs>
>>>  void BM_PathIterateMultipleTimes(benchmark::State &st, GenInputs gen) {
>>> -  using namespace fs;
>>> +  using fs::path;
>>>    const auto in = gen(st.range(0));
>>>    path PP;
>>>    for (auto& Part : in)
>>> @@ -89,14 +88,15 @@ void BM_PathIterateMultipleTimes(benchma
>>>      }
>>>      benchmark::ClobberMemory();
>>>    }
>>> +  st.SetComplexityN(st.range(0));
>>>  }
>>>  BENCHMARK_CAPTURE(BM_PathIterateMultipleTimes, iterate_elements,
>>> -  getRandomStringInputs)->Arg(TestNumInputs);
>>> +  getRandomStringInputs)->Range(8, TestNumInputs)->Complexity();
>>>
>>>
>>>  template <class GenInputs>
>>>  void BM_PathIterateOnce(benchmark::State &st, GenInputs gen) {
>>> -  using namespace fs;
>>> +  using fs::path;
>>>    const auto in = gen(st.range(0));
>>>    path PP;
>>>    for (auto& Part : in)
>>> @@ -109,13 +109,14 @@ void BM_PathIterateOnce(benchmark::State
>>>      }
>>>      benchmark::ClobberMemory();
>>>    }
>>> +  st.SetComplexityN(st.range(0));
>>>  }
>>>  BENCHMARK_CAPTURE(BM_PathIterateOnce, iterate_elements,
>>> -  getRandomStringInputs)->Arg(TestNumInputs);
>>> +  getRandomStringInputs)->Range(8, TestNumInputs)->Complexity();
>>>
>>>  template <class GenInputs>
>>>  void BM_PathIterateOnceBackwards(benchmark::State &st, GenInputs gen) {
>>> -  using namespace fs;
>>> +  using fs::path;
>>>    const auto in = gen(st.range(0));
>>>    path PP;
>>>    for (auto& Part : in)
>>> @@ -135,4 +136,28 @@ void BM_PathIterateOnceBackwards(benchma
>>>  BENCHMARK_CAPTURE(BM_PathIterateOnceBackwards, iterate_elements,
>>>    getRandomStringInputs)->Arg(TestNumInputs);
>>>
>>> +static fs::path getRandomPaths(int NumParts, int PathLen) {
>>> +  fs::path Result;
>>> +  while (NumParts--) {
>>> +    std::string Part = getRandomString(PathLen);
>>> +    Result /= Part;
>>> +  }
>>> +  return Result;
>>> +}
>>> +
>>> +template <class GenInput>
>>> +void BM_LexicallyNormal(benchmark::State &st, GenInput gen, size_t
>>> PathLen) {
>>> +  using fs::path;
>>> +  auto In = gen(st.range(0), PathLen);
>>> +  benchmark::DoNotOptimize(&In);
>>> +  while (st.KeepRunning()) {
>>> +    benchmark::DoNotOptimize(In.lexically_normal());
>>> +  }
>>> +  st.SetComplexityN(st.range(0));
>>> +}
>>> +BENCHMARK_CAPTURE(BM_LexicallyNormal, small_path,
>>> +  getRandomPaths, /*PathLen*/5)->RangeMultiplier(2)->Range(2,
>>> 256)->Complexity();
>>> +BENCHMARK_CAPTURE(BM_LexicallyNormal, large_path,
>>> +  getRandomPaths, /*PathLen*/32)->RangeMultiplier(2)->Range(2,
>>> 256)->Complexity();
>>> +
>>>  BENCHMARK_MAIN();
>>>
>>> Modified: libcxx/trunk/include/experimental/filesystem
>>> URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/exp
>>> erimental/filesystem?rev=329028&r1=329027&r2=329028&view=diff
>>> ============================================================
>>> ==================
>>> --- libcxx/trunk/include/experimental/filesystem (original)
>>> +++ libcxx/trunk/include/experimental/filesystem Mon Apr  2 16:03:41
>>> 2018
>>> @@ -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 @@ public:
>>>
>>>  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 @@ public:
>>>      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 @@ public:
>>>          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 @@ public:
>>>
>>>      _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 @@ public:
>>>          __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 @@ public:
>>>      _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 @@ void __throw_filesystem_error(_Args&&...
>>>  // 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 @@ _LIBCPP_FUNC_VIS
>>>  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 @@ void current_path(const path& __p, error
>>>      __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, error_code& __ec) {
>>> -    path __base = __current_path(&__ec);
>>> -    if (__ec) return {};
>>> -    return __canonical(__p, __base, &__ec);
>>> +path canonical(const path& __p) {
>>> +    return __canonical(__p);
>>>  }
>>>
>>>  inline _LIBCPP_INLINE_VISIBILITY
>>> -path canonical(const path& __p, const path& __base, error_code& __ec) {
>>> -    return __canonical(__p, __base, &__ec);
>>> +path canonical(const path& __p, error_code& __ec) {
>>> +    return __canonical(__p, &__ec);
>>>  }
>>>
>>>  inline _LIBCPP_INLINE_VISIBILITY
>>> @@ -1492,7 +1523,8 @@ void create_symlink(const path& __to, co
>>>  }
>>>
>>>  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 @@ void permissions(const path& __p, perms
>>>  }
>>>
>>>  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_canonic
>>> al(__base));
>>> +}
>>> +
>>> +inline _LIBCPP_INLINE_VISIBILITY
>>>  path read_symlink(const path& __p) {
>>>      return __read_symlink(__p);
>>>  }
>>> @@ -1725,6 +1778,29 @@ path read_symlink(const path& __p, error
>>>      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_canonica
>>> l(__base));
>>> +}
>>> +
>>> +
>>>  inline _LIBCPP_INLINE_VISIBILITY
>>>  bool remove(const path& __p) {
>>>      return __remove(__p);
>>> @@ -1796,23 +1872,23 @@ file_status symlink_status(const path& _
>>>  }
>>>
>>>  inline _LIBCPP_INLINE_VISIBILITY
>>> -path system_complete(const path& __p) {
>>> -    return __system_complete(__p);
>>> +path temp_directory_path() {
>>> +    return __temp_directory_path();
>>>  }
>>>
>>>  inline _LIBCPP_INLINE_VISIBILITY
>>> -path system_complete(const path& __p, error_code& __ec) {
>>> -    return __system_complete(__p, &__ec);
>>> +path temp_directory_path(error_code& __ec) {
>>> +    return __temp_directory_path(&__ec);
>>>  }
>>>
>>>  inline _LIBCPP_INLINE_VISIBILITY
>>> -path temp_directory_path() {
>>> -    return __temp_directory_path();
>>> +path weakly_canonical(path const& __p) {
>>> +  return __weakly_canonical(__p);
>>>  }
>>>
>>>  inline _LIBCPP_INLINE_VISIBILITY
>>> -path temp_directory_path(error_code& __ec) {
>>> -    return __temp_directory_path(&__ec);
>>> +path weakly_canonical(path const& __p, error_code& __ec) {
>>> +  return __weakly_canonical(__p, &__ec);
>>>  }
>>>
>>>
>>>
>>> Modified: libcxx/trunk/src/experimental/filesystem/operations.cpp
>>> URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/src/experim
>>> ental/filesystem/operations.cpp?rev=329028&r1=329027&r2=329028&view=diff
>>> ============================================================
>>> ==================
>>> --- libcxx/trunk/src/experimental/filesystem/operations.cpp (original)
>>> +++ libcxx/trunk/src/experimental/filesystem/operations.cpp Mon Apr  2
>>> 16:03:41 2018
>>> @@ -10,8 +10,10 @@
>>>  #include "experimental/filesystem"
>>>  #include "iterator"
>>>  #include "fstream"
>>> -#include "type_traits"
>>>  #include "random"  /* for unique_path */
>>> +#include "string_view"
>>> +#include "type_traits"
>>> +#include "vector"
>>>  #include "cstdlib"
>>>  #include "climits"
>>>
>>> @@ -57,6 +59,250 @@ _LIBCPP_BEGIN_NAMESPACE_EXPERIMENTAL_FIL
>>>  filesystem_error::~filesystem_error() {}
>>>
>>>
>>> +namespace { namespace parser
>>> +{
>>> +
>>> +using string_view_t = path::__string_view;
>>> +using string_view_pair = pair<string_view_t, string_view_t>;
>>> +using PosPtr = path::value_type const*;
>>> +
>>> +struct PathParser {
>>> +  enum ParserState : unsigned char {
>>> +    // Zero is a special sentinel value used by default constructed
>>> iterators.
>>> +    PS_BeforeBegin = 1,
>>> +    PS_InRootName,
>>> +    PS_InRootDir,
>>> +    PS_InFilenames,
>>> +    PS_InTrailingSep,
>>> +    PS_AtEnd
>>> +  };
>>> +
>>> +  const string_view_t Path;
>>> +  string_view_t RawEntry;
>>> +  ParserState State;
>>> +
>>> +private:
>>> +  PathParser(string_view_t P, ParserState State) noexcept
>>> +      : Path(P), State(State) {}
>>> +
>>> +public:
>>> +  PathParser(string_view_t P, string_view_t E, unsigned char S)
>>> +      : Path(P), RawEntry(E), State(static_cast<ParserState>(S)) {
>>> +    // S cannot be '0' or PS_BeforeBegin.
>>> +  }
>>> +
>>> +  static PathParser CreateBegin(string_view_t P) noexcept {
>>> +    PathParser PP(P, PS_BeforeBegin);
>>> +    PP.increment();
>>> +    return PP;
>>> +  }
>>> +
>>> +  static PathParser CreateEnd(string_view_t P) noexcept {
>>> +    PathParser PP(P, PS_AtEnd);
>>> +    return PP;
>>> +  }
>>> +
>>> +  PosPtr peek() const noexcept {
>>> +    auto TkEnd = getNextTokenStartPos();
>>> +    auto End = getAfterBack();
>>> +    return TkEnd == End ? nullptr : TkEnd;
>>> +  }
>>> +
>>> +  void increment() noexcept {
>>> +    const PosPtr End = getAfterBack();
>>> +    const PosPtr Start = getNextTokenStartPos();
>>> +    if (Start == End)
>>> +      return makeState(PS_AtEnd);
>>> +
>>> +    switch (State) {
>>> +    case PS_BeforeBegin: {
>>> +      PosPtr TkEnd = consumeSeparator(Start, End);
>>> +      if (TkEnd)
>>> +        return makeState(PS_InRootDir, Start, TkEnd);
>>> +      else
>>> +        return makeState(PS_InFilenames, Start, consumeName(Start,
>>> End));
>>> +    }
>>> +    case PS_InRootDir:
>>> +      return makeState(PS_InFilenames, Start, consumeName(Start, End));
>>> +
>>> +    case PS_InFilenames: {
>>> +      PosPtr SepEnd = consumeSeparator(Start, End);
>>> +      if (SepEnd != End) {
>>> +        PosPtr TkEnd = consumeName(SepEnd, End);
>>> +        if (TkEnd)
>>> +          return makeState(PS_InFilenames, SepEnd, TkEnd);
>>> +      }
>>> +      return makeState(PS_InTrailingSep, Start, SepEnd);
>>> +    }
>>> +
>>> +    case PS_InTrailingSep:
>>> +      return makeState(PS_AtEnd);
>>> +
>>> +    case PS_InRootName:
>>> +    case PS_AtEnd:
>>> +      _LIBCPP_UNREACHABLE();
>>> +    }
>>> +  }
>>> +
>>> +  void decrement() noexcept {
>>> +    const PosPtr REnd = getBeforeFront();
>>> +    const PosPtr RStart = getCurrentTokenStartPos() - 1;
>>> +    if (RStart == REnd) // we're decrementing the begin
>>> +      return makeState(PS_BeforeBegin);
>>> +
>>> +    switch (State) {
>>> +    case PS_AtEnd: {
>>> +      // Try to consume a trailing separator or root directory first.
>>> +      if (PosPtr SepEnd = consumeSeparator(RStart, REnd)) {
>>> +        if (SepEnd == REnd)
>>> +          return makeState(PS_InRootDir, Path.data(), RStart + 1);
>>> +        return makeState(PS_InTrailingSep, SepEnd + 1, RStart + 1);
>>> +      } else {
>>> +        PosPtr TkStart = consumeName(RStart, REnd);
>>> +        return makeState(PS_InFilenames, TkStart + 1, RStart + 1);
>>> +      }
>>> +    }
>>> +    case PS_InTrailingSep:
>>> +      return makeState(PS_InFilenames, consumeName(RStart, REnd) + 1,
>>> RStart + 1);
>>> +    case PS_InFilenames: {
>>> +      PosPtr SepEnd = consumeSeparator(RStart, REnd);
>>> +      if (SepEnd == REnd)
>>> +        return makeState(PS_InRootDir, Path.data(), RStart + 1);
>>> +      PosPtr TkEnd = consumeName(SepEnd, REnd);
>>> +      return makeState(PS_InFilenames, TkEnd + 1, SepEnd + 1);
>>> +    }
>>> +    case PS_InRootDir:
>>> +      // return makeState(PS_InRootName, Path.data(), RStart + 1);
>>> +    case PS_InRootName:
>>> +    case PS_BeforeBegin:
>>> +      _LIBCPP_UNREACHABLE();
>>> +    }
>>> +  }
>>> +
>>> +  /// \brief Return a view with the "preferred representation" of the
>>> current
>>> +  ///   element. For example trailing separators are represented as a
>>> '.'
>>> +  string_view_t operator*() const noexcept {
>>> +    switch (State) {
>>> +    case PS_BeforeBegin:
>>> +    case PS_AtEnd:
>>> +      return "";
>>> +    case PS_InRootDir:
>>> +      return "/";
>>> +    case PS_InTrailingSep:
>>> +      return "";
>>> +    case PS_InRootName:
>>> +    case PS_InFilenames:
>>> +      return RawEntry;
>>> +    }
>>> +    _LIBCPP_UNREACHABLE();
>>> +  }
>>> +
>>> +  explicit operator bool() const noexcept {
>>> +    return State != PS_BeforeBegin && State != PS_AtEnd;
>>> +  }
>>> +
>>> +  PathParser& operator++() noexcept {
>>> +    increment();
>>> +    return *this;
>>> +  }
>>> +
>>> +  PathParser& operator--() noexcept {
>>> +    decrement();
>>> +    return *this;
>>> +  }
>>> +
>>> +  bool inRootPath() const noexcept {
>>> +    return State == PS_InRootDir || State == PS_InRootName;
>>> +  }
>>> +
>>> +private:
>>> +  void makeState(ParserState NewState, PosPtr Start, PosPtr End)
>>> noexcept {
>>> +    State = NewState;
>>> +    RawEntry = string_view_t(Start, End - Start);
>>> +  }
>>> +  void makeState(ParserState NewState) noexcept {
>>> +    State = NewState;
>>> +    RawEntry = {};
>>> +  }
>>> +
>>> +  PosPtr getAfterBack() const noexcept {
>>> +    return Path.data() + Path.size();
>>> +  }
>>> +
>>> +  PosPtr getBeforeFront() const noexcept {
>>> +    return Path.data() - 1;
>>> +  }
>>> +
>>> +  /// \brief Return a pointer to the first character after the currently
>>> +  ///   lexed element.
>>> +  PosPtr getNextTokenStartPos() const noexcept {
>>> +    switch (State) {
>>> +    case PS_BeforeBegin:
>>> +      return Path.data();
>>> +    case PS_InRootName:
>>> +    case PS_InRootDir:
>>> +    case PS_InFilenames:
>>> +      return &RawEntry.back() + 1;
>>> +    case PS_InTrailingSep:
>>> +    case PS_AtEnd:
>>> +      return getAfterBack();
>>> +    }
>>> +    _LIBCPP_UNREACHABLE();
>>> +  }
>>> +
>>> +  /// \brief Return a pointer to the first character in the currently
>>> lexed
>>> +  ///   element.
>>> +  PosPtr getCurrentTokenStartPos() const noexcept {
>>> +    switch (State) {
>>> +    case PS_BeforeBegin:
>>> +    case PS_InRootName:
>>> +      return &Path.front();
>>> +    case PS_InRootDir:
>>> +    case PS_InFilenames:
>>> +    case PS_InTrailingSep:
>>> +      return &RawEntry.front();
>>> +    case PS_AtEnd:
>>> +      return &Path.back() + 1;
>>> +    }
>>> +    _LIBCPP_UNREACHABLE();
>>> +  }
>>> +
>>> +  PosPtr consumeSeparator(PosPtr P, PosPtr End) const noexcept {
>>> +    if (P == End || *P != '/')
>>> +      return nullptr;
>>> +    const int Inc = P < End ? 1 : -1;
>>> +    P += Inc;
>>> +    while (P != End && *P == '/')
>>> +      P += Inc;
>>> +    return P;
>>> +  }
>>> +
>>> +  PosPtr consumeName(PosPtr P, PosPtr End) const noexcept {
>>> +    if (P == End || *P == '/')
>>> +      return nullptr;
>>> +    const int Inc = P < End ? 1 : -1;
>>> +    P += Inc;
>>> +    while (P != End && *P != '/')
>>> +      P += Inc;
>>> +    return P;
>>> +  }
>>> +};
>>> +
>>> +string_view_pair separate_filename(string_view_t const & s) {
>>> +    if (s == "." || s == ".." || s.empty()) return string_view_pair{s,
>>> ""};
>>> +    auto pos = s.find_last_of('.');
>>> +    if (pos == string_view_t::npos || pos == 0)
>>> +        return string_view_pair{s, string_view_t{}};
>>> +    return string_view_pair{s.substr(0, pos), s.substr(pos)};
>>> +}
>>> +
>>> +string_view_t createView(PosPtr S, PosPtr E) noexcept {
>>> +  return {S, static_cast<size_t>(E - S) + 1};
>>> +}
>>> +
>>> +}} // namespace parser
>>> +
>>> +
>>>  //                       POSIX HELPERS
>>>
>>>  namespace detail { namespace  {
>>> @@ -186,14 +432,33 @@ bool copy_file_impl(const path& from, co
>>>  }} // end namespace detail
>>>
>>>  using detail::set_or_throw;
>>> +using parser::string_view_t;
>>> +using parser::PathParser;
>>> +using parser::createView;
>>> +
>>> +static path __do_absolute(const path& p, path *cwd, std::error_code
>>> *ec) {
>>> +  if (ec) ec->clear();
>>> +    if (p.is_absolute())
>>> +      return p;
>>> +    *cwd = __current_path(ec);
>>> +    if (ec && *ec)
>>> +      return {};
>>> +    return (*cwd) / p;
>>> +}
>>> +
>>> +path __absolute(const path& p, std::error_code *ec) {
>>> +    path cwd;
>>> +    return __do_absolute(p, &cwd, ec);
>>> +}
>>>
>>> -path __canonical(path const & orig_p, const path& base, std::error_code
>>> *ec)
>>> +path __canonical(path const & orig_p, std::error_code *ec)
>>>  {
>>> -    path p = absolute(orig_p, base);
>>> +    path cwd;
>>> +    path p = __do_absolute(orig_p, &cwd, ec);
>>>      char buff[PATH_MAX + 1];
>>>      char *ret;
>>>      if ((ret = ::realpath(p.c_str(), buff)) == nullptr) {
>>> -        set_or_throw(ec, "canonical", orig_p, base);
>>> +        set_or_throw(ec, "canonical", orig_p, cwd);
>>>          return {};
>>>      }
>>>      if (ec) ec->clear();
>>> @@ -791,11 +1056,6 @@ file_status __symlink_status(const path&
>>>      return detail::posix_lstat(p, ec);
>>>  }
>>>
>>> -path __system_complete(const path& p, std::error_code *ec) {
>>> -    if (ec) ec->clear();
>>> -    return absolute(p, current_path());
>>> -}
>>> -
>>>  path __temp_directory_path(std::error_code* ec) {
>>>    const char* env_paths[] = {"TMPDIR", "TMP", "TEMP", "TEMPDIR"};
>>>    const char* ret = nullptr;
>>> @@ -820,34 +1080,393 @@ path __temp_directory_path(std::error_co
>>>    return p;
>>>  }
>>>
>>> -// An absolute path is composed according to the table in
>>> [fs.op.absolute].
>>> -path absolute(const path& p, const path& base) {
>>> -    auto root_name = p.root_name();
>>> -    auto root_dir = p.root_directory();
>>>
>>> -    if (!root_name.empty() && !root_dir.empty())
>>> -      return p;
>>> +path __weakly_canonical(const path& p, std::error_code *ec) {
>>> +  if (p.empty())
>>> +    return __canonical("", ec);
>>> +
>>> +  path result;
>>> +  path tmp;
>>> +  tmp.__reserve(p.native().size());
>>> +  auto PP = PathParser::CreateEnd(p.native());
>>> +  --PP;
>>> +  std::vector<string_view_t> DNEParts;
>>>
>>> -    auto abs_base = base.is_absolute() ? base : absolute(base);
>>> +  while (PP.State != PathParser::PS_BeforeBegin) {
>>> +    tmp.assign(createView(p.native().data(), &PP.RawEntry.back()));
>>> +    std::error_code m_ec;
>>> +    file_status st = __status(tmp, &m_ec);
>>> +    if (!status_known(st)) {
>>> +      set_or_throw(m_ec, ec, "weakly_canonical", p);
>>> +      return {};
>>> +    } else if (exists(st)) {
>>> +      result = __canonical(tmp, ec);
>>> +      break;
>>> +    }
>>> +    DNEParts.push_back(*PP);
>>> +    --PP;
>>> +  }
>>> +  if (PP.State == PathParser::PS_BeforeBegin)
>>> +    result = __canonical("", ec);
>>> +  if (ec) ec->clear();
>>> +  if (DNEParts.empty())
>>> +    return result;
>>> +  for (auto It=DNEParts.rbegin(); It != DNEParts.rend(); ++It)
>>> +    result /= *It;
>>> +  return result.lexically_normal();
>>> +}
>>> +
>>> +
>>> +
>>> +///////////////////////////////////////////////////////////
>>> ////////////////////
>>> +//                            path definitions
>>> +///////////////////////////////////////////////////////////
>>> ////////////////////
>>> +
>>> +constexpr path::value_type path::preferred_separator;
>>> +
>>> +path & path::replace_extension(path const & replacement)
>>> +{
>>> +    path p = extension();
>>> +    if (not p.empty()) {
>>> +      __pn_.erase(__pn_.size() - p.native().size());
>>> +    }
>>> +    if (!replacement.empty()) {
>>> +        if (replacement.native()[0] != '.') {
>>> +            __pn_ += ".";
>>> +        }
>>> +        __pn_.append(replacement.__pn_);
>>> +    }
>>> +    return *this;
>>> +}
>>> +
>>> +///////////////////////////////////////////////////////////
>>> ////////////////////
>>> +// path.decompose
>>> +
>>> +string_view_t path::__root_name() const
>>> +{
>>> +    auto PP = PathParser::CreateBegin(__pn_);
>>> +    if (PP.State == PathParser::PS_InRootName)
>>> +      return *PP;
>>> +    return {};
>>> +}
>>>
>>> -    /* !has_root_name && !has_root_dir */
>>> -    if (root_name.empty() && root_dir.empty())
>>> +string_view_t path::__root_directory() const
>>> +{
>>> +    auto PP = PathParser::CreateBegin(__pn_);
>>> +    if (PP.State == PathParser::PS_InRootName)
>>> +      ++PP;
>>> +    if (PP.State == PathParser::PS_InRootDir)
>>> +      return *PP;
>>> +    return {};
>>> +}
>>> +
>>> +string_view_t path::__root_path_raw() const
>>> +{
>>> +    auto PP = PathParser::CreateBegin(__pn_);
>>> +    if (PP.State == PathParser::PS_InRootName) {
>>> +      auto NextCh = PP.peek();
>>> +      if (NextCh && *NextCh == '/') {
>>> +        ++PP;
>>> +        return createView(__pn_.data(), &PP.RawEntry.back());
>>> +      }
>>> +      return PP.RawEntry;
>>> +    }
>>> +    if (PP.State == PathParser::PS_InRootDir)
>>> +      return *PP;
>>> +    return {};
>>> +}
>>> +
>>> +static bool ConsumeRootDir(PathParser* PP) {
>>> +  while (PP->State <= PathParser::PS_InRootDir)
>>> +    ++(*PP);
>>> +  return PP->State == PathParser::PS_AtEnd;
>>> +}
>>> +
>>> +string_view_t path::__relative_path() const
>>> +{
>>> +    auto PP = PathParser::CreateBegin(__pn_);
>>> +    if (ConsumeRootDir(&PP))
>>> +      return {};
>>> +    return createView(PP.RawEntry.data(), &__pn_.back());
>>> +}
>>> +
>>> +string_view_t path::__parent_path() const
>>> +{
>>> +    if (empty())
>>> +      return {};
>>> +    // Determine if we have a root path but not a relative path. In
>>> that case
>>> +    // return *this.
>>>      {
>>> -      return abs_base / p;
>>> +      auto PP = PathParser::CreateBegin(__pn_);
>>> +      if (ConsumeRootDir(&PP))
>>> +        return __pn_;
>>>      }
>>> -    else if (!root_name.empty()) /* has_root_name && !has_root_dir */
>>> +    // Otherwise remove a single element from the end of the path, and
>>> return
>>> +    // a string representing that path
>>>      {
>>> -      return  root_name / abs_base.root_directory()
>>> -              /
>>> -              abs_base.relative_path() / p.relative_path();
>>> +      auto PP = PathParser::CreateEnd(__pn_);
>>> +      --PP;
>>> +      if (PP.RawEntry.data() == __pn_.data())
>>> +        return {};
>>> +      --PP;
>>> +      return createView(__pn_.data(), &PP.RawEntry.back());
>>>      }
>>> -    else /* !has_root_name && has_root_dir */
>>> +}
>>> +
>>> +string_view_t path::__filename() const
>>> +{
>>> +    if (empty()) return {};
>>>      {
>>> -      if (abs_base.has_root_name())
>>> -        return abs_base.root_name() / p;
>>> -      // else p is absolute,  return outside of block
>>> +      PathParser PP = PathParser::CreateBegin(__pn_);
>>> +      if (ConsumeRootDir(&PP))
>>> +        return {};
>>>      }
>>> -    return p;
>>> +    return *(--PathParser::CreateEnd(__pn_));
>>>  }
>>>
>>> +string_view_t path::__stem() const
>>> +{
>>> +    return parser::separate_filename(__filename()).first;
>>> +}
>>> +
>>> +string_view_t path::__extension() const
>>> +{
>>> +    return parser::separate_filename(__filename()).second;
>>> +}
>>> +
>>> +///////////////////////////////////////////////////////////
>>> /////////////////
>>> +// path.gen
>>> +
>>> +
>>> +enum PathPartKind : unsigned char {
>>> +  PK_None,
>>> +  PK_RootSep,
>>> +  PK_Filename,
>>> +  PK_Dot,
>>> +  PK_DotDot,
>>> +  PK_TrailingSep
>>> +};
>>> +
>>> +static PathPartKind ClassifyPathPart(string_view_t Part) {
>>> +  if (Part.empty())
>>> +    return PK_TrailingSep;
>>> +  if (Part == ".")
>>> +    return PK_Dot;
>>> +  if (Part == "..")
>>> +    return PK_DotDot;
>>> +  if (Part == "/")
>>> +    return PK_RootSep;
>>> +  return PK_Filename;
>>> +}
>>> +
>>> +path path::lexically_normal() const {
>>> +  if (__pn_.empty())
>>> +    return *this;
>>> +
>>> +  using PartKindPair = std::pair<string_view_t, PathPartKind>;
>>> +  std::vector<PartKindPair> Parts;
>>> +  // Guess as to how many elements the path has to avoid reallocating.
>>> +  Parts.reserve(32);
>>> +
>>> +  // Track the total size of the parts as we collect them. This allows
>>> the
>>> +  // resulting path to reserve the correct amount of memory.
>>> +  size_t NewPathSize = 0;
>>> +  auto AddPart = [&](PathPartKind K, string_view_t P) {
>>> +    NewPathSize += P.size();
>>> +    Parts.emplace_back(P, K);
>>> +  };
>>> +  auto LastPartKind = [&]() {
>>> +    if (Parts.empty())
>>> +      return PK_None;
>>> +    return Parts.back().second;
>>> +  };
>>> +
>>> +  bool MaybeNeedTrailingSep = false;
>>> +  // Build a stack containing the remaining elements of the path,
>>> popping off
>>> +  // elements which occur before a '..' entry.
>>> +  for (auto PP = PathParser::CreateBegin(__pn_); PP; ++PP) {
>>> +    auto Part = *PP;
>>> +    PathPartKind Kind = ClassifyPathPart(Part);
>>> +    switch (Kind) {
>>> +    case PK_Filename:
>>> +    case PK_RootSep: {
>>> +      // Add all non-dot and non-dot-dot elements to the stack of
>>> elements.
>>> +      AddPart(Kind, Part);
>>> +      MaybeNeedTrailingSep = false;
>>> +      break;
>>> +    }
>>> +    case PK_DotDot: {
>>> +      // Only push a ".." element if there are no elements preceding
>>> the "..",
>>> +      // or if the preceding element is itself "..".
>>> +      auto LastKind = LastPartKind();
>>> +      if (LastKind == PK_Filename) {
>>> +        NewPathSize -= Parts.back().first.size();
>>> +        Parts.pop_back();
>>> +      } else if (LastKind != PK_RootSep)
>>> +        AddPart(PK_DotDot, "..");
>>> +      MaybeNeedTrailingSep = LastKind == PK_Filename;
>>> +      break;
>>> +    }
>>> +    case PK_Dot:
>>> +    case PK_TrailingSep: {
>>> +      MaybeNeedTrailingSep = true;
>>> +      break;
>>> +    }
>>> +    case PK_None:
>>> +      _LIBCPP_UNREACHABLE();
>>> +    }
>>> +  }
>>> +  // [fs.path.generic]p6.8: If the path is empty, add a dot.
>>> +  if (Parts.empty())
>>> +     return ".";
>>> +
>>> +  // [fs.path.generic]p6.7: If the last filename is dot-dot, remove any
>>> +  // trailing directory-separator.
>>> +  bool NeedTrailingSep = MaybeNeedTrailingSep && LastPartKind() ==
>>> PK_Filename;
>>> +
>>> +  path Result;
>>> +  Result.__pn_.reserve(Parts.size() + NewPathSize + NeedTrailingSep);
>>> +  for (auto &PK : Parts)
>>> +    Result /= PK.first;
>>> +
>>> +  if (NeedTrailingSep)
>>> +    Result /= "";
>>> +
>>> +  return Result;
>>> +}
>>> +
>>> +static int DetermineLexicalElementCount(PathParser PP) {
>>> +  int Count = 0;
>>> +  for (; PP; ++PP) {
>>> +    auto Elem = *PP;
>>> +    if (Elem == "..")
>>> +      --Count;
>>> +    else if (Elem != ".")
>>> +      ++Count;
>>> +  }
>>> +  return Count;
>>> +}
>>> +
>>> +path path::lexically_relative(const path& base) const {
>>> +  { // perform root-name/root-directory mismatch checks
>>> +    auto PP = PathParser::CreateBegin(__pn_);
>>> +    auto PPBase = PathParser::CreateBegin(base.__pn_);
>>> +    auto CheckIterMismatchAtBase = [&]() {
>>> +        return PP.State != PPBase.State && (
>>> +            PP.inRootPath() || PPBase.inRootPath());
>>> +    };
>>> +    if (PP.State == PathParser::PS_InRootName &&
>>> +        PPBase.State == PathParser::PS_InRootName) {
>>> +      if (*PP != *PPBase)
>>> +        return {};
>>> +    } else if (CheckIterMismatchAtBase())
>>> +      return {};
>>> +
>>> +    if (PP.inRootPath()) ++PP;
>>> +    if (PPBase.inRootPath()) ++PPBase;
>>> +    if (CheckIterMismatchAtBase())
>>> +      return {};
>>> +  }
>>> +
>>> +  // Find the first mismatching element
>>> +  auto PP = PathParser::CreateBegin(__pn_);
>>> +  auto PPBase = PathParser::CreateBegin(base.__pn_);
>>> +  while (PP && PPBase && PP.State == PPBase.State &&
>>> +         *PP == *PPBase) {
>>> +    ++PP;
>>> +    ++PPBase;
>>> +  }
>>> +
>>> +  // If there is no mismatch, return ".".
>>> +  if (!PP && !PPBase)
>>> +    return ".";
>>> +
>>> +  // Otherwise, determine the number of elements, 'n', which are not
>>> dot or
>>> +  // dot-dot minus the number of dot-dot elements.
>>> +  int ElemCount = DetermineLexicalElementCount(PPBase);
>>> +  if (ElemCount < 0)
>>> +    return {};
>>> +
>>> +  // return a path constructed with 'n' dot-dot elements, followed by
>>> the the
>>> +  // elements of '*this' after the mismatch.
>>> +  path Result;
>>> +  // FIXME: Reserve enough room in Result that it won't have to
>>> re-allocate.
>>> +  while (ElemCount--)
>>> +    Result /= "..";
>>> +  for (; PP; ++PP)
>>> +    Result /= *PP;
>>> +  return Result;
>>> +}
>>> +
>>> +///////////////////////////////////////////////////////////
>>> /////////////////
>>> +// path.comparisons
>>> +int path::__compare(string_view_t __s) const {
>>> +    auto PP = PathParser::CreateBegin(__pn_);
>>> +    auto PP2 = PathParser::CreateBegin(__s);
>>> +    while (PP && PP2) {
>>> +        int res = (*PP).compare(*PP2);
>>> +        if (res != 0) return res;
>>> +        ++PP; ++PP2;
>>> +    }
>>> +    if (PP.State == PP2.State && !PP)
>>> +        return 0;
>>> +    if (!PP)
>>> +        return -1;
>>> +    return 1;
>>> +}
>>> +
>>> +///////////////////////////////////////////////////////////
>>> /////////////////
>>> +// path.nonmembers
>>> +size_t hash_value(const path& __p) noexcept {
>>> +  auto PP = PathParser::CreateBegin(__p.native());
>>> +  size_t hash_value = 0;
>>> +  std::hash<string_view_t> hasher;
>>> +  while (PP) {
>>> +    hash_value = __hash_combine(hash_value, hasher(*PP));
>>> +    ++PP;
>>> +  }
>>> +  return hash_value;
>>> +}
>>> +
>>> +///////////////////////////////////////////////////////////
>>> /////////////////
>>> +// path.itr
>>> +path::iterator path::begin() const
>>> +{
>>> +    auto PP = PathParser::CreateBegin(__pn_);
>>> +    iterator it;
>>> +    it.__path_ptr_ = this;
>>> +    it.__state_ = PP.State;
>>> +    it.__entry_ = PP.RawEntry;
>>> +    it.__stashed_elem_.__assign_view(*PP);
>>> +    return it;
>>> +}
>>> +
>>> +path::iterator path::end() const
>>> +{
>>> +    iterator it{};
>>> +    it.__state_ = PathParser::PS_AtEnd;
>>> +    it.__path_ptr_ = this;
>>> +    return it;
>>> +}
>>> +
>>> +path::iterator& path::iterator::__increment() {
>>> +  static_assert(__at_end == PathParser::PS_AtEnd, "");
>>> +  PathParser PP(__path_ptr_->native(), __entry_, __state_);
>>> +  ++PP;
>>> +  __state_ = PP.State;
>>> +  __entry_ = PP.RawEntry;
>>> +  __stashed_elem_.__assign_view(*PP);
>>> +  return *this;
>>> +}
>>> +
>>> +path::iterator& path::iterator::__decrement() {
>>> +  PathParser PP(__path_ptr_->native(), __entry_, __state_);
>>> +  --PP;
>>> +  __state_ = PP.State;
>>> +  __entry_ = PP.RawEntry;
>>> +  __stashed_elem_.__assign_view(*PP);
>>> +  return *this;
>>> +}
>>> +
>>> +
>>>  _LIBCPP_END_NAMESPACE_EXPERIMENTAL_FILESYSTEM
>>>
>>> Removed: libcxx/trunk/src/experimental/filesystem/path.cpp
>>> URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/src/experim
>>> ental/filesystem/path.cpp?rev=329027&view=auto
>>> ============================================================
>>> ==================
>>> --- libcxx/trunk/src/experimental/filesystem/path.cpp (original)
>>> +++ libcxx/trunk/src/experimental/filesystem/path.cpp (removed)
>>> @@ -1,448 +0,0 @@
>>> -//===--------------------- filesystem/path.cpp
>>> ----------------------------===//
>>> -//
>>> -//                     The LLVM Compiler Infrastructure
>>> -//
>>> -// This file is dual licensed under the MIT and the University of
>>> Illinois Open
>>> -// Source Licenses. See LICENSE.TXT for details.
>>> -//
>>> -//===------------------------------------------------------
>>> ----------------===//
>>> -#include "experimental/filesystem"
>>> -#include "string_view"
>>> -#include "utility"
>>> -
>>> -namespace { namespace parser
>>> -{
>>> -using namespace std;
>>> -using namespace std::experimental::filesystem;
>>> -
>>> -using string_view_t = path::__string_view;
>>> -using string_view_pair = pair<string_view_t, string_view_t>;
>>> -using PosPtr = path::value_type const*;
>>> -
>>> -struct PathParser {
>>> -  enum ParserState : unsigned char {
>>> -    // Zero is a special sentinel value used by default constructed
>>> iterators.
>>> -    PS_BeforeBegin = 1,
>>> -    PS_InRootName,
>>> -    PS_InRootDir,
>>> -    PS_InFilenames,
>>> -    PS_InTrailingSep,
>>> -    PS_AtEnd
>>> -  };
>>> -
>>> -  const string_view_t Path;
>>> -  string_view_t RawEntry;
>>> -  ParserState State;
>>> -
>>> -private:
>>> -  PathParser(string_view_t P, ParserState State) noexcept
>>> -      : Path(P), State(State) {}
>>> -
>>> -public:
>>> -  PathParser(string_view_t P, string_view_t E, unsigned char S)
>>> -      : Path(P), RawEntry(E), State(static_cast<ParserState>(S)) {
>>> -    // S cannot be '0' or PS_BeforeBegin.
>>> -  }
>>> -
>>> -  static PathParser CreateBegin(string_view_t P) noexcept {
>>> -    PathParser PP(P, PS_BeforeBegin);
>>> -    PP.increment();
>>> -    return PP;
>>> -  }
>>> -
>>> -  static PathParser CreateEnd(string_view_t P) noexcept {
>>> -    PathParser PP(P, PS_AtEnd);
>>> -    return PP;
>>> -  }
>>> -
>>> -  PosPtr peek() const noexcept {
>>> -    auto TkEnd = getNextTokenStartPos();
>>> -    auto End = getAfterBack();
>>> -    return TkEnd == End ? nullptr : TkEnd;
>>> -  }
>>> -
>>> -  void increment() noexcept {
>>> -    const PosPtr End = getAfterBack();
>>> -    const PosPtr Start = getNextTokenStartPos();
>>> -    if (Start == End)
>>> -      return makeState(PS_AtEnd);
>>> -
>>> -    switch (State) {
>>> -    case PS_BeforeBegin: {
>>> -      PosPtr TkEnd = consumeSeparator(Start, End);
>>> -      // If we consumed exactly two separators we have a root name.
>>> -      if (TkEnd && TkEnd == Start + 2) {
>>> -        // FIXME Do we need to consume a name or is '//' a root name on
>>> its own?
>>> -        // what about '//.', '//..', '//...'?
>>> -        auto NameEnd = consumeName(TkEnd, End);
>>> -        if (NameEnd)
>>> -          TkEnd = NameEnd;
>>> -        return makeState(PS_InRootName, Start, TkEnd);
>>> -      }
>>> -      else if (TkEnd)
>>> -        return makeState(PS_InRootDir, Start, TkEnd);
>>> -      else
>>> -        return makeState(PS_InFilenames, Start, consumeName(Start,
>>> End));
>>> -    }
>>> -
>>> -    case PS_InRootName:
>>> -      return makeState(PS_InRootDir, Start, consumeSeparator(Start,
>>> End));
>>> -    case PS_InRootDir:
>>> -      return makeState(PS_InFilenames, Start, consumeName(Start, End));
>>> -
>>> -    case PS_InFilenames: {
>>> -      PosPtr SepEnd = consumeSeparator(Start, End);
>>> -      if (SepEnd != End) {
>>> -        PosPtr TkEnd = consumeName(SepEnd, End);
>>> -        if (TkEnd)
>>> -          return makeState(PS_InFilenames, SepEnd, TkEnd);
>>> -      }
>>> -      return makeState(PS_InTrailingSep, Start, SepEnd);
>>> -    }
>>> -
>>> -    case PS_InTrailingSep:
>>> -      return makeState(PS_AtEnd);
>>> -
>>> -    case PS_AtEnd:
>>> -      _LIBCPP_UNREACHABLE();
>>> -    }
>>> -  }
>>> -
>>> -  void decrement() noexcept {
>>> -    const PosPtr REnd = getBeforeFront();
>>> -    const PosPtr RStart = getCurrentTokenStartPos() - 1;
>>> -
>>> -    switch (State) {
>>> -    case PS_AtEnd: {
>>> -      // Try to consume a trailing separator or root directory first.
>>> -      if (PosPtr SepEnd = consumeSeparator(RStart, REnd)) {
>>> -        if (SepEnd == REnd)
>>> -          return makeState((RStart == REnd + 2) ? PS_InRootName :
>>> PS_InRootDir,
>>> -                           Path.data(), RStart + 1);
>>> -        // Check if we're seeing the root directory separator
>>> -        auto PP = CreateBegin(Path);
>>> -        bool InRootDir = PP.State == PS_InRootName &&
>>> -            &PP.RawEntry.back() == SepEnd;
>>> -        return makeState(InRootDir ? PS_InRootDir : PS_InTrailingSep,
>>> -                         SepEnd + 1, RStart + 1);
>>> -      } else {
>>> -        PosPtr TkStart = consumeName(RStart, REnd);
>>> -        if (TkStart == REnd + 2 && consumeSeparator(TkStart, REnd) ==
>>> REnd)
>>> -          return makeState(PS_InRootName, Path.data(), RStart + 1);
>>> -        else
>>> -          return makeState(PS_InFilenames, TkStart + 1, RStart + 1);
>>> -      }
>>> -    }
>>> -    case PS_InTrailingSep:
>>> -      return makeState(PS_InFilenames, consumeName(RStart, REnd) + 1,
>>> RStart + 1);
>>> -    case PS_InFilenames: {
>>> -      PosPtr SepEnd = consumeSeparator(RStart, REnd);
>>> -      if (SepEnd == REnd)
>>> -        return makeState((RStart == REnd + 2) ? PS_InRootName :
>>> PS_InRootDir,
>>> -                         Path.data(), RStart + 1);
>>> -      PosPtr TkEnd = consumeName(SepEnd, REnd);
>>> -      if (TkEnd == REnd + 2 && consumeSeparator(TkEnd, REnd) == REnd)
>>> -        return makeState(PS_InRootDir, SepEnd + 1, RStart + 1);
>>> -      return makeState(PS_InFilenames, TkEnd + 1, SepEnd + 1);
>>> -    }
>>> -    case PS_InRootDir:
>>> -      return makeState(PS_InRootName, Path.data(), RStart + 1);
>>> -    case PS_InRootName:
>>> -    case PS_BeforeBegin:
>>> -      _LIBCPP_UNREACHABLE();
>>> -    }
>>> -  }
>>> -
>>> -  /// \brief Return a view with the "preferred representation" of the
>>> current
>>> -  ///   element. For example trailing separators are represented as a
>>> '.'
>>> -  string_view_t operator*() const noexcept {
>>> -    switch (State) {
>>> -    case PS_BeforeBegin:
>>> -    case PS_AtEnd:
>>> -      return "";
>>> -    case PS_InRootDir:
>>> -      return "/";
>>> -    case PS_InTrailingSep:
>>> -      return ".";
>>> -    case PS_InRootName:
>>> -    case PS_InFilenames:
>>> -      return RawEntry;
>>> -    }
>>> -    _LIBCPP_UNREACHABLE();
>>> -  }
>>> -
>>> -  explicit operator bool() const noexcept {
>>> -    return State != PS_BeforeBegin && State != PS_AtEnd;
>>> -  }
>>> -
>>> -  PathParser& operator++() noexcept {
>>> -    increment();
>>> -    return *this;
>>> -  }
>>> -
>>> -  PathParser& operator--() noexcept {
>>> -    decrement();
>>> -    return *this;
>>> -  }
>>> -
>>> -private:
>>> -  void makeState(ParserState NewState, PosPtr Start, PosPtr End)
>>> noexcept {
>>> -    State = NewState;
>>> -    RawEntry = string_view_t(Start, End - Start);
>>> -  }
>>> -  void makeState(ParserState NewState) noexcept {
>>> -    State = NewState;
>>> -    RawEntry = {};
>>> -  }
>>> -
>>> -  PosPtr getAfterBack() const noexcept {
>>> -    return Path.data() + Path.size();
>>> -  }
>>> -
>>> -  PosPtr getBeforeFront() const noexcept {
>>> -    return Path.data() - 1;
>>> -  }
>>> -
>>> -  /// \brief Return a pointer to the first character after the currently
>>> -  ///   lexed element.
>>> -  PosPtr getNextTokenStartPos() const noexcept {
>>> -    switch (State) {
>>> -    case PS_BeforeBegin:
>>> -      return Path.data();
>>> -    case PS_InRootName:
>>> -    case PS_InRootDir:
>>> -    case PS_InFilenames:
>>> -      return &RawEntry.back() + 1;
>>> -    case PS_InTrailingSep:
>>> -    case PS_AtEnd:
>>> -      return getAfterBack();
>>> -    }
>>> -    _LIBCPP_UNREACHABLE();
>>> -  }
>>> -
>>> -  /// \brief Return a pointer to the first character in the currently
>>> lexed
>>> -  ///   element.
>>> -  PosPtr getCurrentTokenStartPos() const noexcept {
>>> -    switch (State) {
>>> -    case PS_BeforeBegin:
>>> -    case PS_InRootName:
>>> -      return &Path.front();
>>> -    case PS_InRootDir:
>>> -    case PS_InFilenames:
>>> -    case PS_InTrailingSep:
>>> -      return &RawEntry.front();
>>> -    case PS_AtEnd:
>>> -      return &Path.back() + 1;
>>> -    }
>>> -    _LIBCPP_UNREACHABLE();
>>> -  }
>>> -
>>> -  PosPtr consumeSeparator(PosPtr P, PosPtr End) const noexcept {
>>> -    if (P == End || *P != '/')
>>> -      return nullptr;
>>> -    const int Inc = P < End ? 1 : -1;
>>> -    P += Inc;
>>> -    while (P != End && *P == '/')
>>> -      P += Inc;
>>> -    return P;
>>> -  }
>>> -
>>> -  PosPtr consumeName(PosPtr P, PosPtr End) const noexcept {
>>> -    if (P == End || *P == '/')
>>> -      return nullptr;
>>> -    const int Inc = P < End ? 1 : -1;
>>> -    P += Inc;
>>> -    while (P != End && *P != '/')
>>> -      P += Inc;
>>> -    return P;
>>> -  }
>>> -};
>>> -
>>> -string_view_pair separate_filename(string_view_t const & s) {
>>> -    if (s == "." || s == ".." || s.empty()) return string_view_pair{s,
>>> ""};
>>> -    auto pos = s.find_last_of('.');
>>> -    if (pos == string_view_t::npos)
>>> -        return string_view_pair{s, string_view_t{}};
>>> -    return string_view_pair{s.substr(0, pos), s.substr(pos)};
>>> -}
>>> -
>>> -string_view_t createView(PosPtr S, PosPtr E) noexcept {
>>> -  return {S, static_cast<size_t>(E - S) + 1};
>>> -}
>>> -
>>> -}} // namespace parser
>>> -
>>> -_LIBCPP_BEGIN_NAMESPACE_EXPERIMENTAL_FILESYSTEM
>>> -
>>> -using parser::string_view_t;
>>> -using parser::string_view_pair;
>>> -using parser::PathParser;
>>> -using parser::createView;
>>> -
>>> -///////////////////////////////////////////////////////////
>>> ////////////////////
>>> -//                            path definitions
>>> -///////////////////////////////////////////////////////////
>>> ////////////////////
>>> -
>>> -constexpr path::value_type path::preferred_separator;
>>> -
>>> -path & path::replace_extension(path const & replacement)
>>> -{
>>> -    path p = extension();
>>> -    if (not p.empty()) {
>>> -      __pn_.erase(__pn_.size() - p.native().size());
>>> -    }
>>> -    if (!replacement.empty()) {
>>> -        if (replacement.native()[0] != '.') {
>>> -            __pn_ += ".";
>>> -        }
>>> -        __pn_.append(replacement.__pn_);
>>> -    }
>>> -    return *this;
>>> -}
>>> -
>>> -///////////////////////////////////////////////////////////
>>> ////////////////////
>>> -// path.decompose
>>> -
>>> -string_view_t path::__root_name() const
>>> -{
>>> -    auto PP = PathParser::CreateBegin(__pn_);
>>> -    if (PP.State == PathParser::PS_InRootName)
>>> -      return *PP;
>>> -    return {};
>>> -}
>>> -
>>> -string_view_t path::__root_directory() const
>>> -{
>>> -    auto PP = PathParser::CreateBegin(__pn_);
>>> -    if (PP.State == PathParser::PS_InRootName)
>>> -      ++PP;
>>> -    if (PP.State == PathParser::PS_InRootDir)
>>> -      return *PP;
>>> -    return {};
>>> -}
>>> -
>>> -string_view_t path::__root_path_raw() const
>>> -{
>>> -    auto PP = PathParser::CreateBegin(__pn_);
>>> -    if (PP.State == PathParser::PS_InRootName) {
>>> -      auto NextCh = PP.peek();
>>> -      if (NextCh && *NextCh == '/') {
>>> -        ++PP;
>>> -        return createView(__pn_.data(), &PP.RawEntry.back());
>>> -      }
>>> -      return PP.RawEntry;
>>> -    }
>>> -    if (PP.State == PathParser::PS_InRootDir)
>>> -      return *PP;
>>> -    return {};
>>> -}
>>> -
>>> -string_view_t path::__relative_path() const
>>> -{
>>> -    auto PP = PathParser::CreateBegin(__pn_);
>>> -    while (PP.State <= PathParser::PS_InRootDir)
>>> -      ++PP;
>>> -    if (PP.State == PathParser::PS_AtEnd)
>>> -      return {};
>>> -    return createView(PP.RawEntry.data(), &__pn_.back());
>>> -}
>>> -
>>> -string_view_t path::__parent_path() const
>>> -{
>>> -    if (empty())
>>> -      return {};
>>> -    auto PP = PathParser::CreateEnd(__pn_);
>>> -    --PP;
>>> -    if (PP.RawEntry.data() == __pn_.data())
>>> -      return {};
>>> -    --PP;
>>> -    return createView(__pn_.data(), &PP.RawEntry.back());
>>> -}
>>> -
>>> -string_view_t path::__filename() const
>>> -{
>>> -    if (empty()) return {};
>>> -    return *(--PathParser::CreateEnd(__pn_));
>>> -}
>>> -
>>> -string_view_t path::__stem() const
>>> -{
>>> -    return parser::separate_filename(__filename()).first;
>>> -}
>>> -
>>> -string_view_t path::__extension() const
>>> -{
>>> -    return parser::separate_filename(__filename()).second;
>>> -}
>>> -
>>> -///////////////////////////////////////////////////////////
>>> /////////////////
>>> -// path.comparisons
>>> -int path::__compare(string_view_t __s) const {
>>> -    auto PP = PathParser::CreateBegin(__pn_);
>>> -    auto PP2 = PathParser::CreateBegin(__s);
>>> -    while (PP && PP2) {
>>> -        int res = (*PP).compare(*PP2);
>>> -        if (res != 0) return res;
>>> -        ++PP; ++PP2;
>>> -    }
>>> -    if (PP.State == PP2.State && PP.State == PathParser::PS_AtEnd)
>>> -        return 0;
>>> -    if (PP.State == PathParser::PS_AtEnd)
>>> -        return -1;
>>> -    return 1;
>>> -}
>>> -
>>> -///////////////////////////////////////////////////////////
>>> /////////////////
>>> -// path.nonmembers
>>> -size_t hash_value(const path& __p) noexcept {
>>> -  auto PP = PathParser::CreateBegin(__p.native());
>>> -  size_t hash_value = 0;
>>> -  std::hash<string_view_t> hasher;
>>> -  while (PP) {
>>> -    hash_value = __hash_combine(hash_value, hasher(*PP));
>>> -    ++PP;
>>> -  }
>>> -  return hash_value;
>>> -}
>>> -
>>> -///////////////////////////////////////////////////////////
>>> /////////////////
>>> -// path.itr
>>> -path::iterator path::begin() const
>>> -{
>>> -    auto PP = PathParser::CreateBegin(__pn_);
>>> -    iterator it;
>>> -    it.__path_ptr_ = this;
>>> -    it.__state_ = PP.State;
>>> -    it.__entry_ = PP.RawEntry;
>>> -    it.__stashed_elem_.__assign_view(*PP);
>>> -    return it;
>>> -}
>>> -
>>> -path::iterator path::end() const
>>> -{
>>> -    iterator it{};
>>> -    it.__state_ = PathParser::PS_AtEnd;
>>> -    it.__path_ptr_ = this;
>>> -    return it;
>>> -}
>>> -
>>> -path::iterator& path::iterator::__increment() {
>>> -  static_assert(__at_end == PathParser::PS_AtEnd, "");
>>> -  PathParser PP(__path_ptr_->native(), __entry_, __state_);
>>> -  ++PP;
>>> -  __state_ = PP.State;
>>> -  __entry_ = PP.RawEntry;
>>> -  __stashed_elem_.__assign_view(*PP);
>>> -  return *this;
>>> -}
>>> -
>>> -path::iterator& path::iterator::__decrement() {
>>> -  PathParser PP(__path_ptr_->native(), __entry_, __state_);
>>> -  --PP;
>>> -  __state_ = PP.State;
>>> -  __entry_ = PP.RawEntry;
>>> -  __stashed_elem_.__assign_view(*PP);
>>> -  return *this;
>>> -}
>>> -
>>> -_LIBCPP_END_NAMESPACE_EXPERIMENTAL_FILESYSTEM
>>>
>>> Removed: libcxx/trunk/test/libcxx/experimental/filesystem/class.path/
>>> path.member/path.append.pass.cpp
>>> URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/libcxx
>>> /experimental/filesystem/class.path/path.member/path.append.
>>> pass.cpp?rev=329027&view=auto
>>> ============================================================
>>> ==================
>>> --- libcxx/trunk/test/libcxx/experimental/filesystem/class.path/
>>> path.member/path.append.pass.cpp (original)
>>> +++ libcxx/trunk/test/libcxx/experimental/filesystem/class.path/
>>> path.member/path.append.pass.cpp (removed)
>>> @@ -1,70 +0,0 @@
>>> -//===------------------------------------------------------
>>> ----------------===//
>>> -//
>>> -//                     The LLVM Compiler Infrastructure
>>> -//
>>> -// This file is dual licensed under the MIT and the University of
>>> Illinois Open
>>> -// Source Licenses. See LICENSE.TXT for details.
>>> -//
>>> -//===------------------------------------------------------
>>> ----------------===//
>>> -
>>> -// UNSUPPORTED: c++98, c++03
>>> -
>>> -// <experimental/filesystem>
>>> -
>>> -// class path
>>> -
>>> -// path& operator/=(path const&)
>>> -// path operator/(path const&, path const&)
>>> -
>>> -
>>> -#define _LIBCPP_DEBUG 0
>>> -#define _LIBCPP_ASSERT(x, m) ((x) ? (void)0 : (void)::AssertCount++)
>>> -int AssertCount = 0;
>>> -
>>> -#include <experimental/filesystem>
>>> -#include <type_traits>
>>> -#include <string_view>
>>> -#include <cassert>
>>> -
>>> -#include "test_macros.h"
>>> -#include "test_iterators.h"
>>> -#include "count_new.hpp"
>>> -#include "filesystem_test_helper.hpp"
>>> -
>>> -namespace fs = std::experimental::filesystem;
>>> -
>>> -int main()
>>> -{
>>> -  using namespace fs;
>>> -  {
>>> -    path lhs("//foo");
>>> -    path rhs("/bar");
>>> -    assert(AssertCount == 0);
>>> -    lhs /= rhs;
>>> -    assert(AssertCount == 0);
>>> -  }
>>> -  {
>>> -    path lhs("//foo");
>>> -    path rhs("/bar");
>>> -    assert(AssertCount == 0);
>>> -    (void)(lhs / rhs);
>>> -    assert(AssertCount == 0);
>>> -  }
>>> -  {
>>> -    path lhs("//foo");
>>> -    path rhs("//bar");
>>> -    assert(AssertCount == 0);
>>> -    lhs /= rhs;
>>> -    assert(AssertCount == 1);
>>> -    AssertCount = 0;
>>> -  }
>>> -  {
>>> -    path lhs("//foo");
>>> -    path rhs("//bar");
>>> -    assert(AssertCount == 0);
>>> -    (void)(lhs / rhs);
>>> -    assert(AssertCount == 1);
>>> -  }
>>> -  // FIXME The same error is not diagnosed for the append(Source) and
>>> -  // append(It, It) overloads.
>>> -}
>>>
>>> Modified: libcxx/trunk/test/std/experimental/filesystem/class.path/pat
>>> h.itr/iterator.pass.cpp
>>> URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/ex
>>> perimental/filesystem/class.path/path.itr/iterator.pass.cpp?
>>> rev=329028&r1=329027&r2=329028&view=diff
>>> ============================================================
>>> ==================
>>> --- libcxx/trunk/test/std/experimental/filesystem/class.path/path.itr/iterator.pass.cpp
>>> (original)
>>> +++ libcxx/trunk/test/std/experimental/filesystem/class.path/path.itr/iterator.pass.cpp
>>> Mon Apr  2 16:03:41 2018
>>> @@ -83,14 +83,14 @@ void checkBeginEndBasic() {
>>>    }
>>>    {
>>>      path p("//root_name//first_dir////second_dir");
>>> -    const path expect[] = {"//root_name", "/", "first_dir",
>>> "second_dir"};
>>> +    const path expect[] = {"/", "root_name", "first_dir", "second_dir"};
>>>      assert(checkCollectionsEqual(p.begin(), p.end(),
>>> std::begin(expect), std::end(expect)));
>>>      assert(checkCollectionsEqualBackwards(p.begin(), p.end(),
>>> std::begin(expect), std::end(expect)));
>>>
>>>    }
>>>    {
>>>      path p("////foo/bar/baz///");
>>> -    const path expect[] = {"/", "foo", "bar", "baz", "."};
>>> +    const path expect[] = {"/", "foo", "bar", "baz", ""};
>>>      assert(checkCollectionsEqual(p.begin(), p.end(),
>>> std::begin(expect), std::end(expect)));
>>>      assert(checkCollectionsEqualBackwards(p.begin(), p.end(),
>>> std::begin(expect), std::end(expect)));
>>>
>>>
>>> Modified: libcxx/trunk/test/std/experimental/filesystem/class.path/pat
>>> h.member/path.append.pass.cpp
>>> URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/ex
>>> perimental/filesystem/class.path/path.member/path.append.pas
>>> s.cpp?rev=329028&r1=329027&r2=329028&view=diff
>>> ============================================================
>>> ==================
>>> --- libcxx/trunk/test/std/experimental/filesystem/class.path/path.member/path.append.pass.cpp
>>> (original)
>>> +++ libcxx/trunk/test/std/experimental/filesystem/class.path/path.member/path.append.pass.cpp
>>> Mon Apr  2 16:03:41 2018
>>> @@ -31,6 +31,7 @@
>>>  #include "test_iterators.h"
>>>  #include "count_new.hpp"
>>>  #include "filesystem_test_helper.hpp"
>>> +#include "verbose_assert.h"
>>>
>>>
>>>  struct AppendOperatorTestcase {
>>> @@ -45,13 +46,22 @@ const AppendOperatorTestcase Cases[] =
>>>          {S(""),     S(""),      S("")}
>>>        , {S("p1"),   S("p2"),    S("p1/p2")}
>>>        , {S("p1/"),  S("p2"),    S("p1/p2")}
>>> -      , {S("p1"),   S("/p2"),   S("p1/p2")}
>>> -      , {S("p1/"),  S("/p2"),   S("p1//p2")}
>>> +      , {S("p1"),   S("/p2"),   S("/p2")}
>>> +      , {S("p1/"),  S("/p2"),   S("/p2")}
>>>        , {S("p1"),   S("\\p2"),  S("p1/\\p2")}
>>>        , {S("p1\\"), S("p2"),  S("p1\\/p2")}
>>>        , {S("p1\\"), S("\\p2"),  S("p1\\/\\p2")}
>>> -      , {S("p1"),   S(""),      S("p1")}
>>>        , {S(""),     S("p2"),    S("p2")}
>>> +      , {S("/p1"),  S("p2"),    S("/p1/p2")}
>>> +      , {S("/p1"),  S("/p2"),    S("/p2")}
>>> +      , {S("/p1/p3"),  S("p2"),    S("/p1/p3/p2")}
>>> +      , {S("/p1/p3/"),  S("p2"),    S("/p1/p3/p2")}
>>> +      , {S("/p1/"),  S("p2"),    S("/p1/p2")}
>>> +      , {S("/p1/p3/"),  S("/p2/p4"),    S("/p2/p4")}
>>> +      , {S("/"),    S(""),      S("/")}
>>> +      , {S("/p1"), S("/p2/"), S("/p2/")}
>>> +      , {S("p1"),   S(""),      S("p1/")}
>>> +      , {S("p1/"),  S(""),      S("p1/")}
>>>      };
>>>
>>>
>>> @@ -59,7 +69,8 @@ const AppendOperatorTestcase LongLHSCase
>>>      {
>>>          {S("p1"),   S("p2"),    S("p1/p2")}
>>>        , {S("p1/"),  S("p2"),    S("p1/p2")}
>>> -      , {S("p1"),   S("/p2"),   S("p1/p2")}
>>> +      , {S("p1"),   S("/p2"),   S("/p2")}
>>> +      , {S("/p1"),  S("p2"),    S("/p1/p2")}
>>>      };
>>>  #undef S
>>>
>>> @@ -98,7 +109,7 @@ void doAppendSourceAllocTest(AppendOpera
>>>        DisableAllocationGuard g;
>>>        LHS /= RHS;
>>>      }
>>> -    assert(LHS == E);
>>> +    ASSERT_PRED(PathEq, LHS , E);
>>>    }
>>>    // basic_string_view
>>>    {
>>> @@ -108,7 +119,7 @@ void doAppendSourceAllocTest(AppendOpera
>>>        DisableAllocationGuard g;
>>>        LHS /= RHS;
>>>      }
>>> -    assert(LHS == E);
>>> +    assert(PathEq(LHS, E));
>>>    }
>>>    // CharT*
>>>    {
>>> @@ -118,7 +129,7 @@ void doAppendSourceAllocTest(AppendOpera
>>>        DisableAllocationGuard g;
>>>        LHS /= RHS;
>>>      }
>>> -    assert(LHS == E);
>>> +    assert(PathEq(LHS, E));
>>>    }
>>>    {
>>>      path LHS(L); PathReserve(LHS, ReserveSize);
>>> @@ -127,7 +138,7 @@ void doAppendSourceAllocTest(AppendOpera
>>>        DisableAllocationGuard g;
>>>        LHS.append(RHS, StrEnd(RHS));
>>>      }
>>> -    assert(LHS == E);
>>> +    assert(PathEq(LHS, E));
>>>    }
>>>    // input iterator - For non-native char types, appends needs to copy
>>> the
>>>    // iterator range into a contiguous block of memory before it can
>>> perform the
>>> @@ -143,7 +154,7 @@ void doAppendSourceAllocTest(AppendOpera
>>>        if (DisableAllocations) g.requireExactly(0);
>>>        LHS /= RHS;
>>>      }
>>> -    assert(LHS == E);
>>> +    assert(PathEq(LHS, E));
>>>    }
>>>    {
>>>      path LHS(L); PathReserve(LHS, ReserveSize);
>>> @@ -154,7 +165,7 @@ void doAppendSourceAllocTest(AppendOpera
>>>        if (DisableAllocations) g.requireExactly(0);
>>>        LHS.append(RHS, REnd);
>>>      }
>>> -    assert(LHS == E);
>>> +    assert(PathEq(LHS, E));
>>>    }
>>>  }
>>>
>>> @@ -171,17 +182,18 @@ void doAppendSourceTest(AppendOperatorTe
>>>    const Ptr E = TC.expect;
>>>    // basic_string
>>>    {
>>> -    path LHS(L);
>>> +    path Result(L);
>>>      Str RHS(R);
>>> -    path& Ref = (LHS /= RHS);
>>> -    assert(LHS == E);
>>> -    assert(&Ref == &LHS);
>>> +    path& Ref = (Result /= RHS);
>>> +    ASSERT_EQ(Result, E)
>>> +        << DISPLAY(L) << DISPLAY(R);
>>> +    assert(&Ref == &Result);
>>>    }
>>>    {
>>>      path LHS(L);
>>>      Str RHS(R);
>>>      path& Ref = LHS.append(RHS);
>>> -    assert(LHS == E);
>>> +    assert(PathEq(LHS, E));
>>>      assert(&Ref == &LHS);
>>>    }
>>>    // basic_string_view
>>> @@ -189,14 +201,14 @@ void doAppendSourceTest(AppendOperatorTe
>>>      path LHS(L);
>>>      StrView RHS(R);
>>>      path& Ref = (LHS /= RHS);
>>> -    assert(LHS == E);
>>> +    assert(PathEq(LHS, E));
>>>      assert(&Ref == &LHS);
>>>    }
>>>    {
>>>      path LHS(L);
>>>      StrView RHS(R);
>>>      path& Ref = LHS.append(RHS);
>>> -    assert(LHS == E);
>>> +    assert(PathEq(LHS, E));
>>>      assert(&Ref == &LHS);
>>>    }
>>>    // Char*
>>> @@ -204,21 +216,22 @@ void doAppendSourceTest(AppendOperatorTe
>>>      path LHS(L);
>>>      Str RHS(R);
>>>      path& Ref = (LHS /= RHS);
>>> -    assert(LHS == E);
>>> +    assert(PathEq(LHS, E));
>>>      assert(&Ref == &LHS);
>>>    }
>>>    {
>>>      path LHS(L);
>>>      Ptr RHS(R);
>>>      path& Ref = LHS.append(RHS);
>>> -    assert(LHS == E);
>>> +    assert(PathEq(LHS, E));
>>>      assert(&Ref == &LHS);
>>>    }
>>>    {
>>>      path LHS(L);
>>>      Ptr RHS(R);
>>>      path& Ref = LHS.append(RHS, StrEnd(RHS));
>>> -    assert(LHS == E);
>>> +    ASSERT_PRED(PathEq, LHS, E)
>>> +        << DISPLAY(L) << DISPLAY(R);
>>>      assert(&Ref == &LHS);
>>>    }
>>>    // iterators
>>> @@ -226,13 +239,13 @@ void doAppendSourceTest(AppendOperatorTe
>>>      path LHS(L);
>>>      InputIter RHS(R);
>>>      path& Ref = (LHS /= RHS);
>>> -    assert(LHS == E);
>>> +    assert(PathEq(LHS, E));
>>>      assert(&Ref == &LHS);
>>>    }
>>>    {
>>>      path LHS(L); InputIter RHS(R);
>>>      path& Ref = LHS.append(RHS);
>>> -    assert(LHS == E);
>>> +    assert(PathEq(LHS, E));
>>>      assert(&Ref == &LHS);
>>>    }
>>>    {
>>> @@ -240,7 +253,7 @@ void doAppendSourceTest(AppendOperatorTe
>>>      InputIter RHS(R);
>>>      InputIter REnd(StrEnd(R));
>>>      path& Ref = LHS.append(RHS, REnd);
>>> -    assert(LHS == E);
>>> +    assert(PathEq(LHS, E));
>>>      assert(&Ref == &LHS);
>>>    }
>>>  }
>>> @@ -304,11 +317,14 @@ int main()
>>>    using namespace fs;
>>>    for (auto const & TC : Cases) {
>>>      {
>>> -      path LHS((const char*)TC.lhs);
>>> -      path RHS((const char*)TC.rhs);
>>> -      path& Ref = (LHS /= RHS);
>>> -      assert(LHS == (const char*)TC.expect);
>>> -      assert(&Ref == &LHS);
>>> +      const char* LHS_In = TC.lhs;
>>> +      const char* RHS_In = TC.rhs;
>>> +      path LHS(LHS_In);
>>> +      path RHS(RHS_In);
>>> +      path& Res = (LHS /= RHS);
>>> +      ASSERT_PRED(PathEq, Res, (const char*)TC.expect)
>>> +          << DISPLAY(LHS_In) << DISPLAY(RHS_In);
>>> +      assert(&Res == &LHS);
>>>      }
>>>      doAppendSourceTest<char>    (TC);
>>>      doAppendSourceTest<wchar_t> (TC);
>>>
>>> Modified: libcxx/trunk/test/std/experimental/filesystem/class.path/pat
>>> h.member/path.compare.pass.cpp
>>> URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/ex
>>> perimental/filesystem/class.path/path.member/path.compare.pa
>>> ss.cpp?rev=329028&r1=329027&r2=329028&view=diff
>>> ============================================================
>>> ==================
>>> --- libcxx/trunk/test/std/experimental/filesystem/class.path/path.member/path.compare.pass.cpp
>>> (original)
>>> +++ libcxx/trunk/test/std/experimental/filesystem/class.path/path.member/path.compare.pass.cpp
>>> Mon Apr  2 16:03:41 2018
>>> @@ -26,6 +26,7 @@
>>>  //
>>>  // size_t hash_value(path const&) noexcept;
>>>
>>> +
>>>  #include "filesystem_include.hpp"
>>>  #include <type_traits>
>>>  #include <vector>
>>> @@ -35,7 +36,7 @@
>>>  #include "test_iterators.h"
>>>  #include "count_new.hpp"
>>>  #include "filesystem_test_helper.hpp"
>>> -
>>> +#include "verbose_assert.h"
>>>
>>>  struct PathCompareTest {
>>>    const char* LHS;
>>> @@ -57,8 +58,9 @@ const PathCompareTest CompareTestCases[]
>>>      {"a/b/c", "b/a/c", -1},
>>>      {"a/b", "a/b/c", -1},
>>>      {"a/b/c", "a/b", 1},
>>> -    {"a/b/", "a/b/.", 0},
>>> -    {"a/b//////", "a/b/////.", 0},
>>> +    {"a/b/", "a/b/.", -1},
>>> +    {"a/b/", "a/b",    1},
>>> +    {"a/b//////", "a/b/////.", -1},
>>>      {"a/.././b", "a///..//.////b", 0},
>>>      {"//foo//bar///baz////", "//foo/bar/baz/", 0}, // duplicate
>>> separators
>>>      {"///foo/bar", "/foo/bar", 0}, // "///" is not a root directory
>>> @@ -94,8 +96,13 @@ int main()
>>>        int ret2 = normalize_ret(p1.compare(R));
>>>        int ret3 = normalize_ret(p1.compare(TC.RHS));
>>>        int ret4 = normalize_ret(p1.compare(RV));
>>> -      assert(ret1 == ret2 && ret1 == ret3 && ret1 == ret4);
>>> -      assert(ret1 == E);
>>> +
>>> +      g.release();
>>> +      ASSERT_EQ(ret1, ret2);
>>> +      ASSERT_EQ(ret1, ret3);
>>> +      ASSERT_EQ(ret1, ret4);
>>> +      ASSERT_EQ(ret1, E)
>>> +          << DISPLAY(TC.LHS) << DISPLAY(TC.RHS);
>>>
>>>        // check signatures
>>>        ASSERT_NOEXCEPT(p1.compare(p2));
>>>
>>> Modified: libcxx/trunk/test/std/experimental/filesystem/class.path/pat
>>> h.member/path.decompose/empty.fail.cpp
>>> URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/ex
>>> perimental/filesystem/class.path/path.member/path.decompose/
>>> empty.fail.cpp?rev=329028&r1=329027&r2=329028&view=diff
>>> ============================================================
>>> ==================
>>> --- libcxx/trunk/test/std/experimental/filesystem/class.path/pat
>>> h.member/path.decompose/empty.fail.cpp (original)
>>> +++ libcxx/trunk/test/std/experimental/filesystem/class.path/pat
>>> h.member/path.decompose/empty.fail.cpp Mon Apr  2 16:03:41 2018
>>> @@ -18,6 +18,7 @@
>>>  // UNSUPPORTED: clang-3.3, clang-3.4, clang-3.5, clang-3.6, clang-3.7,
>>> clang-3.8
>>>
>>>  #include "filesystem_include.hpp"
>>> +
>>>  #include "test_macros.h"
>>>
>>>  int main ()
>>>
>>> Modified: libcxx/trunk/test/std/experimental/filesystem/class.path/pat
>>> h.member/path.decompose/path.decompose.pass.cpp
>>> URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/ex
>>> perimental/filesystem/class.path/path.member/path.decompose/
>>> path.decompose.pass.cpp?rev=329028&r1=329027&r2=329028&view=diff
>>> ============================================================
>>> ==================
>>> --- libcxx/trunk/test/std/experimental/filesystem/class.path/pat
>>> h.member/path.decompose/path.decompose.pass.cpp (original)
>>> +++ libcxx/trunk/test/std/experimental/filesystem/class.path/pat
>>> h.member/path.decompose/path.decompose.pass.cpp Mon Apr  2 16:03:41 2018
>>> @@ -53,6 +53,14 @@
>>>  #include "test_iterators.h"
>>>  #include "count_new.hpp"
>>>  #include "filesystem_test_helper.hpp"
>>> +#include "assert_checkpoint.h"
>>> +#include "verbose_assert.h"
>>> +
>>> +struct ComparePathExact {
>>> +  bool operator()(std::string const& LHS, std::string const& RHS) const
>>> {
>>> +    return LHS == RHS;
>>> +  }
>>> +};
>>>
>>>  struct PathDecomposeTestcase
>>>  {
>>> @@ -72,80 +80,89 @@ const PathDecomposeTestcase PathTestCase
>>>      , {".", {"."}, "", "", "", ".", "", "."}
>>>      , {"..", {".."}, "", "", "", "..", "", ".."}
>>>      , {"foo", {"foo"}, "", "", "", "foo", "", "foo"}
>>> -    , {"/", {"/"}, "/", "", "/", "", "", "/"}
>>> +    , {"/", {"/"}, "/", "", "/", "", "/", ""}
>>>      , {"/foo", {"/", "foo"}, "/", "", "/", "foo", "/", "foo"}
>>> -    , {"foo/", {"foo", "."}, "", "", "", "foo/", "foo", "."}
>>> -    , {"/foo/", {"/", "foo", "."}, "/", "", "/", "foo/", "/foo", "."}
>>> +    , {"foo/", {"foo", ""}, "", "", "", "foo/", "foo", ""}
>>> +    , {"/foo/", {"/", "foo", ""}, "/", "", "/", "foo/", "/foo", ""}
>>>      , {"foo/bar", {"foo","bar"}, "",  "", "",  "foo/bar", "foo", "bar"}
>>>      , {"/foo//bar", {"/","foo","bar"}, "/", "", "/", "foo/bar", "/foo",
>>> "bar"}
>>> -    , {"//net", {"//net"}, "//net", "//net", "", "", "", "//net"}
>>> -    , {"//net/foo", {"//net", "/", "foo"}, "//net/", "//net", "/",
>>> "foo", "//net/", "foo"}
>>> -    , {"///foo///", {"/", "foo", "."}, "/", "", "/", "foo///",
>>> "///foo", "."}
>>> +    , {"//net", {"/", "net"}, "/", "", "/", "net", "/", "net"}
>>> +    , {"//net/foo", {"/", "net", "foo"}, "/", "", "/", "net/foo",
>>> "/net", "foo"}
>>> +    , {"///foo///", {"/", "foo", ""}, "/", "", "/", "foo///", "///foo",
>>> ""}
>>>      , {"///foo///bar", {"/", "foo", "bar"}, "/", "", "/", "foo///bar",
>>> "///foo", "bar"}
>>>      , {"/.", {"/", "."}, "/", "", "/", ".", "/", "."}
>>> -    , {"./", {".", "."}, "", "", "", "./", ".", "."}
>>> +    , {"./", {".", ""}, "", "", "", "./", ".", ""}
>>>      , {"/..", {"/", ".."}, "/", "", "/", "..", "/", ".."}
>>> -    , {"../", {"..", "."}, "", "", "", "../", "..", "."}
>>> +    , {"../", {"..", ""}, "", "", "", "../", "..", ""}
>>>      , {"foo/.", {"foo", "."}, "", "", "", "foo/.", "foo", "."}
>>>      , {"foo/..", {"foo", ".."}, "", "", "", "foo/..", "foo", ".."}
>>> -    , {"foo/./", {"foo", ".", "."}, "", "", "", "foo/./", "foo/.", "."}
>>> +    , {"foo/./", {"foo", ".", ""}, "", "", "", "foo/./", "foo/.", ""}
>>>      , {"foo/./bar", {"foo", ".", "bar"}, "", "", "", "foo/./bar",
>>> "foo/.", "bar"}
>>> -    , {"foo/../", {"foo", "..", "."}, "", "", "", "foo/../", "foo/..",
>>> "."}
>>> +    , {"foo/../", {"foo", "..", ""}, "", "", "", "foo/../", "foo/..",
>>> ""}
>>>      , {"foo/../bar", {"foo", "..", "bar"}, "", "", "", "foo/../bar",
>>> "foo/..", "bar"}
>>>      , {"c:", {"c:"}, "", "", "", "c:", "", "c:"}
>>> -    , {"c:/", {"c:", "."}, "", "", "", "c:/", "c:", "."}
>>> +    , {"c:/", {"c:", ""}, "", "", "", "c:/", "c:", ""}
>>>      , {"c:foo", {"c:foo"}, "", "", "", "c:foo", "", "c:foo"}
>>>      , {"c:/foo", {"c:", "foo"}, "", "", "", "c:/foo", "c:", "foo"}
>>> -    , {"c:foo/", {"c:foo", "."}, "", "", "", "c:foo/", "c:foo", "."}
>>> -    , {"c:/foo/", {"c:", "foo", "."}, "", "", "", "c:/foo/",  "c:/foo",
>>> "."}
>>> +    , {"c:foo/", {"c:foo", ""}, "", "", "", "c:foo/", "c:foo", ""}
>>> +    , {"c:/foo/", {"c:", "foo", ""}, "", "", "", "c:/foo/",  "c:/foo",
>>> ""}
>>>      , {"c:/foo/bar", {"c:", "foo", "bar"}, "", "", "", "c:/foo/bar",
>>> "c:/foo", "bar"}
>>>      , {"prn:", {"prn:"}, "", "", "", "prn:", "", "prn:"}
>>>      , {"c:\\", {"c:\\"}, "", "", "", "c:\\", "", "c:\\"}
>>>      , {"c:\\foo", {"c:\\foo"}, "", "", "", "c:\\foo", "", "c:\\foo"}
>>>      , {"c:foo\\", {"c:foo\\"}, "", "", "", "c:foo\\", "", "c:foo\\"}
>>>      , {"c:\\foo\\", {"c:\\foo\\"}, "", "", "", "c:\\foo\\", "",
>>> "c:\\foo\\"}
>>> -    , {"c:\\foo/",  {"c:\\foo", "."}, "", "", "", "c:\\foo/",
>>> "c:\\foo", "."}
>>> +    , {"c:\\foo/",  {"c:\\foo", ""}, "", "", "", "c:\\foo/", "c:\\foo",
>>> ""}
>>>      , {"c:/foo\\bar", {"c:", "foo\\bar"}, "", "", "", "c:/foo\\bar",
>>> "c:", "foo\\bar"}
>>> -    , {"//", {"//"}, "//", "//", "", "", "", "//"}
>>> +    , {"//", {"/"}, "/", "", "/", "", "/", ""}
>>>    };
>>>
>>>  void decompPathTest()
>>>  {
>>>    using namespace fs;
>>>    for (auto const & TC : PathTestCases) {
>>> -    path p(TC.raw);
>>> -    assert(p == TC.raw);
>>> -
>>> -    assert(p.root_path() == TC.root_path);
>>> -    assert(p.has_root_path() !=  TC.root_path.empty());
>>> -
>>> -    assert(p.root_name() == TC.root_name);
>>> -    assert(p.has_root_name() !=  TC.root_name.empty());
>>> -
>>> -    assert(p.root_directory() == TC.root_directory);
>>> -    assert(p.has_root_directory() !=  TC.root_directory.empty());
>>> -
>>> -    assert(p.relative_path() == TC.relative_path);
>>> -    assert(p.has_relative_path() !=  TC.relative_path.empty());
>>> -
>>> -    assert(p.parent_path() == TC.parent_path);
>>> -    assert(p.has_parent_path() !=  TC.parent_path.empty());
>>> -
>>> -    assert(p.filename() == TC.filename);
>>> -    assert(p.has_filename() !=  TC.filename.empty());
>>> -
>>> -    assert(p.is_absolute() == p.has_root_directory());
>>> -    assert(p.is_relative() !=  p.is_absolute());
>>> -
>>> -    assert(checkCollectionsEqual(p.begin(), p.end(),
>>> -                                 TC.elements.begin(),
>>> TC.elements.end()));
>>> +    CHECKPOINT(TC.raw.c_str());
>>> +    fs::path p(TC.raw);
>>> +    ASSERT(p == TC.raw);
>>> +
>>> +    ASSERT_EQ(p.root_path(), TC.root_path);
>>> +    ASSERT_NEQ(p.has_root_path(), TC.root_path.empty());
>>> +
>>> +    ASSERT(p.root_name().native().empty())
>>> +        << DISPLAY(p.root_name());
>>> +    ASSERT_EQ(p.root_name(),TC.root_name);
>>> +    ASSERT_NEQ(p.has_root_name(), TC.root_name.empty());
>>> +
>>> +    ASSERT_EQ(p.root_directory(), TC.root_directory);
>>> +    ASSERT_NEQ(p.has_root_directory(), TC.root_directory.empty());
>>> +
>>> +    ASSERT_EQ(p.relative_path(), TC.relative_path);
>>> +    ASSERT_NEQ(p.has_relative_path(), TC.relative_path.empty());
>>> +
>>> +    ASSERT_EQ(p.parent_path(), TC.parent_path);
>>> +    ASSERT_NEQ(p.has_parent_path(), TC.parent_path.empty());
>>> +
>>> +    ASSERT_EQ(p.filename(), TC.filename);
>>> +    ASSERT_NEQ(p.has_filename(), TC.filename.empty());
>>> +
>>> +    ASSERT_EQ(p.is_absolute(), p.has_root_directory());
>>> +    ASSERT_NEQ(p.is_relative(), p.is_absolute());
>>> +    if (p.empty())
>>> +      ASSERT(p.is_relative());
>>> +
>>> +    ASSERT_COLLECTION_EQ_COMP(
>>> +        p.begin(), p.end(),
>>> +        TC.elements.begin(), TC.elements.end(),
>>> +        ComparePathExact()
>>> +    );
>>>      // check backwards
>>>
>>>      std::vector<fs::path> Parts;
>>>      for (auto it = p.end(); it != p.begin(); )
>>>        Parts.push_back(*--it);
>>> -    assert(checkCollectionsEqual(Parts.begin(), Parts.end(),
>>> -                                 TC.elements.rbegin(),
>>> TC.elements.rend()));
>>> +    ASSERT_COLLECTION_EQ_COMP(Parts.begin(), Parts.end(),
>>> +                                 TC.elements.rbegin(),
>>> TC.elements.rend(),
>>> +                              ComparePathExact());
>>>    }
>>>  }
>>>
>>> @@ -163,10 +180,12 @@ const FilenameDecompTestcase FilenameTes
>>>      {"", "", "", ""}
>>>    , {".", ".", ".", ""}
>>>    , {"..", "..", "..", ""}
>>> -  , {"/", "/", "/", ""}
>>> +  , {"/", "", "", ""}
>>>    , {"foo", "foo", "foo", ""}
>>>    , {"/foo/bar.txt", "bar.txt", "bar", ".txt"}
>>>    , {"foo..txt", "foo..txt", "foo.", ".txt"}
>>> +  , {".profile", ".profile", ".profile", ""}
>>> +  , {".profile.txt", ".profile.txt", ".profile", ".txt"}
>>>  };
>>>
>>>
>>> @@ -174,18 +193,19 @@ void decompFilenameTest()
>>>  {
>>>    using namespace fs;
>>>    for (auto const & TC : FilenameTestCases) {
>>> -    path p(TC.raw);
>>> -    assert(p == TC.raw);
>>> +    CHECKPOINT(TC.raw.c_str());
>>> +    fs::path p(TC.raw);
>>> +    ASSERT_EQ(p, TC.raw);
>>>      ASSERT_NOEXCEPT(p.empty());
>>>
>>> -    assert(p.filename() == TC.filename);
>>> -    assert(p.has_filename() != TC.filename.empty());
>>> +    ASSERT_EQ(p.filename(), TC.filename);
>>> +    ASSERT_NEQ(p.has_filename(), TC.filename.empty());
>>>
>>> -    assert(p.stem() == TC.stem);
>>> -    assert(p.has_stem() != TC.stem.empty());
>>> +    ASSERT_EQ(p.stem(), TC.stem);
>>> +    ASSERT_NEQ(p.has_stem(), TC.stem.empty());
>>>
>>> -    assert(p.extension() == TC.extension);
>>> -    assert(p.has_extension() != TC.extension.empty());
>>> +    ASSERT_EQ(p.extension(), TC.extension);
>>> +    ASSERT_NEQ(p.has_extension(), TC.extension.empty());
>>>    }
>>>  }
>>>
>>>
>>> Added: libcxx/trunk/test/std/experimental/filesystem/class.path/pat
>>> h.member/path.gen/lexically_normal.pass.cpp
>>> URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/ex
>>> perimental/filesystem/class.path/path.member/path.gen/lexica
>>> lly_normal.pass.cpp?rev=329028&view=auto
>>> ============================================================
>>> ==================
>>> --- libcxx/trunk/test/std/experimental/filesystem/class.path/pat
>>> h.member/path.gen/lexically_normal.pass.cpp (added)
>>> +++ libcxx/trunk/test/std/experimental/filesystem/class.path/pat
>>> h.member/path.gen/lexically_normal.pass.cpp Mon Apr  2 16:03:41 2018
>>> @@ -0,0 +1,142 @@
>>> +//===------------------------------------------------------
>>> ----------------===//
>>> +//
>>> +//                     The LLVM Compiler Infrastructure
>>> +//
>>> +// This file is dual licensed under the MIT and the University of
>>> Illinois Open
>>> +// Source Licenses. See LICENSE.TXT for details.
>>> +//
>>> +//===------------------------------------------------------
>>> ----------------===//
>>> +
>>> +// UNSUPPORTED: c++98, c++03
>>> +
>>> +// <experimental/filesystem>
>>> +
>>> +// class path
>>> +
>>> +// path lexically_normal() const;
>>> +
>>> +#include "filesystem_include.hpp"
>>> +#include <type_traits>
>>> +#include <vector>
>>> +#include <iostream>
>>> +#include <cassert>
>>> +
>>> +#include "test_macros.h"
>>> +#include "test_iterators.h"
>>> +#include "count_new.hpp"
>>> +#include "filesystem_test_helper.hpp"
>>> +
>>> +
>>> +int main() {
>>> +  // clang-format off
>>> +  struct {
>>> +    std::string input;
>>> +    std::string expect;
>>> +  } TestCases[] = {
>>> +      {"", ""},
>>> +      {"/a/b/c", "/a/b/c"},
>>> +      {"/a/b//c", "/a/b/c"},
>>> +      {"foo/./bar/..", "foo/"},
>>> +      {"foo/.///bar/../", "foo/"},
>>> +      {"/a/b/", "/a/b/"},
>>> +      {"a/b", "a/b"},
>>> +      {"a/b/.", "a/b/"},
>>> +      {"a/b/./", "a/b/"},
>>> +      {"a/..", "."},
>>> +      {".", "."},
>>> +      {"./", "."},
>>> +      {"./.", "."},
>>> +      {"./..", ".."},
>>> +      {"..", ".."},
>>> +      {"../..", "../.."},
>>> +      {"/../", "/"},
>>> +      {"/../..", "/"},
>>> +      {"/../../", "/"},
>>> +      {"..", ".."},
>>> +      {"../", ".."},
>>> +      {"/a/b/c/../", "/a/b/"},
>>> +      {"/a/b/./", "/a/b/"},
>>> +      {"/a/b/c/../d", "/a/b/d"},
>>> +      {"/a/b/c/../d/", "/a/b/d/"},
>>> +      {"//a/", "/a/"},
>>> +      {"//a/b/", "/a/b/"},
>>> +      {"//a/b/.", "/a/b/"},
>>> +      {"//a/..", "/"},
>>> +      ///===------------------------------------------------------
>>> ---------===//
>>> +      /// Tests specifically for the clauses under [fs.path.generic]p6
>>> +      ///===------------------------------------------------------
>>> ---------===//
>>> +      // p1: If the path is empty, stop.
>>> +      {"", ""},
>>> +      // p2: Replace each slash character in the root-name with a
>>> preferred
>>> +      // separator.
>>> +      {"NO_ROOT_NAME_ON_LINUX", "NO_ROOT_NAME_ON_LINUX"},
>>> +      // p3: Replace each directory-separator with a
>>> preferred-separator.
>>> +      // [ Note: The generic pathname grammar ([fs.path.generic])
>>> defines
>>> +      //   directory-separator as one or more slashes and
>>> preferred-separators.
>>> +      //   — end note ]
>>> +      {"/", "/"},
>>> +      {"//", "/"},
>>> +      {"///", "/"},
>>> +      {"a/b", "a/b"},
>>> +      {"a//b", "a/b"},
>>> +      {"a///b", "a/b"},
>>> +      {"a/b/", "a/b/"},
>>> +      {"a/b//", "a/b/"},
>>> +      {"a/b///", "a/b/"},
>>> +      {"///a////b//////", "/a/b/"},
>>> +      // p4: Remove each dot filename and any immediately following
>>> directory
>>> +      // separators
>>> +      {"foo/.", "foo/"},
>>> +      {"foo/./bar/.", "foo/bar/"},
>>> +      {"./foo/././bar/./", "foo/bar/"},
>>> +      {".///foo//.////./bar/.///", "foo/bar/"},
>>> +      // p5: As long as any appear, remove a non-dot-dot filename
>>> immediately
>>> +      // followed by a directory-separator and a dot-dot filename,
>>> along with
>>> +      // any immediately following directory separator.
>>> +      {"foo/..", "."},
>>> +      {"foo/../", "."},
>>> +      {"foo/bar/..", "foo/"},
>>> +      {"foo/bar/../", "foo/"},
>>> +      {"foo/bar/../..", "."},
>>> +      {"foo/bar/../../", "."},
>>> +      {"foo/bar/baz/../..", "foo/"},
>>> +      {"foo/bar/baz/../../", "foo/"},
>>> +      {"foo/bar/./..", "foo/"},
>>> +      {"foo/bar/./../", "foo/"},
>>> +      // p6: If there is a root-directory, remove all dot-dot filenames
>>> and any
>>> +      // directory-separators immediately following them. [ Note:
>>> These dot-dot
>>> +      // filenames attempt to refer to nonexistent parent directories.
>>> — end note ]
>>> +      {"/..", "/"},
>>> +      {"/../", "/"},
>>> +      {"/foo/../..", "/"},
>>> +      {"/../foo", "/foo"},
>>> +      {"/../foo/../..", "/"},
>>> +      // p7: If the last filename is dot-dot, remove any trailing
>>> +      // directory-separator.
>>> +      {"../", ".."},
>>> +      {"../../", "../.."},
>>> +      {"foo/../bar/../..///", ".."},
>>> +      {"foo/../bar/..//..///../", "../.."},
>>> +      // p8: If the path is empty, add a dot
>>> +      {".", "."},
>>> +      {"./", "."},
>>> +      {"foo/..", "."}
>>> +  };
>>> +  // clang-format on
>>> +  int ID = 0;
>>> +  bool Failed = false;
>>> +  for (auto& TC : TestCases) {
>>> +    ++ID;
>>> +    fs::path p(TC.input);
>>> +    const fs::path output = p.lexically_normal();
>>> +    if (!PathEq(output, TC.expect)) {
>>> +      Failed = true;
>>> +      std::cerr << "TEST CASE #" << ID << " FAILED: \n";
>>> +      std::cerr << "  Input: '" << TC.input << "'\n";
>>> +      std::cerr << "  Expected: '" << TC.expect << "'\n";
>>> +      std::cerr << "  Output: '" << output.native() << "'";
>>> +      std::cerr << std::endl;
>>> +    }
>>> +  }
>>> +  return Failed;
>>> +}
>>>
>>> Added: libcxx/trunk/test/std/experimental/filesystem/class.path/pat
>>> h.member/path.gen/lexically_relative_and_proximate.pass.cpp
>>> URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/ex
>>> perimental/filesystem/class.path/path.member/path.gen/lexica
>>> lly_relative_and_proximate.pass.cpp?rev=329028&view=auto
>>> ============================================================
>>> ==================
>>> --- libcxx/trunk/test/std/experimental/filesystem/class.path/pat
>>> h.member/path.gen/lexically_relative_and_proximate.pass.cpp (added)
>>> +++ libcxx/trunk/test/std/experimental/filesystem/class.path/pat
>>> h.member/path.gen/lexically_relative_and_proximate.pass.cpp Mon Apr  2
>>> 16:03:41 2018
>>> @@ -0,0 +1,89 @@
>>> +//===------------------------------------------------------
>>> ----------------===//
>>> +//
>>> +//                     The LLVM Compiler Infrastructure
>>> +//
>>> +// This file is dual licensed under the MIT and the University of
>>> Illinois Open
>>> +// Source Licenses. See LICENSE.TXT for details.
>>> +//
>>> +//===------------------------------------------------------
>>> ----------------===//
>>> +
>>> +// UNSUPPORTED: c++98, c++03
>>> +
>>> +// <experimental/filesystem>
>>> +
>>> +// class path
>>> +
>>> +// path lexically_relative(const path& p) const;
>>> +// path lexically_proximate(const path& p) const;
>>> +
>>> +#include "filesystem_include.hpp"
>>> +#include <type_traits>
>>> +#include <vector>
>>> +#include <iostream>
>>> +#include <cassert>
>>> +
>>> +#include "test_macros.h"
>>> +#include "test_iterators.h"
>>> +#include "count_new.hpp"
>>> +#include "filesystem_test_helper.hpp"
>>> +
>>> +
>>> +int main() {
>>> +  // clang-format off
>>> +  struct {
>>> +    std::string input;
>>> +    std::string base;
>>> +    std::string expect;
>>> +  } TestCases[] = {
>>> +      {"", "", "."},
>>> +      {"/", "a", ""},
>>> +      {"a", "/", ""},
>>> +      {"//net", "a", ""},
>>> +      {"a", "//net", ""},
>>> +      {"//net/", "//net", ""},
>>> +      {"//net", "//net/", ".."},
>>> +      {"//base", "a", ""},
>>> +      {"a", "a", "."},
>>> +      {"a/b", "a/b", "."},
>>> +      {"a/b/c/", "a/b/c/", "."},
>>> +      {"//net", "//net", "."},
>>> +      {"//net/", "//net/", "."},
>>> +      {"//net/a/b", "//net/a/b", "."},
>>> +      {"/a/d", "/a/b/c", "../../d"},
>>> +      {"/a/b/c", "/a/d", "../b/c"},
>>> +      {"a/b/c", "a", "b/c"},
>>> +      {"a/b/c", "a/b/c/x/y", "../.."},
>>> +      {"a/b/c", "a/b/c", "."},
>>> +      {"a/b", "c/d", "../../a/b"}
>>> +  };
>>> +  // clang-format on
>>> +  int ID = 0;
>>> +  bool Failed = false;
>>> +  for (auto& TC : TestCases) {
>>> +    ++ID;
>>> +    const fs::path p(TC.input);
>>> +    const fs::path output = p.lexically_relative(TC.base);
>>> +    auto ReportErr = [&](const char* Testing, fs::path const& Output,
>>> +                                              fs::path const& Expected)
>>> {
>>> +      Failed = true;
>>> +      std::cerr << "TEST CASE #" << ID << " FAILED: \n";
>>> +      std::cerr << "  Testing: " << Testing << "\n";
>>> +      std::cerr << "  Input: '" << TC.input << "'\n";
>>> +      std::cerr << "  Base: '" << TC.base << "'\n";
>>> +      std::cerr << "  Expected: '" << Expected << "'\n";
>>> +      std::cerr << "  Output: '" << Output.native() << "'";
>>> +      std::cerr << std::endl;
>>> +    };
>>> +    if (!PathEq(output, TC.expect))
>>> +      ReportErr("path::lexically_relative", output, TC.expect);
>>> +    const fs::path proximate_output = p.lexically_proximate(TC.base);
>>> +    // [path.gen] lexically_proximate
>>> +    // Returns: If the value of lexically_relative(base) is not an
>>> empty path,
>>> +    // return it.Otherwise return *this.
>>> +    const fs::path proximate_expected = output.native().empty() ? p
>>> +        : output;
>>> +    if (!PathEq(proximate_expected, proximate_output))
>>> +      ReportErr("path::lexically_proximate", proximate_output,
>>> proximate_expected);
>>> +  }
>>> +  return Failed;
>>> +}
>>>
>>> Modified: libcxx/trunk/test/std/experimental/filesystem/class.path/pat
>>> h.member/path.generic.obs/generic_string_alloc.pass.cpp
>>> URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/ex
>>> perimental/filesystem/class.path/path.member/path.generic.ob
>>> s/generic_string_alloc.pass.cpp?rev=329028&r1=329027&r2=329028&view=diff
>>> ============================================================
>>> ==================
>>> --- libcxx/trunk/test/std/experimental/filesystem/class.path/pat
>>> h.member/path.generic.obs/generic_string_alloc.pass.cpp (original)
>>> +++ libcxx/trunk/test/std/experimental/filesystem/class.path/pat
>>> h.member/path.generic.obs/generic_string_alloc.pass.cpp Mon Apr  2
>>> 16:03:41 2018
>>> @@ -28,7 +28,6 @@
>>>  #include "min_allocator.h"
>>>  #include "filesystem_test_helper.hpp"
>>>
>>> -
>>>  MultiStringType longString = MKSTR("abcdefghijklmnopqrstuvw
>>> xyzABCDEFGHIJKLMNOPQRSTUVWXYZ/123456789/abcdefghijklmnopqrst
>>> uvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzAB
>>> CDEFGHIJKLMNOPQRSTUVWXYZ");
>>>
>>>
>>>
>>> Modified: libcxx/trunk/test/std/experimental/filesystem/class.path/pat
>>> h.member/path.generic.obs/named_overloads.pass.cpp
>>> URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/ex
>>> perimental/filesystem/class.path/path.member/path.generic.ob
>>> s/named_overloads.pass.cpp?rev=329028&r1=329027&r2=329028&view=diff
>>> ============================================================
>>> ==================
>>> --- libcxx/trunk/test/std/experimental/filesystem/class.path/pat
>>> h.member/path.generic.obs/named_overloads.pass.cpp (original)
>>> +++ libcxx/trunk/test/std/experimental/filesystem/class.path/pat
>>> h.member/path.generic.obs/named_overloads.pass.cpp Mon Apr  2 16:03:41
>>> 2018
>>> @@ -30,7 +30,6 @@
>>>  #include "min_allocator.h"
>>>  #include "filesystem_test_helper.hpp"
>>>
>>> -
>>>  MultiStringType longString = MKSTR("abcdefghijklmnopqrstuvw
>>> xyzABCDEFGHIJKLMNOPQRSTUVWXYZ/123456789/abcdefghijklmnopqrst
>>> uvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzAB
>>> CDEFGHIJKLMNOPQRSTUVWXYZ");
>>>
>>>  int main()
>>>
>>> Modified: libcxx/trunk/test/std/experimental/filesystem/class.path/pat
>>> h.member/path.modifiers/remove_filename.pass.cpp
>>> URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/ex
>>> perimental/filesystem/class.path/path.member/path.modifiers/
>>> remove_filename.pass.cpp?rev=329028&r1=329027&r2=329028&view=diff
>>> ============================================================
>>> ==================
>>> --- libcxx/trunk/test/std/experimental/filesystem/class.path/pat
>>> h.member/path.modifiers/remove_filename.pass.cpp (original)
>>> +++ libcxx/trunk/test/std/experimental/filesystem/class.path/pat
>>> h.member/path.modifiers/remove_filename.pass.cpp Mon Apr  2 16:03:41
>>> 2018
>>> @@ -23,7 +23,7 @@
>>>  #include "test_iterators.h"
>>>  #include "count_new.hpp"
>>>  #include "filesystem_test_helper.hpp"
>>> -
>>> +#include "verbose_assert.h"
>>>
>>>  struct RemoveFilenameTestcase {
>>>    const char* value;
>>> @@ -33,27 +33,29 @@ struct RemoveFilenameTestcase {
>>>  const RemoveFilenameTestcase TestCases[] =
>>>    {
>>>        {"", ""}
>>> -    , {"/", ""}
>>> -    , {"//", ""}
>>> -    , {"///", ""}
>>> +    , {"/", "/"}
>>> +    , {"//", "//"}
>>> +    , {"///", "///"}
>>>      , {"\\", ""}
>>>      , {".", ""}
>>>      , {"..", ""}
>>>      , {"/foo", "/"}
>>> -    , {"//foo", ""}
>>> -    , {"//foo/", ""}
>>> -    , {"//foo///", ""}
>>> -    , {"///foo", "/"}
>>> -    , {"///foo/", "///foo"}
>>> -    , {"/foo/", "/foo"}
>>> -    , {"/foo/.", "/foo"}
>>> -    , {"/foo/..", "/foo"}
>>> -    , {"/foo/////", "/foo"}
>>> +    , {"foo/bar", "foo/"}
>>> +    , {"foo/", "foo/"}
>>> +    , {"//foo", "//"}
>>> +    , {"//foo/", "//foo/"}
>>> +    , {"//foo///", "//foo///"}
>>> +    , {"///foo", "///"}
>>> +    , {"///foo/", "///foo/"}
>>> +    , {"/foo/", "/foo/"}
>>> +    , {"/foo/.", "/foo/"}
>>> +    , {"/foo/..", "/foo/"}
>>> +    , {"/foo/////", "/foo/////"}
>>>      , {"/foo\\\\", "/"}
>>> -    , {"/foo//\\/", "/foo//\\"}
>>> -    , {"///foo", "/"}
>>> +    , {"/foo//\\/", "/foo//\\/"}
>>> +    , {"///foo", "///"}
>>>      , {"file.txt", ""}
>>> -    , {"bar/../baz/./file.txt", "bar/../baz/."}
>>> +    , {"bar/../baz/./file.txt", "bar/../baz/./"}
>>>    };
>>>
>>>  int main()
>>> @@ -64,16 +66,8 @@ int main()
>>>      path p(p_orig);
>>>      assert(p == TC.value);
>>>      path& Ref = (p.remove_filename());
>>> -    assert(p == TC.expect);
>>> +    ASSERT_EQ(p, TC.expect) << DISPLAY(p_orig);
>>>      assert(&Ref == &p);
>>> -    {
>>> -      const path parentp = p_orig.parent_path();
>>> -      if (parentp == p_orig.root_name()) {
>>> -
>>> -        assert(p.empty());
>>> -      } else {
>>> -        assert(p == parentp);
>>> -      }
>>> -    }
>>> +    assert(!p.has_filename());
>>>    }
>>>  }
>>>
>>> Modified: libcxx/trunk/test/std/experimental/filesystem/class.path/pat
>>> h.member/path.modifiers/replace_filename.pass.cpp
>>> URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/ex
>>> perimental/filesystem/class.path/path.member/path.modifiers/
>>> replace_filename.pass.cpp?rev=329028&r1=329027&r2=329028&view=diff
>>> ============================================================
>>> ==================
>>> --- libcxx/trunk/test/std/experimental/filesystem/class.path/pat
>>> h.member/path.modifiers/replace_filename.pass.cpp (original)
>>> +++ libcxx/trunk/test/std/experimental/filesystem/class.path/pat
>>> h.member/path.modifiers/replace_filename.pass.cpp Mon Apr  2 16:03:41
>>> 2018
>>> @@ -23,7 +23,8 @@
>>>  #include "test_iterators.h"
>>>  #include "count_new.hpp"
>>>  #include "filesystem_test_helper.hpp"
>>> -
>>> +#include "assert_checkpoint.h"
>>> +#include "verbose_assert.h"
>>>
>>>  struct ReplaceFilenameTestcase {
>>>    const char* value;
>>> @@ -36,9 +37,9 @@ const ReplaceFilenameTestcase TestCases[
>>>        {"/foo", "/bar", "bar"}
>>>      , {"/foo", "/", ""}
>>>      , {"foo", "bar", "bar"}
>>> -    , {"/", "bar", "bar"}
>>> +    , {"/", "/bar", "bar"}
>>>      , {"\\", "bar", "bar"}
>>> -    , {"///", "bar", "bar"}
>>> +    , {"///", "///bar", "bar"}
>>>      , {"\\\\", "bar", "bar"}
>>>      , {"\\/\\", "\\/bar", "bar"}
>>>      , {".", "bar", "bar"}
>>> @@ -52,9 +53,11 @@ int main()
>>>    using namespace fs;
>>>    for (auto const & TC : TestCases) {
>>>      path p(TC.value);
>>> -    assert(p == TC.value);
>>> +    ASSERT_EQ(p, TC.value);
>>>      path& Ref = (p.replace_filename(TC.filename));
>>> -    assert(p == TC.expect);
>>> +    ASSERT_EQ(p, TC.expect)
>>> +        << DISPLAY(TC.value)
>>> +        << DISPLAY(TC.filename);
>>>      assert(&Ref == &p);
>>>      // Tests Effects "as-if": remove_filename() append(filename)
>>>      {
>>> @@ -62,7 +65,7 @@ int main()
>>>        path replace(TC.filename);
>>>        p2.remove_filename();
>>>        p2 /= replace;
>>> -      assert(p2 == p);
>>> +      ASSERT_EQ(p, p2);
>>>      }
>>>    }
>>>  }
>>>
>>> Added: libcxx/trunk/test/std/experimental/filesystem/fs.enum/enum.p
>>> erm_options.pass.cpp
>>> URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/ex
>>> perimental/filesystem/fs.enum/enum.perm_options.pass.cpp?rev
>>> =329028&view=auto
>>> ============================================================
>>> ==================
>>> --- libcxx/trunk/test/std/experimental/filesystem/fs.enum/enum.perm_options.pass.cpp
>>> (added)
>>> +++ libcxx/trunk/test/std/experimental/filesystem/fs.enum/enum.perm_options.pass.cpp
>>> Mon Apr  2 16:03:41 2018
>>> @@ -0,0 +1,48 @@
>>> +//===------------------------------------------------------
>>> ----------------===//
>>> +//
>>> +//                     The LLVM Compiler Infrastructure
>>> +//
>>> +// This file is dual licensed under the MIT and the University of
>>> Illinois Open
>>> +// Source Licenses. See LICENSE.TXT for details.
>>> +//
>>> +//===------------------------------------------------------
>>> ----------------===//
>>> +
>>> +// UNSUPPORTED: c++98, c++03
>>> +
>>> +// <experimental/filesystem>
>>> +
>>> +// enum class perm_options;
>>> +
>>> +#include "filesystem_include.hpp"
>>> +#include <type_traits>
>>> +#include <cassert>
>>> +#include <sys/stat.h>
>>> +
>>> +#include "test_macros.h"
>>> +#include "check_bitmask_types.hpp"
>>> +
>>> +
>>> +constexpr fs::perm_options ME(int val) {
>>> +  return static_cast<fs::perm_options>(val);
>>> +}
>>> +
>>> +int main() {
>>> +  typedef fs::perm_options E;
>>> +  static_assert(std::is_enum<E>::value, "");
>>> +
>>> +  // Check that E is a scoped enum by checking for conversions.
>>> +  typedef std::underlying_type<E>::type UT;
>>> +  static_assert(!std::is_convertible<E, UT>::value, "");
>>> +
>>> +  static_assert(std::is_same<UT, unsigned char >::value, ""); //
>>> Implementation detail
>>> +
>>> +  typedef check_bitmask_type<E, E::replace, E::nofollow> BitmaskTester;
>>> +  assert(BitmaskTester::check());
>>> +
>>> +  static_assert(
>>> +        E::replace  == ME(1) &&
>>> +        E::add      == ME(2) &&
>>> +        E::remove   == ME(4) &&
>>> +        E::nofollow == ME(8),
>>> +        "Expected enumeration values do not match");
>>> +}
>>>
>>> Modified: libcxx/trunk/test/std/experimental/filesystem/fs.op.funcs/fs
>>> .op.absolute/absolute.pass.cpp
>>> URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/ex
>>> perimental/filesystem/fs.op.funcs/fs.op.absolute/absolute.pa
>>> ss.cpp?rev=329028&r1=329027&r2=329028&view=diff
>>> ============================================================
>>> ==================
>>> --- libcxx/trunk/test/std/experimental/filesystem/fs.op.funcs/fs.op.absolute/absolute.pass.cpp
>>> (original)
>>> +++ libcxx/trunk/test/std/experimental/filesystem/fs.op.funcs/fs.op.absolute/absolute.pass.cpp
>>> Mon Apr  2 16:03:41 2018
>>> @@ -28,89 +28,30 @@ TEST_SUITE(filesystem_absolute_path_test
>>>  TEST_CASE(absolute_signature_test)
>>>  {
>>>      const path p; ((void)p);
>>> +    std::error_code ec;
>>>      ASSERT_NOT_NOEXCEPT(absolute(p));
>>> -    ASSERT_NOT_NOEXCEPT(absolute(p, p));
>>> +    ASSERT_NOT_NOEXCEPT(absolute(p, ec));
>>>  }
>>>
>>> -// There are 4 cases is the proposal for absolute path.
>>> -// Each scope tests one of the cases.
>>> -TEST_CASE(absolute_path_test)
>>> -{
>>> -    // has_root_name() && has_root_directory()
>>> -    {
>>> -        const path p("//net/foo");
>>> -        const path base("//net/bar/baz");
>>> -        TEST_REQUIRE(p.has_root_name());
>>> -        TEST_REQUIRE(p.has_root_directory());
>>> -        TEST_CHECK(p.is_absolute());
>>> -        path ret = absolute(p, base);
>>> -        TEST_CHECK(ret.is_absolute());
>>> -        TEST_CHECK(ret == p);
>>> -    }
>>> -    // !has_root_name() && has_root_directory()
>>> -    {
>>> -        const path p("/foo");
>>> -        const path base("//net/bar");
>>> -        TEST_REQUIRE(not p.has_root_name());
>>> -        TEST_REQUIRE(p.has_root_directory());
>>> -        TEST_CHECK(p.is_absolute());
>>> -        // ensure absolute(base) is not recursively called
>>> -        TEST_REQUIRE(base.has_root_name());
>>> -        TEST_REQUIRE(base.has_root_directory());
>>> -
>>> -        path ret = absolute(p, base);
>>> -        TEST_CHECK(ret.is_absolute());
>>> -        TEST_CHECK(ret.has_root_name());
>>> -        TEST_CHECK(ret.root_name() == path("//net"));
>>> -        TEST_CHECK(ret.has_root_directory());
>>> -        TEST_CHECK(ret.root_directory() == path("/"));
>>> -        TEST_CHECK(ret == path("//net/foo"));
>>> -    }
>>> -    // has_root_name() && !has_root_directory()
>>> -    {
>>> -        const path p("//net");
>>> -        const path base("//net/foo/bar");
>>> -        TEST_REQUIRE(p.has_root_name());
>>> -        TEST_REQUIRE(not p.has_root_directory());
>>> -        TEST_CHECK(not p.is_absolute());
>>> -        // absolute is called recursively on base. The following
>>> conditions
>>> -        // must be true for it to return base unmodified
>>> -        TEST_REQUIRE(base.has_root_name());
>>> -        TEST_REQUIRE(base.has_root_directory());
>>> -        path ret = absolute(p, base);
>>> -        const path expect("//net/foo/bar");
>>> -        TEST_CHECK(ret.is_absolute());
>>> -        TEST_CHECK(ret == path("//net/foo/bar"));
>>> -    }
>>> -    // !has_root_name() && !has_root_directory()
>>> -    {
>>> -        const path p("bar/baz");
>>> -        const path base("//net/foo");
>>> -        TEST_REQUIRE(not p.has_root_name());
>>> -        TEST_REQUIRE(not p.has_root_directory());
>>> -        TEST_REQUIRE(base.has_root_name());
>>> -        TEST_REQUIRE(base.has_root_directory());
>>> -
>>> -        path ret = absolute(p, base);
>>> -        TEST_CHECK(ret.is_absolute());
>>> -        TEST_CHECK(ret == path("//net/foo/bar/baz"));
>>> -    }
>>> -}
>>>
>>> -TEST_CASE(absolute_path_with_default_base)
>>> +TEST_CASE(basic_test)
>>>  {
>>> -    const path testCases[] = {
>>> -        "//net/foo", //  has_root_name() &&  has_root_directory()
>>> -        "/foo",      // !has_root_name() &&  has_root_directory()
>>> -        "//net",     //  has_root_name() && !has_root_directory()
>>> -        "bar/baz"    // !has_root_name() && !has_root_directory()
>>> +    const fs::path cwd = fs::current_path();
>>> +    const struct {
>>> +      std::string input;
>>> +      std::string expect;
>>> +    } TestCases [] = {
>>> +        {"", cwd / ""},
>>> +        {"foo", cwd / "foo"},
>>> +        {"foo/", cwd / "foo/"},
>>> +        {"/already_absolute", "/already_absolute"}
>>>      };
>>> -    const path base = current_path();
>>> -    for (auto& p : testCases) {
>>> -        const path ret = absolute(p);
>>> -        const path expect = absolute(p, base);
>>> +    for (auto& TC : TestCases) {
>>> +        std::error_code ec = GetTestEC();
>>> +        const path ret = absolute(TC.input, ec);
>>> +        TEST_CHECK(!ec);
>>>          TEST_CHECK(ret.is_absolute());
>>> -        TEST_CHECK(ret == expect);
>>> +        TEST_CHECK(PathEq(ret, TC.expect));
>>>      }
>>>  }
>>>
>>>
>>> Modified: libcxx/trunk/test/std/experimental/filesystem/fs.op.funcs/fs
>>> .op.canonical/canonical.pass.cpp
>>> URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/ex
>>> perimental/filesystem/fs.op.funcs/fs.op.canonical/canonical.
>>> pass.cpp?rev=329028&r1=329027&r2=329028&view=diff
>>> ============================================================
>>> ==================
>>> --- libcxx/trunk/test/std/experimental/filesystem/fs.op.funcs/fs
>>> .op.canonical/canonical.pass.cpp (original)
>>> +++ libcxx/trunk/test/std/experimental/filesystem/fs.op.funcs/fs
>>> .op.canonical/canonical.pass.cpp Mon Apr  2 16:03:41 2018
>>> @@ -11,9 +11,8 @@
>>>
>>>  // <experimental/filesystem>
>>>
>>> -// 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);
>>>
>>>  #include "filesystem_include.hpp"
>>>  #include <type_traits>
>>> @@ -25,6 +24,15 @@
>>>
>>>  using namespace fs;
>>>
>>> +struct CWDGuard {
>>> +  path OldCWD;
>>> +  CWDGuard() : OldCWD(fs::current_path()) { }
>>> +  ~CWDGuard() { fs::current_path(OldCWD); }
>>> +
>>> +  CWDGuard(CWDGuard const&) = delete;
>>> +  CWDGuard& operator=(CWDGuard const&) = delete;
>>> +};
>>> +
>>>  TEST_SUITE(filesystem_canonical_path_test_suite)
>>>
>>>  TEST_CASE(signature_test)
>>> @@ -32,15 +40,14 @@ TEST_CASE(signature_test)
>>>      const path p; ((void)p);
>>>      std::error_code ec; ((void)ec);
>>>      ASSERT_NOT_NOEXCEPT(canonical(p));
>>> -    ASSERT_NOT_NOEXCEPT(canonical(p, p));
>>>      ASSERT_NOT_NOEXCEPT(canonical(p, ec));
>>> -    ASSERT_NOT_NOEXCEPT(canonical(p, p, ec));
>>>  }
>>>
>>>  // There are 4 cases is the proposal for absolute path.
>>>  // Each scope tests one of the cases.
>>>  TEST_CASE(test_canonical)
>>>  {
>>> +    CWDGuard guard;
>>>      // has_root_name() && has_root_directory()
>>>      const path Root = StaticEnv::Root;
>>>      const path RootName = Root.filename();
>>> @@ -65,54 +72,51 @@ TEST_CASE(test_canonical)
>>>          { SymlinkName, StaticEnv::File, StaticEnv::Root}
>>>      };
>>>      for (auto& TC : testCases) {
>>> -        std::error_code ec;
>>> -        const path ret = canonical(TC.p, TC.base, ec);
>>> +        std::error_code ec = GetTestEC();
>>> +        fs::current_path(TC.base);
>>> +        const path ret = canonical(TC.p, ec);
>>>          TEST_REQUIRE(!ec);
>>> -        const path ret2 = canonical(TC.p, TC.base);
>>> -        TEST_CHECK(ret == TC.expect);
>>> -        TEST_CHECK(ret == ret2);
>>> +        const path ret2 = canonical(TC.p);
>>> +        TEST_CHECK(PathEq(ret, TC.expect));
>>> +        TEST_CHECK(PathEq(ret, ret2));
>>>          TEST_CHECK(ret.is_absolute());
>>>      }
>>>  }
>>>
>>>  TEST_CASE(test_dne_path)
>>>  {
>>> -    std::error_code ec;
>>> +    std::error_code ec = GetTestEC();
>>>      {
>>>          const path ret = canonical(StaticEnv::DNE, ec);
>>> -        TEST_REQUIRE(ec);
>>> -        TEST_CHECK(ret == path{});
>>> -    }
>>> -    ec.clear();
>>> -    {
>>> -        const path ret = canonical(StaticEnv::DNE, StaticEnv::Root, ec);
>>> +        TEST_CHECK(ec != GetTestEC());
>>>          TEST_REQUIRE(ec);
>>>          TEST_CHECK(ret == path{});
>>>      }
>>>      {
>>>          TEST_CHECK_THROW(filesystem_error, canonical(StaticEnv::DNE));
>>> -        TEST_CHECK_THROW(filesystem_error, canonical(StaticEnv::DNE,
>>> StaticEnv::Root));
>>>      }
>>>  }
>>>
>>>  TEST_CASE(test_exception_contains_paths)
>>>  {
>>>  #ifndef TEST_HAS_NO_EXCEPTIONS
>>> +    CWDGuard guard;
>>>      const path p = "blabla/dne";
>>> -    const path base = StaticEnv::Root;
>>>      try {
>>> -        canonical(p, base);
>>> +        canonical(p);
>>>          TEST_REQUIRE(false);
>>>      } catch (filesystem_error const& err) {
>>>          TEST_CHECK(err.path1() == p);
>>> -        TEST_CHECK(err.path2() == base);
>>> +        // libc++ provides the current path as the second path in the
>>> exception
>>> +        LIBCPP_ONLY(TEST_CHECK(err.path2() == current_path()));
>>>      }
>>> +    fs::current_path(StaticEnv::Dir);
>>>      try {
>>>          canonical(p);
>>>          TEST_REQUIRE(false);
>>>      } catch (filesystem_error const& err) {
>>>          TEST_CHECK(err.path1() == p);
>>> -        TEST_CHECK(err.path2() == current_path());
>>> +        LIBCPP_ONLY(TEST_CHECK(err.path2() == StaticEnv::Dir));
>>>      }
>>>  #endif
>>>  }
>>>
>>> Modified: libcxx/trunk/test/std/experimental/filesystem/fs.op.funcs/fs
>>> .op.last_write_time/last_write_time.pass.cpp
>>> URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/ex
>>> perimental/filesystem/fs.op.funcs/fs.op.last_write_time/last
>>> _write_time.pass.cpp?rev=329028&r1=329027&r2=329028&view=diff
>>> ============================================================
>>> ==================
>>> --- libcxx/trunk/test/std/experimental/filesystem/fs.op.funcs/fs
>>> .op.last_write_time/last_write_time.pass.cpp (original)
>>> +++ libcxx/trunk/test/std/experimental/filesystem/fs.op.funcs/fs
>>> .op.last_write_time/last_write_time.pass.cpp Mon Apr  2 16:03:41 2018
>>> @@ -17,7 +17,6 @@
>>>  // void last_write_time(const path& p, file_time_type new_type,
>>>  //                      std::error_code& ec) noexcept;
>>>
>>> -
>>>  #include "filesystem_include.hpp"
>>>  #include <type_traits>
>>>  #include <chrono>
>>> @@ -33,7 +32,6 @@
>>>
>>>  using namespace fs;
>>>
>>> -
>>>  std::pair<std::time_t, std::time_t> GetTimes(path const& p) {
>>>      using Clock = file_time_type::clock;
>>>      struct ::stat st;
>>>
>>> Added: libcxx/trunk/test/std/experimental/filesystem/fs.op.funcs/fs
>>> .op.proximate/proximate.pass.cpp
>>> URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/ex
>>> perimental/filesystem/fs.op.funcs/fs.op.proximate/proximate.
>>> pass.cpp?rev=329028&view=auto
>>> ============================================================
>>> ==================
>>> --- libcxx/trunk/test/std/experimental/filesystem/fs.op.funcs/fs
>>> .op.proximate/proximate.pass.cpp (added)
>>> +++ libcxx/trunk/test/std/experimental/filesystem/fs.op.funcs/fs
>>> .op.proximate/proximate.pass.cpp Mon Apr  2 16:03:41 2018
>>> @@ -0,0 +1,125 @@
>>> +//===------------------------------------------------------
>>> ----------------===//
>>> +//
>>> +//                     The LLVM Compiler Infrastructure
>>> +//
>>> +// This file is dual licensed under the MIT and the University of
>>> Illinois Open
>>> +// Source Licenses. See LICENSE.TXT for details.
>>> +//
>>> +//===------------------------------------------------------
>>> ----------------===//
>>> +
>>> +// UNSUPPORTED: c++98, c++03
>>> +
>>> +// <experimental/filesystem>
>>> +
>>> +// 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);
>>> +
>>> +#include "filesystem_include.hpp"
>>> +#include <type_traits>
>>> +#include <vector>
>>> +#include <iostream>
>>> +#include <cassert>
>>> +
>>> +#include "test_macros.h"
>>> +#include "test_iterators.h"
>>> +#include "count_new.hpp"
>>> +#include "rapid-cxx-test.hpp"
>>> +#include "filesystem_test_helper.hpp"
>>> +
>>> +
>>> +static int count_path_elems(const fs::path& p) {
>>> +  int count = 0;
>>> +  for (auto& elem : p) {
>>> +    if (elem != "/" && elem != "")
>>> +      ++count;
>>> +  }
>>> +  return count;
>>> +}
>>> +
>>> +TEST_SUITE(filesystem_proximate_path_test_suite)
>>> +
>>> +
>>> +TEST_CASE(signature_test)
>>> +{
>>> +    using fs::path;
>>> +    const path p; ((void)p);
>>> +    std::error_code ec; ((void)ec);
>>> +    ASSERT_NOT_NOEXCEPT(proximate(p));
>>> +    ASSERT_NOT_NOEXCEPT(proximate(p, p));
>>> +    ASSERT_NOT_NOEXCEPT(proximate(p, ec));
>>> +    ASSERT_NOT_NOEXCEPT(proximate(p, p, ec));
>>> +}
>>> +
>>> +TEST_CASE(basic_test) {
>>> +  using fs::path;
>>> +  const path cwd = fs::current_path();
>>> +  const path parent_cwd = cwd.parent_path();
>>> +  const path curdir = cwd.filename();
>>> +  TEST_REQUIRE(!cwd.native().empty());
>>> +  int cwd_depth = count_path_elems(cwd);
>>> +  path dot_dot_to_root;
>>> +  for (int i=0; i < cwd_depth; ++i)
>>> +    dot_dot_to_root /= "..";
>>> +  path relative_cwd = cwd.native().substr(1);
>>> +  // clang-format off
>>> +  struct {
>>> +    std::string input;
>>> +    std::string base;
>>> +    std::string expect;
>>> +  } TestCases[] = {
>>> +      {"", "", "."},
>>> +      {cwd, "a", ".."},
>>> +      {parent_cwd, "a", "../.."},
>>> +      {"a", cwd, "a"},
>>> +      {"a", parent_cwd, "fs.op.proximate/a"},
>>> +      {"/", "a", dot_dot_to_root / ".."},
>>> +      {"/", "a/b", dot_dot_to_root / "../.."},
>>> +      {"/", "a/b/", dot_dot_to_root / "../../.."},
>>> +      {"a", "/", relative_cwd / "a"},
>>> +      {"a/b", "/", relative_cwd / "a/b"},
>>> +      {"a", "/net", ".." / relative_cwd / "a"},
>>> +      {"//net/", "//net", "/net/"},
>>> +      {"//net", "//net/", ".."},
>>> +      {"//net", "//net", "."},
>>> +      {"//net/", "//net/", "."},
>>> +      {"//base", "a", dot_dot_to_root / "../base"},
>>> +      {"a", "a", "."},
>>> +      {"a/b", "a/b", "."},
>>> +      {"a/b/c/", "a/b/c/", "."},
>>> +      {"//net/a/b", "//net/a/b", "."},
>>> +      {"/a/d", "/a/b/c", "../../d"},
>>> +      {"/a/b/c", "/a/d", "../b/c"},
>>> +      {"a/b/c", "a", "b/c"},
>>> +      {"a/b/c", "a/b/c/x/y", "../.."},
>>> +      {"a/b/c", "a/b/c", "."},
>>> +      {"a/b", "c/d", "../../a/b"}
>>> +  };
>>> +  // clang-format on
>>> +  int ID = 0;
>>> +  for (auto& TC : TestCases) {
>>> +    ++ID;
>>> +    std::error_code ec = GetTestEC();
>>> +    fs::path p(TC.input);
>>> +    const fs::path output = fs::proximate(p, TC.base, ec);
>>> +    TEST_CHECK(!ec);
>>> +    TEST_CHECK(PathEq(output, TC.expect));
>>> +    if (!PathEq(output, TC.expect)) {
>>> +      const path canon_input = fs::weakly_canonical(TC.input);
>>> +      const path canon_base = fs::weakly_canonical(TC.base);
>>> +      const path lexically_p = canon_input.lexically_proximat
>>> e(canon_base);
>>> +      std::cerr << "TEST CASE #" << ID << " FAILED: \n";
>>> +      std::cerr << "  Input: '" << TC.input << "'\n";
>>> +      std::cerr << "  Base: '" << TC.base << "'\n";
>>> +      std::cerr << "  Expected: '" << TC.expect << "'\n";
>>> +      std::cerr << "  Output:   '" << output.native() << "'\n";
>>> +      std::cerr << "  Lex Prox: '" << lexically_p.native() << "'\n";
>>> +      std::cerr << "  Canon Input: " <<  canon_input << "\n";
>>> +      std::cerr << "  Canon Base: " << canon_base << "\n";
>>> +
>>> +      std::cerr << std::endl;
>>> +    }
>>> +  }
>>> +}
>>> +
>>> +TEST_SUITE_END()
>>>
>>> Added: libcxx/trunk/test/std/experimental/filesystem/fs.op.funcs/fs
>>> .op.relative/relative.pass.cpp
>>> URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/ex
>>> perimental/filesystem/fs.op.funcs/fs.op.relative/relative.pa
>>> ss.cpp?rev=329028&view=auto
>>> ============================================================
>>> ==================
>>> --- libcxx/trunk/test/std/experimental/filesystem/fs.op.funcs/fs.op.relative/relative.pass.cpp
>>> (added)
>>> +++ libcxx/trunk/test/std/experimental/filesystem/fs.op.funcs/fs.op.relative/relative.pass.cpp
>>> Mon Apr  2 16:03:41 2018
>>> @@ -0,0 +1,78 @@
>>> +//===------------------------------------------------------
>>> ----------------===//
>>> +//
>>> +//                     The LLVM Compiler Infrastructure
>>> +//
>>> +// This file is dual licensed under the MIT and the University of
>>> Illinois Open
>>> +// Source Licenses. See LICENSE.TXT for details.
>>> +//
>>> +//===------------------------------------------------------
>>> ----------------===//
>>> +
>>> +// UNSUPPORTED: c++98, c++03
>>> +
>>> +// <experimental/filesystem>
>>> +
>>> +// 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);
>>> +
>>> +#include "filesystem_include.hpp"
>>> +#include <type_traits>
>>> +#include <vector>
>>> +#include <iostream>
>>> +#include <cassert>
>>> +
>>> +#include "test_macros.h"
>>> +#include "test_iterators.h"
>>> +#include "count_new.hpp"
>>> +#include "rapid-cxx-test.hpp"
>>> +#include "filesystem_test_helper.hpp"
>>> +
>>> +
>>> +TEST_SUITE(filesystem_proximate_path_test_suite)
>>> +
>>> +TEST_CASE(test_signature) {
>>> +
>>> +}
>>> +int main() {
>>> +  // clang-format off
>>> +  struct {
>>> +    std::string input;
>>> +    std::string expect;
>>> +  } TestCases[] = {
>>> +      {"", fs::current_path()},
>>> +      {".", fs::current_path()},
>>> +      {StaticEnv::File, StaticEnv::File},
>>> +      {StaticEnv::Dir, StaticEnv::Dir},
>>> +      {StaticEnv::SymlinkToDir, StaticEnv::Dir},
>>> +      {StaticEnv::SymlinkToDir / "dir2/.", StaticEnv::Dir / "dir2"},
>>> +      // FIXME? If the trailing separator occurs in a part of the path
>>> that exists,
>>> +      // it is ommitted. Otherwise it is added to the end of the result.
>>> +      {StaticEnv::SymlinkToDir / "dir2/./", StaticEnv::Dir / "dir2"},
>>> +      {StaticEnv::SymlinkToDir / "dir2/DNE/./", StaticEnv::Dir /
>>> "dir2/DNE/"},
>>> +      {StaticEnv::SymlinkToDir / "dir2", StaticEnv::Dir2},
>>> +      {StaticEnv::SymlinkToDir / "dir2/../dir2/DNE/..", StaticEnv::Dir2
>>> / ""},
>>> +      {StaticEnv::SymlinkToDir / "dir2/dir3/../DNE/DNE2",
>>> StaticEnv::Dir2 / "DNE/DNE2"},
>>> +      {StaticEnv::Dir / "../dir1", StaticEnv::Dir},
>>> +      {StaticEnv::Dir / "./.", StaticEnv::Dir},
>>> +      {StaticEnv::Dir / "DNE/../foo", StaticEnv::Dir / "foo"}
>>> +  };
>>> +  // clang-format on
>>> +  int ID = 0;
>>> +  bool Failed = false;
>>> +  for (auto& TC : TestCases) {
>>> +    ++ID;
>>> +    fs::path p(TC.input);
>>> +    const fs::path output = fs::weakly_canonical(p);
>>> +    if (output != TC.expect) {
>>> +      Failed = true;
>>> +      std::cerr << "TEST CASE #" << ID << " FAILED: \n";
>>> +      std::cerr << "  Input: '" << TC.input << "'\n";
>>> +      std::cerr << "  Expected: '" << TC.expect << "'\n";
>>> +      std::cerr << "  Output: '" << output.native() << "'";
>>> +      std::cerr << std::endl;
>>> +    }
>>> +  }
>>> +  return Failed;
>>> +}
>>> +
>>> +TEST_SUITE_END()
>>>
>>> Removed: libcxx/trunk/test/std/experimental/filesystem/fs.op.funcs/fs
>>> .op.system_complete/system_complete.pass.cpp
>>> URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/ex
>>> perimental/filesystem/fs.op.funcs/fs.op.system_complete/syst
>>> em_complete.pass.cpp?rev=329027&view=auto
>>> ============================================================
>>> ==================
>>> --- libcxx/trunk/test/std/experimental/filesystem/fs.op.funcs/fs
>>> .op.system_complete/system_complete.pass.cpp (original)
>>> +++ libcxx/trunk/test/std/experimental/filesystem/fs.op.funcs/fs
>>> .op.system_complete/system_complete.pass.cpp (removed)
>>> @@ -1,58 +0,0 @@
>>> -//===------------------------------------------------------
>>> ----------------===//
>>> -//
>>> -//                     The LLVM Compiler Infrastructure
>>> -//
>>> -// This file is dual licensed under the MIT and the University of
>>> Illinois Open
>>> -// Source Licenses. See LICENSE.TXT for details.
>>> -//
>>> -//===------------------------------------------------------
>>> ----------------===//
>>> -
>>> -// UNSUPPORTED: c++98, c++03
>>> -
>>> -// <experimental/filesystem>
>>> -
>>> -// path system_complete(const path& p);
>>> -// path system_complete(const path& p, error_code& ec);
>>> -
>>> -// Note: For POSIX based operating systems, 'system_complete(p)' has the
>>> -// same semantics as 'absolute(p, current_path())'.
>>> -
>>> -#include "filesystem_include.hpp"
>>> -#include <type_traits>
>>> -#include <cassert>
>>> -
>>> -#include "test_macros.h"
>>> -#include "rapid-cxx-test.hpp"
>>> -#include "filesystem_test_helper.hpp"
>>> -
>>> -using namespace fs;
>>> -
>>> -TEST_SUITE(filesystem_system_complete_test_suite)
>>> -
>>> -TEST_CASE(signature_test)
>>> -{
>>> -    const path p; ((void)p);
>>> -    std::error_code ec; ((void)ec);
>>> -    ASSERT_NOT_NOEXCEPT(system_complete(p));
>>> -    ASSERT_NOT_NOEXCEPT(system_complete(p, ec));
>>> -}
>>> -
>>> -
>>> -TEST_CASE(basic_system_complete_tests)
>>> -{
>>> -    const path testCases[] = {
>>> -        "//net/foo", //  has_root_name() &&  has_root_directory()
>>> -        "/foo",      // !has_root_name() &&  has_root_directory()
>>> -        "//net",     //  has_root_name() && !has_root_directory()
>>> -        "bar/baz"    // !has_root_name() && !has_root_directory()
>>> -    };
>>> -    const path base = current_path();
>>> -    for (auto& p : testCases) {
>>> -        const path ret = system_complete(p);
>>> -        const path expect = absolute(p, base);
>>> -        TEST_CHECK(ret.is_absolute());
>>> -        TEST_CHECK(ret == expect);
>>> -    }
>>> -}
>>> -
>>> -TEST_SUITE_END()
>>>
>>> Added: libcxx/trunk/test/std/experimental/filesystem/fs.op.funcs/fs
>>> .op.weakly_canonical/weakly_canonical.pass.cpp
>>> URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/ex
>>> perimental/filesystem/fs.op.funcs/fs.op.weakly_canonical/wea
>>> kly_canonical.pass.cpp?rev=329028&view=auto
>>> ============================================================
>>> ==================
>>> --- libcxx/trunk/test/std/experimental/filesystem/fs.op.funcs/fs
>>> .op.weakly_canonical/weakly_canonical.pass.cpp (added)
>>> +++ libcxx/trunk/test/std/experimental/filesystem/fs.op.funcs/fs
>>> .op.weakly_canonical/weakly_canonical.pass.cpp Mon Apr  2 16:03:41 2018
>>> @@ -0,0 +1,76 @@
>>> +//===------------------------------------------------------
>>> ----------------===//
>>> +//
>>> +//                     The LLVM Compiler Infrastructure
>>> +//
>>> +// This file is dual licensed under the MIT and the University of
>>> Illinois Open
>>> +// Source Licenses. See LICENSE.TXT for details.
>>> +//
>>> +//===------------------------------------------------------
>>> ----------------===//
>>> +
>>> +// UNSUPPORTED: c++98, c++03
>>> +
>>> +// <experimental/filesystem>
>>> +
>>> +// path weakly_canonical(const path& p);
>>> +// path weakly_canonical(const path& p, error_code& ec);
>>> +
>>> +#include "filesystem_include.hpp"
>>> +#include <type_traits>
>>> +#include <vector>
>>> +#include <iostream>
>>> +#include <cassert>
>>> +
>>> +#include "test_macros.h"
>>> +#include "test_iterators.h"
>>> +#include "count_new.hpp"
>>> +#include "filesystem_test_helper.hpp"
>>> +
>>> +
>>> +int main() {
>>> +  // clang-format off
>>> +  struct {
>>> +    std::string input;
>>> +    std::string expect;
>>> +  } TestCases[] = {
>>> +      {"", fs::current_path()},
>>> +      {".", fs::current_path()},
>>> +      {"/", "/"},
>>> +      {"/foo", "/foo"},
>>> +      {"/.", "/"},
>>> +      {"/./", "/"},
>>> +      {"a/b", fs::current_path() / "a/b"},
>>> +      {"a", fs::current_path() / "a"},
>>> +      {"a/b/", fs::current_path() / "a/b/"},
>>> +      {StaticEnv::File, StaticEnv::File},
>>> +      {StaticEnv::Dir, StaticEnv::Dir},
>>> +      {StaticEnv::SymlinkToDir, StaticEnv::Dir},
>>> +      {StaticEnv::SymlinkToDir / "dir2/.", StaticEnv::Dir / "dir2"},
>>> +      // FIXME? If the trailing separator occurs in a part of the path
>>> that exists,
>>> +      // it is ommitted. Otherwise it is added to the end of the result.
>>> +      {StaticEnv::SymlinkToDir / "dir2/./", StaticEnv::Dir / "dir2"},
>>> +      {StaticEnv::SymlinkToDir / "dir2/DNE/./", StaticEnv::Dir /
>>> "dir2/DNE/"},
>>> +      {StaticEnv::SymlinkToDir / "dir2", StaticEnv::Dir2},
>>> +      {StaticEnv::SymlinkToDir / "dir2/../dir2/DNE/..", StaticEnv::Dir2
>>> / ""},
>>> +      {StaticEnv::SymlinkToDir / "dir2/dir3/../DNE/DNE2",
>>> StaticEnv::Dir2 / "DNE/DNE2"},
>>> +      {StaticEnv::Dir / "../dir1", StaticEnv::Dir},
>>> +      {StaticEnv::Dir / "./.", StaticEnv::Dir},
>>> +      {StaticEnv::Dir / "DNE/../foo", StaticEnv::Dir / "foo"}
>>> +  };
>>> +  // clang-format on
>>> +  int ID = 0;
>>> +  bool Failed = false;
>>> +  for (auto& TC : TestCases) {
>>> +    ++ID;
>>> +    fs::path p(TC.input);
>>> +    const fs::path output = fs::weakly_canonical(p);
>>> +    if (!PathEq(output, TC.expect)) {
>>> +      Failed = true;
>>> +      std::cerr << "TEST CASE #" << ID << " FAILED: \n";
>>> +      std::cerr << "  Input: '" << TC.input << "'\n";
>>> +      std::cerr << "  Expected: '" << TC.expect << "'\n";
>>> +      std::cerr << "  Output: '" << output.native() << "'";
>>> +      std::cerr << std::endl;
>>> +    }
>>> +  }
>>> +  return Failed;
>>> +}
>>>
>>> Modified: libcxx/trunk/test/support/filesystem_test_helper.hpp
>>> URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/suppor
>>> t/filesystem_test_helper.hpp?rev=329028&r1=329027&r2=329028&view=diff
>>> ============================================================
>>> ==================
>>> --- libcxx/trunk/test/support/filesystem_test_helper.hpp (original)
>>> +++ libcxx/trunk/test/support/filesystem_test_helper.hpp Mon Apr  2
>>> 16:03:41 2018
>>> @@ -9,7 +9,6 @@
>>>  #include <random>
>>>  #include <chrono>
>>>
>>> -
>>>  // static test helpers
>>>
>>>  #ifndef LIBCXX_FILESYSTEM_STATIC_TEST_ROOT
>>> @@ -400,4 +399,8 @@ void SleepFor(std::chrono::seconds dur)
>>>          ;
>>>  }
>>>
>>> +inline bool PathEq(fs::path const& LHS, fs::path const& RHS) {
>>> +  return LHS.native() == RHS.native();
>>> +}
>>> +
>>>  #endif /* FILESYSTEM_TEST_HELPER_HPP */
>>>
>>> Added: libcxx/trunk/test/support/verbose_assert.h
>>> URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/suppor
>>> t/verbose_assert.h?rev=329028&view=auto
>>> ============================================================
>>> ==================
>>> --- libcxx/trunk/test/support/verbose_assert.h (added)
>>> +++ libcxx/trunk/test/support/verbose_assert.h Mon Apr  2 16:03:41 2018
>>> @@ -0,0 +1,222 @@
>>> +#ifndef TEST_SUPPORT_VERBOSE_ASSERT
>>> +#define TEST_SUPPORT_VERBOSE_ASSERT
>>> +
>>> +#include <iostream>
>>> +#include <cstdio>
>>> +#include <sstream>
>>> +#include <string>
>>> +#include "test_macros.h"
>>> +
>>> +namespace verbose_assert {
>>> +
>>> +typedef std::basic_ostream<char>&(EndLType)(std::basic_ostream<char>&);
>>> +
>>> +template <class Stream, class Tp,
>>> +    class = decltype(std::declval<Stream&>() << std::declval<Tp
>>> const&>())>
>>> +std::true_type IsStreamableImp(int);
>>> +template <class Stream, class Tp> std::false_type IsStreamableImp(long);
>>> +
>>> +template <class Stream, class Tp>
>>> +struct IsStreamable : decltype(IsStreamableImp<Stream, Tp>(0)) {};
>>> +
>>> +template <class Tp, int ST = (IsStreamable<decltype(std::cerr),
>>> Tp>::value ? 1
>>> +        : (IsStreamable<decltype(std::wcerr), Tp>::value ? 2 : -1))>
>>> +struct SelectStream {
>>> +  static_assert(ST == -1, "specialization required for ST != -1");
>>> +  static void Print(Tp const&) { std::clog << "Value Not
>>> Streamable!\n"; }
>>> +};
>>> +
>>> +template <class Tp>
>>> +struct SelectStream<Tp, 1> {
>>> +  static void Print(Tp const& val) { std::cerr << val; }
>>> +};
>>> +
>>> +template <class Tp>
>>> +struct SelectStream<Tp, 2> {
>>> +  static void Print(Tp const& val) { std::wcerr << val; }
>>> +};
>>> +
>>> +struct AssertData {
>>> +  AssertData(const char* xcheck, const char* xfile, const char* xfunc,
>>> +             unsigned long xline, bool xpassed = true)
>>> +      : passed(xpassed), check(xcheck), file(xfile), func(xfunc),
>>> line(xline),
>>> +        msg() {}
>>> +
>>> +  AssertData& SetFailed(std::string xmsg = std::string()) {
>>> +    msg = xmsg;
>>> +    passed = false;
>>> +    return *this;
>>> +  }
>>> +
>>> +  void PrintFailed() const {
>>> +    std::fprintf(stderr, "%s:%lu %s: Assertion '%s' failed.\n", file,
>>> line,
>>> +                 func, check);
>>> +    if (!msg.empty())
>>> +      std::fprintf(stderr, "%s\n", msg.data());
>>> +  }
>>> +
>>> +  bool passed;
>>> +  const char* check;
>>> +  const char* file;
>>> +  const char* func;
>>> +  unsigned long line;
>>> +  std::string msg;
>>> +};
>>> +
>>> +// AssertHandler is the class constructed by failing CHECK macros.
>>> AssertHandler
>>> +// will log information about the failures and abort when it is
>>> destructed.
>>> +class AssertHandler {
>>> +public:
>>> +  AssertHandler(AssertData const& Data)
>>> +      : passed(Data.passed) {
>>> +    if (!passed)
>>> +      Data.PrintFailed();
>>> +  }
>>> +
>>> +  ~AssertHandler() TEST_NOEXCEPT_FALSE {
>>> +    if (!passed) {
>>> +      error_log << std::endl;
>>> +      std::abort();
>>> +    }
>>> +  }
>>> +
>>> +  class LogType {
>>> +    friend class AssertHandler;
>>> +
>>> +    template <class Tp>
>>> +    friend LogType& operator<<(LogType& log, Tp const& value) {
>>> +      if (!log.is_disabled) {
>>> +        SelectStream<Tp>::Print(value);
>>> +      }
>>> +      return log;
>>> +    }
>>> +
>>> +    friend LogType& operator<<(LogType& log, EndLType* m) {
>>> +      if (!log.is_disabled) {
>>> +        SelectStream<EndLType*>::Print(m);
>>> +      }
>>> +      return log;
>>> +    }
>>> +
>>> +  private:
>>> +    LogType(bool disable) : is_disabled(disable) {}
>>> +    bool is_disabled;
>>> +
>>> +    LogType(LogType const&);
>>> +    LogType& operator=(LogType const&);
>>> +  };
>>> +
>>> +  LogType& GetLog() {
>>> +    if (passed)
>>> +      return null_log;
>>> +    return error_log;
>>> +  }
>>> +
>>> +private:
>>> +  static LogType null_log;
>>> +  static LogType error_log;
>>> +
>>> +  AssertHandler& operator=(const AssertHandler&) = delete;
>>> +  AssertHandler(const AssertHandler&) = delete;
>>> +  AssertHandler() = delete;
>>> +
>>> +private:
>>> +  bool passed;
>>> +};
>>> +
>>> +AssertHandler::LogType AssertHandler::null_log(true);
>>> +AssertHandler::LogType AssertHandler::error_log(false);
>>> +
>>> +template <class It1>
>>> +std::string PrintRange(const char* Name, It1 F, It1 E) {
>>> +  std::stringstream ss;
>>> +  ss << "  " << Name << " = [";
>>> +  while (F != E) {
>>> +    ss << *F;
>>> +    ++F;
>>> +    if (F != E)
>>> +      ss << ", ";
>>> +  }
>>> +  ss << "]\n";
>>> +  return ss.str();
>>> +}
>>> +
>>> +template <class Tp, class Up>
>>> +std::string PrintMismatch(Tp const& LHS, Up const& RHS, int Elem) {
>>> +  std::stringstream ss;
>>> +  ss << "  Element " << Elem << " mismatched: `" << LHS << "` != `" <<
>>> RHS
>>> +     << "`!\n";
>>> +  return ss.str();
>>> +};
>>> +
>>> +struct EqualToComp {
>>> +  template <class Tp, class Up>
>>> +  bool operator()(Tp const& LHS, Up const& RHS) const {
>>> +    return LHS == RHS;
>>> +  }
>>> +};
>>> +
>>> +template <class It1, class It2, class Comp>
>>> +AssertData CheckCollectionsEqual(It1 F1, It1 E1, It2 F2, It2 E2,
>>> +                                 AssertData Data, Comp C =
>>> EqualToComp()) {
>>> +  const It1 F1Orig = F1;
>>> +  const It2 F2Orig = F2;
>>> +  bool Failed = false;
>>> +  std::string ErrorMsg;
>>> +  int Idx = 0;
>>> +  while (F1 != E1 && F2 != E2) {
>>> +    if (!(C(*F1, *F2))) {
>>> +      ErrorMsg += PrintMismatch(*F1, *F2, Idx);
>>> +      Failed = true;
>>> +      break;
>>> +    }
>>> +    ++Idx;
>>> +    ++F1;
>>> +    ++F2;
>>> +  }
>>> +  if (!Failed && (F1 != E1 || F2 != E2)) {
>>> +    ErrorMsg += "  Ranges have different sizes!\n";
>>> +    Failed = true;
>>> +  }
>>> +  if (Failed) {
>>> +    ErrorMsg += PrintRange("LHS", F1Orig, E1);
>>> +    ErrorMsg += PrintRange("RHS", F2Orig, E2);
>>> +    Data.SetFailed(ErrorMsg);
>>> +  }
>>> +  return Data;
>>> +}
>>> +} // namespace verbose_assert
>>> +
>>> +#ifdef __GNUC__
>>> +#define ASSERT_FN_NAME() __PRETTY_FUNCTION__
>>> +#else
>>> +#define ASSERT_FN_NAME() __func__
>>> +#endif
>>> +
>>> +#define DISPLAY(...) "    " #__VA_ARGS__ " = " << (__VA_ARGS__) << "\n"
>>> +
>>> +#define ASSERT(...)
>>>         \
>>> +  ::verbose_assert::AssertHandler(::verbose_assert::AssertData(
>>>         \
>>> +    #__VA_ARGS__, __FILE__, ASSERT_FN_NAME(),
>>> __LINE__,(__VA_ARGS__))).GetLog()
>>> +
>>> +#define ASSERT_EQ(LHS, RHS) \
>>> +  ASSERT(LHS == RHS) << DISPLAY(LHS) << DISPLAY(RHS)
>>> +#define ASSERT_NEQ(LHS, RHS) \
>>> +  ASSERT(LHS != RHS) << DISPLAY(LHS) << DISPLAY(RHS)
>>> +#define ASSERT_PRED(PRED, LHS, RHS) \
>>> +  ASSERT(PRED(LHS, RHS)) << DISPLAY(LHS) << DISPLAY(RHS)
>>> +
>>> +#define ASSERT_COLLECTION_EQ_COMP(F1, E1, F2, E2, Comp)
>>>         \
>>> +  (::verbose_assert::AssertHandler(
>>>         \
>>> +       ::verbose_assert::CheckCollectionsEqual(
>>>         \
>>> +           F1, E1, F2, E2,
>>>        \
>>> +           ::verbose_assert::AssertData("CheckCollectionsEqual(" #F1
>>> ", " #E1  \
>>> +                                        ", " #F2 ", " #E2 ")",
>>>        \
>>> +                                        __FILE__, ASSERT_FN_NAME(),
>>> __LINE__), \
>>> +           Comp))
>>>         \
>>> +       .GetLog())
>>> +
>>> +#define ASSERT_COLLECTION_EQ(F1, E1, F2, E2)
>>>        \
>>> +  ASSERT_COLLECTION_EQ_COMP(F1, E1, F2, E2,
>>> ::verbose_assert::EqualToComp())
>>> +
>>> +#endif
>>>
>>> Modified: libcxx/trunk/www/cxx1z_status.html
>>> URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/www/cxx1z_s
>>> tatus.html?rev=329028&r1=329027&r2=329028&view=diff
>>> ============================================================
>>> ==================
>>> --- libcxx/trunk/www/cxx1z_status.html (original)
>>> +++ libcxx/trunk/www/cxx1z_status.html Mon Apr  2 16:03:41 2018
>>> @@ -111,7 +111,7 @@
>>>         <tr><td><a href="https://wg21.link/p0180r2
>>> ">p0180r2</a></td><td>LWG</td><td>Reserve a New Library Namespace for
>>> Future Standardization</td><td>Oulu</td><td><i>Nothing to
>>> do</i></td><td>n/a</td></tr>
>>>         <tr><td><a href="https://wg21.link/p0181r1
>>> ">p0181r1</a></td><td>LWG</td><td>Ordered by
>>> Default</td><td>Oulu</td><td><i>Removed in
>>> Kona</i></td><td>n/a</td></tr>
>>>         <tr><td><a href="https://wg21.link/p0209r2
>>> ">p0209r2</a></td><td>LWG</td><td>make_from_tuple: apply for
>>> construction</td><td>Oulu</td><td>Complete</td><td>3.9</td></tr>
>>> -       <tr><td><a href="https://wg21.link/p0219r1
>>> ">p0219r1</a></td><td>LWG</td><td>Relative Paths for
>>> Filesystem</td><td>Oulu</td><td></td><td></td></tr>
>>> +       <tr><td><a href="https://wg21.link/p0219r1
>>> ">p0219r1</a></td><td>LWG</td><td>Relative Paths for
>>> Filesystem</td><td>Oulu</td><td>Complete</td><td>7.0</td></tr>
>>>         <tr><td><a href="https://wg21.link/p0254r2
>>> ">p0254r2</a></td><td>LWG</td><td>Integrating std::string_view and
>>> std::string</td><td>Oulu</td><td>Complete</td><td>4.0</td></tr>
>>>         <tr><td><a href="https://wg21.link/p0258r2
>>> ">p0258r2</a></td><td>LWG</td><td>has_unique_object_represe
>>> ntations</td><td>Oulu</td><td>Complete</td><td>6.0</td></tr>
>>>         <tr><td><a href="https://wg21.link/p0295r0
>>> ">p0295r0</a></td><td>LWG</td><td>Adopt Selected Library Fundamentals
>>> V2 Components for C++17</td><td>Oulu</td><td>Com
>>> plete</td><td>4.0</td></tr>
>>> @@ -153,7 +153,7 @@
>>>         <tr><td><a href="https://wg21.link/P0433R2
>>> ">P0433R2</a></td><td>LWG</td><td>Toward a resolution of US7 and US14:
>>> Integrating template deduction for class templates into the standard
>>> library</td><td>Kona</td><td><i>In progress</i></td><td>7.0</td></tr>
>>>         <tr><td><a href="https://wg21.link/P0452R1
>>> ">P0452R1</a></td><td>LWG</td><td>Unifying <numeric> Parallel
>>> Algorithms</td><td>Kona</td><td></td><td></td></tr>
>>>         <tr><td><a href="https://wg21.link/P0467R2
>>> ">P0467R2</a></td><td>LWG</td><td>Iterator Concerns for Parallel
>>> Algorithms</td><td>Kona</td><td></td><td></td></tr>
>>> -       <tr><td><a href="https://wg21.link/P0492R2
>>> ">P0492R2</a></td><td>LWG</td><td>Proposed Resolution of C++17 National
>>> Body Comments for Filesystems</td><td>Kona</td><td></td><td></td></tr>
>>> +       <tr><td><a href="https://wg21.link/P0492R2
>>> ">P0492R2</a></td><td>LWG</td><td>Proposed Resolution of C++17 National
>>> Body Comments for Filesystems</td><td>Kona</td><
>>> td>Complete</td><td>7.0</td></tr>
>>>         <tr><td><a href="https://wg21.link/P0518R1
>>> ">P0518R1</a></td><td>LWG</td><td>Allowing copies as arguments to
>>> function objects given to parallel algorithms in response to
>>> CH11</td><td>Kona</td><td></td><td></td></tr>
>>>         <tr><td><a href="https://wg21.link/P0523R1
>>> ">P0523R1</a></td><td>LWG</td><td>Wording for CH 10: Complexity of
>>> parallel algorithms</td><td>Kona</td><td></td><td></td></tr>
>>>         <tr><td><a href="https://wg21.link/P0548R1
>>> ">P0548R1</a></td><td>LWG</td><td>common_type and
>>> duration</td><td>Kona</td><td>Complete</td><td>5.0</td></tr>
>>>
>>> Modified: libcxx/trunk/www/cxx2a_status.html
>>> URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/www/cxx2a_s
>>> tatus.html?rev=329028&r1=329027&r2=329028&view=diff
>>> ============================================================
>>> ==================
>>> --- libcxx/trunk/www/cxx2a_status.html (original)
>>> +++ libcxx/trunk/www/cxx2a_status.html Mon Apr  2 16:03:41 2018
>>> @@ -164,7 +164,7 @@
>>>         <tr><td><a href="https://wg21.link/LWG3015
>>> ">3015</a></td><td><tt>copy_options::<i>unspecified</i></tt>
>>> underspecified</td><td>Jacksonville</td><td><i>Nothing to
>>> do</i></td></tr>
>>>         <tr><td><a href="https://wg21.link/LWG3017">3017</a></td><td><tt>list
>>> splice</tt> functions should use <tt>addressof</tt></td><td>Jac
>>> ksonville</td><td></td></tr>
>>>         <tr><td><a href="https://wg21.link/LWG3020
>>> ">3020</a></td><td>[networking.ts] Remove spurious nested
>>> <tt>value_type</tt> buffer sequence requirement</td><td>Jacksonvil
>>> le</td><td></td></tr>
>>> -       <tr><td><a href="https://wg21.link/LWG3026
>>> ">3026</a></td><td><tt>filesystem::weakly_canonical</tt> still defined
>>> in terms of <tt>canonical(p, base)</tt></td><td>Jacksonvill
>>> e</td><td></td></tr>
>>> +       <tr><td><a href="https://wg21.link/LWG3026
>>> ">3026</a></td><td><tt>filesystem::weakly_canonical</tt> still defined
>>> in terms of <tt>canonical(p, base)</tt></td><td>Jacksonvill
>>> e</td><td>Complete</td></tr>
>>>         <tr><td><a href="https://wg21.link/LWG3030">3030</a></td><td>Who
>>> shall meet the requirements of <tt>try_lock</tt>?</td><td>Jacksonville</td><td><i>Nothing
>>> to do</i></td></tr>
>>>         <tr><td><a href="https://wg21.link/LWG3034">3034</a></td><td>P0767R1
>>> breaks previously-standard-layout types</td><td>Jacksonville</td
>>> ><td>Complete</td></tr>
>>>         <tr><td><a href="https://wg21.link/LWG3035
>>> ">3035</a></td><td><tt>std::allocator</tt>'s constructors should be
>>> <tt>constexpr</tt></td><td>Jacksonville</td><td>Complete</td></tr>
>>>
>>>
>>> _______________________________________________
>>> cfe-commits mailing list
>>> cfe-commits at lists.llvm.org
>>> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
>>>
>>
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20180402/33a1fdf2/attachment-0001.html>


More information about the cfe-commits mailing list