summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorPatrick Wildt <patrick@cvs.openbsd.org>2016-09-03 18:39:34 +0000
committerPatrick Wildt <patrick@cvs.openbsd.org>2016-09-03 18:39:34 +0000
commitf71d91379a2e46d52c257bc9f3c903d9e20764ea (patch)
treec27ae9c7fa2525156cd88ace1d0ea280341b21f1 /lib
parentb8010d56f684d16e3dcba9149692ea0e118e9406 (diff)
Import libc++ 3.9.0
Diffstat (limited to 'lib')
-rw-r--r--lib/libcxx/src/experimental/filesystem/directory_iterator.cpp148
-rw-r--r--lib/libcxx/src/experimental/filesystem/operations.cpp184
-rw-r--r--lib/libcxx/src/experimental/filesystem/path.cpp557
3 files changed, 366 insertions, 523 deletions
diff --git a/lib/libcxx/src/experimental/filesystem/directory_iterator.cpp b/lib/libcxx/src/experimental/filesystem/directory_iterator.cpp
index a552fdc4461..fa217ba7a12 100644
--- a/lib/libcxx/src/experimental/filesystem/directory_iterator.cpp
+++ b/lib/libcxx/src/experimental/filesystem/directory_iterator.cpp
@@ -1,32 +1,28 @@
-//===------------------ directory_iterator.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 "__config"
-#if defined(_LIBCPP_WIN32API)
-#define WIN32_LEAN_AND_MEAN
-#include <Windows.h>
-#else
#include <dirent.h>
-#endif
#include <errno.h>
_LIBCPP_BEGIN_NAMESPACE_EXPERIMENTAL_FILESYSTEM
namespace { namespace detail {
-#if !defined(_LIBCPP_WIN32API)
inline error_code capture_errno() {
_LIBCPP_ASSERT(errno, "Expected errno to be non-zero");
return error_code{errno, std::generic_category()};
}
-#endif
+
+template <class ...Args>
+inline bool capture_error_or_throw(std::error_code* user_ec,
+ const char* msg, Args&&... args)
+{
+ std::error_code my_ec = capture_errno();
+ if (user_ec) {
+ *user_ec = my_ec;
+ return true;
+ }
+ __libcpp_throw(filesystem_error(msg, std::forward<Args>(args)..., my_ec));
+ return false;
+}
template <class ...Args>
inline bool set_or_throw(std::error_code& my_ec,
@@ -37,91 +33,29 @@ inline bool set_or_throw(std::error_code& my_ec,
*user_ec = my_ec;
return true;
}
- __throw_filesystem_error(msg, std::forward<Args>(args)..., my_ec);
+ __libcpp_throw(filesystem_error(msg, std::forward<Args>(args)..., my_ec));
return false;
}
-#if !defined(_LIBCPP_WIN32API)
-inline path::string_type posix_readdir(DIR *dir_stream, error_code& ec) {
+typedef path::string_type string_type;
+
+
+inline string_type posix_readdir(DIR *dir_stream, error_code& ec) {
struct dirent* dir_entry_ptr = nullptr;
errno = 0; // zero errno in order to detect errors
- ec.clear();
if ((dir_entry_ptr = ::readdir(dir_stream)) == nullptr) {
- if (errno)
- ec = capture_errno();
+ ec = capture_errno();
return {};
} else {
+ ec.clear();
return dir_entry_ptr->d_name;
}
}
-#endif
}} // namespace detail
using detail::set_or_throw;
-#if defined(_LIBCPP_WIN32API)
-class __dir_stream {
-public:
- __dir_stream() = delete;
- __dir_stream& operator=(const __dir_stream&) = delete;
-
- __dir_stream(__dir_stream&& __ds) noexcept
- : __stream_(__ds.__stream_), __root_(std::move(__ds.__root_)),
- __entry_(std::move(__ds.__entry_)) {
- __ds.__stream_ = INVALID_HANDLE_VALUE;
- }
-
- __dir_stream(const path& root, directory_options opts, error_code& ec)
- : __stream_(INVALID_HANDLE_VALUE), __root_(root) {
- __stream_ = ::FindFirstFile(root.c_str(), &__data_);
- if (__stream_ == INVALID_HANDLE_VALUE) {
- ec = error_code(::GetLastError(), std::generic_category());
- const bool ignore_permission_denied =
- bool(opts & directory_options::skip_permission_denied);
- if (ignore_permission_denied && ec.value() == ERROR_ACCESS_DENIED)
- ec.clear();
- return;
- }
- }
-
- ~__dir_stream() noexcept {
- if (__stream_ == INVALID_HANDLE_VALUE)
- return;
- close();
- }
-
- bool good() const noexcept { return __stream_ != INVALID_HANDLE_VALUE; }
-
- bool advance(error_code& ec) {
- while (::FindNextFile(__stream_, &__data_)) {
- if (!strcmp(__data_.cFileName, ".") || strcmp(__data_.cFileName, ".."))
- continue;
- __entry_.assign(__root_ / __data_.cFileName);
- return true;
- }
- ec = error_code(::GetLastError(), std::generic_category());
- close();
- return false;
- }
-
-private:
- std::error_code close() noexcept {
- std::error_code ec;
- if (!::FindClose(__stream_))
- ec = error_code(::GetLastError(), std::generic_category());
- __stream_ = INVALID_HANDLE_VALUE;
- return ec;
- }
-
- HANDLE __stream_{INVALID_HANDLE_VALUE};
- WIN32_FIND_DATA __data_;
-
-public:
- path __root_;
- directory_entry __entry_;
-};
-#else
class __dir_stream {
public:
__dir_stream() = delete;
@@ -183,7 +117,6 @@ public:
path __root_;
directory_entry __entry_;
};
-#endif
// directory_iterator
@@ -216,7 +149,7 @@ directory_iterator& directory_iterator::__increment(error_code *ec)
}
-directory_entry const& directory_iterator::__dereference() const {
+directory_entry const& directory_iterator::__deref() const {
_LIBCPP_ASSERT(__imp_, "Attempting to dereference an invalid iterator");
return __imp_->__entry_;
}
@@ -262,7 +195,7 @@ int recursive_directory_iterator::depth() const {
return __imp_->__stack_.size() - 1;
}
-const directory_entry& recursive_directory_iterator::__dereference() const {
+const directory_entry& recursive_directory_iterator::__deref() const {
return __imp_->__stack_.top().__entry_;
}
@@ -296,43 +229,24 @@ void recursive_directory_iterator::__advance(error_code* ec) {
}
bool recursive_directory_iterator::__try_recursion(error_code *ec) {
+
bool rec_sym =
bool(options() & directory_options::follow_directory_symlink);
-
auto& curr_it = __imp_->__stack_.top();
- bool skip_rec = false;
- std::error_code m_ec;
- if (!rec_sym) {
- file_status st = curr_it.__entry_.symlink_status(m_ec);
- if (m_ec && status_known(st))
- m_ec.clear();
- if (m_ec || is_symlink(st) || !is_directory(st))
- skip_rec = true;
- } else {
- file_status st = curr_it.__entry_.status(m_ec);
- if (m_ec && status_known(st))
- m_ec.clear();
- if (m_ec || !is_directory(st))
- skip_rec = true;
- }
-
- if (!skip_rec) {
+ if (is_directory(curr_it.__entry_.status()) &&
+ (!is_symlink(curr_it.__entry_.symlink_status()) || rec_sym))
+ {
+ std::error_code m_ec;
__dir_stream new_it(curr_it.__entry_.path(), __imp_->__options_, m_ec);
if (new_it.good()) {
__imp_->__stack_.push(_VSTD::move(new_it));
return true;
}
- }
- if (m_ec) {
- const bool allow_eacess = bool(__imp_->__options_
- & directory_options::skip_permission_denied);
- if (m_ec.value() == EACCES && allow_eacess) {
- if (ec) ec->clear();
- } else {
- __imp_.reset();
- set_or_throw(m_ec, ec,
- "recursive_directory_iterator::operator++()");
+ if (m_ec) {
+ __imp_.reset();
+ set_or_throw(m_ec, ec,
+ "recursive_directory_iterator::operator++()");
}
}
return false;
diff --git a/lib/libcxx/src/experimental/filesystem/operations.cpp b/lib/libcxx/src/experimental/filesystem/operations.cpp
index 662fa7b8626..369996fcbe6 100644
--- a/lib/libcxx/src/experimental/filesystem/operations.cpp
+++ b/lib/libcxx/src/experimental/filesystem/operations.cpp
@@ -15,8 +15,6 @@
#include "cstdlib"
#include "climits"
-#include "filesystem_time_helper.h"
-
#include <unistd.h>
#include <sys/stat.h>
#include <sys/statvfs.h>
@@ -37,9 +35,12 @@ namespace detail { namespace {
using value_type = path::value_type;
using string_type = path::string_type;
+
+
inline std::error_code capture_errno() {
- _LIBCPP_ASSERT(errno, "Expected errno to be non-zero");
- return std::error_code(errno, std::generic_category());
+ _LIBCPP_ASSERT(errno, "Expected errno to be non-zero");
+ std::error_code m_ec(errno, std::generic_category());
+ return m_ec;
}
void set_or_throw(std::error_code const& m_ec, std::error_code* ec,
@@ -50,7 +51,7 @@ void set_or_throw(std::error_code const& m_ec, std::error_code* ec,
} else {
string msg_s("std::experimental::filesystem::");
msg_s += msg;
- __throw_filesystem_error(msg_s, p, p2, m_ec);
+ __libcpp_throw(filesystem_error(msg_s, p, p2, m_ec));
}
}
@@ -182,20 +183,20 @@ void __copy(const path& from, const path& to, copy_options options,
const bool sym_status2 = bool(options &
copy_options::copy_symlinks);
- std::error_code m_ec1;
+ std::error_code m_ec;
struct ::stat f_st = {};
const file_status f = sym_status || sym_status2
- ? detail::posix_lstat(from, f_st, &m_ec1)
- : detail::posix_stat(from, f_st, &m_ec1);
- if (m_ec1)
- return set_or_throw(m_ec1, ec, "copy", from, to);
+ ? detail::posix_lstat(from, f_st, &m_ec)
+ : detail::posix_stat(from, f_st, &m_ec);
+ if (m_ec)
+ return set_or_throw(m_ec, ec, "copy", from, to);
struct ::stat t_st = {};
- const file_status t = sym_status ? detail::posix_lstat(to, t_st, &m_ec1)
- : detail::posix_stat(to, t_st, &m_ec1);
+ const file_status t = sym_status ? detail::posix_lstat(to, t_st, &m_ec)
+ : detail::posix_stat(to, t_st, &m_ec);
if (not status_known(t))
- return set_or_throw(m_ec1, ec, "copy", from, to);
+ return set_or_throw(m_ec, ec, "copy", from, to);
if (!exists(f) || is_other(f) || is_other(t)
|| (is_directory(f) && is_regular_file(t))
@@ -235,11 +236,12 @@ void __copy(const path& from, const path& to, copy_options options,
}
return;
}
- else if (is_directory(f) && bool(copy_options::create_symlinks & options)) {
- return set_or_throw(make_error_code(errc::is_a_directory), ec, "copy");
- }
- else if (is_directory(f) && (bool(copy_options::recursive & options) ||
- copy_options::none == options)) {
+ else if (is_directory(f)) {
+ if (not bool(copy_options::recursive & options) &&
+ bool(copy_options::__in_recursive_copy & options))
+ {
+ return;
+ }
if (!exists(t)) {
// create directory to with attributes from 'from'.
@@ -249,9 +251,9 @@ void __copy(const path& from, const path& to, copy_options options,
directory_iterator it = ec ? directory_iterator(from, *ec)
: directory_iterator(from);
if (ec && *ec) { return; }
- std::error_code m_ec2;
- for (; it != directory_iterator(); it.increment(m_ec2)) {
- if (m_ec2) return set_or_throw(m_ec2, ec, "copy", from, to);
+ std::error_code m_ec;
+ for (; it != directory_iterator(); it.increment(m_ec)) {
+ if (m_ec) return set_or_throw(m_ec, ec, "copy", from, to);
__copy(it->path(), to / it->path().filename(),
options | copy_options::__in_recursive_copy, ec);
if (ec && *ec) { return; }
@@ -281,10 +283,6 @@ bool __copy_file(const path& from, const path& to, copy_options options,
}
const bool to_exists = exists(to_st);
- if (to_exists && !is_regular_file(to_st)) {
- set_or_throw(make_error_code(errc::not_supported), ec, "copy_file", from, to);
- return false;
- }
if (to_exists && bool(copy_options::skip_existing & options)) {
return false;
}
@@ -305,8 +303,6 @@ bool __copy_file(const path& from, const path& to, copy_options options,
set_or_throw(make_error_code(errc::file_exists), ec, "copy", from, to);
return false;
}
-
- _LIBCPP_UNREACHABLE();
}
void __copy_symlink(const path& existing_symlink, const path& new_symlink,
@@ -428,20 +424,17 @@ void __current_path(const path& p, std::error_code *ec) {
bool __equivalent(const path& p1, const path& p2, std::error_code *ec)
{
- auto make_unsupported_error = [&]() {
- set_or_throw(make_error_code(errc::not_supported), ec,
- "equivalent", p1, p2);
- return false;
- };
std::error_code ec1, ec2;
struct ::stat st1 = {};
struct ::stat st2 = {};
auto s1 = detail::posix_stat(p1.native(), st1, &ec1);
- if (!exists(s1))
- return make_unsupported_error();
auto s2 = detail::posix_stat(p2.native(), st2, &ec2);
- if (!exists(s2))
- return make_unsupported_error();
+
+ if ((!exists(s1) && !exists(s2)) || (is_other(s1) && is_other(s2))) {
+ set_or_throw(make_error_code(errc::not_supported), ec,
+ "equivalent", p1, p2);
+ return false;
+ }
if (ec) ec->clear();
return (st1.st_dev == st2.st_dev && st1.st_ino == st2.st_ino);
}
@@ -483,50 +476,55 @@ bool __fs_is_empty(const path& p, std::error_code *ec)
std::error_code m_ec;
struct ::stat pst;
auto st = detail::posix_stat(p, pst, &m_ec);
- if (m_ec) {
- set_or_throw(m_ec, ec, "is_empty", p);
- return false;
- }
- else if (!is_directory(st) && !is_regular_file(st)) {
- m_ec = make_error_code(errc::not_supported);
- set_or_throw(m_ec, ec, "is_empty");
- return false;
- }
- else if (is_directory(st)) {
- auto it = ec ? directory_iterator(p, *ec) : directory_iterator(p);
- if (ec && *ec)
- return false;
- return it == directory_iterator{};
- }
+ if (is_directory(st))
+ return directory_iterator(p) == directory_iterator{};
else if (is_regular_file(st))
return static_cast<std::uintmax_t>(pst.st_size) == 0;
-
- _LIBCPP_UNREACHABLE();
+ // else
+ set_or_throw(m_ec, ec, "is_empty", p);
+ return false;
}
namespace detail { namespace {
-using TimeSpec = struct timespec;
-using StatT = struct stat;
+template <class CType, class ChronoType>
+bool checked_set(CType* out, ChronoType time) {
+ using Lim = numeric_limits<CType>;
+ if (time > Lim::max() || time < Lim::min())
+ return false;
+ *out = static_cast<CType>(time);
+ return true;
+}
+
+constexpr long long min_seconds = file_time_type::duration::min().count()
+ / file_time_type::period::den;
-#if defined(__APPLE__)
-TimeSpec extract_mtime(StatT const& st) { return st.st_mtimespec; }
-__attribute__((unused)) // Suppress warning
-TimeSpec extract_atime(StatT const& st) { return st.st_atimespec; }
-#else
-TimeSpec extract_mtime(StatT const& st) { return st.st_mtim; }
-__attribute__((unused)) // Suppress warning
-TimeSpec extract_atime(StatT const& st) { return st.st_atim; }
-#endif
+template <class SubSecDurT, class SubSecT>
+bool set_times_checked(time_t* sec_out, SubSecT* subsec_out, file_time_type tp) {
+ using namespace chrono;
+ auto dur = tp.time_since_epoch();
+ auto sec_dur = duration_cast<seconds>(dur);
+ auto subsec_dur = duration_cast<SubSecDurT>(dur - sec_dur);
+ // The tv_nsec and tv_usec fields must not be negative so adjust accordingly
+ if (subsec_dur.count() < 0) {
+ if (sec_dur.count() > min_seconds) {
+
+ sec_dur -= seconds(1);
+ subsec_dur += seconds(1);
+ } else {
+ subsec_dur = SubSecDurT::zero();
+ }
+ }
+ return checked_set(sec_out, sec_dur.count())
+ && checked_set(subsec_out, subsec_dur.count());
+}
}} // end namespace detail
-using FSTime = fs_time_util<file_time_type, time_t, struct timespec>;
file_time_type __last_write_time(const path& p, std::error_code *ec)
{
- using namespace ::std::chrono;
std::error_code m_ec;
struct ::stat st;
detail::posix_stat(p, st, &m_ec);
@@ -535,13 +533,7 @@ file_time_type __last_write_time(const path& p, std::error_code *ec)
return file_time_type::min();
}
if (ec) ec->clear();
- auto ts = detail::extract_mtime(st);
- if (!FSTime::is_representable(ts)) {
- set_or_throw(error_code(EOVERFLOW, generic_category()), ec,
- "last_write_time", p);
- return file_time_type::min();
- }
- return FSTime::convert_timespec(ts);
+ return file_time_type::clock::from_time_t(st.st_mtime);
}
void __last_write_time(const path& p, file_time_type new_time,
@@ -562,11 +554,10 @@ void __last_write_time(const path& p, file_time_type new_time,
set_or_throw(m_ec, ec, "last_write_time", p);
return;
}
- auto atime = detail::extract_atime(st);
struct ::timeval tbuf[2];
- tbuf[0].tv_sec = atime.tv_sec;
- tbuf[0].tv_usec = duration_cast<microseconds>(nanoseconds(atime.tv_nsec)).count();
- const bool overflowed = !FSTime::set_times_checked<microseconds>(
+ tbuf[0].tv_sec = st.st_atime;
+ tbuf[0].tv_usec = 0;
+ const bool overflowed = !detail::set_times_checked<microseconds>(
&tbuf[1].tv_sec, &tbuf[1].tv_usec, new_time);
if (overflowed) {
@@ -582,7 +573,7 @@ void __last_write_time(const path& p, file_time_type new_time,
tbuf[0].tv_sec = 0;
tbuf[0].tv_nsec = UTIME_OMIT;
- const bool overflowed = !FSTime::set_times_checked<nanoseconds>(
+ const bool overflowed = !detail::set_times_checked<nanoseconds>(
&tbuf[1].tv_sec, &tbuf[1].tv_nsec, new_time);
if (overflowed) {
set_or_throw(make_error_code(errc::invalid_argument),
@@ -710,7 +701,7 @@ void __rename(const path& from, const path& to, std::error_code *ec) {
}
void __resize_file(const path& p, std::uintmax_t size, std::error_code *ec) {
- if (::truncate(p.c_str(), static_cast<::off_t>(size)) == -1)
+ if (::truncate(p.c_str(), static_cast<long>(size)) == -1)
set_or_throw(ec, "resize_file", p);
else if (ec)
ec->clear();
@@ -729,7 +720,7 @@ space_info __space(const path& p, std::error_code *ec) {
// Multiply with overflow checking.
auto do_mult = [&](std::uintmax_t& out, std::uintmax_t other) {
out = other * m_svfs.f_frsize;
- if (other == 0 || out / other != m_svfs.f_frsize)
+ if (out / other != m_svfs.f_frsize || other == 0)
out = static_cast<std::uintmax_t>(-1);
};
do_mult(si.capacity, m_svfs.f_blocks);
@@ -751,28 +742,23 @@ path __system_complete(const path& p, std::error_code *ec) {
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;
-
- for (auto& ep : env_paths)
- if ((ret = std::getenv(ep)))
- break;
- if (ret == nullptr)
- ret = "/tmp";
-
- path p(ret);
- std::error_code m_ec;
- if (!exists(p, m_ec) || !is_directory(p, m_ec)) {
+path __temp_directory_path(std::error_code *ec) {
+ const char* env_paths[] = {"TMPDIR", "TMP", "TEMP", "TEMPDIR"};
+ const char* ret = nullptr;
+ for (auto & ep : env_paths) {
+ if ((ret = std::getenv(ep)))
+ break;
+ }
+ path p(ret ? ret : "/tmp");
+ std::error_code m_ec;
+ if (is_directory(p, m_ec)) {
+ if (ec) ec->clear();
+ return p;
+ }
if (!m_ec || m_ec == make_error_code(errc::no_such_file_or_directory))
- m_ec = make_error_code(errc::not_a_directory);
+ m_ec = make_error_code(errc::not_a_directory);
set_or_throw(m_ec, ec, "temp_directory_path");
return {};
- }
-
- if (ec)
- ec->clear();
- return p;
}
// An absolute path is composed according to the table in [fs.op.absolute].
diff --git a/lib/libcxx/src/experimental/filesystem/path.cpp b/lib/libcxx/src/experimental/filesystem/path.cpp
index dd4026cfe13..38c449832f6 100644
--- a/lib/libcxx/src/experimental/filesystem/path.cpp
+++ b/lib/libcxx/src/experimental/filesystem/path.cpp
@@ -7,284 +7,241 @@
//
//===----------------------------------------------------------------------===//
#include "experimental/filesystem"
-#include "string_view"
+#include "experimental/string_view"
#include "utility"
+_LIBCPP_BEGIN_NAMESPACE_EXPERIMENTAL_FILESYSTEM
+
+_LIBCPP_CONSTEXPR path::value_type path::preferred_separator;
+
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;
+using string_type = string_view;
+using value_type = path::value_type;
-private:
- PathParser(string_view_t P, ParserState State) noexcept
- : Path(P), State(State) {}
+using string_view_pair = pair<string_view, string_view>;
-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.
- }
+// status reporting
+constexpr size_t npos = static_cast<size_t>(-1);
- static PathParser CreateBegin(string_view_t P) noexcept {
- PathParser PP(P, PS_BeforeBegin);
- PP.increment();
- return PP;
- }
+inline bool good(size_t pos) { return pos != npos; }
- static PathParser CreateEnd(string_view_t P) noexcept {
- PathParser PP(P, PS_AtEnd);
- return PP;
- }
+// lexical elements
+constexpr value_type preferred_separator = path::preferred_separator;
+constexpr value_type const * preferred_separator_str = "/";
+constexpr value_type const * dot = ".";
- PosPtr peek() const noexcept {
- auto TkEnd = getNextTokenStartPos();
- auto End = getAfterBack();
- return TkEnd == End ? nullptr : TkEnd;
- }
+// forward //
+bool is_separator(string_type const &, size_t);
+bool is_root_name(const string_type&, size_t);
+bool is_root_directory(string_type const &, size_t);
+bool is_trailing_separator(string_type const &, size_t);
- 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));
- }
+size_t start_of(string_type const &, size_t);
+size_t end_of(string_type const &, size_t);
- 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);
- }
+size_t root_name_start(const string_type& s);
+size_t root_name_end(const string_type&);
- case PS_InTrailingSep:
- return makeState(PS_AtEnd);
+size_t root_directory_start(string_type const &);
+size_t root_directory_end(string_type const &);
- case PS_AtEnd:
- _LIBCPP_UNREACHABLE();
- }
- }
+string_view_pair separate_filename(string_type const &);
+string_view extract_raw(string_type const &, size_t);
+string_view extract_preferred(string_type const &, size_t);
- 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);
- }
+inline bool is_separator(const string_type& s, size_t pos) {
+ return (pos < s.size() && s[pos] == preferred_separator);
+}
+
+inline bool is_root_name(const string_type& s, size_t pos) {
+ return good(pos) && pos == 0 ? root_name_start(s) == pos : false;
+}
+
+inline bool is_root_directory(const string_type& s, size_t pos) {
+ return good(pos) ? root_directory_start(s) == pos : false;
+}
+
+inline bool is_trailing_separator(const string_type& s, size_t pos) {
+ return (pos < s.size() && is_separator(s, pos) &&
+ end_of(s, pos) == s.size()-1 &&
+ !is_root_directory(s, pos) && !is_root_name(s, pos));
+}
+
+size_t start_of(const string_type& s, size_t pos) {
+ if (pos >= s.size()) return npos;
+ bool in_sep = (s[pos] == preferred_separator);
+ while (pos - 1 < s.size() &&
+ (s[pos-1] == preferred_separator) == in_sep)
+ { --pos; }
+ if (pos == 2 && !in_sep && s[0] == preferred_separator &&
+ s[1] == preferred_separator)
+ { return 0; }
+ return pos;
+}
+
+size_t end_of(const string_type& s, size_t pos) {
+ if (pos >= s.size()) return npos;
+ // special case for root name
+ if (pos == 0 && is_root_name(s, pos)) return root_name_end(s);
+ bool in_sep = (s[pos] == preferred_separator);
+ while (pos + 1 < s.size() && (s[pos+1] == preferred_separator) == in_sep)
+ { ++pos; }
+ return pos;
+}
+
+inline size_t root_name_start(const string_type& s) {
+ return good(root_name_end(s)) ? 0 : npos;
+}
+
+size_t root_name_end(const string_type& s) {
+ if (s.size() < 2 || s[0] != preferred_separator
+ || s[1] != preferred_separator) {
+ return npos;
}
- 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);
+ if (s.size() == 2) {
+ return 1;
}
- case PS_InRootDir:
- return makeState(PS_InRootName, Path.data(), RStart + 1);
- case PS_InRootName:
- case PS_BeforeBegin:
- _LIBCPP_UNREACHABLE();
+ size_t index = 2; // current position
+ if (s[index] == preferred_separator) {
+ return npos;
}
- }
-
- /// \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;
+ while (index + 1 < s.size() && s[index+1] != preferred_separator) {
+ ++index;
}
- _LIBCPP_UNREACHABLE();
- }
+ return index;
+}
- explicit operator bool() const noexcept {
- return State != PS_BeforeBegin && State != PS_AtEnd;
+size_t root_directory_start(const string_type& s) {
+ size_t e = root_name_end(s);
+ if (!good(e))
+ return is_separator(s, 0) ? 0 : npos;
+ return is_separator(s, e + 1) ? e + 1 : npos;
+}
+
+size_t root_directory_end(const string_type& s) {
+ size_t st = root_directory_start(s);
+ if (!good(st)) return npos;
+ size_t index = st;
+ while (index + 1 < s.size() && s[index + 1] == preferred_separator)
+ { ++index; }
+ return index;
+}
+
+string_view_pair separate_filename(string_type const & s) {
+ if (s == "." || s == ".." || s.empty()) return string_view_pair{s, ""};
+ auto pos = s.find_last_of('.');
+ if (pos == string_type::npos) return string_view_pair{s, string_view{}};
+ return string_view_pair{s.substr(0, pos), s.substr(pos)};
+}
+
+inline string_view extract_raw(const string_type& s, size_t pos) {
+ size_t end_i = end_of(s, pos);
+ if (!good(end_i)) return string_view{};
+ return string_view(s).substr(pos, end_i - pos + 1);
+}
+
+string_view extract_preferred(const string_type& s, size_t pos) {
+ string_view raw = extract_raw(s, pos);
+ if (raw.empty())
+ return raw;
+ if (is_trailing_separator(s, pos))
+ return string_view{dot};
+ if (is_separator(s, pos) && !is_root_name(s, pos))
+ return string_view(preferred_separator_str);
+ return raw;
+}
+
+}} // namespace parser
+
+
+////////////////////////////////////////////////////////////////////////////////
+// path_view_iterator
+////////////////////////////////////////////////////////////////////////////////
+namespace {
+
+struct path_view_iterator {
+ const string_view __s_;
+ size_t __pos_;
+
+ explicit path_view_iterator(string_view const& __s) : __s_(__s), __pos_(__s_.empty() ? parser::npos : 0) {}
+ explicit path_view_iterator(string_view const& __s, size_t __p) : __s_(__s), __pos_(__p) {}
+
+ string_view operator*() const {
+ return parser::extract_preferred(__s_, __pos_);
}
- PathParser& operator++() noexcept {
+ path_view_iterator& operator++() {
increment();
return *this;
}
- PathParser& operator--() noexcept {
+ path_view_iterator& operator--() {
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 = {};
+ void increment() {
+ if (__pos_ == parser::npos) return;
+ while (! set_position(parser::end_of(__s_, __pos_)+1))
+ ;
+ return;
}
- 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();
+ void decrement() {
+ if (__pos_ == 0) {
+ set_position(0);
+ }
+ else if (__pos_ == parser::npos) {
+ auto const str_size = __s_.size();
+ set_position(parser::start_of(
+ __s_, str_size != 0 ? str_size - 1 : str_size));
+ } else {
+ while (!set_position(parser::start_of(__s_, __pos_-1)))
+ ;
}
- _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;
+ bool set_position(size_t pos) {
+ if (pos >= __s_.size()) {
+ __pos_ = parser::npos;
+ } else {
+ __pos_ = pos;
}
- _LIBCPP_UNREACHABLE();
+ return valid_iterator_position();
}
- 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;
+ bool valid_iterator_position() const {
+ if (__pos_ == parser::npos) return true; // end position is valid
+ return (!parser::is_separator (__s_, __pos_) ||
+ parser::is_root_directory (__s_, __pos_) ||
+ parser::is_trailing_separator(__s_, __pos_) ||
+ parser::is_root_name (__s_, __pos_));
}
- 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;
+ bool is_end() const { return __pos_ == parser::npos; }
+
+ inline bool operator==(path_view_iterator const& __p) {
+ return __pos_ == __p.__pos_;
}
};
-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)};
+path_view_iterator pbegin(path const& p) {
+ return path_view_iterator(p.native());
}
-string_view_t createView(PosPtr S, PosPtr E) noexcept {
- return {S, static_cast<size_t>(E - S) + 1};
+path_view_iterator pend(path const& p) {
+ path_view_iterator __p(p.native());
+ __p.__pos_ = parser::npos;
+ return __p;
}
-}} // namespace parser
-
-_LIBCPP_BEGIN_NAMESPACE_EXPERIMENTAL_FILESYSTEM
-
-using parser::string_view_t;
-using parser::string_view_pair;
-using parser::PathParser;
-using parser::createView;
-
+} // end namespace
///////////////////////////////////////////////////////////////////////////////
// path definitions
///////////////////////////////////////////////////////////////////////////////
-constexpr path::value_type path::preferred_separator;
-
path & path::replace_extension(path const & replacement)
{
path p = extension();
@@ -303,145 +260,131 @@ path & path::replace_extension(path const & replacement)
///////////////////////////////////////////////////////////////////////////////
// path.decompose
-string_view_t path::__root_name() const
+string_view path::__root_name() const
{
- auto PP = PathParser::CreateBegin(__pn_);
- if (PP.State == PathParser::PS_InRootName)
- return *PP;
- return {};
+ return parser::is_root_name(__pn_, 0)
+ ? parser::extract_preferred(__pn_, 0)
+ : string_view{};
}
-string_view_t path::__root_directory() const
+string_view 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;
+ auto start_i = parser::root_directory_start(__pn_);
+ if(!parser::good(start_i)) {
+ return {};
}
- if (PP.State == PathParser::PS_InRootDir)
- return *PP;
- return {};
+ return parser::extract_preferred(__pn_, start_i);
}
-string_view_t path::__relative_path() const
+string_view 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());
+ if (empty()) {
+ return {__pn_};
+ }
+ auto end_i = parser::root_directory_end(__pn_);
+ if (not parser::good(end_i)) {
+ end_i = parser::root_name_end(__pn_);
+ }
+ if (not parser::good(end_i)) {
+ return {__pn_};
+ }
+ return string_view(__pn_).substr(end_i+1);
}
-string_view_t path::__parent_path() const
+string_view 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());
+ if (empty() || pbegin(*this) == --pend(*this)) {
+ return {};
+ }
+ auto end_it = --(--pend(*this));
+ auto end_i = parser::end_of(__pn_, end_it.__pos_);
+ return string_view(__pn_).substr(0, end_i+1);
}
-string_view_t path::__filename() const
+string_view path::__filename() const
{
- if (empty()) return {};
- return *(--PathParser::CreateEnd(__pn_));
+ return empty() ? string_view{} : *--pend(*this);
}
-string_view_t path::__stem() const
+string_view path::__stem() const
{
return parser::separate_filename(__filename()).first;
}
-string_view_t path::__extension() const
+string_view 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);
+int path::__compare(const value_type* __s) const {
+ path_view_iterator thisIter(this->native());
+ path_view_iterator sIter(__s);
+ while (!thisIter.is_end() && !sIter.is_end()) {
+ int res = (*thisIter).compare(*sIter);
if (res != 0) return res;
- ++PP; ++PP2;
+ ++thisIter; ++sIter;
}
- if (PP.State == PP2.State && PP.State == PathParser::PS_AtEnd)
+ if (thisIter.is_end() && sIter.is_end())
return 0;
- if (PP.State == PathParser::PS_AtEnd)
+ if (thisIter.is_end())
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;
+size_t hash_value(const path& __p) _NOEXCEPT {
+ path_view_iterator thisIter(__p.native());
+ struct HashPairT {
+ size_t first;
+ size_t second;
+ };
+ HashPairT hp = {0, 0};
+ std::hash<string_view> hasher;
+ std::__scalar_hash<decltype(hp)> pair_hasher;
+ while (!thisIter.is_end()) {
+ hp.second = hasher(*thisIter);
+ hp.first = pair_hasher(hp);
+ ++thisIter;
}
- return hash_value;
+ return hp.first;
}
////////////////////////////////////////////////////////////////////////////
// path.itr
path::iterator path::begin() const
{
- auto PP = PathParser::CreateBegin(__pn_);
+ path_view_iterator pit = pbegin(*this);
iterator it;
it.__path_ptr_ = this;
- it.__state_ = PP.State;
- it.__entry_ = PP.RawEntry;
- it.__stashed_elem_.__assign_view(*PP);
+ it.__pos_ = pit.__pos_;
+ it.__elem_.__assign_view(*pit);
return it;
}
path::iterator path::end() const
{
iterator it{};
- it.__state_ = PathParser::PS_AtEnd;
it.__path_ptr_ = this;
+ it.__pos_ = parser::npos;
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);
+ path_view_iterator it(__path_ptr_->native(), __pos_);
+ it.increment();
+ __pos_ = it.__pos_;
+ __elem_.__assign_view(*it);
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);
+ path_view_iterator it(__path_ptr_->native(), __pos_);
+ it.decrement();
+ __pos_ = it.__pos_;
+ __elem_.__assign_view(*it);
return *this;
}