[libcxx] r329028 - Implement filesystem NB comments, relative paths, and related issues.
Eric Fiselier via cfe-commits
cfe-commits at lists.llvm.org
Mon Apr 2 19:48:06 PDT 2018
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/
>> path.member/path.gen/
>> libcxx/trunk/test/std/experimental/filesystem/class.path/
>> path.member/path.gen/lexically_normal.pass.cpp
>> libcxx/trunk/test/std/experimental/filesystem/class.path/
>> path.member/path.gen/lexically_relative_and_proximate.pass.cpp
>> libcxx/trunk/test/std/experimental/filesystem/fs.enum/enum.
>> perm_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/
>> path.itr/iterator.pass.cpp
>> libcxx/trunk/test/std/experimental/filesystem/class.path/
>> path.member/path.append.pass.cpp
>> libcxx/trunk/test/std/experimental/filesystem/class.path/
>> path.member/path.compare.pass.cpp
>> libcxx/trunk/test/std/experimental/filesystem/class.path/
>> path.member/path.decompose/empty.fail.cpp
>> libcxx/trunk/test/std/experimental/filesystem/class.path/
>> path.member/path.decompose/path.decompose.pass.cpp
>> libcxx/trunk/test/std/experimental/filesystem/class.path/
>> path.member/path.generic.obs/generic_string_alloc.pass.cpp
>> libcxx/trunk/test/std/experimental/filesystem/class.path/
>> path.member/path.generic.obs/named_overloads.pass.cpp
>> libcxx/trunk/test/std/experimental/filesystem/class.path/
>> path.member/path.modifiers/remove_filename.pass.cpp
>> libcxx/trunk/test/std/experimental/filesystem/class.path/
>> path.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/
>> path.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/
>> path.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/
>> path.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/
>> path.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/
>> path.member/path.decompose/empty.fail.cpp (original)
>> +++ libcxx/trunk/test/std/experimental/filesystem/class.path/
>> path.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/
>> path.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/
>> path.member/path.decompose/path.decompose.pass.cpp (original)
>> +++ libcxx/trunk/test/std/experimental/filesystem/class.path/
>> path.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/
>> path.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/
>> path.member/path.gen/lexically_normal.pass.cpp (added)
>> +++ libcxx/trunk/test/std/experimental/filesystem/class.path/
>> path.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/
>> path.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/
>> path.member/path.gen/lexically_relative_and_proximate.pass.cpp (added)
>> +++ libcxx/trunk/test/std/experimental/filesystem/class.path/
>> path.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/
>> path.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/
>> path.member/path.generic.obs/generic_string_alloc.pass.cpp (original)
>> +++ libcxx/trunk/test/std/experimental/filesystem/class.path/
>> path.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/
>> path.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/
>> path.member/path.generic.obs/named_overloads.pass.cpp (original)
>> +++ libcxx/trunk/test/std/experimental/filesystem/class.path/
>> path.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/
>> path.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/
>> path.member/path.modifiers/remove_filename.pass.cpp (original)
>> +++ libcxx/trunk/test/std/experimental/filesystem/class.path/
>> path.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/
>> path.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/
>> path.member/path.modifiers/replace_filename.pass.cpp (original)
>> +++ libcxx/trunk/test/std/experimental/filesystem/class.path/
>> path.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.
>> perm_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_
>> status.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_repre
>> sentations</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>Complete</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_
>> status.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/a7d0dc36/attachment-0001.html>
More information about the cfe-commits
mailing list