diff options
author | dim <dim@FreeBSD.org> | 2016-12-26 20:36:37 +0000 |
---|---|---|
committer | dim <dim@FreeBSD.org> | 2016-12-26 20:36:37 +0000 |
commit | 06210ae42d418d50d8d9365d5c9419308ae9e7ee (patch) | |
tree | ab60b4cdd6e430dda1f292a46a77ddb744723f31 /contrib/libc++/src | |
parent | 2dd166267f53df1c3748b4325d294b9b839de74b (diff) | |
download | FreeBSD-src-06210ae42d418d50d8d9365d5c9419308ae9e7ee.zip FreeBSD-src-06210ae42d418d50d8d9365d5c9419308ae9e7ee.tar.gz |
MFC r309124:
Upgrade our copies of clang, llvm, lldb, compiler-rt and libc++ to 3.9.0
release, and add lld 3.9.0. Also completely revamp the build system for
clang, llvm, lldb and their related tools.
Please note that from 3.5.0 onwards, clang, llvm and lldb require C++11
support to build; see UPDATING for more information.
Release notes for llvm, clang and lld are available here:
<http://llvm.org/releases/3.9.0/docs/ReleaseNotes.html>
<http://llvm.org/releases/3.9.0/tools/clang/docs/ReleaseNotes.html>
<http://llvm.org/releases/3.9.0/tools/lld/docs/ReleaseNotes.html>
Thanks to Ed Maste, Bryan Drewery, Andrew Turner, Antoine Brodin and Jan
Beich for their help.
Relnotes: yes
MFC r309147:
Pull in r282174 from upstream llvm trunk (by Krzysztof Parzyszek):
[PPC] Set SP after loading data from stack frame, if no red zone is
present
Follow-up to r280705: Make sure that the SP is only restored after
all data is loaded from the stack frame, if there is no red zone.
This completes the fix for
https://llvm.org/bugs/show_bug.cgi?id=26519.
Differential Revision: https://reviews.llvm.org/D24466
Reported by: Mark Millard
PR: 214433
MFC r309149:
Pull in r283060 from upstream llvm trunk (by Hal Finkel):
[PowerPC] Refactor soft-float support, and enable PPC64 soft float
This change enables soft-float for PowerPC64, and also makes
soft-float disable all vector instruction sets for both 32-bit and
64-bit modes. This latter part is necessary because the PPC backend
canonicalizes many Altivec vector types to floating-point types, and
so soft-float breaks scalarization support for many operations. Both
for embedded targets and for operating-system kernels desiring
soft-float support, it seems reasonable that disabling hardware
floating-point also disables vector instructions (embedded targets
without hardware floating point support are unlikely to have Altivec,
etc. and operating system kernels desiring not to use floating-point
registers to lower syscall cost are unlikely to want to use vector
registers either). If someone needs this to work, we'll need to
change the fact that we promote many Altivec operations to act on
v4f32. To make it possible to disable Altivec when soft-float is
enabled, hardware floating-point support needs to be expressed as a
positive feature, like the others, and not a negative feature,
because target features cannot have dependencies on the disabling of
some other feature. So +soft-float has now become -hard-float.
Fixes PR26970.
Pull in r283061 from upstream clang trunk (by Hal Finkel):
[PowerPC] Enable soft-float for PPC64, and +soft-float -> -hard-float
Enable soft-float support on PPC64, as the backend now supports it.
Also, the backend now uses -hard-float instead of +soft-float, so set
the target features accordingly.
Fixes PR26970.
Reported by: Mark Millard
PR: 214433
MFC r309212:
Add a few missed clang 3.9.0 files to OptionalObsoleteFiles.
MFC r309262:
Fix packaging for clang, lldb and lld 3.9.0
During the upgrade of clang/llvm etc to 3.9.0 in r309124, the PACKAGE
directive in the usr.bin/clang/*.mk files got dropped accidentally.
Restore it, with a few minor changes and additions:
* Correct license in clang.ucl to NCSA
* Add PACKAGE=clang for clang and most of the "ll" tools
* Put lldb in its own package
* Put lld in its own package
Reviewed by: gjb, jmallett
Differential Revision: https://reviews.freebsd.org/D8666
MFC r309656:
During the bootstrap phase, when building the minimal llvm library on
PowerPC, add lib/Support/Atomic.cpp. This is needed because upstream
llvm revision r271821 disabled the use of std::call_once, which causes
some fallback functions from Atomic.cpp to be used instead.
Reported by: Mark Millard
PR: 214902
MFC r309835:
Tentatively apply https://reviews.llvm.org/D18730 to work around gcc PR
70528 (bogus error: constructor required before non-static data member).
This should fix buildworld with the external gcc package.
Reported by: https://jenkins.freebsd.org/job/FreeBSD_HEAD_amd64_gcc/
MFC r310194:
Upgrade our copies of clang, llvm, lld, lldb, compiler-rt and libc++ to
3.9.1 release.
Please note that from 3.5.0 onwards, clang, llvm and lldb require C++11
support to build; see UPDATING for more information.
Release notes for llvm, clang and lld will be available here:
<http://releases.llvm.org/3.9.1/docs/ReleaseNotes.html>
<http://releases.llvm.org/3.9.1/tools/clang/docs/ReleaseNotes.html>
<http://releases.llvm.org/3.9.1/tools/lld/docs/ReleaseNotes.html>
Relnotes: yes
Diffstat (limited to 'contrib/libc++/src')
-rw-r--r-- | contrib/libc++/src/algorithm.cpp | 6 | ||||
-rw-r--r-- | contrib/libc++/src/bind.cpp | 21 | ||||
-rw-r--r-- | contrib/libc++/src/condition_variable.cpp | 10 | ||||
-rw-r--r-- | contrib/libc++/src/experimental/filesystem/directory_iterator.cpp | 256 | ||||
-rw-r--r-- | contrib/libc++/src/experimental/filesystem/operations.cpp | 794 | ||||
-rw-r--r-- | contrib/libc++/src/experimental/filesystem/path.cpp | 391 | ||||
-rw-r--r-- | contrib/libc++/src/experimental/memory_resource.cpp | 144 | ||||
-rw-r--r-- | contrib/libc++/src/locale.cpp | 233 | ||||
-rw-r--r-- | contrib/libc++/src/memory.cpp | 14 | ||||
-rw-r--r-- | contrib/libc++/src/mutex.cpp | 74 | ||||
-rw-r--r-- | contrib/libc++/src/regex.cpp | 18 | ||||
-rw-r--r-- | contrib/libc++/src/strstream.cpp | 9 | ||||
-rw-r--r-- | contrib/libc++/src/system_error.cpp | 57 | ||||
-rw-r--r-- | contrib/libc++/src/thread.cpp | 24 |
14 files changed, 1756 insertions, 295 deletions
diff --git a/contrib/libc++/src/algorithm.cpp b/contrib/libc++/src/algorithm.cpp index e548856..e9752b0 100644 --- a/contrib/libc++/src/algorithm.cpp +++ b/contrib/libc++/src/algorithm.cpp @@ -48,14 +48,14 @@ template bool __insertion_sort_incomplete<__less<long double>&, long double*>(lo template unsigned __sort5<__less<long double>&, long double*>(long double*, long double*, long double*, long double*, long double*, __less<long double>&); #ifndef _LIBCPP_HAS_NO_THREADS -static pthread_mutex_t __rs_mut = PTHREAD_MUTEX_INITIALIZER; +static __libcpp_mutex_t __rs_mut = _LIBCPP_MUTEX_INITIALIZER; #endif unsigned __rs_default::__c_ = 0; __rs_default::__rs_default() { #ifndef _LIBCPP_HAS_NO_THREADS - pthread_mutex_lock(&__rs_mut); + __libcpp_mutex_lock(&__rs_mut); #endif __c_ = 1; } @@ -69,7 +69,7 @@ __rs_default::~__rs_default() { #ifndef _LIBCPP_HAS_NO_THREADS if (--__c_ == 0) - pthread_mutex_unlock(&__rs_mut); + __libcpp_mutex_unlock(&__rs_mut); #else --__c_; #endif diff --git a/contrib/libc++/src/bind.cpp b/contrib/libc++/src/bind.cpp index cab0b7c..b318fc1 100644 --- a/contrib/libc++/src/bind.cpp +++ b/contrib/libc++/src/bind.cpp @@ -7,6 +7,7 @@ // //===----------------------------------------------------------------------===// +#define _LIBCPP_BUILDING_BIND #include "functional" _LIBCPP_BEGIN_NAMESPACE_STD @@ -14,16 +15,16 @@ _LIBCPP_BEGIN_NAMESPACE_STD namespace placeholders { -__ph<1> _1; -__ph<2> _2; -__ph<3> _3; -__ph<4> _4; -__ph<5> _5; -__ph<6> _6; -__ph<7> _7; -__ph<8> _8; -__ph<9> _9; -__ph<10> _10; +const __ph<1> _1{}; +const __ph<2> _2{}; +const __ph<3> _3{}; +const __ph<4> _4{}; +const __ph<5> _5{}; +const __ph<6> _6{}; +const __ph<7> _7{}; +const __ph<8> _8{}; +const __ph<9> _9{}; +const __ph<10> _10{}; } // placeholders diff --git a/contrib/libc++/src/condition_variable.cpp b/contrib/libc++/src/condition_variable.cpp index 5fd5fc8..bfb4bf3 100644 --- a/contrib/libc++/src/condition_variable.cpp +++ b/contrib/libc++/src/condition_variable.cpp @@ -20,19 +20,19 @@ _LIBCPP_BEGIN_NAMESPACE_STD condition_variable::~condition_variable() { - pthread_cond_destroy(&__cv_); + __libcpp_condvar_destroy(&__cv_); } void condition_variable::notify_one() _NOEXCEPT { - pthread_cond_signal(&__cv_); + __libcpp_condvar_signal(&__cv_); } void condition_variable::notify_all() _NOEXCEPT { - pthread_cond_broadcast(&__cv_); + __libcpp_condvar_broadcast(&__cv_); } void @@ -41,7 +41,7 @@ condition_variable::wait(unique_lock<mutex>& lk) _NOEXCEPT if (!lk.owns_lock()) __throw_system_error(EPERM, "condition_variable::wait: mutex not locked"); - int ec = pthread_cond_wait(&__cv_, lk.mutex()->native_handle()); + int ec = __libcpp_condvar_wait(&__cv_, lk.mutex()->native_handle()); if (ec) __throw_system_error(ec, "condition_variable wait failed"); } @@ -71,7 +71,7 @@ condition_variable::__do_timed_wait(unique_lock<mutex>& lk, ts.tv_sec = ts_sec_max; ts.tv_nsec = giga::num - 1; } - int ec = pthread_cond_timedwait(&__cv_, lk.mutex()->native_handle(), &ts); + int ec = __libcpp_condvar_timedwait(&__cv_, lk.mutex()->native_handle(), &ts); if (ec != 0 && ec != ETIMEDOUT) __throw_system_error(ec, "condition_variable timed_wait failed"); } diff --git a/contrib/libc++/src/experimental/filesystem/directory_iterator.cpp b/contrib/libc++/src/experimental/filesystem/directory_iterator.cpp new file mode 100644 index 0000000..fa217ba --- /dev/null +++ b/contrib/libc++/src/experimental/filesystem/directory_iterator.cpp @@ -0,0 +1,256 @@ +#include "experimental/filesystem" +#include <dirent.h> +#include <errno.h> + +_LIBCPP_BEGIN_NAMESPACE_EXPERIMENTAL_FILESYSTEM + +namespace { namespace detail { + +inline error_code capture_errno() { + _LIBCPP_ASSERT(errno, "Expected errno to be non-zero"); + return error_code{errno, std::generic_category()}; +} + +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, + std::error_code* user_ec, + const char* msg, Args&&... args) +{ + if (user_ec) { + *user_ec = my_ec; + return true; + } + __libcpp_throw(filesystem_error(msg, std::forward<Args>(args)..., my_ec)); + return false; +} + +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 + if ((dir_entry_ptr = ::readdir(dir_stream)) == nullptr) { + ec = capture_errno(); + return {}; + } else { + ec.clear(); + return dir_entry_ptr->d_name; + } +} + +}} // namespace detail + +using detail::set_or_throw; + +class __dir_stream { +public: + __dir_stream() = delete; + __dir_stream& operator=(const __dir_stream&) = delete; + + __dir_stream(__dir_stream&& other) noexcept + : __stream_(other.__stream_), __root_(std::move(other.__root_)), + __entry_(std::move(other.__entry_)) + { + other.__stream_ = nullptr; + } + + + __dir_stream(const path& root, directory_options opts, error_code& ec) + : __stream_(nullptr), + __root_(root) + { + if ((__stream_ = ::opendir(root.c_str())) == nullptr) { + ec = detail::capture_errno(); + const bool allow_eacess = + bool(opts & directory_options::skip_permission_denied); + if (allow_eacess && ec.value() == EACCES) + ec.clear(); + return; + } + advance(ec); + } + + ~__dir_stream() noexcept + { if (__stream_) close(); } + + bool good() const noexcept { return __stream_ != nullptr; } + + bool advance(error_code &ec) { + while (true) { + auto str = detail::posix_readdir(__stream_, ec); + if (str == "." || str == "..") { + continue; + } else if (ec || str.empty()) { + close(); + return false; + } else { + __entry_.assign(__root_ / str); + return true; + } + } + } +private: + std::error_code close() noexcept { + std::error_code m_ec; + if (::closedir(__stream_) == -1) + m_ec = detail::capture_errno(); + __stream_ = nullptr; + return m_ec; + } + + DIR * __stream_{nullptr}; +public: + path __root_; + directory_entry __entry_; +}; + +// directory_iterator + +directory_iterator::directory_iterator(const path& p, error_code *ec, + directory_options opts) +{ + std::error_code m_ec; + __imp_ = make_shared<__dir_stream>(p, opts, m_ec); + if (ec) *ec = m_ec; + if (!__imp_->good()) { + __imp_.reset(); + if (m_ec) + set_or_throw(m_ec, ec, + "directory_iterator::directory_iterator(...)", p); + } +} + +directory_iterator& directory_iterator::__increment(error_code *ec) +{ + _LIBCPP_ASSERT(__imp_, "Attempting to increment an invalid iterator"); + std::error_code m_ec; + if (!__imp_->advance(m_ec)) { + __imp_.reset(); + if (m_ec) + set_or_throw(m_ec, ec, "directory_iterator::operator++()"); + } else { + if (ec) ec->clear(); + } + return *this; + +} + +directory_entry const& directory_iterator::__deref() const { + _LIBCPP_ASSERT(__imp_, "Attempting to dereference an invalid iterator"); + return __imp_->__entry_; +} + +// recursive_directory_iterator + +struct recursive_directory_iterator::__shared_imp { + stack<__dir_stream> __stack_; + directory_options __options_; +}; + +recursive_directory_iterator::recursive_directory_iterator(const path& p, + directory_options opt, error_code *ec) + : __imp_(nullptr), __rec_(true) +{ + if (ec) ec->clear(); + std::error_code m_ec; + __dir_stream new_s(p, opt, m_ec); + if (m_ec) set_or_throw(m_ec, ec, "recursive_directory_iterator", p); + if (m_ec || !new_s.good()) return; + + __imp_ = _VSTD::make_shared<__shared_imp>(); + __imp_->__options_ = opt; + __imp_->__stack_.push(_VSTD::move(new_s)); +} + +void recursive_directory_iterator::__pop(error_code* ec) +{ + _LIBCPP_ASSERT(__imp_, "Popping the end iterator"); + if (ec) ec->clear(); + __imp_->__stack_.pop(); + if (__imp_->__stack_.size() == 0) + __imp_.reset(); + else + __advance(ec); +} + +directory_options recursive_directory_iterator::options() const { + return __imp_->__options_; +} + +int recursive_directory_iterator::depth() const { + return __imp_->__stack_.size() - 1; +} + +const directory_entry& recursive_directory_iterator::__deref() const { + return __imp_->__stack_.top().__entry_; +} + +recursive_directory_iterator& +recursive_directory_iterator::__increment(error_code *ec) +{ + if (ec) ec->clear(); + if (recursion_pending()) { + if (__try_recursion(ec) || (ec && *ec)) + return *this; + } + __rec_ = true; + __advance(ec); + return *this; +} + +void recursive_directory_iterator::__advance(error_code* ec) { + // REQUIRES: ec must be cleared before calling this function. + const directory_iterator end_it; + auto& stack = __imp_->__stack_; + std::error_code m_ec; + while (stack.size() > 0) { + if (stack.top().advance(m_ec)) + return; + if (m_ec) break; + stack.pop(); + } + __imp_.reset(); + if (m_ec) + set_or_throw(m_ec, ec, "recursive_directory_iterator::operator++()"); +} + +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(); + + 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) { + __imp_.reset(); + set_or_throw(m_ec, ec, + "recursive_directory_iterator::operator++()"); + } + } + return false; +} + + +_LIBCPP_END_NAMESPACE_EXPERIMENTAL_FILESYSTEM diff --git a/contrib/libc++/src/experimental/filesystem/operations.cpp b/contrib/libc++/src/experimental/filesystem/operations.cpp new file mode 100644 index 0000000..369996f --- /dev/null +++ b/contrib/libc++/src/experimental/filesystem/operations.cpp @@ -0,0 +1,794 @@ +//===--------------------- filesystem/ops.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 "iterator" +#include "fstream" +#include "type_traits" +#include "random" /* for unique_path */ +#include "cstdlib" +#include "climits" + +#include <unistd.h> +#include <sys/stat.h> +#include <sys/statvfs.h> +#include <fcntl.h> /* values for fchmodat */ +#if !defined(UTIME_OMIT) +#include <sys/time.h> // for ::utimes as used in __last_write_time +#endif + +_LIBCPP_BEGIN_NAMESPACE_EXPERIMENTAL_FILESYSTEM + +filesystem_error::~filesystem_error() {} + + +// POSIX HELPERS + +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"); + 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, + const char* msg, path const& p = {}, path const& p2 = {}) +{ + if (ec) { + *ec = m_ec; + } else { + string msg_s("std::experimental::filesystem::"); + msg_s += msg; + __libcpp_throw(filesystem_error(msg_s, p, p2, m_ec)); + } +} + +void set_or_throw(std::error_code* ec, const char* msg, + path const& p = {}, path const& p2 = {}) +{ + return set_or_throw(capture_errno(), ec, msg, p, p2); +} + +perms posix_get_perms(const struct ::stat & st) noexcept { + return static_cast<perms>(st.st_mode) & perms::mask; +} + +::mode_t posix_convert_perms(perms prms) { + return static_cast< ::mode_t>(prms & perms::mask); +} + +file_status create_file_status(std::error_code& m_ec, path const& p, + struct ::stat& path_stat, + std::error_code* ec) +{ + if (ec) *ec = m_ec; + if (m_ec && (m_ec.value() == ENOENT || m_ec.value() == ENOTDIR)) { + return file_status(file_type::not_found); + } + else if (m_ec) { + set_or_throw(m_ec, ec, "posix_stat", p); + return file_status(file_type::none); + } + // else + + file_status fs_tmp; + auto const mode = path_stat.st_mode; + if (S_ISLNK(mode)) fs_tmp.type(file_type::symlink); + else if (S_ISREG(mode)) fs_tmp.type(file_type::regular); + else if (S_ISDIR(mode)) fs_tmp.type(file_type::directory); + else if (S_ISBLK(mode)) fs_tmp.type(file_type::block); + else if (S_ISCHR(mode)) fs_tmp.type(file_type::character); + else if (S_ISFIFO(mode)) fs_tmp.type(file_type::fifo); + else if (S_ISSOCK(mode)) fs_tmp.type(file_type::socket); + else fs_tmp.type(file_type::unknown); + + fs_tmp.permissions(detail::posix_get_perms(path_stat)); + return fs_tmp; +} + +file_status posix_stat(path const & p, struct ::stat& path_stat, + std::error_code* ec) +{ + std::error_code m_ec; + if (::stat(p.c_str(), &path_stat) == -1) + m_ec = detail::capture_errno(); + return create_file_status(m_ec, p, path_stat, ec); +} + +file_status posix_stat(path const & p, std::error_code* ec) { + struct ::stat path_stat; + return posix_stat(p, path_stat, ec); +} + +file_status posix_lstat(path const & p, struct ::stat & path_stat, + std::error_code* ec) +{ + std::error_code m_ec; + if (::lstat(p.c_str(), &path_stat) == -1) + m_ec = detail::capture_errno(); + return create_file_status(m_ec, p, path_stat, ec); +} + +file_status posix_lstat(path const & p, std::error_code* ec) { + struct ::stat path_stat; + return posix_lstat(p, path_stat, ec); +} + +bool stat_equivalent(struct ::stat& st1, struct ::stat& st2) { + return (st1.st_dev == st2.st_dev && st1.st_ino == st2.st_ino); +} + +// DETAIL::MISC + + +bool copy_file_impl(const path& from, const path& to, perms from_perms, + std::error_code *ec) +{ + std::ifstream in(from.c_str(), std::ios::binary); + std::ofstream out(to.c_str(), std::ios::binary); + + if (in.good() && out.good()) { + using InIt = std::istreambuf_iterator<char>; + using OutIt = std::ostreambuf_iterator<char>; + InIt bin(in); + InIt ein; + OutIt bout(out); + std::copy(bin, ein, bout); + } + if (out.fail() || in.fail()) { + set_or_throw(make_error_code(errc::operation_not_permitted), + ec, "copy_file", from, to); + return false; + } + __permissions(to, from_perms, ec); + // TODO what if permissions fails? + return true; +} + +}} // end namespace detail + +using detail::set_or_throw; + +path __canonical(path const & orig_p, const path& base, std::error_code *ec) +{ + path p = absolute(orig_p, base); + char buff[PATH_MAX + 1]; + char *ret; + if ((ret = ::realpath(p.c_str(), buff)) == nullptr) { + set_or_throw(ec, "canonical", orig_p, base); + return {}; + } + if (ec) ec->clear(); + return {ret}; +} + +void __copy(const path& from, const path& to, copy_options options, + std::error_code *ec) +{ + const bool sym_status = bool(options & + (copy_options::create_symlinks | copy_options::skip_symlinks)); + + const bool sym_status2 = bool(options & + copy_options::copy_symlinks); + + std::error_code m_ec; + struct ::stat f_st = {}; + const file_status f = sym_status || sym_status2 + ? 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_ec) + : detail::posix_stat(to, t_st, &m_ec); + + if (not status_known(t)) + 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)) + || detail::stat_equivalent(f_st, t_st)) + { + return set_or_throw(make_error_code(errc::function_not_supported), + ec, "copy", from, to); + } + + if (ec) ec->clear(); + + if (is_symlink(f)) { + if (bool(copy_options::skip_symlinks & options)) { + // do nothing + } else if (not exists(t)) { + __copy_symlink(from, to, ec); + } else { + set_or_throw(make_error_code(errc::file_exists), + ec, "copy", from, to); + } + return; + } + else if (is_regular_file(f)) { + if (bool(copy_options::directories_only & options)) { + // do nothing + } + else if (bool(copy_options::create_symlinks & options)) { + __create_symlink(from, to, ec); + } + else if (bool(copy_options::create_hard_links & options)) { + __create_hard_link(from, to, ec); + } + else if (is_directory(t)) { + __copy_file(from, to / from.filename(), options, ec); + } else { + __copy_file(from, to, options, ec); + } + return; + } + 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'. + __create_directory(to, from, ec); + if (ec && *ec) { return; } + } + directory_iterator it = ec ? directory_iterator(from, *ec) + : directory_iterator(from); + if (ec && *ec) { return; } + 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; } + } + } +} + + +bool __copy_file(const path& from, const path& to, copy_options options, + std::error_code *ec) +{ + if (ec) ec->clear(); + + std::error_code m_ec; + auto from_st = detail::posix_stat(from, &m_ec); + if (not is_regular_file(from_st)) { + if (not m_ec) + m_ec = make_error_code(errc::not_supported); + set_or_throw(m_ec, ec, "copy_file", from, to); + return false; + } + + auto to_st = detail::posix_stat(to, &m_ec); + if (!status_known(to_st)) { + set_or_throw(m_ec, ec, "copy_file", from, to); + return false; + } + + const bool to_exists = exists(to_st); + if (to_exists && bool(copy_options::skip_existing & options)) { + return false; + } + else if (to_exists && bool(copy_options::update_existing & options)) { + auto from_time = __last_write_time(from, ec); + if (ec && *ec) { return false; } + auto to_time = __last_write_time(to, ec); + if (ec && *ec) { return false; } + if (from_time <= to_time) { + return false; + } + return detail::copy_file_impl(from, to, from_st.permissions(), ec); + } + else if (!to_exists || bool(copy_options::overwrite_existing & options)) { + return detail::copy_file_impl(from, to, from_st.permissions(), ec); + } + else { + set_or_throw(make_error_code(errc::file_exists), ec, "copy", from, to); + return false; + } +} + +void __copy_symlink(const path& existing_symlink, const path& new_symlink, + std::error_code *ec) +{ + const path real_path(__read_symlink(existing_symlink, ec)); + if (ec && *ec) { return; } + // NOTE: proposal says you should detect if you should call + // create_symlink or create_directory_symlink. I don't think this + // is needed with POSIX + __create_symlink(real_path, new_symlink, ec); +} + + +bool __create_directories(const path& p, std::error_code *ec) +{ + std::error_code m_ec; + auto const st = detail::posix_stat(p, &m_ec); + if (!status_known(st)) { + set_or_throw(m_ec, ec, "create_directories", p); + return false; + } + else if (is_directory(st)) { + if (ec) ec->clear(); + return false; + } + else if (exists(st)) { + set_or_throw(make_error_code(errc::file_exists), + ec, "create_directories", p); + return false; + } + + const path parent = p.parent_path(); + if (!parent.empty()) { + const file_status parent_st = status(parent, m_ec); + if (not status_known(parent_st)) { + set_or_throw(m_ec, ec, "create_directories", p); + return false; + } + if (not exists(parent_st)) { + __create_directories(parent, ec); + if (ec && *ec) { return false; } + } + } + return __create_directory(p, ec); +} + +bool __create_directory(const path& p, std::error_code *ec) +{ + if (ec) ec->clear(); + if (::mkdir(p.c_str(), static_cast<int>(perms::all)) == 0) + return true; + if (errno != EEXIST || !is_directory(p)) + set_or_throw(ec, "create_directory", p); + return false; +} + +bool __create_directory(path const & p, path const & attributes, + std::error_code *ec) +{ + struct ::stat attr_stat; + std::error_code mec; + auto st = detail::posix_stat(attributes, attr_stat, &mec); + if (!status_known(st)) { + set_or_throw(mec, ec, "create_directory", p, attributes); + return false; + } + if (ec) ec->clear(); + if (::mkdir(p.c_str(), attr_stat.st_mode) == 0) + return true; + if (errno != EEXIST || !is_directory(p)) + set_or_throw(ec, "create_directory", p, attributes); + return false; +} + +void __create_directory_symlink(path const & from, path const & to, + std::error_code *ec){ + if (::symlink(from.c_str(), to.c_str()) != 0) + set_or_throw(ec, "create_directory_symlink", from, to); + else if (ec) + ec->clear(); +} + +void __create_hard_link(const path& from, const path& to, std::error_code *ec){ + if (::link(from.c_str(), to.c_str()) == -1) + set_or_throw(ec, "create_hard_link", from, to); + else if (ec) + ec->clear(); +} + +void __create_symlink(path const & from, path const & to, std::error_code *ec) { + + if (::symlink(from.c_str(), to.c_str()) == -1) + set_or_throw(ec, "create_symlink", from, to); + else if (ec) + ec->clear(); +} + +path __current_path(std::error_code *ec) { + auto size = ::pathconf(".", _PC_PATH_MAX); + _LIBCPP_ASSERT(size >= 0, "pathconf returned a 0 as max size"); + + auto buff = std::unique_ptr<char[]>(new char[size + 1]); + char* ret; + if ((ret = ::getcwd(buff.get(), static_cast<size_t>(size))) == nullptr) { + set_or_throw(ec, "current_path"); + return {}; + } + if (ec) ec->clear(); + return {buff.get()}; +} + +void __current_path(const path& p, std::error_code *ec) { + if (::chdir(p.c_str()) == -1) + set_or_throw(ec, "current_path", p); + else if (ec) + ec->clear(); +} + +bool __equivalent(const path& p1, const path& p2, std::error_code *ec) +{ + std::error_code ec1, ec2; + struct ::stat st1 = {}; + struct ::stat st2 = {}; + auto s1 = detail::posix_stat(p1.native(), st1, &ec1); + auto s2 = detail::posix_stat(p2.native(), st2, &ec2); + + 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); +} + + +std::uintmax_t __file_size(const path& p, std::error_code *ec) +{ + std::error_code m_ec; + struct ::stat st; + file_status fst = detail::posix_stat(p, st, &m_ec); + if (!exists(fst) || !is_regular_file(fst)) { + if (!m_ec) + m_ec = make_error_code(errc::not_supported); + set_or_throw(m_ec, ec, "file_size", p); + return static_cast<uintmax_t>(-1); + } + // is_regular_file(p) == true + if (ec) ec->clear(); + return static_cast<std::uintmax_t>(st.st_size); +} + +std::uintmax_t __hard_link_count(const path& p, std::error_code *ec) +{ + std::error_code m_ec; + struct ::stat st; + detail::posix_stat(p, st, &m_ec); + if (m_ec) { + set_or_throw(m_ec, ec, "hard_link_count", p); + return static_cast<std::uintmax_t>(-1); + } + if (ec) ec->clear(); + return static_cast<std::uintmax_t>(st.st_nlink); +} + + +bool __fs_is_empty(const path& p, std::error_code *ec) +{ + if (ec) ec->clear(); + std::error_code m_ec; + struct ::stat pst; + auto st = detail::posix_stat(p, pst, &m_ec); + 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; + // else + set_or_throw(m_ec, ec, "is_empty", p); + return false; +} + + +namespace detail { namespace { + +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; + +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 + + +file_time_type __last_write_time(const path& p, std::error_code *ec) +{ + std::error_code m_ec; + struct ::stat st; + detail::posix_stat(p, st, &m_ec); + if (m_ec) { + set_or_throw(m_ec, ec, "last_write_time", p); + return file_time_type::min(); + } + if (ec) ec->clear(); + return file_time_type::clock::from_time_t(st.st_mtime); +} + +void __last_write_time(const path& p, file_time_type new_time, + std::error_code *ec) +{ + using namespace std::chrono; + std::error_code m_ec; + + // We can use the presence of UTIME_OMIT to detect platforms that do not + // provide utimensat. +#if !defined(UTIME_OMIT) + // This implementation has a race condition between determining the + // last access time and attempting to set it to the same value using + // ::utimes + struct ::stat st; + file_status fst = detail::posix_stat(p, st, &m_ec); + if (m_ec && !status_known(fst)) { + set_or_throw(m_ec, ec, "last_write_time", p); + return; + } + struct ::timeval tbuf[2]; + 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) { + set_or_throw(make_error_code(errc::invalid_argument), ec, + "last_write_time", p); + return; + } + if (::utimes(p.c_str(), tbuf) == -1) { + m_ec = detail::capture_errno(); + } +#else + struct ::timespec tbuf[2]; + tbuf[0].tv_sec = 0; + tbuf[0].tv_nsec = UTIME_OMIT; + + 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), + ec, "last_write_time", p); + return; + } + if (::utimensat(AT_FDCWD, p.c_str(), tbuf, 0) == -1) { + m_ec = detail::capture_errno(); + } +#endif + if (m_ec) + set_or_throw(m_ec, ec, "last_write_time", p); + else if (ec) + ec->clear(); +} + + +void __permissions(const path& p, perms prms, std::error_code *ec) +{ + + const bool resolve_symlinks = !bool(perms::symlink_nofollow & prms); + const bool add_perms = bool(perms::add_perms & prms); + const bool remove_perms = bool(perms::remove_perms & prms); + _LIBCPP_ASSERT(!(add_perms && remove_perms), + "Both add_perms and remove_perms are set"); + + bool set_sym_perms = false; + prms &= perms::mask; + if (!resolve_symlinks || (add_perms || remove_perms)) { + std::error_code m_ec; + file_status st = resolve_symlinks ? detail::posix_stat(p, &m_ec) + : detail::posix_lstat(p, &m_ec); + set_sym_perms = is_symlink(st); + if (m_ec) return set_or_throw(m_ec, ec, "permissions", p); + _LIBCPP_ASSERT(st.permissions() != perms::unknown, + "Permissions unexpectedly unknown"); + if (add_perms) + prms |= st.permissions(); + else if (remove_perms) + prms = st.permissions() & ~prms; + } + const auto real_perms = detail::posix_convert_perms(prms); + +# if defined(AT_SYMLINK_NOFOLLOW) && defined(AT_FDCWD) + const int flags = set_sym_perms ? AT_SYMLINK_NOFOLLOW : 0; + if (::fchmodat(AT_FDCWD, p.c_str(), real_perms, flags) == -1) { + return set_or_throw(ec, "permissions", p); + } +# else + if (set_sym_perms) + return set_or_throw(make_error_code(errc::operation_not_supported), + ec, "permissions", p); + if (::chmod(p.c_str(), real_perms) == -1) { + return set_or_throw(ec, "permissions", p); + } +# endif + if (ec) ec->clear(); +} + + +path __read_symlink(const path& p, std::error_code *ec) { + char buff[PATH_MAX + 1]; + std::error_code m_ec; + ::ssize_t ret; + if ((ret = ::readlink(p.c_str(), buff, PATH_MAX)) == -1) { + set_or_throw(ec, "read_symlink", p); + return {}; + } + _LIBCPP_ASSERT(ret <= PATH_MAX, "TODO"); + _LIBCPP_ASSERT(ret > 0, "TODO"); + if (ec) ec->clear(); + buff[ret] = 0; + return {buff}; +} + + +bool __remove(const path& p, std::error_code *ec) { + if (ec) ec->clear(); + if (::remove(p.c_str()) == -1) { + set_or_throw(ec, "remove", p); + return false; + } + return true; +} + +namespace { + +std::uintmax_t remove_all_impl(path const & p, std::error_code& ec) +{ + const auto npos = static_cast<std::uintmax_t>(-1); + const file_status st = __symlink_status(p, &ec); + if (ec) return npos; + std::uintmax_t count = 1; + if (is_directory(st)) { + for (directory_iterator it(p, ec); !ec && it != directory_iterator(); + it.increment(ec)) { + auto other_count = remove_all_impl(it->path(), ec); + if (ec) return npos; + count += other_count; + } + if (ec) return npos; + } + if (!__remove(p, &ec)) return npos; + return count; +} + +} // end namespace + +std::uintmax_t __remove_all(const path& p, std::error_code *ec) { + std::error_code mec; + auto count = remove_all_impl(p, mec); + if (mec) { + set_or_throw(mec, ec, "remove_all", p); + return static_cast<std::uintmax_t>(-1); + } + if (ec) ec->clear(); + return count; +} + +void __rename(const path& from, const path& to, std::error_code *ec) { + if (::rename(from.c_str(), to.c_str()) == -1) + set_or_throw(ec, "rename", from, to); + else if (ec) + ec->clear(); +} + +void __resize_file(const path& p, std::uintmax_t size, std::error_code *ec) { + if (::truncate(p.c_str(), static_cast<long>(size)) == -1) + set_or_throw(ec, "resize_file", p); + else if (ec) + ec->clear(); +} + +space_info __space(const path& p, std::error_code *ec) { + space_info si; + struct statvfs m_svfs = {}; + if (::statvfs(p.c_str(), &m_svfs) == -1) { + set_or_throw(ec, "space", p); + si.capacity = si.free = si.available = + static_cast<std::uintmax_t>(-1); + return si; + } + if (ec) ec->clear(); + // Multiply with overflow checking. + auto do_mult = [&](std::uintmax_t& out, std::uintmax_t other) { + 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); + do_mult(si.free, m_svfs.f_bfree); + do_mult(si.available, m_svfs.f_bavail); + return si; +} + +file_status __status(const path& p, std::error_code *ec) { + return detail::posix_stat(p, ec); +} + +file_status __symlink_status(const path& p, std::error_code *ec) { + 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; + 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); + set_or_throw(m_ec, ec, "temp_directory_path"); + return {}; +} + +// 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; + + auto abs_base = base.is_absolute() ? base : absolute(base); + + /* !has_root_name && !has_root_dir */ + if (root_name.empty() && root_dir.empty()) + { + return abs_base / p; + } + else if (!root_name.empty()) /* has_root_name && !has_root_dir */ + { + return root_name / abs_base.root_directory() + / + abs_base.relative_path() / p.relative_path(); + } + else /* !has_root_name && has_root_dir */ + { + if (abs_base.has_root_name()) + return abs_base.root_name() / p; + // else p is absolute, return outside of block + } + return p; +} + +_LIBCPP_END_NAMESPACE_EXPERIMENTAL_FILESYSTEM diff --git a/contrib/libc++/src/experimental/filesystem/path.cpp b/contrib/libc++/src/experimental/filesystem/path.cpp new file mode 100644 index 0000000..38c4498 --- /dev/null +++ b/contrib/libc++/src/experimental/filesystem/path.cpp @@ -0,0 +1,391 @@ +//===--------------------- 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 "experimental/string_view" +#include "utility" + +_LIBCPP_BEGIN_NAMESPACE_EXPERIMENTAL_FILESYSTEM + +_LIBCPP_CONSTEXPR path::value_type path::preferred_separator; + +namespace { namespace parser +{ + +using string_type = string_view; +using value_type = path::value_type; + +using string_view_pair = pair<string_view, string_view>; + +// status reporting +constexpr size_t npos = static_cast<size_t>(-1); + +inline bool good(size_t pos) { return pos != npos; } + +// lexical elements +constexpr value_type preferred_separator = path::preferred_separator; +constexpr value_type const * preferred_separator_str = "/"; +constexpr value_type const * dot = "."; + +// 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); + +size_t start_of(string_type const &, size_t); +size_t end_of(string_type const &, size_t); + +size_t root_name_start(const string_type& s); +size_t root_name_end(const string_type&); + +size_t root_directory_start(string_type const &); +size_t root_directory_end(string_type const &); + +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); + +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; + } + if (s.size() == 2) { + return 1; + } + size_t index = 2; // current position + if (s[index] == preferred_separator) { + return npos; + } + while (index + 1 < s.size() && s[index+1] != preferred_separator) { + ++index; + } + return index; +} + +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_); + } + + path_view_iterator& operator++() { + increment(); + return *this; + } + + path_view_iterator& operator--() { + decrement(); + return *this; + } + + void increment() { + if (__pos_ == parser::npos) return; + while (! set_position(parser::end_of(__s_, __pos_)+1)) + ; + return; + } + + 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))) + ; + } + } + + bool set_position(size_t pos) { + if (pos >= __s_.size()) { + __pos_ = parser::npos; + } else { + __pos_ = pos; + } + return valid_iterator_position(); + } + + 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_)); + } + + bool is_end() const { return __pos_ == parser::npos; } + + inline bool operator==(path_view_iterator const& __p) { + return __pos_ == __p.__pos_; + } +}; + +path_view_iterator pbegin(path const& p) { + return path_view_iterator(p.native()); +} + +path_view_iterator pend(path const& p) { + path_view_iterator __p(p.native()); + __p.__pos_ = parser::npos; + return __p; +} + +} // end namespace +/////////////////////////////////////////////////////////////////////////////// +// path definitions +/////////////////////////////////////////////////////////////////////////////// + +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 path::__root_name() const +{ + return parser::is_root_name(__pn_, 0) + ? parser::extract_preferred(__pn_, 0) + : string_view{}; +} + +string_view path::__root_directory() const +{ + auto start_i = parser::root_directory_start(__pn_); + if(!parser::good(start_i)) { + return {}; + } + return parser::extract_preferred(__pn_, start_i); +} + +string_view path::__relative_path() const +{ + 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 path::__parent_path() const +{ + 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 path::__filename() const +{ + return empty() ? string_view{} : *--pend(*this); +} + +string_view path::__stem() const +{ + return parser::separate_filename(__filename()).first; +} + +string_view path::__extension() const +{ + return parser::separate_filename(__filename()).second; +} + +//////////////////////////////////////////////////////////////////////////// +// path.comparisons +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; + ++thisIter; ++sIter; + } + if (thisIter.is_end() && sIter.is_end()) + return 0; + if (thisIter.is_end()) + return -1; + return 1; +} + +//////////////////////////////////////////////////////////////////////////// +// path.nonmembers +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 hp.first; +} + +//////////////////////////////////////////////////////////////////////////// +// path.itr +path::iterator path::begin() const +{ + path_view_iterator pit = pbegin(*this); + iterator it; + it.__path_ptr_ = this; + it.__pos_ = pit.__pos_; + it.__elem_.__assign_view(*pit); + return it; +} + +path::iterator path::end() const +{ + iterator it{}; + it.__path_ptr_ = this; + it.__pos_ = parser::npos; + return it; +} + +path::iterator& path::iterator::__increment() { + path_view_iterator it(__path_ptr_->native(), __pos_); + it.increment(); + __pos_ = it.__pos_; + __elem_.__assign_view(*it); + return *this; +} + +path::iterator& path::iterator::__decrement() { + path_view_iterator it(__path_ptr_->native(), __pos_); + it.decrement(); + __pos_ = it.__pos_; + __elem_.__assign_view(*it); + return *this; +} + +_LIBCPP_END_NAMESPACE_EXPERIMENTAL_FILESYSTEM diff --git a/contrib/libc++/src/experimental/memory_resource.cpp b/contrib/libc++/src/experimental/memory_resource.cpp new file mode 100644 index 0000000..c01eb08 --- /dev/null +++ b/contrib/libc++/src/experimental/memory_resource.cpp @@ -0,0 +1,144 @@ +//===------------------------ memory_resource.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/memory_resource" + +#ifndef _LIBCPP_HAS_NO_ATOMIC_HEADER +#include "atomic" +#elif !defined(_LIBCPP_HAS_NO_THREADS) +#include "mutex" +#endif + +_LIBCPP_BEGIN_NAMESPACE_LFTS_PMR + +// memory_resource + +//memory_resource::~memory_resource() {} + +// new_delete_resource() + +class _LIBCPP_TYPE_VIS_ONLY __new_delete_memory_resource_imp + : public memory_resource +{ +public: + ~__new_delete_memory_resource_imp() = default; + +protected: + virtual void* do_allocate(size_t __size, size_t __align) + { return __allocate(__size); } + + virtual void do_deallocate(void * __p, size_t, size_t) + { __deallocate(__p); } + + virtual bool do_is_equal(memory_resource const & __other) const _NOEXCEPT + { return &__other == this; } +}; + +// null_memory_resource() + +class _LIBCPP_TYPE_VIS_ONLY __null_memory_resource_imp + : public memory_resource +{ +public: + ~__null_memory_resource_imp() = default; + +protected: + virtual void* do_allocate(size_t, size_t) { +#ifndef _LIBCPP_NO_EXCEPTIONS + throw std::bad_alloc(); +#else + abort(); +#endif + } + virtual void do_deallocate(void *, size_t, size_t) {} + virtual bool do_is_equal(memory_resource const & __other) const _NOEXCEPT + { return &__other == this; } +}; + +namespace { + +union ResourceInitHelper { + struct { + __new_delete_memory_resource_imp new_delete_res; + __null_memory_resource_imp null_res; + } resources; + char dummy; + _LIBCPP_CONSTEXPR_AFTER_CXX11 ResourceInitHelper() : resources() {} + ~ResourceInitHelper() {} +}; +// When compiled in C++14 this initialization should be a constant expression. +// Only in C++11 is "init_priority" needed to ensure initialization order. +ResourceInitHelper res_init __attribute__((init_priority (101))); + +} // end namespace + + +memory_resource * new_delete_resource() _NOEXCEPT { + return &res_init.resources.new_delete_res; +} + +memory_resource * null_memory_resource() _NOEXCEPT { + return &res_init.resources.null_res; +} + +// default_memory_resource() + +static memory_resource * +__default_memory_resource(bool set = false, memory_resource * new_res = nullptr) _NOEXCEPT +{ +#ifndef _LIBCPP_HAS_NO_ATOMIC_HEADER + static atomic<memory_resource*> __res = + ATOMIC_VAR_INIT(&res_init.resources.new_delete_res); + if (set) { + new_res = new_res ? new_res : new_delete_resource(); + // TODO: Can a weaker ordering be used? + return _VSTD::atomic_exchange_explicit( + &__res, new_res, memory_order::memory_order_acq_rel); + } + else { + return _VSTD::atomic_load_explicit( + &__res, memory_order::memory_order_acquire); + } +#elif !defined(_LIBCPP_HAS_NO_THREADS) + static memory_resource * res = &res_init.resources.new_delete_res; + static mutex res_lock; + if (set) { + new_res = new_res ? new_res : new_delete_resource(); + lock_guard<mutex> guard(res_lock); + memory_resource * old_res = res; + res = new_res; + return old_res; + } else { + lock_guard<mutex> guard(res_lock); + return res; + } +#else + static memory_resource* res = &res_init.resources.new_delete_res; + if (set) { + new_res = new_res ? new_res : new_delete_resource(); + memory_resource * old_res = res; + res = new_res; + return old_res; + } else { + return res; + } +#endif +} + +memory_resource * get_default_resource() _NOEXCEPT +{ + return __default_memory_resource(); +} + +memory_resource * set_default_resource(memory_resource * __new_res) _NOEXCEPT +{ + return __default_memory_resource(true, __new_res); +} + +_LIBCPP_END_NAMESPACE_LFTS_PMR
\ No newline at end of file diff --git a/contrib/libc++/src/locale.cpp b/contrib/libc++/src/locale.cpp index 6b04e78..da2fd11 100644 --- a/contrib/libc++/src/locale.cpp +++ b/contrib/libc++/src/locale.cpp @@ -123,11 +123,6 @@ const locale::category locale::time; const locale::category locale::messages; const locale::category locale::all; -#if defined(__clang__) -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wpadded" -#endif - class _LIBCPP_HIDDEN locale::__imp : public facet { @@ -163,10 +158,6 @@ private: template <class F> void install_from(const __imp& other); }; -#if defined(__clang__) -#pragma clang diagnostic pop -#endif - locale::__imp::__imp(size_t refs) : facet(refs), facets_(N), @@ -1409,33 +1400,21 @@ ctype_byname<wchar_t>::do_tolower(char_type* low, const char_type* high) const wchar_t ctype_byname<wchar_t>::do_widen(char c) const { -#ifdef _LIBCPP_LOCALE__L_EXTENSIONS - return btowc_l(c, __l); -#else - return __btowc_l(c, __l); -#endif + return __libcpp_btowc_l(c, __l); } const char* ctype_byname<wchar_t>::do_widen(const char* low, const char* high, char_type* dest) const { for (; low != high; ++low, ++dest) -#ifdef _LIBCPP_LOCALE__L_EXTENSIONS - *dest = btowc_l(*low, __l); -#else - *dest = __btowc_l(*low, __l); -#endif + *dest = __libcpp_btowc_l(*low, __l); return low; } char ctype_byname<wchar_t>::do_narrow(char_type c, char dfault) const { -#ifdef _LIBCPP_LOCALE__L_EXTENSIONS - int r = wctob_l(c, __l); -#else - int r = __wctob_l(c, __l); -#endif + int r = __libcpp_wctob_l(c, __l); return r != static_cast<int>(WEOF) ? static_cast<char>(r) : dfault; } @@ -1444,11 +1423,7 @@ ctype_byname<wchar_t>::do_narrow(const char_type* low, const char_type* high, ch { for (; low != high; ++low, ++dest) { -#ifdef _LIBCPP_LOCALE__L_EXTENSIONS - int r = wctob_l(*low, __l); -#else - int r = __wctob_l(*low, __l); -#endif + int r = __libcpp_wctob_l(*low, __l); *dest = r != static_cast<int>(WEOF) ? static_cast<char>(r) : dfault; } return low; @@ -1558,22 +1533,14 @@ codecvt<wchar_t, char, mbstate_t>::do_out(state_type& st, { // save state in case it is needed to recover to_nxt on error mbstate_t save_state = st; -#ifdef _LIBCPP_LOCALE__L_EXTENSIONS - size_t n = wcsnrtombs_l(to, &frm_nxt, static_cast<size_t>(fend-frm), - static_cast<size_t>(to_end-to), &st, __l); -#else - size_t n = __wcsnrtombs_l(to, &frm_nxt, fend-frm, to_end-to, &st, __l); -#endif + size_t n = __libcpp_wcsnrtombs_l(to, &frm_nxt, static_cast<size_t>(fend-frm), + static_cast<size_t>(to_end-to), &st, __l); if (n == size_t(-1)) { // need to recover to_nxt for (to_nxt = to; frm != frm_nxt; ++frm) { -#ifdef _LIBCPP_LOCALE__L_EXTENSIONS - n = wcrtomb_l(to_nxt, *frm, &save_state, __l); -#else - n = __wcrtomb_l(to_nxt, *frm, &save_state, __l); -#endif + n = __libcpp_wcrtomb_l(to_nxt, *frm, &save_state, __l); if (n == size_t(-1)) break; to_nxt += n; @@ -1590,11 +1557,7 @@ codecvt<wchar_t, char, mbstate_t>::do_out(state_type& st, { // Try to write the terminating null extern_type tmp[MB_LEN_MAX]; -#ifdef _LIBCPP_LOCALE__L_EXTENSIONS - n = wcrtomb_l(tmp, intern_type(), &st, __l); -#else - n = __wcrtomb_l(tmp, intern_type(), &st, __l); -#endif + n = __libcpp_wcrtomb_l(tmp, intern_type(), &st, __l); if (n == size_t(-1)) // on error return error; if (n > static_cast<size_t>(to_end-to_nxt)) // is there room? @@ -1627,23 +1590,15 @@ codecvt<wchar_t, char, mbstate_t>::do_in(state_type& st, { // save state in case it is needed to recover to_nxt on error mbstate_t save_state = st; -#ifdef _LIBCPP_LOCALE__L_EXTENSIONS - size_t n = mbsnrtowcs_l(to, &frm_nxt, static_cast<size_t>(fend-frm), - static_cast<size_t>(to_end-to), &st, __l); -#else - size_t n = __mbsnrtowcs_l(to, &frm_nxt, fend-frm, to_end-to, &st, __l); -#endif + size_t n = __libcpp_mbsnrtowcs_l(to, &frm_nxt, static_cast<size_t>(fend-frm), + static_cast<size_t>(to_end-to), &st, __l); if (n == size_t(-1)) { // need to recover to_nxt for (to_nxt = to; frm != frm_nxt; ++to_nxt) { -#ifdef _LIBCPP_LOCALE__L_EXTENSIONS - n = mbrtowc_l(to_nxt, frm, static_cast<size_t>(fend-frm), - &save_state, __l); -#else - n = __mbrtowc_l(to_nxt, frm, fend-frm, &save_state, __l); -#endif + n = __libcpp_mbrtowc_l(to_nxt, frm, static_cast<size_t>(fend-frm), + &save_state, __l); switch (n) { case 0: @@ -1671,11 +1626,7 @@ codecvt<wchar_t, char, mbstate_t>::do_in(state_type& st, if (fend != frm_end) // set up next null terminated sequence { // Try to write the terminating null -#ifdef _LIBCPP_LOCALE__L_EXTENSIONS - n = mbrtowc_l(to_nxt, frm_nxt, 1, &st, __l); -#else - n = __mbrtowc_l(to_nxt, frm_nxt, 1, &st, __l); -#endif + n = __libcpp_mbrtowc_l(to_nxt, frm_nxt, 1, &st, __l); if (n != 0) // on error return error; ++to_nxt; @@ -1695,11 +1646,7 @@ codecvt<wchar_t, char, mbstate_t>::do_unshift(state_type& st, { to_nxt = to; extern_type tmp[MB_LEN_MAX]; -#ifdef _LIBCPP_LOCALE__L_EXTENSIONS - size_t n = wcrtomb_l(tmp, intern_type(), &st, __l); -#else - size_t n = __wcrtomb_l(tmp, intern_type(), &st, __l); -#endif + size_t n = __libcpp_wcrtomb_l(tmp, intern_type(), &st, __l); if (n == size_t(-1) || n == 0) // on error return error; --n; @@ -1713,21 +1660,11 @@ codecvt<wchar_t, char, mbstate_t>::do_unshift(state_type& st, int codecvt<wchar_t, char, mbstate_t>::do_encoding() const _NOEXCEPT { -#ifndef __CloudABI__ -#ifdef _LIBCPP_LOCALE__L_EXTENSIONS - if (mbtowc_l(nullptr, nullptr, MB_LEN_MAX, __l) != 0) -#else - if (__mbtowc_l(nullptr, nullptr, MB_LEN_MAX, __l) != 0) -#endif + if (__libcpp_mbtowc_l(nullptr, nullptr, MB_LEN_MAX, __l) != 0) return -1; -#endif // stateless encoding -#ifdef _LIBCPP_LOCALE__L_EXTENSIONS - if (__l == 0 || MB_CUR_MAX_L(__l) == 1) // there are no known constant length encodings -#else - if (__l == 0 || __mb_cur_max_l(__l) == 1) // there are no known constant length encodings -#endif + if (__l == 0 || __libcpp_mb_cur_max_l(__l) == 1) // there are no known constant length encodings return 1; // which take more than 1 char to form a wchar_t return 0; } @@ -1745,11 +1682,7 @@ codecvt<wchar_t, char, mbstate_t>::do_length(state_type& st, int nbytes = 0; for (size_t nwchar_t = 0; nwchar_t < mx && frm != frm_end; ++nwchar_t) { -#ifdef _LIBCPP_LOCALE__L_EXTENSIONS - size_t n = mbrlen_l(frm, static_cast<size_t>(frm_end-frm), &st, __l); -#else - size_t n = __mbrlen_l(frm, frm_end-frm, &st, __l); -#endif + size_t n = __libcpp_mbrlen_l(frm, static_cast<size_t>(frm_end-frm), &st, __l); switch (n) { case 0: @@ -1771,11 +1704,7 @@ codecvt<wchar_t, char, mbstate_t>::do_length(state_type& st, int codecvt<wchar_t, char, mbstate_t>::do_max_length() const _NOEXCEPT { -#ifdef _LIBCPP_LOCALE__L_EXTENSIONS - return __l == 0 ? 1 : static_cast<int>( MB_CUR_MAX_L(__l)); -#else - return __l == 0 ? 1 : static_cast<int>(__mb_cur_max_l(__l)); -#endif + return __l == 0 ? 1 : static_cast<int>(__libcpp_mb_cur_max_l(__l)); } // Valid UTF ranges @@ -2894,10 +2823,10 @@ ucs4_to_utf16le(const uint32_t* frm, const uint32_t* frm_end, const uint32_t*& f to_nxt = to; if (mode & generate_header) { - if (to_end-to_nxt < 2) + if (to_end - to_nxt < 2) return codecvt_base::partial; - *to_nxt++ = static_cast<uint8_t>(0xFF); - *to_nxt++ = static_cast<uint8_t>(0xFE); + *to_nxt++ = static_cast<uint8_t>(0xFF); + *to_nxt++ = static_cast<uint8_t>(0xFE); } for (; frm_nxt < frm_end; ++frm_nxt) { @@ -4333,11 +4262,7 @@ numpunct_byname<char>::__init(const char* nm) throw runtime_error("numpunct_byname<char>::numpunct_byname" " failed to construct for " + string(nm)); #endif // _LIBCPP_NO_EXCEPTIONS -#ifdef _LIBCPP_LOCALE__L_EXTENSIONS - lconv* lc = localeconv_l(loc.get()); -#else - lconv* lc = __localeconv_l(loc.get()); -#endif + lconv* lc = __libcpp_localeconv_l(loc.get()); if (*lc->decimal_point) __decimal_point_ = *lc->decimal_point; if (*lc->thousands_sep) @@ -4376,11 +4301,7 @@ numpunct_byname<wchar_t>::__init(const char* nm) throw runtime_error("numpunct_byname<char>::numpunct_byname" " failed to construct for " + string(nm)); #endif // _LIBCPP_NO_EXCEPTIONS -#ifdef _LIBCPP_LOCALE__L_EXTENSIONS - lconv* lc = localeconv_l(loc.get()); -#else - lconv* lc = __localeconv_l(loc.get()); -#endif + lconv* lc = __libcpp_localeconv_l(loc.get()); if (*lc->decimal_point) __decimal_point_ = *lc->decimal_point; if (*lc->thousands_sep) @@ -4981,11 +4902,7 @@ __time_get_storage<wchar_t>::__analyze(char fmt, const ctype<wchar_t>& ct) wchar_t* wbb = wbuf; mbstate_t mb = {0}; const char* bb = buf; -#ifdef _LIBCPP_LOCALE__L_EXTENSIONS - size_t j = mbsrtowcs_l( wbb, &bb, countof(wbuf), &mb, __loc_); -#else - size_t j = __mbsrtowcs_l( wbb, &bb, countof(wbuf), &mb, __loc_); -#endif + size_t j = __libcpp_mbsrtowcs_l( wbb, &bb, countof(wbuf), &mb, __loc_); if (j == size_t(-1)) __throw_runtime_error("locale not supported"); wchar_t* wbe = wbb + j; @@ -5165,11 +5082,7 @@ __time_get_storage<wchar_t>::init(const ctype<wchar_t>& ct) strftime_l(buf, countof(buf), "%A", &t, __loc_); mb = mbstate_t(); const char* bb = buf; -#ifdef _LIBCPP_LOCALE__L_EXTENSIONS - size_t j = mbsrtowcs_l(wbuf, &bb, countof(wbuf), &mb, __loc_); -#else - size_t j = __mbsrtowcs_l(wbuf, &bb, countof(wbuf), &mb, __loc_); -#endif + size_t j = __libcpp_mbsrtowcs_l(wbuf, &bb, countof(wbuf), &mb, __loc_); if (j == size_t(-1)) __throw_runtime_error("locale not supported"); wbe = wbuf + j; @@ -5177,11 +5090,7 @@ __time_get_storage<wchar_t>::init(const ctype<wchar_t>& ct) strftime_l(buf, countof(buf), "%a", &t, __loc_); mb = mbstate_t(); bb = buf; -#ifdef _LIBCPP_LOCALE__L_EXTENSIONS - j = mbsrtowcs_l(wbuf, &bb, countof(wbuf), &mb, __loc_); -#else - j = __mbsrtowcs_l(wbuf, &bb, countof(wbuf), &mb, __loc_); -#endif + j = __libcpp_mbsrtowcs_l(wbuf, &bb, countof(wbuf), &mb, __loc_); if (j == size_t(-1)) __throw_runtime_error("locale not supported"); wbe = wbuf + j; @@ -5194,11 +5103,7 @@ __time_get_storage<wchar_t>::init(const ctype<wchar_t>& ct) strftime_l(buf, countof(buf), "%B", &t, __loc_); mb = mbstate_t(); const char* bb = buf; -#ifdef _LIBCPP_LOCALE__L_EXTENSIONS - size_t j = mbsrtowcs_l(wbuf, &bb, countof(wbuf), &mb, __loc_); -#else - size_t j = __mbsrtowcs_l(wbuf, &bb, countof(wbuf), &mb, __loc_); -#endif + size_t j = __libcpp_mbsrtowcs_l(wbuf, &bb, countof(wbuf), &mb, __loc_); if (j == size_t(-1)) __throw_runtime_error("locale not supported"); wbe = wbuf + j; @@ -5206,11 +5111,7 @@ __time_get_storage<wchar_t>::init(const ctype<wchar_t>& ct) strftime_l(buf, countof(buf), "%b", &t, __loc_); mb = mbstate_t(); bb = buf; -#ifdef _LIBCPP_LOCALE__L_EXTENSIONS - j = mbsrtowcs_l(wbuf, &bb, countof(wbuf), &mb, __loc_); -#else - j = __mbsrtowcs_l(wbuf, &bb, countof(wbuf), &mb, __loc_); -#endif + j = __libcpp_mbsrtowcs_l(wbuf, &bb, countof(wbuf), &mb, __loc_); if (j == size_t(-1)) __throw_runtime_error("locale not supported"); wbe = wbuf + j; @@ -5221,11 +5122,7 @@ __time_get_storage<wchar_t>::init(const ctype<wchar_t>& ct) strftime_l(buf, countof(buf), "%p", &t, __loc_); mb = mbstate_t(); const char* bb = buf; -#ifdef _LIBCPP_LOCALE__L_EXTENSIONS - size_t j = mbsrtowcs_l(wbuf, &bb, countof(wbuf), &mb, __loc_); -#else - size_t j = __mbsrtowcs_l(wbuf, &bb, countof(wbuf), &mb, __loc_); -#endif + size_t j = __libcpp_mbsrtowcs_l(wbuf, &bb, countof(wbuf), &mb, __loc_); if (j == size_t(-1)) __throw_runtime_error("locale not supported"); wbe = wbuf + j; @@ -5234,11 +5131,7 @@ __time_get_storage<wchar_t>::init(const ctype<wchar_t>& ct) strftime_l(buf, countof(buf), "%p", &t, __loc_); mb = mbstate_t(); bb = buf; -#ifdef _LIBCPP_LOCALE__L_EXTENSIONS - j = mbsrtowcs_l(wbuf, &bb, countof(wbuf), &mb, __loc_); -#else - j = __mbsrtowcs_l(wbuf, &bb, countof(wbuf), &mb, __loc_); -#endif + j = __libcpp_mbsrtowcs_l(wbuf, &bb, countof(wbuf), &mb, __loc_); if (j == size_t(-1)) __throw_runtime_error("locale not supported"); wbe = wbuf + j; @@ -5513,11 +5406,7 @@ __time_put::__do_put(wchar_t* __wb, wchar_t*& __we, const tm* __tm, __do_put(__nar, __ne, __tm, __fmt, __mod); mbstate_t mb = {0}; const char* __nb = __nar; -#ifdef _LIBCPP_LOCALE__L_EXTENSIONS - size_t j = mbsrtowcs_l(__wb, &__nb, countof(__wb, __we), &mb, __loc_); -#else - size_t j = __mbsrtowcs_l(__wb, &__nb, countof(__wb, __we), &mb, __loc_); -#endif + size_t j = __libcpp_mbsrtowcs_l(__wb, &__nb, countof(__wb, __we), &mb, __loc_); if (j == size_t(-1)) __throw_runtime_error("locale not supported"); __we = __wb + j; @@ -5908,11 +5797,7 @@ moneypunct_byname<char, false>::init(const char* nm) throw runtime_error("moneypunct_byname" " failed to construct for " + string(nm)); #endif // _LIBCPP_NO_EXCEPTIONS -#ifdef _LIBCPP_LOCALE__L_EXTENSIONS - lconv* lc = localeconv_l(loc.get()); -#else - lconv* lc = __localeconv_l(loc.get()); -#endif + lconv* lc = __libcpp_localeconv_l(loc.get()); if (*lc->mon_decimal_point) __decimal_point_ = *lc->mon_decimal_point; else @@ -5956,11 +5841,7 @@ moneypunct_byname<char, true>::init(const char* nm) throw runtime_error("moneypunct_byname" " failed to construct for " + string(nm)); #endif // _LIBCPP_NO_EXCEPTIONS -#ifdef _LIBCPP_LOCALE__L_EXTENSIONS - lconv* lc = localeconv_l(loc.get()); -#else - lconv* lc = __localeconv_l(loc.get()); -#endif + lconv* lc = __libcpp_localeconv_l(loc.get()); if (*lc->mon_decimal_point) __decimal_point_ = *lc->mon_decimal_point; else @@ -6021,11 +5902,7 @@ moneypunct_byname<wchar_t, false>::init(const char* nm) throw runtime_error("moneypunct_byname" " failed to construct for " + string(nm)); #endif // _LIBCPP_NO_EXCEPTIONS -#ifdef _LIBCPP_LOCALE__L_EXTENSIONS - lconv* lc = localeconv_l(loc.get()); -#else - lconv* lc = __localeconv_l(loc.get()); -#endif + lconv* lc = __libcpp_localeconv_l(loc.get()); if (*lc->mon_decimal_point) __decimal_point_ = static_cast<wchar_t>(*lc->mon_decimal_point); else @@ -6038,11 +5915,7 @@ moneypunct_byname<wchar_t, false>::init(const char* nm) wchar_t wbuf[100]; mbstate_t mb = {0}; const char* bb = lc->currency_symbol; -#ifdef _LIBCPP_LOCALE__L_EXTENSIONS - size_t j = mbsrtowcs_l(wbuf, &bb, countof(wbuf), &mb, loc.get()); -#else - size_t j = __mbsrtowcs_l(wbuf, &bb, countof(wbuf), &mb, loc.get()); -#endif + size_t j = __libcpp_mbsrtowcs_l(wbuf, &bb, countof(wbuf), &mb, loc.get()); if (j == size_t(-1)) __throw_runtime_error("locale not supported"); wchar_t* wbe = wbuf + j; @@ -6057,11 +5930,7 @@ moneypunct_byname<wchar_t, false>::init(const char* nm) { mb = mbstate_t(); bb = lc->positive_sign; -#ifdef _LIBCPP_LOCALE__L_EXTENSIONS - j = mbsrtowcs_l(wbuf, &bb, countof(wbuf), &mb, loc.get()); -#else - j = __mbsrtowcs_l(wbuf, &bb, countof(wbuf), &mb, loc.get()); -#endif + j = __libcpp_mbsrtowcs_l(wbuf, &bb, countof(wbuf), &mb, loc.get()); if (j == size_t(-1)) __throw_runtime_error("locale not supported"); wbe = wbuf + j; @@ -6073,11 +5942,7 @@ moneypunct_byname<wchar_t, false>::init(const char* nm) { mb = mbstate_t(); bb = lc->negative_sign; -#ifdef _LIBCPP_LOCALE__L_EXTENSIONS - j = mbsrtowcs_l(wbuf, &bb, countof(wbuf), &mb, loc.get()); -#else - j = __mbsrtowcs_l(wbuf, &bb, countof(wbuf), &mb, loc.get()); -#endif + j = __libcpp_mbsrtowcs_l(wbuf, &bb, countof(wbuf), &mb, loc.get()); if (j == size_t(-1)) __throw_runtime_error("locale not supported"); wbe = wbuf + j; @@ -6104,11 +5969,7 @@ moneypunct_byname<wchar_t, true>::init(const char* nm) throw runtime_error("moneypunct_byname" " failed to construct for " + string(nm)); #endif // _LIBCPP_NO_EXCEPTIONS -#ifdef _LIBCPP_LOCALE__L_EXTENSIONS - lconv* lc = localeconv_l(loc.get()); -#else - lconv* lc = __localeconv_l(loc.get()); -#endif + lconv* lc = __libcpp_localeconv_l(loc.get()); if (*lc->mon_decimal_point) __decimal_point_ = static_cast<wchar_t>(*lc->mon_decimal_point); else @@ -6121,11 +5982,7 @@ moneypunct_byname<wchar_t, true>::init(const char* nm) wchar_t wbuf[100]; mbstate_t mb = {0}; const char* bb = lc->int_curr_symbol; -#ifdef _LIBCPP_LOCALE__L_EXTENSIONS - size_t j = mbsrtowcs_l(wbuf, &bb, countof(wbuf), &mb, loc.get()); -#else - size_t j = __mbsrtowcs_l(wbuf, &bb, countof(wbuf), &mb, loc.get()); -#endif + size_t j = __libcpp_mbsrtowcs_l(wbuf, &bb, countof(wbuf), &mb, loc.get()); if (j == size_t(-1)) __throw_runtime_error("locale not supported"); wchar_t* wbe = wbuf + j; @@ -6144,11 +6001,7 @@ moneypunct_byname<wchar_t, true>::init(const char* nm) { mb = mbstate_t(); bb = lc->positive_sign; -#ifdef _LIBCPP_LOCALE__L_EXTENSIONS - j = mbsrtowcs_l(wbuf, &bb, countof(wbuf), &mb, loc.get()); -#else - j = __mbsrtowcs_l(wbuf, &bb, countof(wbuf), &mb, loc.get()); -#endif + j = __libcpp_mbsrtowcs_l(wbuf, &bb, countof(wbuf), &mb, loc.get()); if (j == size_t(-1)) __throw_runtime_error("locale not supported"); wbe = wbuf + j; @@ -6164,11 +6017,7 @@ moneypunct_byname<wchar_t, true>::init(const char* nm) { mb = mbstate_t(); bb = lc->negative_sign; -#ifdef _LIBCPP_LOCALE__L_EXTENSIONS - j = mbsrtowcs_l(wbuf, &bb, countof(wbuf), &mb, loc.get()); -#else - j = __mbsrtowcs_l(wbuf, &bb, countof(wbuf), &mb, loc.get()); -#endif + j = __libcpp_mbsrtowcs_l(wbuf, &bb, countof(wbuf), &mb, loc.get()); if (j == size_t(-1)) __throw_runtime_error("locale not supported"); wbe = wbuf + j; diff --git a/contrib/libc++/src/memory.cpp b/contrib/libc++/src/memory.cpp index 5b81f26..15e947f 100644 --- a/contrib/libc++/src/memory.cpp +++ b/contrib/libc++/src/memory.cpp @@ -124,15 +124,15 @@ __shared_weak_count::__get_deleter(const type_info&) const _NOEXCEPT #endif // _LIBCPP_NO_RTTI -#if defined(_LIBCPP_HAS_C_ATOMIC_IMP) && !defined(_LIBCPP_HAS_NO_THREADS) +#if !defined(_LIBCPP_HAS_NO_ATOMIC_HEADER) static const std::size_t __sp_mut_count = 16; -static pthread_mutex_t mut_back_imp[__sp_mut_count] = +static __libcpp_mutex_t mut_back_imp[__sp_mut_count] = { - PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, - PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, - PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, - PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER + _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER, + _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER, + _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER, + _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER, _LIBCPP_MUTEX_INITIALIZER }; static mutex* mut_back = reinterpret_cast<std::mutex*>(mut_back_imp); @@ -177,7 +177,7 @@ __get_sp_mut(const void* p) return muts[hash<const void*>()(p) & (__sp_mut_count-1)]; } -#endif // defined(_LIBCPP_HAS_C_ATOMIC_IMP) && !defined(_LIBCPP_HAS_NO_THREADS) +#endif // !defined(_LIBCPP_HAS_NO_ATOMIC_HEADER) void declare_reachable(void*) diff --git a/contrib/libc++/src/mutex.cpp b/contrib/libc++/src/mutex.cpp index 127e67a..9f808ca 100644 --- a/contrib/libc++/src/mutex.cpp +++ b/contrib/libc++/src/mutex.cpp @@ -23,13 +23,13 @@ const adopt_lock_t adopt_lock = {}; mutex::~mutex() { - pthread_mutex_destroy(&__m_); + __libcpp_mutex_destroy(&__m_); } void mutex::lock() { - int ec = pthread_mutex_lock(&__m_); + int ec = __libcpp_mutex_lock(&__m_); if (ec) __throw_system_error(ec, "mutex lock failed"); } @@ -37,13 +37,13 @@ mutex::lock() bool mutex::try_lock() _NOEXCEPT { - return pthread_mutex_trylock(&__m_) == 0; + return __libcpp_mutex_trylock(&__m_) == 0; } void mutex::unlock() _NOEXCEPT { - int ec = pthread_mutex_unlock(&__m_); + int ec = __libcpp_mutex_unlock(&__m_); (void)ec; assert(ec == 0); } @@ -52,36 +52,14 @@ mutex::unlock() _NOEXCEPT recursive_mutex::recursive_mutex() { - pthread_mutexattr_t attr; - int ec = pthread_mutexattr_init(&attr); + int ec = __libcpp_recursive_mutex_init(&__m_); if (ec) - goto fail; - ec = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); - if (ec) - { - pthread_mutexattr_destroy(&attr); - goto fail; - } - ec = pthread_mutex_init(&__m_, &attr); - if (ec) - { - pthread_mutexattr_destroy(&attr); - goto fail; - } - ec = pthread_mutexattr_destroy(&attr); - if (ec) - { - pthread_mutex_destroy(&__m_); - goto fail; - } - return; -fail: - __throw_system_error(ec, "recursive_mutex constructor failed"); + __throw_system_error(ec, "recursive_mutex constructor failed"); } recursive_mutex::~recursive_mutex() { - int e = pthread_mutex_destroy(&__m_); + int e = __libcpp_mutex_destroy(&__m_); (void)e; assert(e == 0); } @@ -89,7 +67,7 @@ recursive_mutex::~recursive_mutex() void recursive_mutex::lock() { - int ec = pthread_mutex_lock(&__m_); + int ec = __libcpp_mutex_lock(&__m_); if (ec) __throw_system_error(ec, "recursive_mutex lock failed"); } @@ -97,7 +75,7 @@ recursive_mutex::lock() void recursive_mutex::unlock() _NOEXCEPT { - int e = pthread_mutex_unlock(&__m_); + int e = __libcpp_mutex_unlock(&__m_); (void)e; assert(e == 0); } @@ -105,7 +83,7 @@ recursive_mutex::unlock() _NOEXCEPT bool recursive_mutex::try_lock() _NOEXCEPT { - return pthread_mutex_trylock(&__m_) == 0; + return __libcpp_mutex_trylock(&__m_) == 0; } // timed_mutex @@ -165,9 +143,9 @@ recursive_timed_mutex::~recursive_timed_mutex() void recursive_timed_mutex::lock() { - pthread_t id = pthread_self(); + __libcpp_thread_id id = __libcpp_thread_get_current_id(); unique_lock<mutex> lk(__m_); - if (pthread_equal(id, __id_)) + if (__libcpp_thread_id_equal(id, __id_)) { if (__count_ == numeric_limits<size_t>::max()) __throw_system_error(EAGAIN, "recursive_timed_mutex lock limit reached"); @@ -183,9 +161,9 @@ recursive_timed_mutex::lock() bool recursive_timed_mutex::try_lock() _NOEXCEPT { - pthread_t id = pthread_self(); + __libcpp_thread_id id = __libcpp_thread_get_current_id(); unique_lock<mutex> lk(__m_, try_to_lock); - if (lk.owns_lock() && (__count_ == 0 || pthread_equal(id, __id_))) + if (lk.owns_lock() && (__count_ == 0 || __libcpp_thread_id_equal(id, __id_))) { if (__count_ == numeric_limits<size_t>::max()) return false; @@ -217,8 +195,8 @@ recursive_timed_mutex::unlock() _NOEXCEPT // keep in sync with: 7741191. #ifndef _LIBCPP_HAS_NO_THREADS -static pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER; -static pthread_cond_t cv = PTHREAD_COND_INITIALIZER; +static __libcpp_mutex_t mut = _LIBCPP_MUTEX_INITIALIZER; +static __libcpp_condvar_t cv = _LIBCPP_CONDVAR_INITIALIZER; #endif /// NOTE: Changes to flag are done via relaxed atomic stores @@ -247,9 +225,9 @@ __call_once(volatile unsigned long& flag, void* arg, void(*func)(void*)) #endif // _LIBCPP_NO_EXCEPTIONS } #else // !_LIBCPP_HAS_NO_THREADS - pthread_mutex_lock(&mut); + __libcpp_mutex_lock(&mut); while (flag == 1) - pthread_cond_wait(&cv, &mut); + __libcpp_condvar_wait(&cv, &mut); if (flag == 0) { #ifndef _LIBCPP_NO_EXCEPTIONS @@ -257,26 +235,26 @@ __call_once(volatile unsigned long& flag, void* arg, void(*func)(void*)) { #endif // _LIBCPP_NO_EXCEPTIONS __libcpp_relaxed_store(&flag, 1ul); - pthread_mutex_unlock(&mut); + __libcpp_mutex_unlock(&mut); func(arg); - pthread_mutex_lock(&mut); + __libcpp_mutex_lock(&mut); __libcpp_relaxed_store(&flag, ~0ul); - pthread_mutex_unlock(&mut); - pthread_cond_broadcast(&cv); + __libcpp_mutex_unlock(&mut); + __libcpp_condvar_broadcast(&cv); #ifndef _LIBCPP_NO_EXCEPTIONS } catch (...) { - pthread_mutex_lock(&mut); + __libcpp_mutex_lock(&mut); __libcpp_relaxed_store(&flag, 0ul); - pthread_mutex_unlock(&mut); - pthread_cond_broadcast(&cv); + __libcpp_mutex_unlock(&mut); + __libcpp_condvar_broadcast(&cv); throw; } #endif // _LIBCPP_NO_EXCEPTIONS } else - pthread_mutex_unlock(&mut); + __libcpp_mutex_unlock(&mut); #endif // !_LIBCPP_HAS_NO_THREADS } diff --git a/contrib/libc++/src/regex.cpp b/contrib/libc++/src/regex.cpp index 17dd6ea..a736359 100644 --- a/contrib/libc++/src/regex.cpp +++ b/contrib/libc++/src/regex.cpp @@ -69,21 +69,12 @@ regex_error::~regex_error() throw() {} namespace { -#if defined(__clang__) -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wpadded" -#endif - struct collationnames { const char* elem_; char char_; }; -#if defined(__clang__) -#pragma clang diagnostic pop -#endif - const collationnames collatenames[] = { {"A", 0x41}, @@ -199,21 +190,12 @@ const collationnames collatenames[] = {"zero", 0x30} }; -#if defined(__clang__) -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wpadded" -#endif - struct classnames { const char* elem_; regex_traits<char>::char_class_type mask_; }; -#if defined(__clang__) -#pragma clang diagnostic pop -#endif - const classnames ClassNames[] = { {"alnum", ctype_base::alnum}, diff --git a/contrib/libc++/src/strstream.cpp b/contrib/libc++/src/strstream.cpp index ea72813..0e2d7ff 100644 --- a/contrib/libc++/src/strstream.cpp +++ b/contrib/libc++/src/strstream.cpp @@ -11,6 +11,7 @@ #include "algorithm" #include "climits" #include "cstring" +#include "__debug" _LIBCPP_BEGIN_NAMESPACE_STD @@ -167,11 +168,13 @@ strstreambuf::overflow(int_type __c) buf = new char[new_size]; if (buf == nullptr) return int_type(EOF); - memcpy(buf, eback(), static_cast<size_t>(old_size)); + if (old_size != 0) { + _LIBCPP_ASSERT(eback(), "overflow copying from NULL"); + memcpy(buf, eback(), static_cast<size_t>(old_size)); + } ptrdiff_t ninp = gptr() - eback(); ptrdiff_t einp = egptr() - eback(); ptrdiff_t nout = pptr() - pbase(); - ptrdiff_t eout = epptr() - pbase(); if (__strmode_ & __allocated) { if (__pfree_) @@ -180,7 +183,7 @@ strstreambuf::overflow(int_type __c) delete [] eback(); } setg(buf, buf + ninp, buf + einp); - setp(buf + einp, buf + einp + eout); + setp(buf + einp, buf + new_size); pbump(static_cast<int>(nout)); __strmode_ |= __allocated; } diff --git a/contrib/libc++/src/system_error.cpp b/contrib/libc++/src/system_error.cpp index 3023e20..87f35ae 100644 --- a/contrib/libc++/src/system_error.cpp +++ b/contrib/libc++/src/system_error.cpp @@ -13,8 +13,17 @@ #include "system_error" #include "include/config_elast.h" +#include "cerrno" #include "cstring" +#include "cstdio" +#include "cstdlib" +#include "cassert" #include "string" +#include "string.h" + +#if defined(__ANDROID__) +#include <android/api-level.h> +#endif _LIBCPP_BEGIN_NAMESPACE_STD @@ -46,10 +55,56 @@ error_category::equivalent(const error_code& code, int condition) const _NOEXCEP return *this == code.category() && code.value() == condition; } +namespace { + +// GLIBC also uses 1024 as the maximum buffer size internally. +constexpr size_t strerror_buff_size = 1024; + +string do_strerror_r(int ev); + +#if defined(__linux__) && !defined(_LIBCPP_HAS_MUSL_LIBC) \ + && (!defined(__ANDROID__) || __ANDROID_API__ >= 23) +// GNU Extended version +string do_strerror_r(int ev) { + char buffer[strerror_buff_size]; + char* ret = ::strerror_r(ev, buffer, strerror_buff_size); + return string(ret); +} +#else +// POSIX version +string do_strerror_r(int ev) { + char buffer[strerror_buff_size]; + const int old_errno = errno; + int ret; + if ((ret = ::strerror_r(ev, buffer, strerror_buff_size)) != 0) { + // If `ret == -1` then the error is specified using `errno`, otherwise + // `ret` represents the error. + const int new_errno = ret == -1 ? errno : ret; + errno = old_errno; + if (new_errno == EINVAL) { + std::snprintf(buffer, strerror_buff_size, "Unknown error %d", ev); + return string(buffer); + } else { + assert(new_errno == ERANGE); + // FIXME maybe? 'strerror_buff_size' is likely to exceed the + // maximum error size so ERANGE shouldn't be returned. + std::abort(); + } + } + return string(buffer); +} +#endif + +} // end namespace + string __do_message::message(int ev) const { - return string(strerror(ev)); +#if defined(_LIBCPP_HAS_NO_THREADS) + return string(::strerror(ev)); +#else + return do_strerror_r(ev); +#endif } class _LIBCPP_HIDDEN __generic_error_category diff --git a/contrib/libc++/src/thread.cpp b/contrib/libc++/src/thread.cpp index bd27f28..467402b 100644 --- a/contrib/libc++/src/thread.cpp +++ b/contrib/libc++/src/thread.cpp @@ -16,10 +16,15 @@ #include "future" #include "limits" #include <sys/types.h> -#if !defined(_WIN32) -# if !defined(__sun__) && !defined(__linux__) && !defined(_AIX) && !defined(__native_client__) && !defined(__CloudABI__) + +#if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) +# include <sys/param.h> +# if defined(BSD) # include <sys/sysctl.h> -# endif // !defined(__sun__) && !defined(__linux__) && !defined(_AIX) && !defined(__native_client__) && !defined(__CloudABI__) +# endif // defined(BSD) +#endif // defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) + +#if !defined(_WIN32) # include <unistd.h> #endif // !_WIN32 @@ -41,14 +46,17 @@ thread::~thread() void thread::join() { - int ec = pthread_join(__t_, 0); + int ec = EINVAL; + if (__t_ != 0) + { + ec = __libcpp_thread_join(&__t_); + if (ec == 0) + __t_ = 0; + } #ifndef _LIBCPP_NO_EXCEPTIONS if (ec) throw system_error(error_code(ec, system_category()), "thread::join failed"); -#else - (void)ec; #endif // _LIBCPP_NO_EXCEPTIONS - __t_ = 0; } void @@ -57,7 +65,7 @@ thread::detach() int ec = EINVAL; if (__t_ != 0) { - ec = pthread_detach(__t_); + ec = __libcpp_thread_detach(&__t_); if (ec == 0) __t_ = 0; } |