[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 16:03:41 PDT 2018
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}/benchmark-libcxx)
set(BENCHMARK_NATIVE_INSTALL ${CMAKE_CURRENT_BINARY_DIR}/benchmark-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/experimental/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_canonical(__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_canonical(__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/experimental/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/experimental/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/experimental/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/experimental/filesystem/class.path/path.member/path.append.pass.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/experimental/filesystem/class.path/path.member/path.compare.pass.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/experimental/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/experimental/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/experimental/filesystem/class.path/path.member/path.gen/lexically_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/experimental/filesystem/class.path/path.member/path.gen/lexically_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/experimental/filesystem/class.path/path.member/path.generic.obs/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("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ/123456789/abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
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/experimental/filesystem/class.path/path.member/path.generic.obs/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("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ/123456789/abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
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/experimental/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/experimental/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/experimental/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/experimental/filesystem/fs.op.funcs/fs.op.absolute/absolute.pass.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/experimental/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/experimental/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/experimental/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_proximate(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/experimental/filesystem/fs.op.funcs/fs.op.relative/relative.pass.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/experimental/filesystem/fs.op.funcs/fs.op.system_complete/system_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/experimental/filesystem/fs.op.funcs/fs.op.weakly_canonical/weakly_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/support/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/support/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_representations</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>Jacksonville</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>Jacksonville</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>Jacksonville</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>Jacksonville</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>
More information about the cfe-commits
mailing list