Index: CMakeLists.txt =================================================================== --- CMakeLists.txt +++ CMakeLists.txt @@ -48,6 +48,7 @@ # Basic options --------------------------------------------------------------- option(LIBCXX_ENABLE_ASSERTIONS "Enable assertions independent of build mode." ON) +option(LIBCXX_ENABLE_FILESYSTEM "Build the C++ filesystem library." ON) option(LIBCXX_ENABLE_SHARED "Build libc++ as a shared library." ON) option(LIBCXX_INCLUDE_TESTS "Build the libc++ tests." ${LLVM_INCLUDE_TESTS}) @@ -122,6 +123,8 @@ This option may only be set to OFF when LIBCXX_ENABLE_THREADS=OFF." ON) option(LIBCXX_HAS_MUSL_LIBC "Build libc++ with support for the Musl C library" OFF) +option(LIBCXX_ENABLE_FILESYSTEM "Build the C++ filesystem library." ON) + # Misc options ---------------------------------------------------------------- # FIXME: Turn -pedantic back ON. It is currently off because it warns # about #include_next which is used everywhere. @@ -394,9 +397,13 @@ include_directories(include) add_subdirectory(include) add_subdirectory(lib) +if (LIBCXX_ENABLE_FILESYSTEM) + add_subdirectory(lib/filesystem) +endif() +add_subdirectory(test) if (LIBCXX_INCLUDE_TESTS) - add_subdirectory(test) + #add_subdirectory(test) endif() if (LIBCXX_INCLUDE_DOCS) add_subdirectory(docs) Index: include/experimental/__config =================================================================== --- include/experimental/__config +++ include/experimental/__config @@ -29,4 +29,14 @@ namespace chrono { namespace experimental { inline namespace fundamentals_v1 { #define _LIBCPP_END_NAMESPACE_CHRONO_LFTS _LIBCPP_END_NAMESPACE_STD } } } +#define _LIBCPP_BEGIN_NAMESPACE_EXPERIMENTAL_FILESYSTEM \ + _LIBCPP_BEGIN_NAMESPACE_EXPERIMENTAL namespace filesystem { \ + inline namespace v1 { + +#define _LIBCPP_END_NAMESPACE_EXPERIMENTAL_FILESYSTEM \ + } } _LIBCPP_END_NAMESPACE_EXPERIMENTAL + + +#define _VSTD_FS ::std::experimental::filesystem::v1 + #endif Index: include/experimental/filesystem =================================================================== --- /dev/null +++ include/experimental/filesystem @@ -0,0 +1,1243 @@ +// -*- C++ -*- +//===--------------------------- filesystem -------------------------------===// +// +// 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. +// +//===----------------------------------------------------------------------===// +#ifndef _LIBCPP_EXPERIMENTAL_FILESYSTEM +#define _LIBCPP_EXPERIMENTAL_FILESYSTEM +/* + filesystem synopsis + + namespace std { namespace experimental { namespace filesystem { inline namespace v1 { + + class path; + + void swap(path& lhs, path& rhs) _NOEXCEPT; + size_t hash_value(const path& p) _NOEXCEPT; + + bool operator==(const path& lhs, const path& rhs) _NOEXCEPT; + bool operator!=(const path& lhs, const path& rhs) _NOEXCEPT; + bool operator< (const path& lhs, const path& rhs) _NOEXCEPT; + bool operator<=(const path& lhs, const path& rhs) _NOEXCEPT; + bool operator> (const path& lhs, const path& rhs) _NOEXCEPT; + bool operator>=(const path& lhs, const path& rhs) _NOEXCEPT; + + path operator/ (const path& lhs, const path& rhs); + + template + basic_ostream& + operator<<(basic_ostream& os, const path& p); + + template + basic_istream& + operator>>(basic_istream& is, path& p); + + template + path u8path(const Source& source); + template + path u8path(InputIterator first, InputIterator last); + + class filesystem_error; + class directory_entry; + + class directory_iterator; + + // enable directory_iterator range-based for statements + directory_iterator begin(directory_iterator iter) noexcept; + directory_iterator end(const directory_iterator&) noexcept; + + class recursive_directory_iterator; + + // enable recursive_directory_iterator range-based for statements + recursive_directory_iterator begin(recursive_directory_iterator iter) noexcept; + recursive_directory_iterator end(const recursive_directory_iterator&) noexcept; + + class file_status; + + struct space_info + { + uintmax_t capacity; + uintmax_t free; + uintmax_t available; + }; + + enum class file_type; + enum class perms; + enum class copy_options; + enum class directory_options; + + typedef chrono::time_point file_time_type; + + // operational functions + + path absolute(const path& p, const path& base=current_path()); + + path canonical(const path& p, const path& base = current_path()); + path canonical(const path& p, error_code& ec); + path canonical(const path& p, const path& base, error_code& ec); + + void copy(const path& from, const path& to); + void copy(const path& from, const path& to, error_code& ec) _NOEXCEPT; + void copy(const path& from, const path& to, copy_options options); + void copy(const path& from, const path& to, copy_options options, + error_code& ec) _NOEXCEPT; + + bool copy_file(const path& from, const path& to); + bool copy_file(const path& from, const path& to, error_code& ec) _NOEXCEPT; + bool copy_file(const path& from, const path& to, copy_options option); + bool copy_file(const path& from, const path& to, copy_options option, + error_code& ec) _NOEXCEPT; + + void copy_symlink(const path& existing_symlink, const path& new_symlink); + void copy_symlink(const path& existing_symlink, const path& new_symlink, + error_code& ec) _NOEXCEPT; + + bool create_directories(const path& p); + bool create_directories(const path& p, error_code& ec) _NOEXCEPT; + + bool create_directory(const path& p); + bool create_directory(const path& p, error_code& ec) _NOEXCEPT; + + bool create_directory(const path& p, const path& attributes); + bool create_directory(const path& p, const path& attributes, + error_code& ec) _NOEXCEPT; + + void create_directory_symlink(const path& to, const path& new_symlink); + void create_directory_symlink(const path& to, const path& new_symlink, + error_code& ec) _NOEXCEPT; + + void create_hard_link(const path& to, const path& new_hard_link); + void create_hard_link(const path& to, const path& new_hard_link, + error_code& ec) _NOEXCEPT; + + void create_symlink(const path& to, const path& new_symlink); + void create_symlink(const path& to, const path& new_symlink, + error_code& ec) _NOEXCEPT; + + path current_path(); + path current_path(error_code& ec); + void current_path(const path& p); + void current_path(const path& p, error_code& ec) _NOEXCEPT; + + bool exists(file_status s) _NOEXCEPT; + bool exists(const path& p); + bool exists(const path& p, error_code& ec) _NOEXCEPT; + + bool equivalent(const path& p1, const path& p2); + bool equivalent(const path& p1, const path& p2, error_code& ec) _NOEXCEPT; + + uintmax_t file_size(const path& p); + uintmax_t file_size(const path& p, error_code& ec) _NOEXCEPT; + + uintmax_t hard_link_count(const path& p); + uintmax_t hard_link_count(const path& p, error_code& ec) _NOEXCEPT; + + bool is_block_file(file_status s) _NOEXCEPT; + bool is_block_file(const path& p); + bool is_block_file(const path& p, error_code& ec) _NOEXCEPT; + + bool is_character_file(file_status s) _NOEXCEPT; + bool is_character_file(const path& p); + bool is_character_file(const path& p, error_code& ec) _NOEXCEPT; + + bool is_directory(file_status s) _NOEXCEPT; + bool is_directory(const path& p); + bool is_directory(const path& p, error_code& ec) _NOEXCEPT; + + bool is_empty(const path& p); + bool is_empty(const path& p, error_code& ec) _NOEXCEPT; + + bool is_fifo(file_status s) _NOEXCEPT; + bool is_fifo(const path& p); + bool is_fifo(const path& p, error_code& ec) _NOEXCEPT; + + bool is_other(file_status s) _NOEXCEPT; + bool is_other(const path& p); + bool is_other(const path& p, error_code& ec) _NOEXCEPT; + + bool is_regular_file(file_status s) _NOEXCEPT; + bool is_regular_file(const path& p); + bool is_regular_file(const path& p, error_code& ec) _NOEXCEPT; + + bool is_socket(file_status s) _NOEXCEPT; + bool is_socket(const path& p); + bool is_socket(const path& p, error_code& ec) _NOEXCEPT; + + bool is_symlink(file_status s) _NOEXCEPT; + bool is_symlink(const path& p); + bool is_symlink(const path& p, error_code& ec) _NOEXCEPT; + + file_time_type last_write_time(const path& p); + file_time_type last_write_time(const path& p, error_code& ec) _NOEXCEPT; + void last_write_time(const path& p, file_time_type new_time); + void last_write_time(const path& p, file_time_type new_time, + error_code& ec) _NOEXCEPT; + + void permissions(const path& p, perms prms); + void permissions(const path& p, perms prms, error_code& ec) _NOEXCEPT; + + path read_symlink(const path& p); + path read_symlink(const path& p, error_code& ec); + + bool remove(const path& p); + bool remove(const path& p, error_code& ec) _NOEXCEPT; + + uintmax_t remove_all(const path& p); + uintmax_t remove_all(const path& p, error_code& ec) _NOEXCEPT; + + void rename(const path& from, const path& to); + void rename(const path& from, const path& to, error_code& ec) _NOEXCEPT; + + void resize_file(const path& p, uintmax_t size); + void resize_file(const path& p, uintmax_t size, error_code& ec) _NOEXCEPT; + + space_info space(const path& p); + space_info space(const path& p, error_code& ec) _NOEXCEPT; + + file_status status(const path& p); + file_status status(const path& p, error_code& ec) _NOEXCEPT; + + bool status_known(file_status s) _NOEXCEPT; + + file_status symlink_status(const path& p); + file_status symlink_status(const path& p, error_code& ec) _NOEXCEPT; + + path system_complete(const path& p); + path system_complete(const path& p, error_code& ec); + + path temp_directory_path(); + path temp_directory_path(error_code& ec); + +} } } } // namespaces std::experimental::filesystem::v1 + +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include // for quoted +#include + +#include <__debug> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +#pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_EXPERIMENTAL_FILESYSTEM + +typedef chrono::time_point file_time_type; + +struct _LIBCPP_TYPE_VIS space_info +{ + uintmax_t capacity; + uintmax_t free; + uintmax_t available; +}; + +enum class _LIBCPP_TYPE_VIS file_type : signed char +{ + none = 0, + not_found = -1, + regular = 1, + directory = 2, + symlink = 3, + block = 4, + character = 5, + fifo = 6, + socket = 7, + unknown = 8 +}; + +enum class _LIBCPP_TYPE_VIS perms : unsigned +{ + none = 0, + + owner_read = 0400, + owner_write = 0200, + owner_exec = 0100, + owner_all = 0700, + + group_read = 040, + group_write = 020, + group_exec = 010, + group_all = 070, + + others_read = 04, + others_write = 02, + others_exec = 01, + others_all = 07, + + all = 0777, + + set_uid = 04000, + set_gid = 02000, + sticky_bit = 01000, + mask = 07777, + unknown = 0xFFFF, + + add_perms = 0x10000, + remove_perms = 0x20000, + resolve_symlinks = 0x40000 +}; + +_LIBCPP_INLINE_VISIBILITY +inline _LIBCPP_CONSTEXPR perms operator&(perms _LHS, perms _RHS) +{ return static_cast(static_cast(_LHS) & static_cast(_RHS)); } + +_LIBCPP_INLINE_VISIBILITY +inline _LIBCPP_CONSTEXPR perms operator|(perms _LHS, perms _RHS) +{ return static_cast(static_cast(_LHS) | static_cast(_RHS)); } + +_LIBCPP_INLINE_VISIBILITY +inline _LIBCPP_CONSTEXPR perms operator^(perms _LHS, perms _RHS) +{ return static_cast(static_cast(_LHS) ^ static_cast(_RHS)); } + +_LIBCPP_INLINE_VISIBILITY +inline _LIBCPP_CONSTEXPR perms operator~(perms _LHS) +{ return static_cast(~static_cast(_LHS)); } + +_LIBCPP_INLINE_VISIBILITY +inline perms& operator&=(perms& _LHS, perms _RHS) +{ return _LHS = _LHS & _RHS; } + +_LIBCPP_INLINE_VISIBILITY +inline perms& operator|=(perms& _LHS, perms _RHS) +{ return _LHS = _LHS | _RHS; } + +_LIBCPP_INLINE_VISIBILITY +inline perms& operator^=(perms& _LHS, perms _RHS) +{ return _LHS = _LHS ^ _RHS; } + +enum class _LIBCPP_TYPE_VIS copy_options : unsigned short +{ + none = 0, + skip_existing = 1, + overwrite_existing = 2, + update_existing = 4, + recursive = 8, + copy_symlinks = 16, + skip_symlinks = 32, + directories_only = 64, + create_symlinks = 128, + create_hard_links = 256, + __in_recursive_copy = 512, +}; + +_LIBCPP_INLINE_VISIBILITY +inline _LIBCPP_CONSTEXPR copy_options operator&(copy_options _LHS, copy_options _RHS) +{ return static_cast(static_cast(_LHS) & static_cast(_RHS)); } + +_LIBCPP_INLINE_VISIBILITY +inline _LIBCPP_CONSTEXPR copy_options operator|(copy_options _LHS, copy_options _RHS) +{ return static_cast(static_cast(_LHS) | static_cast(_RHS)); } + +_LIBCPP_INLINE_VISIBILITY +inline _LIBCPP_CONSTEXPR copy_options operator^(copy_options _LHS, copy_options _RHS) +{ return static_cast(static_cast(_LHS) ^ static_cast(_RHS)); } + +_LIBCPP_INLINE_VISIBILITY +inline _LIBCPP_CONSTEXPR copy_options operator~(copy_options _LHS) +{ return static_cast(~static_cast(_LHS)); } + +_LIBCPP_INLINE_VISIBILITY +inline copy_options& operator&=(copy_options& _LHS, copy_options _RHS) +{ return _LHS = _LHS & _RHS; } + +_LIBCPP_INLINE_VISIBILITY +inline copy_options& operator|=(copy_options& _LHS, copy_options _RHS) +{ return _LHS = _LHS | _RHS; } + +_LIBCPP_INLINE_VISIBILITY +inline copy_options& operator^=(copy_options& _LHS, copy_options _RHS) +{ return _LHS = _LHS ^ _RHS; } + + +enum class directory_options : unsigned char +{ + none = 0, + follow_directory_symlink = 1, + skip_permission_denied = 2 +}; + +_LIBCPP_INLINE_VISIBILITY +inline _LIBCPP_CONSTEXPR directory_options operator&(directory_options _LHS, directory_options _RHS) +{ return static_cast(static_cast(_LHS) & static_cast(_RHS)); } + +_LIBCPP_INLINE_VISIBILITY +inline _LIBCPP_CONSTEXPR directory_options operator|(directory_options _LHS, directory_options _RHS) +{ return static_cast(static_cast(_LHS) | static_cast(_RHS)); } + +_LIBCPP_INLINE_VISIBILITY +inline _LIBCPP_CONSTEXPR directory_options operator^(directory_options _LHS, directory_options _RHS) +{ return static_cast(static_cast(_LHS) ^ static_cast(_RHS)); } + +_LIBCPP_INLINE_VISIBILITY +inline _LIBCPP_CONSTEXPR directory_options operator~(directory_options _LHS) +{ return static_cast(~static_cast(_LHS)); } + +_LIBCPP_INLINE_VISIBILITY +inline directory_options& operator&=(directory_options& _LHS, directory_options _RHS) +{ return _LHS = _LHS & _RHS; } + +_LIBCPP_INLINE_VISIBILITY +inline directory_options& operator|=(directory_options& _LHS, directory_options _RHS) +{ return _LHS = _LHS | _RHS; } + +_LIBCPP_INLINE_VISIBILITY +inline directory_options& operator^=(directory_options& _LHS, directory_options _RHS) +{ return _LHS = _LHS ^ _RHS; } + + +class _LIBCPP_TYPE_VIS file_status +{ +public: + // constructors + _LIBCPP_INLINE_VISIBILITY + explicit file_status(file_type __ft = file_type::none, + perms __prms = perms::unknown) _NOEXCEPT + : __ft_(__ft), __prms_(__prms) + {} + + file_status(const file_status&) _NOEXCEPT = default; + file_status(file_status&&) _NOEXCEPT = default; + + _LIBCPP_INLINE_VISIBILITY + ~file_status() {} + + file_status& operator=(const file_status&) _NOEXCEPT = default; + file_status& operator=(file_status&&) _NOEXCEPT = default; + + // observers + _LIBCPP_ALWAYS_INLINE + file_type type() const _NOEXCEPT { + return __ft_; + } + + _LIBCPP_ALWAYS_INLINE + perms permissions() const _NOEXCEPT { + return __prms_; + } + + // modifiers + _LIBCPP_ALWAYS_INLINE + void type(file_type __ft) _NOEXCEPT { + __ft_ = __ft; + } + + _LIBCPP_ALWAYS_INLINE + void permissions(perms __p) _NOEXCEPT { + __prms_ = __p; + } +private: + file_type __ft_; + perms __prms_; +}; + +class _LIBCPP_TYPE_VIS directory_entry; + +template struct __can_convert_char { + static const bool value = false; +}; +template <> struct __can_convert_char { + static const bool value = true; + using __char_type = char; +}; +template <> struct __can_convert_char { + static const bool value = true; + using __char_type = wchar_t; +}; +template <> struct __can_convert_char { + static const bool value = true; + using __char_type = char16_t; +}; +template <> struct __can_convert_char { + static const bool value = true; + using __char_type = char32_t; +}; + +template +typename enable_if<__can_convert_char<_ECharT>::value, bool>::type +__is_separator(_ECharT __e) { + return __e == _ECharT('/'); +}; + +struct _NullSentinal {}; + +template +using _Void = void; + +template +struct __is_pathable_string : public false_type {}; + +template +struct __is_pathable_string, + _Void::__char_type>> +: public __can_convert_char<_ECharT> +{ + using _Str = basic_string<_ECharT, _Traits, _Alloc>; + using _Base = __can_convert_char<_ECharT>; + static _ECharT const* __range_begin(_Str const& __s) { return __s.data(); } + static _ECharT const* __range_end(_Str const& __s) { return __s.data() + __s.length(); } + static _ECharT __first_or_null(_Str const& __s) { + return __s.empty() ? _ECharT{} : __s[0]; + } +}; + +template ::type, + class _UnqualPtrType = typename remove_const< + typename remove_pointer<_DS>::type>::type, + bool _IsCharPtr = is_pointer<_DS>::value && + __can_convert_char<_UnqualPtrType>::value + > +struct __is_pathable_char_array : false_type {}; + +template +struct __is_pathable_char_array<_Source, _ECharT*, _UPtr, true> + : __can_convert_char::type> +{ + using _Base = __can_convert_char::type>; + + static _ECharT const* __range_begin(const _ECharT* __b) { return __b; } + static _ECharT const* __range_end(const _ECharT* __b) + { + using _Iter = const _ECharT*; + const _ECharT __sentinal = _ECharT{}; + _Iter __e = __b; + for (; *__e != __sentinal; ++__e) + ; + return __e; + } + + static _ECharT __first_or_null(const _ECharT* __b) { return *__b; } +}; + +template ::value, class = void> +struct __is_pathable_iter : false_type {}; + +template +struct __is_pathable_iter<_Iter, true, + _Void::value_type>::__char_type>> + : __can_convert_char::value_type> +{ + using _ECharT = typename iterator_traits<_Iter>::value_type; + using _Base = __can_convert_char<_ECharT>; + + static _Iter __range_begin(_Iter __b) { return __b; } + static _NullSentinal __range_end(_Iter) { return _NullSentinal{}; } + + static _ECharT __first_or_null(_Iter __b) { return *__b; } +}; + +template ::value, + bool _IsCharIterT = __is_pathable_char_array<_Tp>::value, + bool _IsIterT = !_IsCharIterT && __is_pathable_iter<_Tp>::value + > +struct __is_pathable : false_type { + static_assert(!_IsStringT && !_IsCharIterT && !_IsIterT, "Must all be false"); +}; + +template +struct __is_pathable<_Tp, true, false, false> : __is_pathable_string<_Tp> {}; + + +template +struct __is_pathable<_Tp, false, true, false> : __is_pathable_char_array<_Tp> {}; + + +template +struct __is_pathable<_Tp, false, false, true> : __is_pathable_iter<_Tp> {}; + + +template +struct _PathCVT { + static_assert(__can_convert_char<_ECharT>::value, "Char type not convertible"); + + typedef __narrow_to_utf8 _Narrower; + + static void __append_range(string& __dest, _ECharT const* __b, _ECharT const* __e) { + _Narrower()(back_inserter(__dest), __b, __e); + } + + template + static void __append_range(string& __dest, _Iter __b, _Iter __e) { + static_assert(!is_same<_Iter, _ECharT*>::value, "Call const overload"); + if (__b == __e) return; + basic_string<_ECharT> __tmp(__b, __e); + _Narrower()(back_inserter(__dest), __tmp.data(), + __tmp.data() + __tmp.length()); + } + + template + static void __append_range(string& __dest, _Iter __b, _NullSentinal) { + static_assert(!is_same<_Iter, _ECharT*>::value, "Call const overload"); + const _ECharT __sentinal = _ECharT{}; + if (*__b == __sentinal) return; + basic_string<_ECharT> __tmp; + for (; *__b != __sentinal; ++__b) + __tmp.push_back(*__b); + _Narrower()(back_inserter(__dest), __tmp.data(), + __tmp.data() + __tmp.length()); + } + + template + static void __append_source(string& __dest, _Source const& __s) + { + using _Traits = __is_pathable<_Source>; + __append_range(__dest, _Traits::__range_begin(__s), _Traits::__range_end(__s)); + } +}; + +template <> +struct _PathCVT { + template + static void __append_range(string& __dest, _Iter __b, _Iter __e) { + // TODO(EricWF) We get better allocation behavior here if we don't + // provide the same exception safety guarantees as string.append. + // __dest.append(__b, __e); + for (; __b != __e; ++__b) + __dest.push_back(*__b); + } + + template + static void __append_range(string& __dest, _Iter __b, _NullSentinal) { + const char __sentinal = char{}; + for (; *__b != __sentinal; ++__b) + __dest.push_back(*__b); + } + + template + static void __append_source(string& __dest, _Source const& __s) + { + using _Traits = __is_pathable<_Source>; + __append_range(__dest, _Traits::__range_begin(__s), _Traits::__range_end(__s)); + } +}; + + +class _LIBCPP_TYPE_VIS path +{ + template + using _EnableIfPathable = typename + enable_if<__is_pathable<_SourceOrIter>::value, _Tp>::type; + + template + using _SourceChar = typename __is_pathable<_Tp>::__char_type; + + template + using _SourceCVT = _PathCVT<_SourceChar<_Tp>>; + +public: + typedef char value_type; + typedef basic_string string_type; + static _LIBCPP_CONSTEXPR value_type preferred_separator = '/'; + + // constructors and destructor + _LIBCPP_INLINE_VISIBILITY path() _NOEXCEPT {} + _LIBCPP_INLINE_VISIBILITY path(const path& __p) : __pn_(__p.__pn_) {} + _LIBCPP_INLINE_VISIBILITY path(path&& __p) _NOEXCEPT : __pn_(_VSTD::move(__p.__pn_)) {} + + template < + class _Source, + class = _EnableIfPathable<_Source, void> + > + path(const _Source& __src) { + _SourceCVT<_Source>::__append_source(__pn_, __src); + } + + template + path(_InputIt __first, _InputIt __last) { + typedef typename iterator_traits<_InputIt>::value_type _ItVal; + _PathCVT<_ItVal>::__append_range(__pn_, __first, __last); + } + + // TODO + template + > + path(const _Source& __src, const locale& __loc); + template + path(_InputIt __first, _InputIt _last, const locale& __loc); + + _LIBCPP_INLINE_VISIBILITY + ~path() {} + + // assignments + _LIBCPP_INLINE_VISIBILITY + path& operator=(const path& __p) { + __pn_ = __p.__pn_; + return *this; + } + + _LIBCPP_INLINE_VISIBILITY + path& operator=(path&& __p) _NOEXCEPT { + __pn_ = _VSTD::move(__p.__pn_); + return *this; + } + + template + _LIBCPP_INLINE_VISIBILITY + _EnableIfPathable<_Source> + operator=(const _Source& __src) + { return this->assign(__src); } + + + template + _EnableIfPathable<_Source> + assign(const _Source& __src) { + __pn_.clear(); + _SourceCVT<_Source>::__append_source(__pn_, __src); + return *this; + } + + template + path& assign(_InputIt __first, _InputIt __last) { + typedef typename iterator_traits<_InputIt>::value_type _ItVal; + __pn_.clear(); + _PathCVT<_ItVal>::__append_range(__pn_, __first, __last); + return *this; + } + +private: + template + void __append_sep_if_needed(_ECharT __first_or_null) { + const _ECharT __null_val = {}; + bool __append_sep = !empty() && + !__is_separator(__pn_.back()) && + __first_or_null != __null_val && // non-empty + !__is_separator(__first_or_null); + if (__append_sep) + __pn_ += preferred_separator; + } + +public: + // appends + path& operator/=(const path& __p) { + __append_sep_if_needed(__p.empty() ? char{} : __p.__pn_[0]); + __pn_ += __p.native(); + return *this; + } + + template + _LIBCPP_INLINE_VISIBILITY + _EnableIfPathable<_Source> + operator/=(const _Source& __src) { + return this->append(__src); + } + + template + _EnableIfPathable<_Source> + append(const _Source& __src) { + using _Traits = __is_pathable<_Source>; + using _CVT = _PathCVT<_SourceChar<_Source>>; + __append_sep_if_needed(_Traits::__first_or_null(__src)); + _CVT::__append_source(__pn_, __src); + return *this; + } + + template + path& append(_InputIt __first, _InputIt __last) { + typedef typename iterator_traits<_InputIt>::value_type _ItVal; + static_assert(__can_convert_char<_ItVal>::value, "Must convertible"); + using _CVT = _PathCVT<_ItVal>; + if (__first != __last) { + __append_sep_if_needed(*__first); + _CVT::__append_range(__pn_, __first, __last); + } + return *this; + } + + // concatenation + _LIBCPP_INLINE_VISIBILITY + path& operator+=(const path& __x) { + __pn_ += __x.__pn_; + return *this; + } + + _LIBCPP_INLINE_VISIBILITY + path& operator+=(const string_type& __x) { + __pn_ += __x; + return *this; + } + + _LIBCPP_INLINE_VISIBILITY + path& operator+=(const value_type* __x) { + __pn_ += __x; + return *this; + } + + _LIBCPP_INLINE_VISIBILITY + path& operator+=(value_type __x) { + __pn_ += __x; + return *this; + } + + + template + typename enable_if<__can_convert_char<_ECharT>::value, path&>::type + operator+=(_ECharT __x) + { + basic_string<_ECharT> __tmp; + __tmp += __x; + _PathCVT<_ECharT>::__append_source(__pn_, __tmp); + return *this; + } + + template + _EnableIfPathable<_Source> + operator+=(const _Source& __x) { + return this->concat(__x); + } + + template + _EnableIfPathable<_Source> + concat(const _Source& __x){ + _SourceCVT<_Source>::__append_source(__pn_, __x); + return *this; + } + + template + path& concat(_InputIt __first, _InputIt __last) { + typedef typename iterator_traits<_InputIt>::value_type _ItVal; + _PathCVT<_ItVal>::__append_range(__pn_, __first, __last); + return *this; + } + + // modifiers + _LIBCPP_INLINE_VISIBILITY + void clear() _NOEXCEPT { + __pn_.clear(); + } + + path& make_preferred() { return *this; } + path& remove_filename() { return *this = parent_path(); } + + path& replace_filename(const path& __replacement) { + remove_filename(); + return (*this /= __replacement); + } + + path& replace_extension(const path& __replacement = path()); + + _LIBCPP_INLINE_VISIBILITY + void swap(path& __rhs) _NOEXCEPT { + __pn_.swap(__rhs.__pn_); + } + + // native format observers + _LIBCPP_INLINE_VISIBILITY + const string_type& native() const _NOEXCEPT { + return __pn_; + } + + _LIBCPP_INLINE_VISIBILITY + const value_type* c_str() const _NOEXCEPT { return __pn_.c_str(); } + + _LIBCPP_INLINE_VISIBILITY operator string_type() const { return __pn_; } + + template , + class _Allocator = allocator<_ECharT> > + basic_string<_ECharT, _Traits, _Allocator> + string(const _Allocator& __a = _Allocator()) const { + using _CVT = __widen_from_utf8; + using _Str = basic_string<_ECharT, _Traits, _Allocator>; + _Str __s(__a); + __s.reserve(__pn_.size()); + _CVT()(back_inserter(__s), __pn_.data(), __pn_.data() + __pn_.size()); + return __s; + } + + _LIBCPP_INLINE_VISIBILITY std::string string() const { return __pn_; } + _LIBCPP_INLINE_VISIBILITY std::wstring wstring() const { return string(); } + _LIBCPP_INLINE_VISIBILITY std::string u8string() const { return __pn_; } + _LIBCPP_INLINE_VISIBILITY std::u16string u16string() const { return string(); } + _LIBCPP_INLINE_VISIBILITY std::u32string u32string() const { return string(); } + + // generic format observers + template , + class _Allocator = allocator<_ECharT> + > + basic_string<_ECharT, _Traits, _Allocator> + generic_string(const _Allocator& __a = _Allocator()) const { + return string<_ECharT, _Traits, _Allocator>(__a); + } + + std::string generic_string() const { return __pn_; } + std::wstring generic_wstring() const { return string(); } + std::string generic_u8string() const { return __pn_; } + std::u16string generic_u16string() const { return string(); } + std::u32string generic_u32string() const { return string(); } + +private: + _LIBCPP_FUNC_VIS int __compare(const value_type*) const; + _LIBCPP_FUNC_VIS string_view __root_name() const; + _LIBCPP_FUNC_VIS string_view __root_directory() const; + _LIBCPP_FUNC_VIS string_view __relative_path() const; + _LIBCPP_FUNC_VIS string_view __parent_path() const; + _LIBCPP_FUNC_VIS string_view __filename() const; + _LIBCPP_FUNC_VIS string_view __stem() const; + _LIBCPP_FUNC_VIS string_view __extension() const; + +public: + // compare + _LIBCPP_INLINE_VISIBILITY int compare(const path& __p) const _NOEXCEPT { return __compare(__p.c_str());} + _LIBCPP_INLINE_VISIBILITY int compare(const string_type& __s) const { return __compare(__s.c_str()); } + _LIBCPP_INLINE_VISIBILITY int compare(const value_type* __s) const { return __compare(__s); } + + // decomposition + _LIBCPP_INLINE_VISIBILITY path root_name() const { return __root_name().to_string(); } + _LIBCPP_INLINE_VISIBILITY path root_directory() const { return __root_directory().to_string(); } + _LIBCPP_INLINE_VISIBILITY path root_path() const { return root_name().append(__root_directory().to_string()); } + _LIBCPP_INLINE_VISIBILITY path relative_path() const { return __relative_path().to_string(); } + _LIBCPP_INLINE_VISIBILITY path parent_path() const { return __parent_path().to_string(); } + _LIBCPP_INLINE_VISIBILITY path filename() const { return __filename().to_string(); } + _LIBCPP_INLINE_VISIBILITY path stem() const { return __stem().to_string();} + _LIBCPP_INLINE_VISIBILITY path extension() const { return __extension().to_string(); } + + // query + _LIBCPP_INLINE_VISIBILITY bool empty() const _NOEXCEPT { return __pn_.empty(); } + + _LIBCPP_INLINE_VISIBILITY bool has_root_name() const { return !__root_name().empty(); } + _LIBCPP_INLINE_VISIBILITY bool has_root_directory() const { return !__root_directory().empty(); } + _LIBCPP_INLINE_VISIBILITY bool has_root_path() const { return !(__root_name().empty() && __root_directory().empty()); } + _LIBCPP_INLINE_VISIBILITY bool has_relative_path() const { return !__relative_path().empty(); } + _LIBCPP_INLINE_VISIBILITY bool has_parent_path() const { return !__parent_path().empty(); } + _LIBCPP_INLINE_VISIBILITY bool has_filename() const { return !__filename().empty(); } + _LIBCPP_INLINE_VISIBILITY bool has_stem() const { return !__stem().empty(); } + _LIBCPP_INLINE_VISIBILITY bool has_extension() const { return !__extension().empty(); } + + _LIBCPP_INLINE_VISIBILITY bool is_absolute() const { return has_root_directory(); } + _LIBCPP_INLINE_VISIBILITY bool is_relative() const { return !is_absolute(); } + + // iterators + class _LIBCPP_TYPE_VIS iterator; + typedef iterator const_iterator; + + _LIBCPP_FUNC_VIS iterator begin() const; + _LIBCPP_FUNC_VIS iterator end() const; + +private: + inline _LIBCPP_INLINE_VISIBILITY + path& __assign_view(string_view const& __s) noexcept { __pn_ = __s.to_string(); return *this; } + string_type __pn_; +}; + +inline _LIBCPP_INLINE_VISIBILITY +bool operator==(const path& __lhs, const path& __rhs) _NOEXCEPT +{ return __lhs.compare(__rhs) == 0; } + +inline _LIBCPP_INLINE_VISIBILITY +bool operator!=(const path& __lhs, const path& __rhs) _NOEXCEPT +{ return __lhs.compare(__rhs) != 0; } + +inline _LIBCPP_INLINE_VISIBILITY +bool operator<(const path& __lhs, const path& __rhs) _NOEXCEPT +{ return __lhs.compare(__rhs) < 0; } + +inline _LIBCPP_INLINE_VISIBILITY +bool operator<=(const path& __lhs, const path& __rhs) _NOEXCEPT +{ return __lhs.compare(__rhs) <= 0; } + +inline _LIBCPP_INLINE_VISIBILITY +bool operator>(const path& __lhs, const path& __rhs) _NOEXCEPT +{ return __lhs.compare(__rhs) > 0; } + +inline _LIBCPP_INLINE_VISIBILITY +bool operator>=(const path& __lhs, const path& __rhs) _NOEXCEPT +{ return __lhs.compare(__rhs) >= 0; } + +inline _LIBCPP_INLINE_VISIBILITY +path operator/(const path& __lhs, const path& __rhs) { + return path(__lhs) /= __rhs; +} + +inline _LIBCPP_ALWAYS_INLINE +void swap(path& __lhs, path& __rhs) _NOEXCEPT { + __lhs.swap(__rhs); +} + +_LIBCPP_FUNC_VIS +size_t hash_value(const path& __p) _NOEXCEPT; + +template +_LIBCPP_INLINE_VISIBILITY +typename enable_if::value && + is_same<_Traits, char_traits>::value, + basic_ostream<_CharT, _Traits>& +>::type +operator<<(basic_ostream<_CharT, _Traits>& __os, const path& __p) { + __os << std::__quoted(__p.native()); + return __os; +} + +template +_LIBCPP_INLINE_VISIBILITY +typename enable_if::value || + !is_same<_Traits, char_traits>::value, + basic_ostream<_CharT, _Traits>& +>::type +operator<<(basic_ostream<_CharT, _Traits>& __os, const path& __p) { + __os << std::__quoted(__p.string<_CharT, _Traits>()); + return __os; +} + +template +_LIBCPP_INLINE_VISIBILITY +basic_istream<_CharT, _Traits>& +operator>>(basic_istream<_CharT, _Traits>& __is, path& __p) +{ + basic_string<_CharT, _Traits> __tmp; + __is >> __quoted(__tmp); + __p = __tmp; + return __is; +} + +template +_LIBCPP_INLINE_VISIBILITY +typename enable_if<__is_pathable<_Source>::value, path>::type +u8path(const _Source& __s){ + static_assert(is_same::__char_type, char>::value, + "u8path(Source const&) requires Source have a character type of type 'char'"); + return path(__s); +} + +template +_LIBCPP_INLINE_VISIBILITY +typename enable_if<__is_pathable<_InputIt>::value, path>::type +u8path(_InputIt __f, _InputIt __l) { + static_assert(is_same::__char_type, char>::value, + "u8path(Iter, Iter) requires Iter have a value_type of type 'char'"); + return path(__f, __l); +} + +class _LIBCPP_TYPE_VIS path::iterator +{ +public: + typedef bidirectional_iterator_tag iterator_category; + typedef path value_type; + typedef std::ptrdiff_t difference_type; + typedef const path* pointer; + typedef const path& reference; +public: + _LIBCPP_INLINE_VISIBILITY + iterator() : __elem_(), __path_ptr_(nullptr), __pos_(0) {} + + iterator(const iterator&) = default; + ~iterator() = default; + + iterator& operator=(const iterator&) = default; + + _LIBCPP_INLINE_VISIBILITY + reference operator*() const { + return __elem_; + } + + _LIBCPP_INLINE_VISIBILITY + pointer operator->() const { + return &__elem_; + } + + _LIBCPP_INLINE_VISIBILITY + iterator& operator++() { + return __increment(); + } + + _LIBCPP_INLINE_VISIBILITY + iterator operator++(int) { + iterator __it(*this); + this->operator++(); + return __it; + } + + _LIBCPP_INLINE_VISIBILITY + iterator& operator--() { + return __decrement(); + } + + _LIBCPP_INLINE_VISIBILITY + iterator operator--(int) { + iterator __it(*this); + this->operator--(); + return __it; + } + +private: + friend class path; + friend bool operator==(const iterator&, const iterator&); + + _LIBCPP_FUNC_VIS iterator& __increment(); + _LIBCPP_FUNC_VIS iterator& __decrement(); + + path __elem_; + const path* __path_ptr_; + size_t __pos_; +}; + +inline _LIBCPP_INLINE_VISIBILITY +bool operator==(const path::iterator& __lhs, const path::iterator& __rhs) { + return __lhs.__path_ptr_ == __rhs.__path_ptr_ && + __lhs.__pos_ == __rhs.__pos_; +} + +inline _LIBCPP_INLINE_VISIBILITY +bool operator!=(const path::iterator& __lhs, const path::iterator& __rhs) { + return !(__lhs == __rhs); +} + + +class _LIBCPP_EXCEPTION_ABI filesystem_error : public system_error +{ +public: + _LIBCPP_INLINE_VISIBILITY + filesystem_error(const string& __what, error_code __ec) + : system_error(__ec, __what), + __paths_(make_shared<_Storage>(path(), path())) + {} + + _LIBCPP_INLINE_VISIBILITY + filesystem_error(const string& __what, const path& __p1, error_code __ec) + : system_error(__ec, __what), + __paths_(make_shared<_Storage>(__p1, path())) + {} + + _LIBCPP_INLINE_VISIBILITY + filesystem_error(const string& __what, const path& __p1, const path& __p2, + error_code __ec) + : system_error(__ec, __what), + __paths_(make_shared<_Storage>(__p1, __p2)) + {} + + _LIBCPP_INLINE_VISIBILITY + const path& path1() const _NOEXCEPT { + return __paths_->first; + } + + _LIBCPP_INLINE_VISIBILITY + const path& path2() const _NOEXCEPT { + return __paths_->second; + } + + // COMMENTED OUT FOR REVIEW + //_LIBCPP_FUNC_VIS ~filesystem_error() override; // key function + + // TODO(ericwf): Create a custom error message. + //const char* what() const _NOEXCEPT; + +private: + typedef pair _Storage; + shared_ptr<_Storage> __paths_; +}; + +file_status status(path const&); +file_status status(path const&, error_code&) _NOEXCEPT; +file_status symlink_status(path const&); +file_status symlink_status(path const&, error_code&) _NOEXCEPT; + + +class directory_entry +{ + typedef _VSTD_FS::path _Path; + +public: + // constructors and destructors + directory_entry() _NOEXCEPT = default; + directory_entry(directory_entry const&) = default; + directory_entry(directory_entry&&) _NOEXCEPT = default; + + _LIBCPP_INLINE_VISIBILITY + explicit directory_entry(_Path const& __p) : __p_(__p) {} + + ~directory_entry() {} + + directory_entry& operator=(directory_entry const&) = default; + directory_entry& operator=(directory_entry&&) _NOEXCEPT = default; + + _LIBCPP_INLINE_VISIBILITY + void assign(_Path const& __p) { + __p_ = __p; + } + + _LIBCPP_INLINE_VISIBILITY + void replace_filename(_Path const& __p) { + __p_ = __p_.parent_path() / __p; + } + + _LIBCPP_INLINE_VISIBILITY + _Path const& path() const _NOEXCEPT { + return __p_; + } + + _LIBCPP_INLINE_VISIBILITY + operator const _Path&() const _NOEXCEPT { + return __p_; + } + + _LIBCPP_INLINE_VISIBILITY + file_status status() const { + return _VSTD_FS::status(__p_); + } + + _LIBCPP_INLINE_VISIBILITY + file_status status(error_code& __ec) const _NOEXCEPT { + return _VSTD_FS::status(__p_, __ec); + } + + _LIBCPP_INLINE_VISIBILITY + file_status symlink_status() const { + return _VSTD_FS::symlink_status(__p_); + } + + _LIBCPP_INLINE_VISIBILITY + file_status symlink_status(error_code& __ec) const _NOEXCEPT { + return _VSTD_FS::symlink_status(__p_, __ec); + } + + _LIBCPP_INLINE_VISIBILITY + bool operator< (directory_entry const& __rhs) const _NOEXCEPT { + return __p_ < __rhs.__p_; + } + + _LIBCPP_INLINE_VISIBILITY + bool operator==(directory_entry const& __rhs) const _NOEXCEPT { + return __p_ == __rhs.__p_; + } + + _LIBCPP_INLINE_VISIBILITY + bool operator!=(directory_entry const& __rhs) const _NOEXCEPT { + return __p_ != __rhs.__p_; + } + + _LIBCPP_INLINE_VISIBILITY + bool operator<=(directory_entry const& __rhs) const _NOEXCEPT { + return __p_ <= __rhs.__p_; + } + + _LIBCPP_INLINE_VISIBILITY + bool operator> (directory_entry const& __rhs) const _NOEXCEPT { + return __p_ > __rhs.__p_; + } + + _LIBCPP_INLINE_VISIBILITY + bool operator>=(directory_entry const& __rhs) const _NOEXCEPT { + return __p_ >= __rhs.__p_; + } +private: + _Path __p_; +}; + +_LIBCPP_END_NAMESPACE_EXPERIMENTAL_FILESYSTEM + +#endif // _LIBCPP_EXPERIMENTAL_FILESYSTEM Index: include/iomanip =================================================================== --- include/iomanip +++ include/iomanip @@ -512,8 +512,6 @@ return __iom_t10<_CharT>(__tm, __fmt); } -#if _LIBCPP_STD_VER > 11 - template std::basic_ostream<_CharT, _Traits> & __quoted_output ( basic_ostream<_CharT, _Traits> &__os, @@ -631,22 +629,41 @@ return __quoted_output_proxy<_CharT, const _CharT *> ( __s, __end, __delim, __escape ); } + template _LIBCPP_INLINE_VISIBILITY __quoted_output_proxy<_CharT, typename basic_string <_CharT, _Traits, _Allocator>::const_iterator> -quoted ( const basic_string <_CharT, _Traits, _Allocator> &__s, _CharT __delim = _CharT('"'), _CharT __escape=_CharT('\\')) +__quoted ( const basic_string <_CharT, _Traits, _Allocator> &__s, _CharT __delim = _CharT('"'), _CharT __escape=_CharT('\\')) { - return __quoted_output_proxy<_CharT, - typename basic_string <_CharT, _Traits, _Allocator>::const_iterator> + return __quoted_output_proxy<_CharT, + typename basic_string <_CharT, _Traits, _Allocator>::const_iterator> ( __s.cbegin(), __s.cend (), __delim, __escape ); } template __quoted_proxy<_CharT, _Traits, _Allocator> -quoted ( basic_string <_CharT, _Traits, _Allocator> &__s, _CharT __delim = _CharT('"'), _CharT __escape=_CharT('\\')) +__quoted ( basic_string <_CharT, _Traits, _Allocator> &__s, _CharT __delim = _CharT('"'), _CharT __escape=_CharT('\\')) { return __quoted_proxy<_CharT, _Traits, _Allocator>( __s, __delim, __escape ); } + + +#if _LIBCPP_STD_VER > 11 + +template +_LIBCPP_INLINE_VISIBILITY +__quoted_output_proxy<_CharT, typename basic_string <_CharT, _Traits, _Allocator>::const_iterator> +quoted ( const basic_string <_CharT, _Traits, _Allocator> &__s, _CharT __delim = _CharT('"'), _CharT __escape=_CharT('\\')) +{ + return __quoted(__s, __delim, __escape); +} + +template +__quoted_proxy<_CharT, _Traits, _Allocator> +quoted ( basic_string <_CharT, _Traits, _Allocator> &__s, _CharT __delim = _CharT('"'), _CharT __escape=_CharT('\\')) +{ + return__quoted(__s, __delim, __escape); +} #endif _LIBCPP_END_NAMESPACE_STD Index: lib/filesystem/CMakeLists.txt =================================================================== --- /dev/null +++ lib/filesystem/CMakeLists.txt @@ -0,0 +1,22 @@ +file(GLOB FILESYSTEM_SOURCES ../../src/filesystem/*.cpp) +set(FILESYSTEM_HEADERS ../../include/experimental/filesystem) + +add_library(cxx_filesystem STATIC + ${FILESYSTEM_SOURCES} + ${FILESYSTEM_HEADERS} + ) + +split_list(LIBCXX_COMPILE_FLAGS) +split_list(LIBCXX_LINK_FLAGS) + +set_target_properties(cxx_filesystem + PROPERTIES + COMPILE_FLAGS "${LIBCXX_COMPILE_FLAGS}" + LINK_FLAGS "${LIBCXX_LINK_FLAGS}" + OUTPUT_NAME "c++filesystem" + VERSION "1.0" + ) + +install(TARGETS cxx_filesystem + ARCHIVE DESTINATION lib${LIBCXX_LIBDIR_SUFFIX} + ) \ No newline at end of file Index: src/filesystem/path.cpp =================================================================== --- /dev/null +++ src/filesystem/path.cpp @@ -0,0 +1,392 @@ +//===--------------------- 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; + +// status reporting +constexpr size_t npos = static_cast(-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 hasher; + std::__scalar_hash 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 Index: test/CMakeLists.txt =================================================================== --- test/CMakeLists.txt +++ test/CMakeLists.txt @@ -9,6 +9,19 @@ set(LIBCXX_LIT_VARIANT "libcxx" CACHE STRING "Configuration variant to use for LIT.") +if (LIBCXX_CONFIGURE_IDE) + file(GLOB_RECURSE LIBCXX_TEST_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/../include/*) + file(GLOB_RECURSE LIBCXX_SUPPORT_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/support/*) + file(GLOB_RECURSE LIBCXX_TEST_FILES ${CMAKE_CURRENT_SOURCE_DIR}/std/*.pass.cpp) + list(APPEND LIBCXX_TEST_HEADERS ${LIBCXX_SUPPORT_HEADERS}) + add_definitions(-DLIBCXX_FILESYSTEM_DYNAMIC_TEST_ROOT=1) + add_definitions(-DLIBCXX_FILESYSTEM_STATIC_TEST_ROOT=1) + add_definitions(-DLIBCXX_FILESYSTEM_DYNAMIC_TEST_HELPER=1) + include_directories(support) + source_group("TestHeaders" FILES ${LIBCXX_TEST_HEADERS}) + add_executable(cxxtest ${LIBCXX_TEST_FILES} ${LIBCXX_TEST_HEADERS}) +endif() + pythonize_bool(LIBCXX_ENABLE_EXCEPTIONS) pythonize_bool(LIBCXX_ENABLE_RTTI) pythonize_bool(LIBCXX_ENABLE_SHARED) Index: test/libcxx/experimental/filesystem/class.path/path.req/is_pathable.pass.cpp =================================================================== --- /dev/null +++ test/libcxx/experimental/filesystem/class.path/path.req/is_pathable.pass.cpp @@ -0,0 +1,101 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03 + +// + +// template struct __is_pathable + +// [path.req] +// In addition to the requirements (5), function template parameters named +// `Source` shall be one of: +// * basic_string<_ECharT, _Traits, _Alloc> +// * InputIterator with a value_type of _ECharT +// * A character array, which points to a NTCTS after array-to-pointer decay. + + +#include +#include +#include + +#include "test_macros.h" +#include "test_iterators.h" +#include "min_allocator.h" + +namespace fs = std::experimental::filesystem; + +using fs::__is_pathable; + +template +struct Identity { typedef Tp type; }; + +template +Identity CheckSourceType(Source const&); + +template +using GetSourceType = typename decltype(CheckSourceType(std::declval()))::type; + +template ::type> +using CheckPass = std::is_same>; + +template +using CheckPassSource = std::integral_constant::value && + CheckPass::value && + CheckPass::value && + CheckPass::value + >; + +template +struct MakeTestType { + using value_type = CharT; + using string_type = std::basic_string; + using string_type2 = std::basic_string, min_allocator>; + using cstr_type = CharT* const; + using const_cstr_type = const CharT*; + using array_type = CharT[25]; + using const_array_type = const CharT[25]; + using iter_type = input_iterator; + using bad_iter_type = input_iterator; + + template + static void AssertPathable() { + static_assert(__is_pathable::value, ""); + static_assert(CheckPassSource::value, "cannot pass as Source const&"); + ASSERT_SAME_TYPE(CharT, typename __is_pathable::__char_type); + } + + template + static void AssertNotPathable() { + static_assert(!__is_pathable::value, ""); + } + + static void Test() { + AssertPathable(); + AssertPathable(); + AssertPathable(); + AssertPathable(); + AssertPathable(); + AssertPathable(); + AssertPathable(); + + AssertNotPathable(); + AssertNotPathable(); + AssertNotPathable(); + } +}; + +int main() { + MakeTestType::Test(); + MakeTestType::Test(); + MakeTestType::Test(); + MakeTestType::Test(); +} \ No newline at end of file Index: test/libcxx/test/config.py =================================================================== --- test/libcxx/test/config.py +++ test/libcxx/test/config.py @@ -101,6 +101,7 @@ self.configure_execute_external() self.configure_ccache() self.configure_compile_flags() + self.configure_filesystem_compile_flags() self.configure_link_flags() self.configure_env() self.configure_color_diagnostics() @@ -412,6 +413,21 @@ self.config.available_features.add('libcpp-abi-unstable') self.cxx.compile_flags += ['-D_LIBCPP_ABI_UNSTABLE'] + def configure_filesystem_compile_flags(self): + static_env = os.path.join(self.libcxx_src_root, 'test', 'std', 'experimental', 'filesystem', 'static_test_env') + assert os.path.isdir(static_env) + self.cxx.compile_flags += ['-DLIBCXX_FILESYSTEM_STATIC_TEST_ROOT="%s"' % static_env] + + dynamic_env = os.path.join(self.libcxx_obj_root, 'test', 'filesystem', 'dynamic_env') + if not os.path.isdir(dynamic_env): + os.makedirs(dynamic_env) + self.cxx.compile_flags += ['-DLIBCXX_FILESYSTEM_DYNAMIC_TEST_ROOT="%s"' % dynamic_env] + self.env['LIBCXX_FILESYSTEM_DYNAMIC_TEST_ROOT'] = ("%s" % dynamic_env) + + dynamic_helper = os.path.join(self.libcxx_src_root, 'test', 'support', 'filesystem_dynamic_test_helper.py') + assert os.path.isfile(dynamic_helper) + self.cxx.compile_flags += ['-DLIBCXX_FILESYSTEM_DYNAMIC_TEST_HELPER="%s"' % dynamic_helper] + def configure_link_flags(self): no_default_flags = self.get_lit_bool('no_default_flags', False) if not no_default_flags: @@ -422,6 +438,7 @@ self.configure_link_flags_abi_library_path() # Configure libraries + self.configure_filesystem_link_flags() self.configure_link_flags_cxx_library() self.configure_link_flags_abi_library() self.configure_extra_library_flags() @@ -482,6 +499,9 @@ def configure_extra_library_flags(self): self.target_info.add_cxx_link_flags(self.cxx.link_flags) + def configure_filesystem_link_flags(self): + self.cxx.link_flags += ['-lc++filesystem'] + def configure_color_diagnostics(self): use_color = self.get_lit_conf('color_diagnostics') if use_color is None: Index: test/std/experimental/filesystem/class.directory_entry/directory_entry.cons.pass.cpp =================================================================== --- /dev/null +++ test/std/experimental/filesystem/class.directory_entry/directory_entry.cons.pass.cpp @@ -0,0 +1,97 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03 + +// + +// class directory_entry + +// directory_entry() noexcept = default; +// directory_entry(const directory_entry&) = default; +// directory_entry(directory_entry&&) noexcept = default; +// explicit directory_entry(const path); + +#include +#include +#include + +namespace fs = std::experimental::filesystem; + +void test_default_ctor() +{ + using namespace fs; + // Default + { + static_assert(std::is_nothrow_default_constructible::value, + "directory_entry must have a nothrow default constructor"); + directory_entry e; + assert(e.path() == path()); + } +} + + +void test_copy_ctor() +{ + using namespace fs; + // Copy + { + static_assert(std::is_copy_constructible::value, + "directory_entry must be copy constructible"); + static_assert(!std::is_nothrow_copy_constructible::value, + "directory_entry's copy constructor cannot be noexcept"); + const path p("foo/bar/baz"); + const directory_entry e(p); + assert(e.path() == p); + directory_entry e2(e); + assert(e.path() == p); + assert(e2.path() == p); + } + +} + +void test_move_ctor() +{ + using namespace fs; + // Move + { + static_assert(std::is_nothrow_move_constructible::value, + "directory_entry must be nothrow move constructible"); + const path p("foo/bar/baz"); + directory_entry e(p); + assert(e.path() == p); + directory_entry e2(std::move(e)); + assert(e2.path() == p); + assert(e.path() != p); // Testing moved from state. + } +} + +void test_path_ctor() { + using namespace fs; + { + static_assert(std::is_constructible::value, + "directory_entry must be constructible from path"); + static_assert(!std::is_nothrow_constructible::value, + "directory_entry constructor should not be noexcept"); + static_assert(!std::is_convertible::value, + "directory_entry constructor should be explicit"); + } + { + const path p("foo/bar/baz"); + const directory_entry e(p); + assert(p == e.path()); + } +} + +int main() { + test_default_ctor(); + test_copy_ctor(); + test_move_ctor(); + test_path_ctor(); +} \ No newline at end of file Index: test/std/experimental/filesystem/class.directory_entry/directory_entry.mods.pass.cpp =================================================================== --- /dev/null +++ test/std/experimental/filesystem/class.directory_entry/directory_entry.mods.pass.cpp @@ -0,0 +1,113 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03 + +// + +// class directory_entry + +// directory_entry& operator=(directory_entry const&) = default; +// directory_entry& operator=(directory_entry&&) noexcept = default; +// void assign(path const&); +// void replace_filename(path const&); + +#include +#include +#include + +namespace fs = std::experimental::filesystem; + +void test_copy_assign_operator() +{ + using namespace fs; + // Copy + { + static_assert(std::is_copy_assignable::value, + "directory_entry must be copy assignable"); + static_assert(!std::is_nothrow_copy_assignable::value, + "directory_entry's copy assignment cannot be noexcept"); + const path p("foo/bar/baz"); + const path p2("abc"); + const directory_entry e(p); + directory_entry e2; + assert(e.path() == p && e2.path() == path()); + e2 = e; + assert(e.path() == p && e2.path() == p); + directory_entry e3(p2); + e2 = e3; + assert(e2.path() == p2 && e3.path() == p2); + } +} + + +void test_move_assign_operator() +{ + using namespace fs; + // Copy + { + static_assert(std::is_nothrow_move_assignable::value, + "directory_entry is noexcept move assignable"); + const path p("foo/bar/baz"); + const path p2("abc"); + directory_entry e(p); + directory_entry e2(p2); + assert(e.path() == p && e2.path() == p2); + e2 = std::move(e); + assert(e2.path() == p); + assert(e.path() != p); // testing moved from state + } +} + +void test_path_assign_method() +{ + using namespace fs; + const path p("foo/bar/baz"); + const path p2("abc"); + directory_entry e(p); + { + static_assert(std::is_same::value, + "return type should be void"); + static_assert(noexcept(e.assign(p)) == false, "operation must not be noexcept"); + } + { + assert(e.path() == p); + e.assign(p2); + assert(e.path() == p2 && e.path() != p); + e.assign(p); + assert(e.path() == p && e.path() != p2); + } +} + +void test_replace_filename_method() +{ + using namespace fs; + const path p("/path/to/foo.exe"); + const path replace("bar.out"); + const path expect("/path/to/bar.out"); + directory_entry e(p); + { + static_assert(noexcept(e.replace_filename(replace)) == false, + "operation cannot be noexcept"); + static_assert(std::is_same::value, + "operation must return void"); + } + { + assert(e.path() == p); + e.replace_filename(replace); + assert(e.path() == expect); + } +} + +int main() { + test_copy_assign_operator(); + test_move_assign_operator(); + test_path_assign_method(); + test_replace_filename_method(); +} \ No newline at end of file Index: test/std/experimental/filesystem/class.directory_entry/directory_entry.obs/comparisons.pass.cpp =================================================================== --- /dev/null +++ test/std/experimental/filesystem/class.directory_entry/directory_entry.obs/comparisons.pass.cpp @@ -0,0 +1,82 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03 + +// + +// class directory_entry + +// bool operator==(directory_entry const&) const noexcept; +// bool operator!=(directory_entry const&) const noexcept; +// bool operator< (directory_entry const&) const noexcept; +// bool operator<=(directory_entry const&) const noexcept; +// bool operator> (directory_entry const&) const noexcept; +// bool operator>=(directory_entry const&) const noexcept; + + +#include +#include +#include + +namespace fs = std::experimental::filesystem; + +#define CHECK_OP(Op) \ + static_assert(std::is_same::value, ""); \ + static_assert(noexcept(ce.operator Op (ce)), "Operation must be noexcept" ) + +void test_comparison_signatures() { + using namespace fs; + path const p("foo/bar/baz"); + // Check that the operators are member functions with the correct signatures. + { + directory_entry const ce(p); + CHECK_OP(==); + CHECK_OP(!=); + CHECK_OP(< ); + CHECK_OP(<=); + CHECK_OP(> ); + CHECK_OP(>=); + } +} +#undef CHECK_OP + +// The actual semantics of the comparisons are testing via paths operators. +void test_comparisons_simple() { + using namespace fs; + typedef std::pair TestType; + TestType TestCases[] = + { + {"", ""}, + {"", "a"}, + {"a", "a"}, + {"a", "b"}, + {"foo/bar/baz", "foo/bar/baz/"} + }; + auto TestFn = [](path const& LHS, const directory_entry& LHSE, + path const& RHS, const directory_entry& RHSE) { + assert((LHS == RHS) == (LHSE == RHSE)); + assert((LHS != RHS) == (LHSE != RHSE)); + assert((LHS < RHS) == (LHSE < RHSE)); + assert((LHS <= RHS) == (LHSE <= RHSE)); + assert((LHS > RHS) == (LHSE > RHSE)); + assert((LHS >= RHS) == (LHSE >= RHSE)); + }; + for (auto const& TC : TestCases) { + const directory_entry L(TC.first); + const directory_entry R(TC.second); + TestFn(TC.first, L, TC.second, R); + TestFn(TC.second, R, TC.first, L); + } +} + +int main() { + test_comparison_signatures(); + test_comparisons_simple(); +} \ No newline at end of file Index: test/std/experimental/filesystem/class.directory_entry/directory_entry.obs/path.pass.cpp =================================================================== --- /dev/null +++ test/std/experimental/filesystem/class.directory_entry/directory_entry.obs/path.pass.cpp @@ -0,0 +1,89 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03 + +// + +// class directory_entry + +// const path& path() const noexcept; +// operator const path&() const noexcept; + +#include +#include +#include + +namespace fs = std::experimental::filesystem; + +void test_path_method() { + using namespace fs; + const path p("foo/bar/baz.exe"); + const path p2("abc"); + { + directory_entry nce; + const directory_entry e(""); + static_assert(std::is_same::value, ""); + static_assert(std::is_same::value, ""); + static_assert(noexcept(e.path()) && noexcept(nce.path()), ""); + } + { + directory_entry e(p); + path const& pref = e.path(); + assert(pref == p); + assert(&pref == &e.path()); + e.assign(p2); + assert(pref == p2); + assert(&pref == &e.path()); + } +} + +void test_path_conversion() { + using namespace fs; + const path p("foo/bar/baz.exe"); + const path p2("abc"); + { + directory_entry nce; + const directory_entry e(""); + // Check conversions exist + static_assert(std::is_convertible::value, ""); + static_assert(std::is_convertible::value, ""); + static_assert(std::is_convertible::value, ""); + static_assert(std::is_convertible::value, ""); + // Not convertible to non-const + static_assert(!std::is_convertible::value, ""); + static_assert(!std::is_convertible::value, ""); + static_assert(!std::is_convertible::value, ""); + static_assert(!std::is_convertible::value, ""); + // conversions are noexcept + static_assert(noexcept(e.operator fs::path const&()) && + noexcept(e.operator fs::path const&()), ""); + } + // const + { + directory_entry const e(p); + path const& pref = e; + assert(&pref == &e.path()); + } + // non-const + { + directory_entry e(p); + path const& pref = e; + assert(&pref == &e.path()); + + e.assign(p2); + assert(pref == p2); + assert(&pref == &e.path()); + } +} + +int main() { + test_path_method(); + test_path_conversion(); +} \ No newline at end of file Index: test/std/experimental/filesystem/class.directory_entry/directory_entry.obs/status.pass.cpp =================================================================== --- /dev/null +++ test/std/experimental/filesystem/class.directory_entry/directory_entry.obs/status.pass.cpp @@ -0,0 +1,85 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03 + +// + +// class directory_entry + +// file_status status() const; +// file_status status(error_code const&) const noexcept; +// file_status symlink_status() const; +// file_status symlink_status(error_code&) const noexcept; + +#include +#include +#include + +#include "filesystem_test_helper.hpp" + +void test_status() +{ + using namespace fs; + { + const directory_entry e("foo"); + std::error_code ec; + static_assert(std::is_same::value, ""); + static_assert(std::is_same::value, ""); + static_assert(noexcept(e.status()) == false, ""); + static_assert(noexcept(e.status(ec)) == true, ""); + } + auto TestFn = [](path const& p) { + const directory_entry e(p); + std::error_code pec, eec; + file_status ps = fs::status(p, pec); + file_status es = e.status(eec); + assert(ps.type() == es.type()); + assert(ps.permissions() == es.permissions()); + assert(pec == eec); + }; + { + TestFn(StaticEnv::File); + TestFn(StaticEnv::Dir); + TestFn(StaticEnv::SymlinkToFile); + TestFn(StaticEnv::DNE); + } +} + +void test_symlink_status() { + using namespace fs; + { + const directory_entry e("foo"); + std::error_code ec; + static_assert(std::is_same::value, ""); + static_assert(std::is_same::value, ""); + static_assert(noexcept(e.symlink_status()) == false, ""); + static_assert(noexcept(e.symlink_status(ec)) == true, ""); + } + auto TestFn = [](path const& p) { + const directory_entry e(p); + std::error_code pec, eec; + file_status ps = fs::symlink_status(p, pec); + file_status es = e.symlink_status(eec); + assert(ps.type() == es.type()); + assert(ps.permissions() == es.permissions()); + assert(pec == eec); + }; + { + TestFn(StaticEnv::File); + TestFn(StaticEnv::Dir); + TestFn(StaticEnv::SymlinkToFile); + TestFn(StaticEnv::DNE); + } +} + +int main() { + test_status(); + test_symlink_status(); +} \ No newline at end of file Index: test/std/experimental/filesystem/class.file_status/file_status.cons.pass.cpp =================================================================== --- /dev/null +++ test/std/experimental/filesystem/class.file_status/file_status.cons.pass.cpp @@ -0,0 +1,59 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03 + +// + +// class file_status + +// explicit file_status() noexcept; +// explicit file_status(file_type, perms prms = perms::unknown) noexcept; + +#include +#include +#include + +namespace fs = std::experimental::filesystem; + +int main() { + using namespace fs; + + // Default ctor + { + // TODO(EricWF) Test the constructor is marked as explicit. + static_assert(std::is_nothrow_default_constructible::value, + "The default constructor must be noexcept"); + const file_status f; + assert(f.type() == file_type::none); + assert(f.permissions() == perms::unknown); + } + + // Unary ctor + { + static_assert(std::is_nothrow_constructible::value, + "This constructor must be noexcept"); + static_assert(std::is_convertible::value == false, + "This constructor must be explicit"); + + const file_status f(file_type::not_found); + assert(f.type() == file_type::not_found); + assert(f.permissions() == perms::unknown); + } + // Binary ctor + { + // TODO(EricWF) Test the constructor is marked as explicit. + static_assert(std::is_nothrow_constructible::value, + "This constructor must be noexcept"); + + const file_status f(file_type::regular, perms::owner_read); + assert(f.type() == file_type::regular); + assert(f.permissions() == perms::owner_read); + } +} Index: test/std/experimental/filesystem/class.file_status/file_status.mods.pass.cpp =================================================================== --- /dev/null +++ test/std/experimental/filesystem/class.file_status/file_status.mods.pass.cpp @@ -0,0 +1,50 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03 + +// + +// class file_status + +// void type(file_type) noexcept; +// void permissions(perms) noexcept; + +#include +#include +#include + +namespace fs = std::experimental::filesystem; + +int main() { + using namespace fs; + + file_status st; + + // type test + { + static_assert(noexcept(st.type(file_type::regular)), + "operation must be noexcept"); + static_assert(std::is_same::value, + "operation must return void"); + assert(st.type() != file_type::regular); + st.type(file_type::regular); + assert(st.type() == file_type::regular); + } + // permissions test + { + static_assert(noexcept(st.permissions(perms::owner_read)), + "operation must be noexcept"); + static_assert(std::is_same::value, + "operation must return void"); + assert(st.permissions() != perms::owner_read); + st.permissions(perms::owner_read); + assert(st.permissions() == perms::owner_read); + } +} Index: test/std/experimental/filesystem/class.file_status/file_status.obs.pass.cpp =================================================================== --- /dev/null +++ test/std/experimental/filesystem/class.file_status/file_status.obs.pass.cpp @@ -0,0 +1,46 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03 + +// + +// class file_status + +// file_type type() const noexcept; +// perms permissions(p) const noexcept; + +#include +#include +#include + +namespace fs = std::experimental::filesystem; + +int main() { + using namespace fs; + + const file_status st(file_type::regular, perms::owner_read); + + // type test + { + static_assert(noexcept(st.type()), + "operation must be noexcept"); + static_assert(std::is_same::value, + "operation must return file_type"); + assert(st.type() == file_type::regular); + } + // permissions test + { + static_assert(noexcept(st.permissions()), + "operation must be noexcept"); + static_assert(std::is_same::value, + "operation must return perms"); + assert(st.permissions() == perms::owner_read); + } +} Index: test/std/experimental/filesystem/class.filesystem_error/filesystem_error.members.pass.cpp =================================================================== --- /dev/null +++ test/std/experimental/filesystem/class.filesystem_error/filesystem_error.members.pass.cpp @@ -0,0 +1,103 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03 + +// + +// class filesystem_error + +// filesystem_error(const string& what_arg, error_code ec); +// filesystem_error(const string& what_arg, const path& p1, error_code ec); +// filesystem_error(const string& what_arg, const path& p1, const path& p2, error_code ec); +// const std::error_code& code() const; +// const char* what() const noexcept; +// const path& path1() const noexcept; +// const path& path2() const noexcept; + +#include +#include +#include + +#include "test_macros.h" + +namespace fs = std::experimental::filesystem; + +void test_constructors() { + using namespace fs; + + // The string returned by "filesystem_error::what() must contain runtime_error::what() + const std::string what_arg = "Hello World"; + const std::string what_contains = std::runtime_error(what_arg).what(); + assert(what_contains.find(what_arg) != std::string::npos); + auto CheckWhat = [what_contains](filesystem_error const& e) { + std::string s = e.what(); + assert(s.find(what_contains) != std::string::npos); + }; + + std::error_code ec = std::make_error_code(std::errc::file_exists); + const path p1("foo"); + const path p2("bar"); + + // filesystem_error(const string& what_arg, error_code ec); + { + ASSERT_NOT_NOEXCEPT(filesystem_error(what_arg, ec)); + filesystem_error e(what_arg, ec); + CheckWhat(e); + assert(e.code() == ec); + assert(e.path1().empty() && e.path2().empty()); + } + // filesystem_error(const string& what_arg, const path&, error_code ec); + { + ASSERT_NOT_NOEXCEPT(filesystem_error(what_arg, p1, ec)); + filesystem_error e(what_arg, p1, ec); + CheckWhat(e); + assert(e.code() == ec); + assert(e.path1() == p1); + assert(e.path2().empty()); + } + // filesystem_error(const string& what_arg, const path&, const path&, error_code ec); + { + ASSERT_NOT_NOEXCEPT(filesystem_error(what_arg, p1, p2, ec)); + filesystem_error e(what_arg, p1, p2, ec); + CheckWhat(e); + assert(e.code() == ec); + assert(e.path1() == p1); + assert(e.path2() == p2); + } +} + +void test_signatures() +{ + using namespace fs; + const path p; + std::error_code ec; + const filesystem_error e("lala", ec); + // const path& path1() const noexcept; + { + ASSERT_SAME_TYPE(path const&, decltype(e.path1())); + ASSERT_NOEXCEPT(e.path1()); + } + // const path& path2() const noexcept + { + ASSERT_SAME_TYPE(path const&, decltype(e.path2())); + ASSERT_NOEXCEPT(e.path2()); + } + // const char* what() const noexcept + { + ASSERT_SAME_TYPE(const char*, decltype(e.what())); + ASSERT_NOEXCEPT(e.what()); + } +} + +int main() { + static_assert(std::is_base_of::value, ""); + test_constructors(); + test_signatures(); +} \ No newline at end of file Index: test/std/experimental/filesystem/class.path/path.itr/iterator.pass.cpp =================================================================== --- /dev/null +++ test/std/experimental/filesystem/class.path/path.itr/iterator.pass.cpp @@ -0,0 +1,104 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03 + +// + +// class path + +// template +// path(const Source& source); +// template +// path(InputIterator first, InputIterator last); + + +#include +#include +#include +#include + +#include "test_macros.h" +#include "filesystem_test_helper.hpp" + +namespace fs = std::experimental::filesystem; + + +template +std::reverse_iterator mkRev(It it) { + return std::reverse_iterator(it); +} + + +void checkIteratorConcepts() { + using namespace fs; + using It = path::iterator; + using Traits = std::iterator_traits; + ASSERT_SAME_TYPE(Traits::iterator_category, std::bidirectional_iterator_tag); + ASSERT_SAME_TYPE(Traits::value_type, path); + ASSERT_SAME_TYPE(Traits::pointer, path const*); + ASSERT_SAME_TYPE(Traits::reference, path const&); + { + It it; + ASSERT_SAME_TYPE(It&, decltype(++it)); + ASSERT_SAME_TYPE(It, decltype(it++)); + ASSERT_SAME_TYPE(It&, decltype(--it)); + ASSERT_SAME_TYPE(It, decltype(it--)); + ASSERT_SAME_TYPE(Traits::reference, decltype(*it)); + ASSERT_SAME_TYPE(Traits::pointer, decltype(it.operator->())); + ASSERT_SAME_TYPE(std::string const&, decltype(it->native())); + ASSERT_SAME_TYPE(bool, decltype(it == it)); + ASSERT_SAME_TYPE(bool, decltype(it != it)); + } + { + path const p; + ASSERT_SAME_TYPE(It, decltype(p.begin())); + ASSERT_SAME_TYPE(It, decltype(p.end())); + assert(p.begin() == p.end()); + } +} + +void checkBeginEndBasic() { + using namespace fs; + using It = path::iterator; + { + path const p; + ASSERT_SAME_TYPE(It, decltype(p.begin())); + ASSERT_SAME_TYPE(It, decltype(p.end())); + assert(p.begin() == p.end()); + } + { + path const p("foo"); + It default_constructed; + default_constructed = p.begin(); + assert(default_constructed == p.begin()); + assert(default_constructed != p.end()); + default_constructed = p.end(); + assert(default_constructed == p.end()); + assert(default_constructed != p.begin()); + } + { + path p("//root_name//first_dir////second_dir"); + const path expect[] = {"//root_name", "/", "first_dir", "second_dir"}; + assert(checkCollectionsEqual(p.begin(), p.end(), std::begin(expect), std::end(expect))); + assert(checkCollectionsEqual(mkRev(p.end()), mkRev(p.begin()), mkRev(std::end(expect)), mkRev(std::begin(expect)))); + } + { + path p("////foo/bar/baz///"); + const path expect[] = {"/", "foo", "bar", "baz", "."}; + assert(checkCollectionsEqual(p.begin(), p.end(), std::begin(expect), std::end(expect))); + assert(checkCollectionsEqual(mkRev(p.end()), mkRev(p.begin()), mkRev(std::end(expect)), mkRev(std::begin(expect)))); + } +} + +int main() { + using namespace fs; + checkIteratorConcepts(); + checkBeginEndBasic(); // See path.decompose.pass.cpp for more tests. +} Index: test/std/experimental/filesystem/class.path/path.member/path.append.pass.cpp =================================================================== --- /dev/null +++ test/std/experimental/filesystem/class.path/path.member/path.append.pass.cpp @@ -0,0 +1,241 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03 + +// + +// class path + +// path& operator/=(path const&) +// template +// path& operator/=(Source const&); +// template +// path& append(Source const&); +// template +// path& append(InputIterator first, InputIterator last); + + +#include +#include +#include + +#include "test_macros.h" +#include "test_iterators.h" +#include "count_new.hpp" +#include "filesystem_test_helper.hpp" + +namespace fs = std::experimental::filesystem; + +struct AppendOperatorTestcase { + MultiStringType lhs; + MultiStringType rhs; + MultiStringType expect; +}; + +#define S(Str) MKSTR(Str) +const AppendOperatorTestcase Cases[] = + { + {S(""), S(""), S("")} + , {S("p1"), S("p2"), S("p1/p2")} + , {S("p1/"), S("p2"), S("p1/p2")} + , {S("p1"), S("/p2"), S("p1/p2")} + , {S("p1/"), S("/p2"), S("p1//p2")} + , {S("p1"), S("\\p2"), S("p1/\\p2")} + , {S("p1\\"), S("p2"), S("p1\\/p2")} + , {S("p1\\"), S("\\p2"), S("p1\\/\\p2")} + , {S("p1"), S(""), S("p1")} + , {S(""), S("p2"), S("p2")} + }; + + +const AppendOperatorTestcase LongLHSCases[] = + { + {S("p1"), S("p2"), S("p1/p2")} + , {S("p1/"), S("p2"), S("p1/p2")} + , {S("p1"), S("/p2"), S("p1/p2")} + }; +#undef S + + +// The append operator may need to allocate a temporary buffer before a code_cvt +// conversion. Test if this allocation occurs by: +// 1. Create a path, `LHS`, and reserve enough space to append `RHS`. +// This prevents `LHS` from allocating during the actual appending. +// 2. Create a `Source` object `RHS`, which represents a "large" string. +// (The string must not trigger the SSO) +// 3. Append `RHS` to `LHS` and check for the expected allocation behavior. +template +void doAppendSourceAllocTest(AppendOperatorTestcase const& TC) +{ + using namespace fs; + using Ptr = CharT const*; + using Str = std::basic_string; + using InputIter = input_iterator; + + const Ptr L = TC.lhs; + Str RShort = (Ptr)TC.rhs; + Str EShort = (Ptr)TC.expect; + assert(RShort.size() >= 2); + CharT c = RShort.back(); + RShort.append(100, c); + EShort.append(100, c); + const Ptr R = RShort.data(); + const Str& E = EShort; + std::size_t ReserveSize = E.size() + 3; + // basic_string + { + path LHS(L); PathReserve(LHS, ReserveSize); + Str RHS(R); + { + DisableAllocationGuard g; + LHS /= RHS; + } + assert(LHS == E); + } + // CharT* + { + path LHS(L); PathReserve(LHS, ReserveSize); + Ptr RHS(R); + { + DisableAllocationGuard g; + LHS /= RHS; + } + assert(LHS == E); + } + { + path LHS(L); PathReserve(LHS, ReserveSize); + Ptr RHS(R); + { + DisableAllocationGuard g; + LHS.append(RHS, StrEnd(RHS)); + } + assert(LHS == E); + } + // input iterator - For non-native char types, appends needs to copy the + // iterator range into a contigious block of memory before it can perform the + // code_cvt conversions. + // For "char" no allocations will be performed because no conversion is + // required. + bool DisableAllocations = std::is_same::value; + { + path LHS(L); PathReserve(LHS, ReserveSize); + InputIter RHS(R); + { + RequireAllocationGuard g; // requires 1 or more allocations occur by default + if (DisableAllocations) g.requireExactly(0); + LHS /= RHS; + } + assert(LHS == E); + } + { + path LHS(L); PathReserve(LHS, ReserveSize); + InputIter RHS(R); + InputIter REnd(StrEnd(R)); + { + RequireAllocationGuard g; + if (DisableAllocations) g.requireExactly(0); + LHS.append(RHS, REnd); + } + assert(LHS == E); + } +} + +template +void doAppendSourceTest(AppendOperatorTestcase const& TC) +{ + using namespace fs; + using Ptr = CharT const*; + using Str = std::basic_string; + using InputIter = input_iterator; + const Ptr L = TC.lhs; + const Ptr R = TC.rhs; + const Ptr E = TC.expect; + // basic_string + { + path LHS(L); + Str RHS(R); + path& Ref = (LHS /= RHS); + assert(LHS == E); + assert(&Ref == &LHS); + } + { + path LHS(L); + Str RHS(R); + path& Ref = LHS.append(RHS); + assert(LHS == E); + assert(&Ref == &LHS); + } + // Char* + { + path LHS(L); + Str RHS(R); + path& Ref = (LHS /= RHS); + assert(LHS == E); + assert(&Ref == &LHS); + } + { + path LHS(L); + Ptr RHS(R); + path& Ref = LHS.append(RHS); + assert(LHS == E); + assert(&Ref == &LHS); + } + { + path LHS(L); + Ptr RHS(R); + path& Ref = LHS.append(RHS, StrEnd(RHS)); + assert(LHS == E); + assert(&Ref == &LHS); + } + // iterators + { + path LHS(L); + InputIter RHS(R); + path& Ref = (LHS /= RHS); + assert(LHS == E); + assert(&Ref == &LHS); + } + { + path LHS(L); InputIter RHS(R); + path& Ref = LHS.append(RHS); + assert(LHS == E); + assert(&Ref == &LHS); + } + { + path LHS(L); + InputIter RHS(R); + InputIter REnd(StrEnd(R)); + path& Ref = LHS.append(RHS, REnd); + assert(LHS == E); + assert(&Ref == &LHS); + } +} + +int main() +{ + using namespace fs; + for (auto const & TC : Cases) { + { + path LHS((const char*)TC.lhs); + path RHS((const char*)TC.rhs); + path& Ref = (LHS /= RHS); + assert(LHS == (const char*)TC.expect); + assert(&Ref == &LHS); + } + doAppendSourceTest (TC); + doAppendSourceTest (TC); + doAppendSourceTest(TC); + doAppendSourceTest(TC); + } + for (auto const & TC : LongLHSCases) { + doAppendSourceAllocTest(TC); + doAppendSourceAllocTest(TC); + } +} \ No newline at end of file Index: test/std/experimental/filesystem/class.path/path.member/path.assign/copy.pass.cpp =================================================================== --- /dev/null +++ test/std/experimental/filesystem/class.path/path.member/path.assign/copy.pass.cpp @@ -0,0 +1,37 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03 + +// + +// class path + +// path& operator=(path const&); + +#include +#include +#include + +#include "test_macros.h" + +namespace fs = std::experimental::filesystem; + +int main() { + using namespace fs; + static_assert(std::is_copy_assignable::value, ""); + static_assert(!std::is_nothrow_copy_assignable::value, "should not be noexcept"); + const std::string s("foo"); + const path p(s); + path p2; + path& pref = (p2 = p); + assert(p.native() == s); + assert(p2.native() == s); + assert(&pref == &p2); +} \ No newline at end of file Index: test/std/experimental/filesystem/class.path/path.member/path.assign/move.pass.cpp =================================================================== --- /dev/null +++ test/std/experimental/filesystem/class.path/path.member/path.assign/move.pass.cpp @@ -0,0 +1,43 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03 + +// + +// class path + +// path& operator=(path&&) noexcept + +#include +#include +#include + +#include "test_macros.h" +#include "count_new.hpp" + +namespace fs = std::experimental::filesystem; + +int main() { + using namespace fs; + static_assert(std::is_nothrow_move_assignable::value, ""); + assert(globalMemCounter.checkOutstandingNewEq(0)); + const std::string s("we really really really really really really really " + "really really long string so that we allocate"); + assert(globalMemCounter.checkOutstandingNewEq(1)); + path p(s); + { + DisableAllocationGuard g; + path p2; + path& pref = (p2 = std::move(p)); + assert(p2.native() == s); + assert(p.native() != s); // Testing moved from state + assert(&pref == &p2); + } +} \ No newline at end of file Index: test/std/experimental/filesystem/class.path/path.member/path.assign/source.pass.cpp =================================================================== --- /dev/null +++ test/std/experimental/filesystem/class.path/path.member/path.assign/source.pass.cpp @@ -0,0 +1,153 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03 + +// + +// class path + +// template +// path& operator=(Source const&); +// template +// path& assign(Source const&); +// template +// path& assign(InputIterator first, InputIterator last); + + +#include +#include +#include + +#include "test_macros.h" +#include "test_iterators.h" +#include "count_new.hpp" +#include "filesystem_test_helper.hpp" +#include + +namespace fs = std::experimental::filesystem; + +template +void RunTestCase(MultiStringType const& MS) { + using namespace fs; + const char* Expect = MS; + const CharT* TestPath = MS; + const CharT* TestPathEnd = StrEnd(TestPath); + const std::size_t Size = TestPathEnd - TestPath; + const std::size_t SSize = StrEnd(Expect) - Expect; + assert(Size == SSize); + ////////////////////////////////////////////////////////////////////////////// + // basic_string + { + const std::basic_string S(TestPath); + path p; PathReserve(p, S.length() + 1); + { + // string provides a contigious iterator. No allocation needed. + DisableAllocationGuard g; + path& pref = (p = S); + assert(&pref == &p); + } + assert(p.native() == Expect); + assert(p.string() == TestPath); + assert(p.string() == S); + } + { + const std::basic_string S(TestPath); + path p; PathReserve(p, S.length() + 1); + { + DisableAllocationGuard g; + path& pref = p.assign(S); + assert(&pref == &p); + } + assert(p.native() == Expect); + assert(p.string() == TestPath); + assert(p.string() == S); + } + ////////////////////////////////////////////////////////////////////////////// + // Char* pointers + { + path p; PathReserve(p, Size + 1); + { + // char* pointers are contigious and can be used with code_cvt directly. + // no allocations needed. + DisableAllocationGuard g; + path& pref = (p = TestPath); + assert(&pref == &p); + } + assert(p.native() == Expect); + assert(p.string() == TestPath); + } + { + path p; PathReserve(p, Size + 1); + { + DisableAllocationGuard g; + path& pref = p.assign(TestPath); + assert(&pref == &p); + } + assert(p.native() == Expect); + assert(p.string() == TestPath); + } + { + path p; PathReserve(p, Size + 1); + { + DisableAllocationGuard g; + path& pref = p.assign(TestPath, TestPathEnd); + assert(&pref == &p); + } + assert(p.native() == Expect); + assert(p.string() == TestPath); + } + ////////////////////////////////////////////////////////////////////////////// + // Iterators + { + using It = input_iterator; + path p; PathReserve(p, Size + 1); + It it(TestPath); + { + // Iterators cannot be used with code_cvt directly. This assignment + // may allocate if it's larger than a "short-string". + path& pref = (p = it); + assert(&pref == &p); + } + assert(p.native() == Expect); + assert(p.string() == TestPath); + } + { + using It = input_iterator; + path p; PathReserve(p, Size + 1); + It it(TestPath); + { + path& pref = p.assign(it); + assert(&pref == &p); + } + assert(p.native() == Expect); + assert(p.string() == TestPath); + } + { + using It = input_iterator; + path p; PathReserve(p, Size + 1); + It it(TestPath); + It e(TestPathEnd); + { + path& pref = p.assign(it, e); + assert(&pref == &p); + } + assert(p.native() == Expect); + assert(p.string() == TestPath); + } +} + +int main() { + for (auto const& MS : PathList) { + RunTestCase(MS); + RunTestCase(MS); + RunTestCase(MS); + RunTestCase(MS); + } +} \ No newline at end of file Index: test/std/experimental/filesystem/class.path/path.member/path.compare.pass.cpp =================================================================== --- /dev/null +++ test/std/experimental/filesystem/class.path/path.member/path.compare.pass.cpp @@ -0,0 +1,127 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03 + +// + +// class path + +// int compare(path const&) const noexcept; +// int compare(string_type const&) const; +// int compare(value_type const*) const; +// +// bool operator==(path const&, path const&) noexcept; +// bool operator!=(path const&, path const&) noexcept; +// bool operator< (path const&, path const&) noexcept; +// bool operator<=(path const&, path const&) noexcept; +// bool operator> (path const&, path const&) noexcept; +// bool operator>=(path const&, path const&) noexcept; +// +// size_t hash_value(path const&) noexcept; + +#include +#include +#include +#include + +#include "test_macros.h" +#include "test_iterators.h" +#include "count_new.hpp" +#include "filesystem_test_helper.hpp" + +namespace fs = std::experimental::filesystem; + +struct PathCompareTest { + const char* LHS; + const char* RHS; + int expect; +}; + +#define LONGA "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" +#define LONGB "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" +#define LONGC "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC" +#define LONGD "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD" +const PathCompareTest CompareTestCases[] = +{ + {"", "", 0}, + {"a", "", 1}, + {"", "a", -1}, + {"a/b/c", "a/b/c", 0}, + {"b/a/c", "a/b/c", 1}, + {"a/b/c", "b/a/c", -1}, + {"a/b", "a/b/c", -1}, + {"a/b/c", "a/b", 1}, + {"a/b/", "a/b/.", 0}, + {"a/b//////", "a/b/////.", 0}, + {"a/.././b", "a///..//.////b", 0}, + {"//foo//bar///baz////", "//foo/bar/baz/", 0}, // duplicate separators + {"///foo/bar", "/foo/bar", 0}, // "///" is not a root directory + {"/foo/bar/", "/foo/bar", 1}, // trailing separator + {"//" LONGA "////" LONGB "/" LONGC "///" LONGD, "//" LONGA "/" LONGB "/" LONGC "/" LONGD, 0}, + { LONGA "/" LONGB "/" LONGC, LONGA "/" LONGB "/" LONGB, 1} + +}; +#undef LONGA +#undef LONGB +#undef LONGC +#undef LONGD + +int main() +{ + using namespace fs; + for (auto const & TC : CompareTestCases) { + const path p1(TC.LHS); + const path p2(TC.RHS); + const std::string R(TC.RHS); + const int E = TC.expect; + { // compare(...) functions + DisableAllocationGuard g; // none of these operations should allocate + + // check runtime results + int ret1 = p1.compare(p2); + int ret2 = p1.compare(R); + int ret3 = p1.compare(TC.RHS); + assert(ret1 == ret2 && ret1 == ret3); + int normalized_ret = ret1 < 0 ? -1 : (ret1 > 0 ? 1 : 0); + assert(normalized_ret == E); + + // check signatures + ASSERT_NOEXCEPT(p1.compare(p2)); + } + { // comparison operators + DisableAllocationGuard g; // none of these operations should allocate + + // Check runtime result + assert((p1 == p2) == (E == 0)); + assert((p1 != p2) == (E != 0)); + assert((p1 < p2) == (E < 0)); + assert((p1 <= p2) == (E <= 0)); + assert((p1 > p2) == (E > 0)); + assert((p1 >= p2) == (E >= 0)); + + // Check signatures + ASSERT_NOEXCEPT(p1 == p2); + ASSERT_NOEXCEPT(p1 != p2); + ASSERT_NOEXCEPT(p1 < p2); + ASSERT_NOEXCEPT(p1 <= p2); + ASSERT_NOEXCEPT(p1 > p2); + ASSERT_NOEXCEPT(p1 >= p2); + } + { // check hash values + auto h1 = hash_value(p1); + auto h2 = hash_value(p2); + assert((h1 == h2) == (p1 == p2)); + // check signature + ASSERT_SAME_TYPE(size_t, decltype(hash_value(p1))); + ASSERT_NOEXCEPT(hash_value(p1)); + } + } +} + Index: test/std/experimental/filesystem/class.path/path.member/path.concat.pass.cpp =================================================================== --- /dev/null +++ test/std/experimental/filesystem/class.path/path.member/path.concat.pass.cpp @@ -0,0 +1,277 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03 + +// + +// class path + +// path& operator+=(const path& x); +// path& operator+=(const string_type& x); // Implemented as Source template +// path& operator+=(const value_type* x); // Implemented as Source template +// path& operator+=(value_type x); +// template +// path& operator+=(const Source& x); +// template +// path& operator+=(EcharT x); +// template +// path& concat(const Source& x); +// template +// path& concat(InputIterator first, InputIterator last); + + +#include +#include +#include + +#include "test_macros.h" +#include "test_iterators.h" +#include "count_new.hpp" +#include "filesystem_test_helper.hpp" + +namespace fs = std::experimental::filesystem; + +struct ConcatOperatorTestcase { + MultiStringType lhs; + MultiStringType rhs; + MultiStringType expect; +}; + +#define LONGSTR "LONGSTR_LONGSTR_LONGSTR_LONGSTR_LONGSTR_LONGSTR_LONGSTR_LONGSTR_LONGSTR_LONGSTR_LONGSTR_LONGSTR" +#define S(Str) MKSTR(Str) +const ConcatOperatorTestcase Cases[] = + { + {S(""), S(""), S("")} + , {S("p1"), S("p2"), S("p1p2")} + , {S("p1/"), S("/p2"), S("p1//p2")} + , {S(""), S("\\foo/bar/baz"), S("\\foo/bar/baz")} + , {S("c:\\foo"), S(""), S("c:\\foo")} + , {S(LONGSTR), S("foo"), S(LONGSTR "foo")} + , {S("abcdefghijklmnopqrstuvwxyz/\\"), S("/\\123456789"), S("abcdefghijklmnopqrstuvwxyz/\\/\\123456789")} + }; +const ConcatOperatorTestcase LongLHSCases[] = + { + {S(""), S(LONGSTR), S(LONGSTR)} + , {S("p1/"), S(LONGSTR), S("p1/" LONGSTR)} + }; +const ConcatOperatorTestcase CharTestCases[] = + { + {S(""), S("P"), S("P")} + , {S("/fooba"), S("r"), S("/foobar")} + }; +#undef S +#undef LONGSTR + +// The concat operator may need to allocate a temporary buffer before a code_cvt +// conversion. Test if this allocation occurs by: +// 1. Create a path, `LHS`, and reserve enough space to append `RHS`. +// This prevents `LHS` from allocating during the actual appending. +// 2. Create a `Source` object `RHS`, which represents a "large" string. +// (The string must not trigger the SSO) +// 3. Concat `RHS` to `LHS` and check for the expected allocation behavior. +template +void doConcatSourceAllocTest(ConcatOperatorTestcase const& TC) +{ + using namespace fs; + using Ptr = CharT const*; + using Str = std::basic_string; + using InputIter = input_iterator; + + const Ptr L = TC.lhs; + const Ptr R = TC.rhs; + const Ptr E = TC.expect; + std::size_t ReserveSize = StrLen(E) + 1; + // basic_string + { + path LHS(L); PathReserve(LHS, ReserveSize); + Str RHS(R); + { + DisableAllocationGuard g; + LHS += RHS; + } + assert(LHS == E); + } + // CharT* + { + path LHS(L); PathReserve(LHS, ReserveSize); + Ptr RHS(R); + { + DisableAllocationGuard g; + LHS += RHS; + } + assert(LHS == E); + } + { + path LHS(L); PathReserve(LHS, ReserveSize); + Ptr RHS(R); + { + DisableAllocationGuard g; + LHS.concat(RHS, StrEnd(RHS)); + } + assert(LHS == E); + } + // input iterator - For non-native char types, appends needs to copy the + // iterator range into a contigious block of memory before it can perform the + // code_cvt conversions. + // For "char" no allocations will be performed because no conversion is + // required. + bool DisableAllocations = std::is_same::value; + { + path LHS(L); PathReserve(LHS, ReserveSize); + InputIter RHS(R); + { + RequireAllocationGuard g; // requires 1 or more allocations occur by default + if (DisableAllocations) g.requireExactly(0); + LHS += RHS; + } + assert(LHS == E); + } + { + path LHS(L); PathReserve(LHS, ReserveSize); + InputIter RHS(R); + InputIter REnd(StrEnd(R)); + { + RequireAllocationGuard g; + if (DisableAllocations) g.requireExactly(0); + LHS.concat(RHS, REnd); + } + assert(LHS == E); + } +} + +template +void doConcatSourceTest(ConcatOperatorTestcase const& TC) +{ + using namespace fs; + using Ptr = CharT const*; + using Str = std::basic_string; + using InputIter = input_iterator; + const Ptr L = TC.lhs; + const Ptr R = TC.rhs; + const Ptr E = TC.expect; + // basic_string + { + path LHS(L); + Str RHS(R); + path& Ref = (LHS += RHS); + assert(LHS == E); + assert(&Ref == &LHS); + } + { + path LHS(L); + Str RHS(R); + path& Ref = LHS.concat(RHS); + assert(LHS == E); + assert(&Ref == &LHS); + } + // Char* + { + path LHS(L); + Str RHS(R); + path& Ref = (LHS += RHS); + assert(LHS == E); + assert(&Ref == &LHS); + } + { + path LHS(L); + Ptr RHS(R); + path& Ref = LHS.concat(RHS); + assert(LHS == E); + assert(&Ref == &LHS); + } + { + path LHS(L); + Ptr RHS(R); + path& Ref = LHS.concat(RHS, StrEnd(RHS)); + assert(LHS == E); + assert(&Ref == &LHS); + } + // iterators + { + path LHS(L); + InputIter RHS(R); + path& Ref = (LHS += RHS); + assert(LHS == E); + assert(&Ref == &LHS); + } + { + path LHS(L); InputIter RHS(R); + path& Ref = LHS.concat(RHS); + assert(LHS == E); + assert(&Ref == &LHS); + } + { + path LHS(L); + InputIter RHS(R); + InputIter REnd(StrEnd(R)); + path& Ref = LHS.concat(RHS, REnd); + assert(LHS == E); + assert(&Ref == &LHS); + } +} + +template +void doConcatECharTest(ConcatOperatorTestcase const& TC) +{ + using namespace fs; + using Ptr = CharT const*; + const Ptr RStr = TC.rhs; + assert(StrLen(RStr) == 1); + const Ptr L = TC.lhs; + const CharT R = RStr[0]; + const Ptr E = TC.expect; + { + path LHS(L); + path& Ref = (LHS += R); + assert(LHS == E); + assert(&Ref == &LHS); + } +} + +int main() +{ + using namespace fs; + for (auto const & TC : Cases) { + { + path LHS((const char*)TC.lhs); + path RHS((const char*)TC.rhs); + path& Ref = (LHS += RHS); + assert(LHS == (const char*)TC.expect); + assert(&Ref == &LHS); + } + doConcatSourceTest (TC); + doConcatSourceTest (TC); + doConcatSourceTest(TC); + doConcatSourceTest(TC); + } + for (auto const & TC : LongLHSCases) { + // Do path test + { + path LHS((const char*)TC.lhs); + path RHS((const char*)TC.rhs); + const char* E = TC.expect; + PathReserve(LHS, StrLen(E) + 5); + { + DisableAllocationGuard g; + path& Ref = (LHS += RHS); + assert(&Ref == &LHS); + } + assert(LHS == E); + } + doConcatSourceAllocTest(TC); + doConcatSourceAllocTest(TC); + } + for (auto const& TC : CharTestCases) { + doConcatECharTest(TC); + doConcatECharTest(TC); + doConcatECharTest(TC); + doConcatECharTest(TC); + } +} \ No newline at end of file Index: test/std/experimental/filesystem/class.path/path.member/path.construct/copy.pass.cpp =================================================================== --- /dev/null +++ test/std/experimental/filesystem/class.path/path.member/path.construct/copy.pass.cpp @@ -0,0 +1,35 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03 + +// + +// class path + +// path(path const&) + +#include +#include +#include + +#include "test_macros.h" + +namespace fs = std::experimental::filesystem; + +int main() { + using namespace fs; + static_assert(std::is_copy_constructible::value, ""); + static_assert(!std::is_nothrow_copy_constructible::value, "should not be noexcept"); + const std::string s("foo"); + const path p(s); + path p2(p); + assert(p.native() == s); + assert(p2.native() == s); +} \ No newline at end of file Index: test/std/experimental/filesystem/class.path/path.member/path.construct/default.pass.cpp =================================================================== --- /dev/null +++ test/std/experimental/filesystem/class.path/path.member/path.construct/default.pass.cpp @@ -0,0 +1,31 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03 + +// + +// class path + +// path() noexcept + +#include +#include +#include + +#include "test_macros.h" + +namespace fs = std::experimental::filesystem; + +int main() { + using namespace fs; + static_assert(std::is_nothrow_default_constructible::value, ""); + const path p; + assert(p.empty()); +} \ No newline at end of file Index: test/std/experimental/filesystem/class.path/path.member/path.construct/move.pass.cpp =================================================================== --- /dev/null +++ test/std/experimental/filesystem/class.path/path.member/path.construct/move.pass.cpp @@ -0,0 +1,41 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03 + +// + +// class path + +// path(path&&) noexcept + +#include +#include +#include + +#include "test_macros.h" +#include "count_new.hpp" + +namespace fs = std::experimental::filesystem; + +int main() { + using namespace fs; + static_assert(std::is_nothrow_move_constructible::value, ""); + assert(globalMemCounter.checkOutstandingNewEq(0)); + const std::string s("we really really really really really really really " + "really really long string so that we allocate"); + assert(globalMemCounter.checkOutstandingNewEq(1)); + path p(s); + { + DisableAllocationGuard g; + path p2(std::move(p)); + assert(p2.native() == s); + assert(p.native() != s); // Testing moved from state + } +} \ No newline at end of file Index: test/std/experimental/filesystem/class.path/path.member/path.construct/source.pass.cpp =================================================================== --- /dev/null +++ test/std/experimental/filesystem/class.path/path.member/path.construct/source.pass.cpp @@ -0,0 +1,83 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03 + +// + +// class path + +// template +// path(const Source& source); +// template +// path(InputIterator first, InputIterator last); + + +#include +#include +#include + +#include "test_macros.h" +#include "test_iterators.h" +#include "min_allocator.h" +#include "filesystem_test_helper.hpp" + +namespace fs = std::experimental::filesystem; + +template +void RunTestCase(MultiStringType const& MS) { + using namespace fs; + const char* Expect = MS; + const CharT* TestPath = MS; + const CharT* TestPathEnd = StrEnd(TestPath); + const std::size_t Size = TestPathEnd - TestPath; + const std::size_t SSize = StrEnd(Expect) - Expect; + assert(Size == SSize); + // StringTypes + { + const std::basic_string S(TestPath); + path p(S); + assert(p.native() == Expect); + assert(p.string() == TestPath); + assert(p.string() == S); + } + // Char* pointers + { + path p(TestPath); + assert(p.native() == Expect); + assert(p.string() == TestPath); + } + { + path p(TestPath, TestPathEnd); + assert(p.native() == Expect); + assert(p.string() == TestPath); + } + // Iterators + { + using It = input_iterator; + path p(It{TestPath}); + assert(p.native() == Expect); + assert(p.string() == TestPath); + } + { + using It = input_iterator; + path p(It{TestPath}, It{TestPathEnd}); + assert(p.native() == Expect); + assert(p.string() == TestPath); + } +} + +int main() { + for (auto const& MS : PathList) { + RunTestCase(MS); + RunTestCase(MS); + RunTestCase(MS); + RunTestCase(MS); + } +} \ No newline at end of file Index: test/std/experimental/filesystem/class.path/path.member/path.decompose/path.decompose.pass.cpp =================================================================== --- /dev/null +++ test/std/experimental/filesystem/class.path/path.member/path.decompose/path.decompose.pass.cpp @@ -0,0 +1,198 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03 + +// + +// class path + +// 8.4.9 path decomposition [path.decompose] +//------------------------------------------ +// path root_name() const; +// path root_directory() const; +// path root_path() const; +// path relative_path() const; +// path parent_path() const; +// path filename() const; +// path stem() const; +// path extension() const; +//------------------------------- +// 8.4.10 path query [path.query] +//------------------------------- +// bool empty() const noexcept; +// bool has_root_path() const; +// bool has_root_name() const; +// bool has_root_directory() const; +// bool has_relative_path() const; +// bool has_parent_path() const; +// bool has_filename() const; +// bool has_stem() const; +// bool has_extension() const; +// bool is_absolute() const; +// bool is_relative() const; +//------------------------------- +// 8.5 path iterators [path.itr] +//------------------------------- +// iterator begin() const; +// iterator end() const; + + +#include +#include +#include +#include + +#include "test_macros.h" +#include "test_iterators.h" +#include "count_new.hpp" +#include "filesystem_test_helper.hpp" + +template +std::reverse_iterator mkRev(It it) { + return std::reverse_iterator(it); +} + + +namespace fs = std::experimental::filesystem; +struct PathDecomposeTestcase +{ + std::string raw; + std::vector elements; + std::string root_path; + std::string root_name; + std::string root_directory; + std::string relative_path; + std::string parent_path; + std::string filename; +}; + +const PathDecomposeTestcase PathTestCases[] = + { + {"", {}, "", "", "", "", "", ""} + , {".", {"."}, "", "", "", ".", "", "."} + , {"..", {".."}, "", "", "", "..", "", ".."} + , {"foo", {"foo"}, "", "", "", "foo", "", "foo"} + , {"/", {"/"}, "/", "", "/", "", "", "/"} + , {"/foo", {"/", "foo"}, "/", "", "/", "foo", "/", "foo"} + , {"foo/", {"foo", "."}, "", "", "", "foo/", "foo", "."} + , {"/foo/", {"/", "foo", "."}, "/", "", "/", "foo/", "/foo", "."} + , {"foo/bar", {"foo","bar"}, "", "", "", "foo/bar", "foo", "bar"} + , {"/foo//bar", {"/","foo","bar"}, "/", "", "/", "foo/bar", "/foo", "bar"} + , {"//net", {"//net"}, "//net", "//net", "", "", "", "//net"} + , {"//net/foo", {"//net", "/", "foo"}, "//net/", "//net", "/", "foo", "//net/", "foo"} + , {"///foo///", {"/", "foo", "."}, "/", "", "/", "foo///", "///foo", "."} + , {"///foo///bar", {"/", "foo", "bar"}, "/", "", "/", "foo///bar", "///foo", "bar"} + , {"/.", {"/", "."}, "/", "", "/", ".", "/", "."} + , {"./", {".", "."}, "", "", "", "./", ".", "."} + , {"/..", {"/", ".."}, "/", "", "/", "..", "/", ".."} + , {"../", {"..", "."}, "", "", "", "../", "..", "."} + , {"foo/.", {"foo", "."}, "", "", "", "foo/.", "foo", "."} + , {"foo/..", {"foo", ".."}, "", "", "", "foo/..", "foo", ".."} + , {"foo/./", {"foo", ".", "."}, "", "", "", "foo/./", "foo/.", "."} + , {"foo/./bar", {"foo", ".", "bar"}, "", "", "", "foo/./bar", "foo/.", "bar"} + , {"foo/../", {"foo", "..", "."}, "", "", "", "foo/../", "foo/..", "."} + , {"foo/../bar", {"foo", "..", "bar"}, "", "", "", "foo/../bar", "foo/..", "bar"} + , {"c:", {"c:"}, "", "", "", "c:", "", "c:"} + , {"c:/", {"c:", "."}, "", "", "", "c:/", "c:", "."} + , {"c:foo", {"c:foo"}, "", "", "", "c:foo", "", "c:foo"} + , {"c:/foo", {"c:", "foo"}, "", "", "", "c:/foo", "c:", "foo"} + , {"c:foo/", {"c:foo", "."}, "", "", "", "c:foo/", "c:foo", "."} + , {"c:/foo/", {"c:", "foo", "."}, "", "", "", "c:/foo/", "c:/foo", "."} + , {"c:/foo/bar", {"c:", "foo", "bar"}, "", "", "", "c:/foo/bar", "c:/foo", "bar"} + , {"prn:", {"prn:"}, "", "", "", "prn:", "", "prn:"} + , {"c:\\", {"c:\\"}, "", "", "", "c:\\", "", "c:\\"} + , {"c:\\foo", {"c:\\foo"}, "", "", "", "c:\\foo", "", "c:\\foo"} + , {"c:foo\\", {"c:foo\\"}, "", "", "", "c:foo\\", "", "c:foo\\"} + , {"c:\\foo\\", {"c:\\foo\\"}, "", "", "", "c:\\foo\\", "", "c:\\foo\\"} + , {"c:\\foo/", {"c:\\foo", "."}, "", "", "", "c:\\foo/", "c:\\foo", "."} + , {"c:/foo\\bar", {"c:", "foo\\bar"}, "", "", "", "c:/foo\\bar", "c:", "foo\\bar"} + , {"//", {"//"}, "//", "//", "", "", "", "//"} + }; + +void decompPathTest() +{ + using namespace fs; + for (auto const & TC : PathTestCases) { + path p(TC.raw); + assert(p == TC.raw); + + assert(p.root_path() == TC.root_path); + assert(p.has_root_path() == not TC.root_path.empty()); + + assert(p.root_name() == TC.root_name); + assert(p.has_root_name() == not TC.root_name.empty()); + + assert(p.root_directory() == TC.root_directory); + assert(p.has_root_directory() == not TC.root_directory.empty()); + + assert(p.relative_path() == TC.relative_path); + assert(p.has_relative_path() == not TC.relative_path.empty()); + + assert(p.parent_path() == TC.parent_path); + assert(p.has_parent_path() == not TC.parent_path.empty()); + + assert(p.filename() == TC.filename); + assert(p.has_filename() == not TC.filename.empty()); + + assert(p.is_absolute() == p.has_root_directory()); + assert(p.is_relative() == not p.is_absolute()); + + assert(checkCollectionsEqual(p.begin(), p.end(), + TC.elements.begin(), TC.elements.end())); + // check backwards + assert(checkCollectionsEqual(mkRev(p.end()), mkRev(p.begin()), + TC.elements.rbegin(), TC.elements.rend())); + } +} + + +struct FilenameDecompTestcase +{ + std::string raw; + std::string filename; + std::string stem; + std::string extension; +}; + +const FilenameDecompTestcase FilenameTestCases[] = +{ + {"", "", "", ""} + , {".", ".", ".", ""} + , {"..", "..", "..", ""} + , {"/", "/", "/", ""} + , {"foo", "foo", "foo", ""} + , {"/foo/bar.txt", "bar.txt", "bar", ".txt"} + , {"foo..txt", "foo..txt", "foo.", ".txt"} +}; + + +void decompFilenameTest() +{ + using namespace fs; + for (auto const & TC : FilenameTestCases) { + path p(TC.raw); + assert(p == TC.raw); + + assert(p.filename() == TC.filename); + assert(p.has_filename() == not TC.filename.empty()); + + assert(p.stem() == TC.stem); + assert(p.has_stem() == not TC.stem.empty()); + + assert(p.extension() == TC.extension); + assert(p.has_extension() == not TC.extension.empty()); + } +} + +int main() +{ + decompPathTest(); + decompFilenameTest(); +} \ No newline at end of file Index: test/std/experimental/filesystem/class.path/path.member/path.generic.obs/generic_string_alloc.pass.cpp =================================================================== --- /dev/null +++ test/std/experimental/filesystem/class.path/path.member/path.generic.obs/generic_string_alloc.pass.cpp @@ -0,0 +1,57 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03 + +// + +// class path + +// template , +// class Allocator = allocator> +// basic_string +// generic_string(const Allocator& a = Allocator()) const; + +#include +#include +#include + +#include "test_macros.h" +#include "test_iterators.h" +#include "count_new.hpp" +#include "min_allocator.h" +#include "filesystem_test_helper.hpp" + +namespace fs = std::experimental::filesystem; + +MultiStringType longString = MKSTR("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ/123456789/abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"); + + +// generic_string forwards to string. Tests for +// string() are in "path.native.op/string_alloc.pass.cpp". +// generic_string is minimally tested here. +int main() +{ + using namespace fs; + using CharT = wchar_t; + using Traits = std::char_traits; + using Alloc = malloc_allocator; + using Str = std::basic_string; + const wchar_t* expect = longString; + const path p((const char*)longString); + { + DisableAllocationGuard g; + Alloc a; + Alloc::disable_default_constructor = true; + Str s = p.generic_string(a); + assert(s == expect); + assert(Alloc::alloc_count > 0); + assert(Alloc::outstanding_alloc == 1); + } +} \ No newline at end of file Index: test/std/experimental/filesystem/class.path/path.member/path.generic.obs/named_overloads.pass.cpp =================================================================== --- /dev/null +++ test/std/experimental/filesystem/class.path/path.member/path.generic.obs/named_overloads.pass.cpp @@ -0,0 +1,63 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03 + +// + +// class path + +// std::string generic_string() const; +// std::wstring generic_wstring() const; +// std::u8string generic_u8string() const; +// std::u16string generic_u16string() const; +// std::u32string generic_u32string() const; + + +#include +#include +#include + +#include "test_macros.h" +#include "test_iterators.h" +#include "count_new.hpp" +#include "min_allocator.h" +#include "filesystem_test_helper.hpp" + +namespace fs = std::experimental::filesystem; + +MultiStringType longString = MKSTR("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ/123456789/abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"); + +int main() +{ + using namespace fs; + auto const& MS = longString; + const char* value = longString; + const path p(value); + { + std::string s = p.generic_string(); + assert(s == value); + } + { + std::string s = p.generic_u8string(); + assert(s == (const char*)MS); + } + { + std::wstring s = p.generic_wstring(); + assert(s == (const wchar_t*)MS); + } + { + std::u16string s = p.generic_u16string(); + assert(s == (const char16_t*)MS); + } + { + std::u32string s = p.generic_u32string(); + assert(s == (const char32_t*)MS); + } +} \ No newline at end of file Index: test/std/experimental/filesystem/class.path/path.member/path.modifiers/clear.pass.cpp =================================================================== --- /dev/null +++ test/std/experimental/filesystem/class.path/path.member/path.modifiers/clear.pass.cpp @@ -0,0 +1,45 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03 + +// + +// class path + +// void clear() noexcept + +#include +#include +#include + +#include "test_macros.h" +#include "test_iterators.h" +#include "count_new.hpp" +#include "filesystem_test_helper.hpp" + +namespace fs = std::experimental::filesystem; + +int main() { + using namespace fs; + const path p("/foo/bar/baz"); + { + path p; + ASSERT_NOEXCEPT(p.clear()); + ASSERT_SAME_TYPE(void, decltype(p.clear())); + p.clear(); + assert(p.empty()); + } + { + path p2(p); + assert(p == p2); + p2.clear(); + assert(p2.empty()); + } +} \ No newline at end of file Index: test/std/experimental/filesystem/class.path/path.member/path.modifiers/make_preferred.pass.cpp =================================================================== --- /dev/null +++ test/std/experimental/filesystem/class.path/path.member/path.modifiers/make_preferred.pass.cpp @@ -0,0 +1,55 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03 + +// + +// class path + +// path& make_preferred() + +#include +#include +#include + +#include "test_macros.h" +#include "test_iterators.h" +#include "count_new.hpp" +#include "filesystem_test_helper.hpp" + +namespace fs = std::experimental::filesystem; + +struct MakePreferredTestcase { + const char* value; +}; + +const MakePreferredTestcase TestCases[] = + { + {""} + , {"hello_world"} + , {"/"} + , {"/foo/bar/baz/"} + , {"\\"} + , {"\\foo\\bar\\baz\\"} + , {"\\foo\\/bar\\/baz\\"} + }; + +int main() +{ + // This operation is an identity operation on linux. + using namespace fs; + for (auto const & TC : TestCases) { + path p(TC.value); + assert(p == TC.value); + path& Ref = (p.make_preferred()); + assert(p.native() == TC.value); + assert(&Ref == &p); + } +} \ No newline at end of file Index: test/std/experimental/filesystem/class.path/path.member/path.modifiers/remove_filename.pass.cpp =================================================================== --- /dev/null +++ test/std/experimental/filesystem/class.path/path.member/path.modifiers/remove_filename.pass.cpp @@ -0,0 +1,72 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03 + +// + +// class path + +// path& remove_filename() + +#include +#include +#include + +#include "test_macros.h" +#include "test_iterators.h" +#include "count_new.hpp" +#include "filesystem_test_helper.hpp" + +namespace fs = std::experimental::filesystem; + +struct RemoveFilenameTestcase { + const char* value; + const char* expect; +}; + +const RemoveFilenameTestcase TestCases[] = + { + {"", ""} + , {"/", ""} + , {"\\", ""} + , {".", ""} + , {"..", ""} + , {"/foo", "/"} + , {"/foo/", "/foo"} + , {"/foo/.", "/foo"} + , {"/foo/..", "/foo"} + , {"/foo/////", "/foo"} + , {"/foo\\\\", "/"} + , {"/foo//\\/", "/foo//\\"} + , {"file.txt", ""} + , {"bar/../baz/./file.txt", "bar/../baz/."} + }; + +int main() +{ + using namespace fs; + for (auto const & TC : TestCases) { + path const p_orig(TC.value); + path p(p_orig); + assert(p == TC.value); + path& Ref = (p.remove_filename()); + assert(p == TC.expect); + assert(&Ref == &p); + { + const path parentp = p_orig.parent_path(); + if (parentp == p_orig.root_name()) { + + assert(p.empty()); + } else { + assert(p == parentp); + } + } + } +} \ No newline at end of file Index: test/std/experimental/filesystem/class.path/path.member/path.modifiers/replace_extension.pass.cpp =================================================================== --- /dev/null +++ test/std/experimental/filesystem/class.path/path.member/path.modifiers/replace_extension.pass.cpp @@ -0,0 +1,73 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03 + +// + +// class path + +// path& replace_extension(path const& p = path()) + +#include +#include +#include + +#include "test_macros.h" +#include "test_iterators.h" +#include "count_new.hpp" +#include "filesystem_test_helper.hpp" + +namespace fs = std::experimental::filesystem; + +struct ReplaceExtensionTestcase { + const char* value; + const char* expect; + const char* extension; +}; + +const ReplaceExtensionTestcase TestCases[] = + { + {"", "", ""} + , {"foo.cpp", "foo", ""} + , {"foo.cpp", "foo.", "."} + , {"foo..cpp", "foo..txt", "txt"} + , {"", ".txt", "txt"} + , {"", ".txt", ".txt"} + , {"/foo", "/foo.txt", ".txt"} + , {"/foo", "/foo.txt", "txt"} + , {"/foo.cpp", "/foo.txt", ".txt"} + , {"/foo.cpp", "/foo.txt", "txt"} + }; +const ReplaceExtensionTestcase NoArgCases[] = + { + {"", ""} + , {"foo", "foo"} + , {"foo.cpp", "foo"} + , {"foo..cpp", "foo."} +}; + +int main() +{ + using namespace fs; + for (auto const & TC : TestCases) { + path p(TC.value); + assert(p == TC.value); + path& Ref = (p.replace_extension(TC.extension)); + assert(p == TC.expect); + assert(&Ref == &p); + } + for (auto const& TC : NoArgCases) { + path p(TC.value); + assert(p == TC.value); + path& Ref = (p.replace_extension()); + assert(p == TC.expect); + assert(&Ref == &p); + } +} \ No newline at end of file Index: test/std/experimental/filesystem/class.path/path.member/path.modifiers/replace_filename.pass.cpp =================================================================== --- /dev/null +++ test/std/experimental/filesystem/class.path/path.member/path.modifiers/replace_filename.pass.cpp @@ -0,0 +1,69 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03 + +// + +// class path + +// path& replace_filename() + +#include +#include +#include + +#include "test_macros.h" +#include "test_iterators.h" +#include "count_new.hpp" +#include "filesystem_test_helper.hpp" + +namespace fs = std::experimental::filesystem; + +struct ReplaceFilenameTestcase { + const char* value; + const char* expect; + const char* filename; +}; + +const ReplaceFilenameTestcase TestCases[] = + { + {"/foo", "/bar", "bar"} + , {"/foo", "/", ""} + , {"foo", "bar", "bar"} + , {"/", "bar", "bar"} + , {"\\", "bar", "bar"} + , {"///", "bar", "bar"} + , {"\\\\", "bar", "bar"} + , {"\\/\\", "\\/bar", "bar"} + , {".", "bar", "bar"} + , {"..", "bar", "bar"} + , {"/foo\\baz/bong/", "/foo\\baz/bong/bar", "bar"} + , {"/foo\\baz/bong", "/foo\\baz/bar", "bar"} + }; + +int main() +{ + using namespace fs; + for (auto const & TC : TestCases) { + path p(TC.value); + assert(p == TC.value); + path& Ref = (p.replace_filename(TC.filename)); + assert(p == TC.expect); + assert(&Ref == &p); + // Tests Effects "as-if": remove_filename() append(filename) + { + path p2(TC.value); + path replace(TC.filename); + p2.remove_filename(); + p2 /= replace; + assert(p2 == p); + } + } +} \ No newline at end of file Index: test/std/experimental/filesystem/class.path/path.member/path.modifiers/swap.pass.cpp =================================================================== --- /dev/null +++ test/std/experimental/filesystem/class.path/path.member/path.modifiers/swap.pass.cpp @@ -0,0 +1,81 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03 + +// + +// class path + +// void swap(path& rhs) noexcept; + +#include +#include +#include + +#include "test_macros.h" +#include "test_iterators.h" +#include "count_new.hpp" +#include "filesystem_test_helper.hpp" + +namespace fs = std::experimental::filesystem; + +struct SwapTestcase { + const char* value1; + const char* value2; +}; + +#define LONG_STR1 "_THIS_IS_LONG_THIS_IS_LONG_THIS_IS_LONG_THIS_IS_LONG_THIS_IS_LONG_THIS_IS_LONG_THIS_IS_LONG" +#define LONG_STR2 "_THIS_IS_LONG2_THIS_IS_LONG2_THIS_IS_LONG2_THIS_IS_LONG2_THIS_IS_LONG2_THIS_IS_LONG2_THIS_IS_LONG2" +const SwapTestcase TestCases[] = + { + {"", ""} + , {"shortstr", LONG_STR1} + , {LONG_STR1, "shortstr"} + , {LONG_STR1, LONG_STR2} + }; +#undef LONG_STR1 +#undef LONG_STR2 + +int main() +{ + using namespace fs; + { + path p; + ASSERT_NOEXCEPT(p.swap(p)); + ASSERT_SAME_TYPE(void, decltype(p.swap(p))); + } + for (auto const & TC : TestCases) { + path p1(TC.value1); + path p2(TC.value2); + { + DisableAllocationGuard g; + p1.swap(p2); + } + assert(p1 == TC.value2); + assert(p2 == TC.value1); + { + DisableAllocationGuard g; + p1.swap(p2); + } + assert(p1 == TC.value1); + assert(p2 == TC.value2); + } + // self-swap + { + const char* Val = "aoeuaoeuaoeuaoeuaoeuaoeuaoeuaoeuaoeu"; + path p1(Val); + assert(p1 == Val); + { + DisableAllocationGuard g; + p1.swap(p1); + } + assert(p1 == Val); + } +} \ No newline at end of file Index: test/std/experimental/filesystem/class.path/path.member/path.native.obs/c_str.pass.cpp =================================================================== --- /dev/null +++ test/std/experimental/filesystem/class.path/path.member/path.native.obs/c_str.pass.cpp @@ -0,0 +1,43 @@ + +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03 + +// + +// class path + +// const value_type* c_str() const noexcept; + +#include +#include +#include + +#include "test_macros.h" +#include "filesystem_test_helper.hpp" + +namespace fs = std::experimental::filesystem; + +int main() +{ + using namespace fs; + const char* const value = "hello world"; + const std::string str_value = value; + path p(value); + { // Check signature + ASSERT_SAME_TYPE(path::value_type const*, decltype(p.c_str())); + ASSERT_NOEXCEPT(p.c_str()); + } + { + path p(value); + assert(p.c_str() == str_value); + assert(p.native().c_str() == p.c_str()); + } +} \ No newline at end of file Index: test/std/experimental/filesystem/class.path/path.member/path.native.obs/named_overloads.pass.cpp =================================================================== --- /dev/null +++ test/std/experimental/filesystem/class.path/path.member/path.native.obs/named_overloads.pass.cpp @@ -0,0 +1,63 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03 + +// + +// class path + +// std::string string() const; +// std::wstring wstring() const; +// std::u8string u8string() const; +// std::u16string u16string() const; +// std::u32string u32string() const; + + +#include +#include +#include + +#include "test_macros.h" +#include "test_iterators.h" +#include "count_new.hpp" +#include "min_allocator.h" +#include "filesystem_test_helper.hpp" + +namespace fs = std::experimental::filesystem; + +MultiStringType longString = MKSTR("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ/123456789/abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"); + +int main() +{ + using namespace fs; + auto const& MS = longString; + const char* value = longString; + const path p(value); + { + std::string s = p.string(); + assert(s == value); + } + { + std::string s = p.u8string(); + assert(s == (const char*)MS); + } + { + std::wstring s = p.wstring(); + assert(s == (const wchar_t*)MS); + } + { + std::u16string s = p.u16string(); + assert(s == (const char16_t*)MS); + } + { + std::u32string s = p.u32string(); + assert(s == (const char32_t*)MS); + } +} \ No newline at end of file Index: test/std/experimental/filesystem/class.path/path.member/path.native.obs/native.pass.cpp =================================================================== --- /dev/null +++ test/std/experimental/filesystem/class.path/path.member/path.native.obs/native.pass.cpp @@ -0,0 +1,40 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03 + +// + +// class path + +// const string_type& native() const noexcept; + +#include +#include +#include + +#include "test_macros.h" +#include "filesystem_test_helper.hpp" + +namespace fs = std::experimental::filesystem; + +int main() +{ + using namespace fs; + const char* const value = "hello world"; + path p(value); + { // Check signature + ASSERT_SAME_TYPE(path::string_type const&, decltype(p.native())); + ASSERT_NOEXCEPT(p.native()); + } + { // native() is tested elsewhere + path p(value); + assert(p.native() == value); + } +} \ No newline at end of file Index: test/std/experimental/filesystem/class.path/path.member/path.native.obs/operator_string.pass.cpp =================================================================== --- /dev/null +++ test/std/experimental/filesystem/class.path/path.member/path.native.obs/operator_string.pass.cpp @@ -0,0 +1,47 @@ + +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03 + +// + +// class path + +// operator string_type() const; + +#include +#include +#include + +#include "test_macros.h" +#include "filesystem_test_helper.hpp" + +namespace fs = std::experimental::filesystem; + +int main() +{ + using namespace fs; + using string_type = path::string_type; + const char* const value = "hello world"; + path p(value); + { // Check signature + static_assert(std::is_convertible::value, ""); + static_assert(std::is_constructible::value, ""); + ASSERT_SAME_TYPE(string_type, decltype(p.operator string_type())); + ASSERT_NOT_NOEXCEPT(p.operator string_type()); + } + { + path p(value); + assert(p.native() == value); + string_type s = p; + assert(s == value); + assert(p == value); + } +} \ No newline at end of file Index: test/std/experimental/filesystem/class.path/path.member/path.native.obs/string_alloc.pass.cpp =================================================================== --- /dev/null +++ test/std/experimental/filesystem/class.path/path.member/path.native.obs/string_alloc.pass.cpp @@ -0,0 +1,113 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03 + +// + +// class path + +// template , +// class Allocator = allocator> +// basic_string +// string(const Allocator& a = Allocator()) const; + +#include +#include +#include + +#include "test_macros.h" +#include "test_iterators.h" +#include "count_new.hpp" +#include "min_allocator.h" +#include "filesystem_test_helper.hpp" + +namespace fs = std::experimental::filesystem; + +MultiStringType shortString = MKSTR("abc"); +MultiStringType longString = MKSTR("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ/123456789/abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"); + +template +void doShortStringTest(MultiStringType const& MS) { + using namespace fs; + using Ptr = CharT const*; + using Str = std::basic_string; + using Alloc = std::allocator; + Ptr value = MS; + const path p((const char*)MS); + { + DisableAllocationGuard g; // should not allocate because + Str s = p.string(); + assert(s == value); + Str s2 = p.string(Alloc{}); + assert(s2 == value); + } +} + +template +void doLongStringTest(MultiStringType const& MS) { + using namespace fs; + using Ptr = CharT const*; + using Str = std::basic_string; + Ptr value = MS; + const path p((const char*)MS); + { // Default allocator + using Alloc = std::allocator; + RequireAllocationGuard g; // should not allocate because + Str s = p.string(); + assert(s == value); + Str s2 = p.string(Alloc{}); + assert(s2 == value); + } + using MAlloc = malloc_allocator; + MAlloc::reset(); + { // Other allocator - default construct + using Traits = std::char_traits; + using AStr = std::basic_string; + DisableAllocationGuard g; + AStr s = p.string(); + assert(s == value); + assert(MAlloc::alloc_count > 0); + assert(MAlloc::outstanding_alloc == 1); + } + MAlloc::reset(); + { // Other allocator - provided copy + using Traits = std::char_traits; + using AStr = std::basic_string; + DisableAllocationGuard g; + MAlloc a; + // don't allow another allocator to be default constructed. + MAlloc::disable_default_constructor = true; + AStr s = p.string(a); + assert(s == value); + assert(MAlloc::alloc_count > 0); + assert(MAlloc::outstanding_alloc == 1); + } + MAlloc::reset(); + ///////////////////////////////////////////////////////////////////////////// +} + +int main() +{ + using namespace fs; + { + auto const& S = shortString; + doShortStringTest(S); + doShortStringTest(S); + doShortStringTest(S); + doShortStringTest(S); + } + { + auto const& S = longString; + doLongStringTest(S); + doLongStringTest(S); + doLongStringTest(S); + doLongStringTest(S); + } +} \ No newline at end of file Index: test/std/experimental/filesystem/class.path/path.member/path.query/tested_in_path_decompose.pass.cpp =================================================================== --- /dev/null +++ test/std/experimental/filesystem/class.path/path.member/path.query/tested_in_path_decompose.pass.cpp @@ -0,0 +1,32 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03 + +// + +// class path + +//------------------------------- +// 8.4.10 path query [path.query] +//------------------------------- +// bool empty() const noexcept; +// bool has_root_path() const; +// bool has_root_name() const; +// bool has_root_directory() const; +// bool has_relative_path() const; +// bool has_parent_path() const; +// bool has_filename() const; +// bool has_stem() const; +// bool has_extension() const; +// bool is_absolute() const; +// bool is_relative() const; + +// tested in path.decompose +int main() {} Index: test/std/experimental/filesystem/class.path/path.nonmember/append_op.pass.cpp =================================================================== --- /dev/null +++ test/std/experimental/filesystem/class.path/path.nonmember/append_op.pass.cpp @@ -0,0 +1,34 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03 + +// + +// path operator/(path const&, path const&); + +#include +#include +#include + +#include "test_macros.h" +#include "filesystem_test_helper.hpp" + +namespace fs = std::experimental::filesystem; + +// This is mainly tested via the member append functions. +int main() +{ + using namespace fs; + path p1("abc"); + path p2("def"); + path p3 = p1 / p2; + assert(p3 == "abc/def"); +} + Index: test/std/experimental/filesystem/class.path/path.nonmember/comparison_ops_tested_elsewhere.pass.cpp =================================================================== --- /dev/null +++ test/std/experimental/filesystem/class.path/path.nonmember/comparison_ops_tested_elsewhere.pass.cpp @@ -0,0 +1,14 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03 + +// The comparison operators are tested as part of [path.compare] +// in class.path/path.members/path.compare.pass.cpp +int main() {} Index: test/std/experimental/filesystem/class.path/path.nonmember/hash_value_tested_elswhere.pass.cpp =================================================================== --- /dev/null +++ test/std/experimental/filesystem/class.path/path.nonmember/hash_value_tested_elswhere.pass.cpp @@ -0,0 +1,14 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03 + +// The "hash_value" function is tested as part of [path.compare] +// in class.path/path.members/path.compare.pass.cpp +int main() {} Index: test/std/experimental/filesystem/class.path/path.nonmember/path.factory.pass.cpp =================================================================== --- /dev/null +++ test/std/experimental/filesystem/class.path/path.nonmember/path.factory.pass.cpp @@ -0,0 +1,54 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03 + +// + +// template +// path u8path(Source const&); +// template +// path u8path(InputIter, InputIter); + +#include +#include +#include + +#include "test_macros.h" +#include "test_iterators.h" +#include "count_new.hpp" +#include "filesystem_test_helper.hpp" + +namespace fs = std::experimental::filesystem; + +int main() +{ + using namespace fs; + const char* In1 = "abcd/efg"; + const std::string In2(In1); + const auto In3 = In2.begin(); + const auto In3End = In2.end(); + { + path p = fs::u8path(In1); + assert(p == In1); + } + { + path p = fs::u8path(In2); + assert(p == In1); + } + { + path p = fs::u8path(In3); + assert(p == In1); + } + { + path p = fs::u8path(In3, In3End); + assert(p == In1); + } +} + Index: test/std/experimental/filesystem/class.path/path.nonmember/path.io.pass.cpp =================================================================== --- /dev/null +++ test/std/experimental/filesystem/class.path/path.nonmember/path.io.pass.cpp @@ -0,0 +1,66 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03 + +// + +// class path + +// template +// basic_ostream& +// operator<<(basic_ostream& os, const path& p); +// +// template +// basic_istream& +// operator>>(basic_istream& is, path& p) +// + +#include +#include +#include +#include + +#include "test_macros.h" +#include "test_iterators.h" +#include "count_new.hpp" +#include "filesystem_test_helper.hpp" + +MultiStringType InStr = MKSTR("abcdefg/\"hijklmnop\"/qrstuvwxyz/123456789"); +MultiStringType OutStr = MKSTR("\"abcdefg/\\\"hijklmnop\\\"/qrstuvwxyz/123456789\""); + +template +void doIOTest() { + using namespace fs; + using Ptr = const CharT*; + using StrStream = std::basic_stringstream; + const char* const InCStr = InStr; + const Ptr E = OutStr; + const path p((const char*)InStr); + StrStream ss; + { // test output + auto& ret = (ss << p); + assert(ss.str() == E); + assert(&ret == &ss); + } + { // test input + path p_in; + auto& ret = ss >> p_in; + assert(p_in.native() == (const char*)InStr); + assert(&ret == &ss); + } +} + + +int main() { + doIOTest(); + doIOTest(); + //doIOTest(); + //doIOTest(); +} \ No newline at end of file Index: test/std/experimental/filesystem/class.path/path.nonmember/path.io.unicode_bug.pass.cpp =================================================================== --- /dev/null +++ test/std/experimental/filesystem/class.path/path.nonmember/path.io.unicode_bug.pass.cpp @@ -0,0 +1,69 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03 + +// + +// class path + +// template +// basic_ostream& +// operator<<(basic_ostream& os, const path& p); +// +// template +// basic_istream& +// operator>>(basic_istream& is, path& p) +// + +// TODO(EricWF) This test fails because "std::quoted" fails to compile +// for char16_t and char32_t types. Combine with path.io.pass.cpp when this +// passes. +// XFAIL: * + +#include +#include +#include +#include + +#include "test_macros.h" +#include "test_iterators.h" +#include "count_new.hpp" +#include "filesystem_test_helper.hpp" + +MultiStringType InStr = MKSTR("abcdefg/\"hijklmnop\"/qrstuvwxyz/123456789"); +MultiStringType OutStr = MKSTR("\"abcdefg/\\\"hijklmnop\\\"/qrstuvwxyz/123456789\""); + +template +void doIOTest() { + using namespace fs; + using Ptr = const CharT*; + using StrStream = std::basic_stringstream; + const char* const InCStr = InStr; + const Ptr E = OutStr; + const path p((const char*)InStr); + StrStream ss; + { // test output + auto& ret = (ss << p); + assert(ss.str() == E); + assert(&ret == &ss); + } + { // test input + path p_in; + auto& ret = ss >> p_in; + assert(p_in.native() == (const char*)InStr); + assert(&ret == &ss); + } +} + + +int main() { + doIOTest(); + doIOTest(); +} \ No newline at end of file Index: test/std/experimental/filesystem/class.path/path.nonmember/swap.pass.cpp =================================================================== --- /dev/null +++ test/std/experimental/filesystem/class.path/path.nonmember/swap.pass.cpp @@ -0,0 +1,50 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03 + +// + +// void swap(path& lhs, path& rhs) noexcept; + +#include +#include +#include + +#include "test_macros.h" +#include "count_new.hpp" +#include "filesystem_test_helper.hpp" + +namespace fs = std::experimental::filesystem; + +// NOTE: this is tested in path.members/path.modifiers via the member swap. +int main() +{ + using namespace fs; + const char* value1 = "foo/bar/baz"; + const char* value2 = "_THIS_IS_LONG_THIS_IS_LONG_THIS_IS_LONG_THIS_IS_LONG_THIS_IS_LONG_THIS_IS_LONG_THIS_IS_LONG"; + path p1(value1); + path p2(value2); + { + using namespace std; using namespace fs; + ASSERT_NOEXCEPT(swap(p1, p2)); + ASSERT_SAME_TYPE(void, decltype(swap(p1, p2))); + } + { + DisableAllocationGuard g; + using namespace std; + using namespace fs; + swap(p1, p2); + assert(p1.native() == value2); + assert(p2.native() == value1); + swap(p1, p2); + assert(p1.native() == value1); + assert(p2.native() == value2); + } +} \ No newline at end of file Index: test/std/experimental/filesystem/class.path/synop.pass.cpp =================================================================== --- /dev/null +++ test/std/experimental/filesystem/class.path/synop.pass.cpp @@ -0,0 +1,39 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03 + +// + +// class path + +// typedef ... value_type; +// typedef basic_string string_type; +// static constexpr value_type preferred_separator = ...; + +#include +#include +#include + +#include "test_macros.h" + +namespace fs = std::experimental::filesystem; + +int main() { + using namespace fs; + ASSERT_SAME_TYPE(path::value_type, char); + ASSERT_SAME_TYPE(path::string_type, std::basic_string); + { + ASSERT_SAME_TYPE(const path::value_type, decltype(path::preferred_separator)); + static_assert(path::preferred_separator == '/', ""); + // Make preferred_separator ODR used by taking it's address. + const char* dummy = &path::preferred_separator; + ((void)dummy); + } +} \ No newline at end of file Index: test/std/experimental/filesystem/fs.enum/check_bitmask_types.hpp =================================================================== --- /dev/null +++ test/std/experimental/filesystem/fs.enum/check_bitmask_types.hpp @@ -0,0 +1,75 @@ +#ifndef TEST_BITMASK_TYPE_HPP +#define TEST_BITMASK_TYPE_HPP + +#include +#include + +#include "test_macros.h" + + +template ::type, + UT UVal1 = static_cast(Val1), + UT UVal2 = static_cast(Val2), + UT UZero = static_cast(0), + EnumType Zero = static_cast(0) + > +struct check_bitmask_type { + + static constexpr UT dcast(EnumType e) { return static_cast(e); } + static constexpr UT unpromote(decltype(~UZero) promoted) { return static_cast(promoted); } + // We need two values that are non-zero and share at least one bit. + static_assert(Val1 != Zero && Val2 != Zero, ""); + static_assert(Val1 != Val2, ""); + static_assert((UVal1 & UVal2) == 0, ""); + + + static bool check() + { + { + EnumType ValRef = Val1; + ASSERT_SAME_TYPE(EnumType, decltype(Val1 & Val2)); + ASSERT_SAME_TYPE(EnumType, decltype(Val1 | Val2)); + ASSERT_SAME_TYPE(EnumType, decltype(Val1 ^ Val2)); + ASSERT_SAME_TYPE(EnumType, decltype(~Val1)); + ASSERT_SAME_TYPE(EnumType&, decltype(ValRef &= Val2)); + ASSERT_SAME_TYPE(EnumType&, decltype(ValRef |= Val2)); + ASSERT_SAME_TYPE(EnumType&, decltype(ValRef ^= Val2)); + } + + static_assert((Val1 & Zero) == Zero, ""); + static_assert((Val1 & Val1) == Val1, ""); + static_assert(dcast(Val1 & Val2) == (UVal1 & UVal2), ""); + + static_assert((Val1 | Zero) == Val1, ""); + static_assert(dcast(Val1 | Val2) == (UVal1 | UVal2), ""); + + static_assert((Val1 ^ Zero) == Val1, ""); + static_assert(dcast(Val1 ^ Val2) == (UVal1 ^ UVal2), ""); + + static_assert(dcast(~Zero) == unpromote(~UZero), ""); + static_assert(dcast(~Val1) == unpromote(~UVal1), ""); + + { + EnumType e = Val1; + EnumType& eref = (e &= Val2); + assert(&eref == &e); + assert(dcast(eref) == (UVal1 & UVal2)); + } + { + EnumType e = Val1; + EnumType& eref = (e |= Val2); + assert(&eref == &e); + assert(dcast(eref) == (UVal1 | UVal2)); + } + { + EnumType e = Val1; + EnumType& eref = (e ^= Val2); + assert(&eref == &e); + assert(dcast(eref) == (UVal1 ^ UVal2)); + } + return true; + } +}; + +#endif // TEST_BITMASK_TYPE Index: test/std/experimental/filesystem/fs.enum/enum.copy_options.pass.cpp =================================================================== --- /dev/null +++ test/std/experimental/filesystem/fs.enum/enum.copy_options.pass.cpp @@ -0,0 +1,64 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03 + +// + +// enum class copy_options; + +#include +#include +#include + +#include "check_bitmask_types.hpp" +#include "test_macros.h" + +namespace fs = std::experimental::filesystem; + +constexpr fs::copy_options ME(int val) { return static_cast(val); } + +int main() { + typedef fs::copy_options E; + static_assert(std::is_enum::value, ""); + + // Check that E is a scoped enum by checking for conversions. + typedef std::underlying_type::type UT; + static_assert(!std::is_convertible::value, ""); + + static_assert(std::is_same::value, ""); // Implementation detail + + typedef check_bitmask_type BitmaskTester; + assert(BitmaskTester::check()); + + static_assert( + E::none == ME(0), + "Expected enumeration values do not match"); + // Option group for copy_file + static_assert( + E::skip_existing == ME(1) && + E::overwrite_existing == ME(2) && + E::update_existing == ME(4), + "Expected enumeration values do not match"); + // Option group for copy on directories + static_assert( + E::recursive == ME(8), + "Expected enumeration values do not match"); + // Option group for copy on symlinks + static_assert( + E::copy_symlinks == ME(16) && + E::skip_symlinks == ME(32), + "Expected enumeration values do not match"); + // Option group for changing form of copy + static_assert( + E::directories_only == ME(64) && + E::create_symlinks == ME(128) && + E::create_hard_links == ME(256), + "Expected enumeration values do not match"); +} Index: test/std/experimental/filesystem/fs.enum/enum.directory_options.pass.cpp =================================================================== --- /dev/null +++ test/std/experimental/filesystem/fs.enum/enum.directory_options.pass.cpp @@ -0,0 +1,46 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03 + +// + +// enum class directory_options; + +#include +#include +#include +#include + +#include "test_macros.h" +#include "check_bitmask_types.hpp" + +namespace fs = std::experimental::filesystem; + +constexpr fs::directory_options ME(int val) { return static_cast(val); } + +int main() { + typedef fs::directory_options E; + static_assert(std::is_enum::value, ""); + + // Check that E is a scoped enum by checking for conversions. + typedef std::underlying_type::type UT; + static_assert(!std::is_convertible::value, ""); + static_assert(std::is_same::value, ""); + + typedef check_bitmask_type BitmaskTester; + assert(BitmaskTester::check()); + + static_assert( + E::none == ME(0) && + E::follow_directory_symlink == ME(1) && + E::skip_permission_denied == ME(2), + "Expected enumeration values do not match"); + +} Index: test/std/experimental/filesystem/fs.enum/enum.file_type.pass.cpp =================================================================== --- /dev/null +++ test/std/experimental/filesystem/fs.enum/enum.file_type.pass.cpp @@ -0,0 +1,48 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03 + +// + +// enum class file_type; + +#include +#include +#include + +#include "test_macros.h" + +namespace fs = std::experimental::filesystem; + +constexpr fs::file_type ME(int val) { return static_cast(val); } + +int main() { + typedef fs::file_type E; + static_assert(std::is_enum::value, ""); + + // Check that E is a scoped enum by checking for conversions. + typedef std::underlying_type::type UT; + static_assert(!std::is_convertible::value, ""); + + static_assert(std::is_same::value, ""); // Implementation detail + + static_assert( + E::none == ME(0) && + E::not_found == ME(-1) && + E::regular == ME(1) && + E::directory == ME(2) && + E::symlink == ME(3) && + E::block == ME(4) && + E::character == ME(5) && + E::fifo == ME(6) && + E::socket == ME(7) && + E::unknown == ME(8), + "Expected enumeration values do not match"); +} Index: test/std/experimental/filesystem/fs.enum/enum.perms.pass.cpp =================================================================== --- /dev/null +++ test/std/experimental/filesystem/fs.enum/enum.perms.pass.cpp @@ -0,0 +1,69 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03 + +// + +// enum class perms; + +#include +#include +#include +#include + +#include "test_macros.h" +#include "check_bitmask_types.hpp" + +namespace fs = std::experimental::filesystem; + +constexpr fs::perms ME(int val) { return static_cast(val); } + +int main() { + typedef fs::perms E; + static_assert(std::is_enum::value, ""); + + // Check that E is a scoped enum by checking for conversions. + typedef std::underlying_type::type UT; + static_assert(!std::is_convertible::value, ""); + + static_assert(std::is_same::value, ""); // Implementation detail + + typedef check_bitmask_type BitmaskTester; + assert(BitmaskTester::check()); + + static_assert( + E::none == ME(0) && + + E::owner_read == ME(0400) && + E::owner_write == ME(0200) && + E::owner_exec == ME(0100) && + E::owner_all == ME(0700) && + + E::group_read == ME(040) && + E::group_write == ME(020) && + E::group_exec == ME(010) && + E::group_all == ME(070) && + + E::others_read == ME(04) && + E::others_write == ME(02) && + E::others_exec == ME(01) && + E::others_all == ME(07) && + E::all == ME(0777) && + E::set_uid == ME(04000) && + E::set_gid == ME(02000) && + E::sticky_bit == ME(01000) && + E::mask == ME(07777) && + E::unknown == ME(0xFFFF) && + E::add_perms == ME(0x10000) && + E::remove_perms == ME(0x20000) && + E::resolve_symlinks == ME(0x40000), + "Expected enumeration values do not match"); + +} Index: test/std/experimental/filesystem/fs.error.report/tested_elsewhere.pass.cpp =================================================================== --- /dev/null +++ test/std/experimental/filesystem/fs.error.report/tested_elsewhere.pass.cpp @@ -0,0 +1,12 @@ +//===----------------------------------------------------------------------===// +// +// 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. +// +//===----------------------------------------------------------------------===// + +int main() +{ +} Index: test/std/experimental/filesystem/fs.filesystem.synopsis/file_time_type.pass.cpp =================================================================== --- /dev/null +++ test/std/experimental/filesystem/fs.filesystem.synopsis/file_time_type.pass.cpp @@ -0,0 +1,31 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03 + +// + +// typedef TrivialClock file_time_type; + +#include +#include +#include + +// system_clock is used because it meets the requirements of TrivialClock, +// and it's resolution and range of system_clock should match the operating +// systems file time type. +typedef std::chrono::system_clock ExpectedClock; +typedef std::chrono::time_point ExpectedTimePoint; + +int main() { + static_assert(std::is_same< + std::experimental::filesystem::file_time_type, + ExpectedTimePoint + >::value, ""); +} Index: test/std/experimental/filesystem/fs.req.macros/feature_macro.pass.cpp =================================================================== --- /dev/null +++ test/std/experimental/filesystem/fs.req.macros/feature_macro.pass.cpp @@ -0,0 +1,27 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03 + +// + +// #define __cpp_lib_experimental_filesystem 201406L + +// TODO(EricWF) The feature test macro is not defined until the implementation is complete. +// XFAIL: * + +#include + +#ifndef __cpp_lib_experimental_filesystem +#error Filesystem feature test macro is not defined (__cpp_lib_experimental_filesystem) +#elif __cpp_lib_experimental_filesystem != 201406L +#error Filesystem feature test macro has an incorrect value (__cpp_lib_experimental_filesystem) +#endif + +int main() { } Index: test/std/experimental/filesystem/fs.req.namespace/namespace.pass.cpp =================================================================== --- /dev/null +++ test/std/experimental/filesystem/fs.req.namespace/namespace.pass.cpp @@ -0,0 +1,24 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03 + +// + +// namespace std::experimental::filesystem::v1 + +#include +#include + +int main() { + static_assert(std::is_same< + std::experimental::filesystem::path, + std::experimental::filesystem::v1::path + >::value, ""); +} Index: test/std/experimental/filesystem/static_test_env/bad_symlink =================================================================== --- /dev/null +++ test/std/experimental/filesystem/static_test_env/bad_symlink @@ -0,0 +1 @@ +DNE \ No newline at end of file Index: test/std/experimental/filesystem/static_test_env/dir1/file2 =================================================================== --- /dev/null +++ test/std/experimental/filesystem/static_test_env/dir1/file2 @@ -0,0 +1 @@ +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa \ No newline at end of file Index: test/std/experimental/filesystem/static_test_env/non_empty_file =================================================================== --- /dev/null +++ test/std/experimental/filesystem/static_test_env/non_empty_file @@ -0,0 +1 @@ +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa \ No newline at end of file Index: test/std/experimental/filesystem/static_test_env/symlink_to_empty_file =================================================================== --- /dev/null +++ test/std/experimental/filesystem/static_test_env/symlink_to_empty_file @@ -0,0 +1 @@ +empty_file \ No newline at end of file Index: test/std/experimental/filesystem/test.pass.cpp =================================================================== --- /dev/null +++ test/std/experimental/filesystem/test.pass.cpp @@ -0,0 +1,5 @@ +#include "filesystem_test_helper.hpp" + +int main() { + +} \ No newline at end of file Index: test/support/count_new.hpp =================================================================== --- test/support/count_new.hpp +++ test/support/count_new.hpp @@ -132,6 +132,11 @@ return disable_checking || n != new_called; } + bool checkNewCalledGreaterThan(int n) const + { + return disable_checking || new_called > n; + } + bool checkDeleteCalledEq(int n) const { return disable_checking || n == delete_called; @@ -255,4 +260,33 @@ DisableAllocationGuard& operator=(DisableAllocationGuard const&); }; + +struct RequireAllocationGuard { + explicit RequireAllocationGuard(std::size_t RequireAtLeast = 1) + : m_req_alloc(RequireAtLeast), + m_new_count_on_init(globalMemCounter.new_called), + m_outstanding_new_on_init(globalMemCounter.outstanding_new), + m_exactly(false) + { + } + + void requireAtLeast(std::size_t N) { m_req_alloc = N; m_exactly = false; } + void requireExactly(std::size_t N) { m_req_alloc = N; m_exactly = true; } + + ~RequireAllocationGuard() { + assert(globalMemCounter.checkOutstandingNewEq(m_outstanding_new_on_init)); + std::size_t Expect = m_new_count_on_init + m_req_alloc; + assert(globalMemCounter.checkNewCalledEq(Expect) || + (!m_exactly && globalMemCounter.checkNewCalledGreaterThan(Expect))); + } + +private: + std::size_t m_req_alloc; + const std::size_t m_new_count_on_init; + const std::size_t m_outstanding_new_on_init; + bool m_exactly; + RequireAllocationGuard(RequireAllocationGuard const&); + RequireAllocationGuard& operator=(RequireAllocationGuard const&); +}; + #endif /* COUNT_NEW_HPP */ Index: test/support/filesystem_dynamic_test_helper.py =================================================================== --- /dev/null +++ test/support/filesystem_dynamic_test_helper.py @@ -0,0 +1,143 @@ + +import sys +import os +import stat +import subprocess +import shutil +import socket + +# Ensure that this is being run on a specific platform +assert sys.platform.startswith('linux') or sys.platform.startswith('darwin') or\ + sys.platform.startswith('cygwin') + + +def env_path(): + ep = os.environ.get('LIBCXX_FILESYSTEM_DYNAMIC_TEST_ROOT') + assert ep is not None + ep = os.path.realpath(ep) + assert os.path.isdir(ep) + ep + +# Make sure we don't try and write outside of env_path. +# All paths used should be sanitized +def sanitize_env_path(p): + p = os.path.join(env_path(), p) + p = os.path.realpath(p) + pre = os.path.commonprefix([env_path(), p]) + assert pre == env_path() + return p + + +""" +Some of the tests restrict permissions to induce failures. +Before we delete the test enviroment, we have to walk it and re-raise the +permissions. +""" +def set_env_perms(root_p): + root_p = sanitize_env_path(root_p) + for root, dirs, files in os.walk(root_p): + for d in dirs: + d = os.path.join(root, d) + try: + os.chmod(d, 0o777) + except OSError as e: + pass + for f in files: + f = os.path.join(root, f) + try: + os.chmod(f, 0o777) + except OSError as e: + pass + + +def remove_all_impl_1(root_p): + for root, dirs, files in os.walk(root_p, topdown=False): + for f in files: + try: + os.remove(os.path.join(root, f)) + except OSError: + pass + for d in dirs: + try: + os.rmdir(os.path.join(root, d)) + except OSError as e: + pass + try: + os.rmdir(root) + except OSError: + pass + + +def remove_all_impl_2(root_p): + for root, dirs, files in os.walk(root_p, topdown=False): + for f in files: + os.remove(os.path.join(root, f)) + for d in dirs: + os.rmdir(os.path.join(root, d)) + os.rmdir(root) + + +""" +Nothing in pythons os module seems to work for recursive deletion. +Symlinks don't get removed the first time. Sometimes we have to make a second +pass to actually delete the directory. +""" +def remove_all(root_p): + root_p = sanitize_env_path(root_p) + remove_all_impl_1(root_p) + if os.path.exists(root_p): + remove_all_impl_2(root_p) + + +def init(root_p): + root_p = sanitize_env_path(root_p) + assert not os.path.exists(root_p) + os.makedirs(root_p) + + +def clean(root_p): + set_env_perms(root_p) + remove_all(root_p) + + +def create_file(fname, size): + fname = sanitize_env_path(fname) + with open(fname, 'w') as f: + for c in ['a'] * size: + f.write(c) + + +def create_dir(dname, mode=0o777): + + dname = sanitize_env_path(dname) + os.mkdir(dname, mode) + + +def create_symlink(source, link): + source = sanitize_env_path(source) + link = sanitize_env_path(link) + os.symlink(source, link) + + +def create_hardlink(source, link): + source = sanitize_env_path(source) + link = sanitize_env_path(link) + os.link(source, link) + + +def create_fifo(source, mode=0o666): + source = sanitize_env_path(source) + os.mkfifo(source, mode) + + +def create_socket(source): + source = sanitize_env_path(source) + mode = 0600|stat.S_IFSOCK + os.mknod(source, mode) + + +if __name__ == '__main__': + command = " ".join(sys.argv[1:]) + eval(command) + sys.exit(0) + Index: test/support/filesystem_test_helper.hpp =================================================================== --- /dev/null +++ test/support/filesystem_test_helper.hpp @@ -0,0 +1,308 @@ +#ifndef FILESYSTEM_TEST_HELPER_HPP +#define FILESYSTEM_TEST_HELPER_HPP + +#include +#include +#include // for tempnam +#include + +namespace fs = std::experimental::filesystem; + +// static test helpers + +#ifndef LIBCXX_FILESYSTEM_STATIC_TEST_ROOT +#warning "STATIC TESTS DISABLED" +#else // LIBCXX_FILESYSTEM_STATIC_TEST_ROOT + +inline fs::path static_test_env_path() +{ + static const fs::path env_path = LIBCXX_FILESYSTEM_STATIC_TEST_ROOT; + return env_path; +} + +inline fs::path make_static_env_path(fs::path const& p) +{ + return static_test_env_path() / p; +} + +namespace StaticEnv { + +inline fs::path makePath(fs::path const& p) { + return static_test_env_path() / p; +} + +static const fs::path EnvRoot = LIBCXX_FILESYSTEM_STATIC_TEST_ROOT; + +static const fs::path TestFileList[] = { + makePath("empty_file"), + makePath("non_empty_file"), + makePath("dir1/file1"), + makePath("dir1/file2") +}; +const std::size_t TestFileListSize = sizeof(TestFileList) / sizeof(fs::path); + +static const fs::path TestDirList[] = { + makePath("dir1"), + makePath("dir1/dir2"), + makePath("dir1/dir2/dir3") +}; +const std::size_t TestDirListSize = sizeof(TestDirList) / sizeof(fs::path); + +static const fs::path File = TestFileList[0]; +static const fs::path Dir = TestDirList[0]; +static const fs::path SymlinkToFile = makePath("symlink_to_empty_file"); +static const fs::path DNE = makePath("DNE"); + +} // namespace StaticEnv + +#endif // LIBCXX_FILESYSTEM_STATIC_TEST_ROOT + + +#ifndef LIBCXX_FILESYSTEM_DYNAMIC_TEST_ROOT +#warning LIBCXX_FILESYSTEM_DYNAMIC_TEST_ROOT must be defined +#else // LIBCXX_FILESYSTEM_DYNAMIC_TEST_ROOT + +#ifndef LIBCXX_FILESYSTEM_DYNAMIC_TEST_HELPER +#error LIBCXX_FILESYSTEM_DYNAMIC_TEST_HELPER must be defined +#endif +// dynamic test helpers + +inline fs::path test_env_path() +{ + static const fs::path env_path = LIBCXX_FILESYSTEM_DYNAMIC_TEST_ROOT; + return env_path; +} + +inline fs::path random_env_path() +{ + // assert that tmpdir is not set. + char* tmpdir = std::getenv("TMPDIR"); + assert(!tmpdir); + char* s = ::tempnam(test_env_path().c_str(), "test."); + fs::path p(s); + std::free(s); + return p; +} + +inline std::string +fs_make_cmd(std::string const& cmd_name, std::string const& arg) +{ + std::string cmd = cmd_name + "('" + arg + "')"; + return cmd; +} + +inline std::string +fs_make_cmd(std::string const& cmd_name,std::string const& arg1, std::string const& arg2) +{ + std::string cmd = cmd_name + "('"; + cmd += arg1 + "', '"; + cmd += arg2 + "')"; + return cmd; +} + +inline std::string +fs_make_cmd(std::string const& cmd_name, std::string const& arg1, std::size_t const& arg2) +{ + std::string cmd = cmd_name + "('"; + cmd += arg1 + "', "; + cmd += std::to_string(arg2) + ")"; + return cmd; +} + +inline void fs_helper_run(std::string const& raw_cmd) { + // check that the fs test root in the enviroment matches what we were + // compiled with. + char* fs_root = std::getenv("LIBCXX_FILESYSTEM_DYNAMIC_TEST_ROOT"); + assert(fs_root); + assert(std::string(fs_root) == LIBCXX_FILESYSTEM_DYNAMIC_TEST_ROOT); + + std::string cmd = LIBCXX_FILESYSTEM_DYNAMIC_TEST_HELPER; + cmd += "\""; + cmd += raw_cmd; + cmd += "\""; + int ret = std::system(cmd.c_str()); + assert(ret == 0); +} + +struct scoped_test_env +{ + scoped_test_env() + : test_root(random_env_path()) + { + fs_helper_run(fs_make_cmd("init", test_root)); + } + + scoped_test_env(scoped_test_env const &) = delete; + scoped_test_env & operator=(scoped_test_env const &) = delete; + + ~scoped_test_env() + { + fs_helper_run(fs_make_cmd("clean", test_root)); + } + + fs::path make_env_path(fs::path const & p) + { + return test_root / p; + } + + std::string sanitize_path(std::string const & raw) + { + if (raw.substr(0, test_root.native().size()) == test_root) { + return raw; + } else { + return test_root / fs::path(raw); + } + } + + void create_file(std::string filename, std::size_t size = 0) + { + filename = sanitize_path(filename); + fs_helper_run(fs_make_cmd("create_file", filename, size)); + } + + void create_dir(std::string filename) + { + filename = sanitize_path(filename); + fs_helper_run(fs_make_cmd("create_dir", filename)); + } + + void create_symlink(std::string source, std::string to) + { + source = sanitize_path(source); + to = sanitize_path(to); + fs_helper_run(fs_make_cmd("create_symlink", source, to)); + } + + void create_hardlink(std::string source, std::string to) + { + source = sanitize_path(source); + to = sanitize_path(to); + fs_helper_run(fs_make_cmd("create_hardlink", source, to)); + } + + void create_fifo(std::string file) + { + file = sanitize_path(file); + fs_helper_run(fs_make_cmd("create_fifo", file)); + } + + void create_socket(std::string file) + { + file = sanitize_path(file); + fs_helper_run(fs_make_cmd("create_socket", file)); + } + + fs::path const test_root; +}; + +#endif // LIBCXX_FILESYSTEM_DYNAMIC_TEST_ROOT + +// Misc test types + + +#define CONCAT2(LHS, RHS) LHS##RHS +#define CONCAT(LHS, RHS) CONCAT2(LHS, RHS) +#define MKSTR(Str) {Str, CONCAT(L, Str), CONCAT(u, Str), CONCAT(U, Str)} + +struct MultiStringType { + const char* s; + const wchar_t* w; + const char16_t* u16; + const char32_t* u32; + + operator const char* () const { return s; } + operator const wchar_t* () const { return w; } + operator const char16_t* () const { return u16; } + operator const char32_t* () const { return u32; } +}; + + +const MultiStringType PathList[] = { + MKSTR(""), + MKSTR(" "), + MKSTR("//"), + MKSTR("."), + MKSTR(".."), + MKSTR("foo"), + MKSTR("/"), + MKSTR("/foo"), + MKSTR("foo/"), + MKSTR("/foo/"), + MKSTR("foo/bar"), + MKSTR("/foo/bar"), + MKSTR("//net"), + MKSTR("//net/foo"), + MKSTR("///foo///"), + MKSTR("///foo///bar"), + MKSTR("/."), + MKSTR("./"), + MKSTR("/.."), + MKSTR("../"), + MKSTR("foo/."), + MKSTR("foo/.."), + MKSTR("foo/./"), + MKSTR("foo/./bar"), + MKSTR("foo/../"), + MKSTR("foo/../bar"), + MKSTR("c:"), + MKSTR("c:/"), + MKSTR("c:foo"), + MKSTR("c:/foo"), + MKSTR("c:foo/"), + MKSTR("c:/foo/"), + MKSTR("c:/foo/bar"), + MKSTR("prn:"), + MKSTR("c:\\"), + MKSTR("c:\\foo"), + MKSTR("c:foo\\"), + MKSTR("c:\\foo\\"), + MKSTR("c:\\foo/"), + MKSTR("c:/foo\\bar"), + MKSTR("//"), + MKSTR("/finally/we/need/one/really/really/really/really/really/really/really/long/string") +}; +const unsigned PathListSize = sizeof(PathList) / sizeof(MultiStringType); + +template +Iter IterEnd(Iter B) { + using VT = typename std::iterator_traits::value_type; + for (; *B != VT{}; ++B) + ; + return B; +} + +template +const CharT* StrEnd(CharT const* P) { + return IterEnd(P); +} + +template +std::size_t StrLen(CharT const* P) { + return StrEnd(P) - P; +} + +// Testing the allocation behavior of the code_cvt functions requires +// *knowning* that the allocation was not done by "path::__str_". +// This hack forces path to allocate enough memory. +inline void PathReserve(fs::path& p, std::size_t N) { + auto const& native_ref = p.native(); + const_cast(native_ref).reserve(N); +} + + +template +bool checkCollectionsEqual( + Iter1 start1, Iter1 const end1 + , Iter2 start2, Iter2 const end2 + ) +{ + while (start1 != end1 && start2 != end2) { + if (*start1 != *start2) { + return false; + } + ++start1; ++start2; + } + return (start1 == end1 && start2 == end2); +} + +#endif /* FILESYSTEM_TEST_HELPER_HPP */ \ No newline at end of file Index: test/support/min_allocator.h =================================================================== --- test/support/min_allocator.h +++ test/support/min_allocator.h @@ -11,6 +11,7 @@ #define MIN_ALLOCATOR_H #include +#include #include "test_macros.h" @@ -39,6 +40,55 @@ friend bool operator!=(bare_allocator x, bare_allocator y) {return !(x == y);} }; +struct malloc_allocator_base { + static size_t alloc_count; + static size_t dealloc_count; + static size_t outstanding_alloc; + static bool disable_default_constructor; + + static void reset() { + assert(outstanding_alloc == 0); + disable_default_constructor = false; + alloc_count = 0; + dealloc_count = 0; + outstanding_alloc = 0; + } +}; + + +size_t malloc_allocator_base::alloc_count = 0; +size_t malloc_allocator_base::dealloc_count = 0; +size_t malloc_allocator_base::outstanding_alloc = 0; +bool malloc_allocator_base::disable_default_constructor = false; + + +template +class malloc_allocator : public malloc_allocator_base +{ +public: + typedef T value_type; + + malloc_allocator() TEST_NOEXCEPT { assert(!disable_default_constructor); } + + template + malloc_allocator(malloc_allocator) TEST_NOEXCEPT {} + + T* allocate(std::size_t n) + {; + ++alloc_count; ++outstanding_alloc; + return static_cast(std::malloc(n*sizeof(T))); + } + + void deallocate(T* p, std::size_t) + { + ++dealloc_count; --outstanding_alloc; + std::free(static_cast(p)); + } + + friend bool operator==(malloc_allocator, malloc_allocator) {return true;} + friend bool operator!=(malloc_allocator x, malloc_allocator y) {return !(x == y);} +}; + #if __cplusplus >= 201103L Index: test/support/test_iterators.h =================================================================== --- test/support/test_iterators.h +++ test/support/test_iterators.h @@ -12,6 +12,7 @@ #include #include +#include #include #include "test_macros.h" Index: test/support/test_macros.h =================================================================== --- test/support/test_macros.h +++ test/support/test_macros.h @@ -91,8 +91,23 @@ template <> struct static_assert_incomplete_test {}; template struct static_assert_check {}; +template struct test_is_same { enum { value = false}; }; +template struct test_is_same { enum { value = true}; }; + + } // end namespace test_detail +#define ASSERT_SAME_TYPE(...) \ + static_assert(test_detail::test_is_same<__VA_ARGS__>::value, \ + "Return type differs from expected type") + +#define ASSERT_NOEXCEPT(...) \ + static_assert(noexcept(__VA_ARGS__), "Expression expected to be noexcept") + + +#define ASSERT_NOT_NOEXCEPT(...) \ + static_assert(noexcept(__VA_ARGS__) == false, "Expression expected NOT to be noexcept") + #if !TEST_HAS_FEATURE(cxx_rtti) && !defined(__cxx_rtti) #define TEST_HAS_NO_RTTI @@ -107,4 +122,6 @@ #define TEST_HAS_SANITIZERS #endif + + #endif // SUPPORT_TEST_MACROS_HPP