Merge branch 'feature-cpp20-support'

This commit is contained in:
Steffen Schuemann 2020-12-31 10:33:42 +01:00
commit fed499b543
7 changed files with 319 additions and 352 deletions

View File

@ -1,5 +1,6 @@
#!/bin/sh
cd build
echo "Tests run as user: $USER"
ctest -E Windows
if [ -f "test/std_filesystem_test" ]; then
test/std_filesystem_test || true

View File

@ -1,6 +1,11 @@
cmake_minimum_required(VERSION 3.7.2)
project(ghcfilesystem)
if(POLICY CMP0110)
cmake_policy(PUSH)
cmake_policy(SET CMP0110 OLD)
endif()
include(CMakeDependentOption)
cmake_dependent_option(GHC_FILESYSTEM_BUILD_TESTING
@ -54,3 +59,6 @@ if(GHC_FILESYSTEM_WITH_INSTALL)
install(EXPORT ghcFilesystemConfig NAMESPACE ghcFilesystem:: DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/ghcFilesystem)
endif()
if(POLICY CMP0110)
cmake_policy(POP)
endif()

View File

@ -10,19 +10,19 @@
# Filesystem
This is a header-only single-file std::filesystem compatible helper library,
based on the C++17 specs, but implemented for C++11, C++14 or C++17 (tightly following
the C++17 with very few documented exceptions). It is currently tested on
based on the C++17 and C++20 specs, but implemented for C++11, C++14, C++17 or C++20
(tightly following the C++17 standard with very few documented exceptions). It is currently tested on
macOS 10.12/10.14/10.15, Windows 10, Ubuntu 18.04, CentOS 7, CentOS 8, FreeBSD 12
and Alpine ARM/ARM64 Linux but should work on other systems too, as long as you have
at least a C++11 compatible compiler. It should work with Android NDK, Emscripten and I even
had reports of it beeing used on iOS (within sandboxing constraints).
had reports of it being used on iOS (within sandboxing constraints).
It is of course in its own namespace `ghc::filesystem` to not interfere with a regular `std::filesystem` should you use it in a mixed C++17
environment (which is possible).
*Test coverage is above 90%, and starting with v1.3.6
*Test coverage is well above 90%, and starting with v1.3.6
more time was invested in benchmarking and optimizing parts of the library. I'll try
to continue to optimize some parts and refactor others, striving
to improve it as long as it doesn't introduce additional C++17 compatibility
to improve it as long as it doesn't introduce additional C++17/C++20 compatibility
issues. Feedback is always welcome. Simply open an issue if you see something missing
or wrong or not behaving as expected and I'll comment.*
@ -43,6 +43,8 @@ and a draft close to that version is
It is from after the standardization of C++17 but it contains the latest filesystem
interface changes compared to the
[Working Draft N4659](https://github.com/cplusplus/draft/raw/master/papers/n4659.pdf).
Staring with v1.4.0, when compiled using C++20, it adapts to the changes according to path sorting order
and `std::u8string` handling from [Working Draft N4680](https://isocpp.org/files/papers/N4860.pdf).
I want to thank the people working on improving C++, I really liked how the language
evolved with C++11 and the following standards. Keep on the good work!
@ -62,9 +64,9 @@ as I currently don't test with the Android NDK, I wouldn't call it a
supported platform yet, same is valid for using it with Emscripten. It is now
part of the detected platforms, I fixed the obvious issues and ran some tests with
it, so it should be fine. All in all, I don't see it replacing `std::filesystem`
where full C++17 is available, it doesn't try to be a "better"
`std::filesystem`, just a drop-in if you can't use it (with the exception
of the UTF-8 preference on Windows).
where full C++17 or C++20 is available, it doesn't try to be a "better"
`std::filesystem`, just an almost drop-in if you can't use it (with the exception
of the UTF-8 preference).
This implementation is following the ["UTF-8 Everywhere" philosophy](https://utf8everywhere.org/) in that all
`std::string` instances will be interpreted the same as `std::u8string` encoding
@ -343,17 +345,18 @@ change anything. I still need to investigate this.
As this implementation is based on existing code from my private helper
classes, it derived some constraints of it, leading to some differences
between this and the standard C++17 API.
between this and the standard C++17/C++20 API.
### LWG Defects
This implementation has switchable behavior for the LWG defects
[#2682](https://wg21.cmeerw.net/lwg/issue2682),
[#2935](http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#2935) and
[#2935](http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#2935),
[#2936](http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#2936) and
[#2937](http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#2937).
The currently selected behavior is following
[#2682](https://wg21.cmeerw.net/lwg/issue2682),
The currently selected behavior (starting from v1.4.0) is following
[#2682](https://wg21.cmeerw.net/lwg/issue2682), [#2936](http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#2936),
[#2937](http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#2937) but
not following [#2935](http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#2935),
as I feel it is a bug to report no error on a `create_directory()` or `create_directories()`
@ -520,6 +523,19 @@ to the expected behavior.
## Release Notes
### v1.4.0 (WIP)
* Enhancements for [#71](https://github.com/gulrak/filesystem/issues/71), when compiled with C++20:
* `char8_t` and `std::u8string` are supported where `Source` is the parameter type
* `fs::path::u8string()` and `fs::path::generic_u8string()` now return a `std::u8string`
* The _spaceship operator_ `<=>` is now supported for `fs::path`
* With the define `GHC_FILESYSTEM_ENFORCE_CPP17_API` `ghc::filesystem` will fall back
to the old `fs::path::u8string()` and `fs::path::generic_u8string()` API if preferred
* Bugfix for `fs::proximate(p, ec)` where the internal call to `fs::current_path()` was not
using the `error_code` variant, throwing possible exceptions instead of setting `ec`.
* Some cleanup work to reduce preprocessor directives for better readability and remove unneeded
template specializations.
### [v1.3.10](https://github.com/gulrak/filesystem/releases/tag/v1.3.10)
* Fix for [#81](https://github.com/gulrak/filesystem/issues/81), fixed issues with

View File

@ -41,3 +41,21 @@ if(CMAKE_CXX_COMPILER_ID MATCHES MSVC AND (CMAKE_CXX_COMPILER_VERSION VERSION_EQ
endif()
endmacro()
macro(AddTestExecutableWithStdCpp cppStd)
add_executable(filesystem_test_cpp${cppStd} ${ARGN})
set_property(TARGET filesystem_test_cpp${cppStd} PROPERTY CXX_STANDARD ${cppStd})
target_link_libraries(filesystem_test_cpp${cppStd} ghc_filesystem)
target_compile_options(filesystem_test_cpp${cppStd} PRIVATE
$<$<BOOL:${EMSCRIPTEN}>:-s DISABLE_EXCEPTION_CATCHING=0>
$<$<CXX_COMPILER_ID:Clang>:-Wall -Wextra -Wshadow -Wconversion -Wsign-conversion -Wpedantic -Werror -Wno-error=deprecated-declarations>
$<$<CXX_COMPILER_ID:GNU>:-Wall -Wextra -Wshadow -Wconversion -Wsign-conversion -Wpedantic -Wno-psabi -Werror -Wno-error=deprecated-declarations>
$<$<CXX_COMPILER_ID:MSVC>:/WX /wd"4996">)
if(CMAKE_CXX_COMPILER_ID MATCHES MSVC)
target_compile_definitions(filesystem_test_cpp${cppStd} PRIVATE _CRT_SECURE_NO_WARNINGS)
endif()
if(EMSCRIPTEN)
set_target_properties(filesystem_test_cpp${cppStd} PROPERTIES LINK_FLAGS "-g4 -s DISABLE_EXCEPTION_CATCHING=0 -s ALLOW_MEMORY_GROWTH=1")
endif()
ParseAndAddCatchTests(filesystem_test_cpp${cppStd})
endmacro()

View File

@ -1,6 +1,6 @@
//---------------------------------------------------------------------------------------
//
// ghc::filesystem - A C++17-like filesystem implementation for C++11/C++14/C++17
// ghc::filesystem - A C++17-like filesystem implementation for C++11/C++14/C++17/C++20
//
//---------------------------------------------------------------------------------------
//
@ -76,6 +76,19 @@
#error "Operating system currently not supported!"
#endif
#define GHC_OS_DETECTED
#if (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L)
# if _MSVC_LANG == 201703L
# define GHC_FILESYSTEM_RUNNING_CPP17
# else
# define GHC_FILESYSTEM_RUNNING_CPP20
# endif
#elif (defined(__cplusplus) && __cplusplus >= 201703L)
# if __cplusplus == 201703L
# define GHC_FILESYSTEM_RUNNING_CPP17
# else
# define GHC_FILESYSTEM_RUNNING_CPP20
# endif
#endif
#endif
#if defined(GHC_FILESYSTEM_IMPLEMENTATION)
@ -141,6 +154,13 @@
#include <Availability.h>
#endif
#if defined(__cpp_impl_three_way_comparison) && defined(__has_include)
#if __has_include(<compare>)
#define GHC_HAS_THREEWAY_COMP
#include <compare>
#endif
#endif
#include <algorithm>
#include <cctype>
#include <chrono>
@ -159,6 +179,13 @@
#include <vector>
#else // GHC_EXPAND_IMPL
#if defined(__cpp_impl_three_way_comparison) && defined(__has_include)
#if __has_include(<compare>)
#define GHC_HAS_THREEWAY_COMP
#include <compare>
#endif
#endif
#include <chrono>
#include <fstream>
#include <memory>
@ -174,6 +201,10 @@
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Behaviour Switches (see README.md, should match the config in test/filesystem_test.cpp):
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Enforce C++17 API where possible when compiling for C++20, handles the following cases:
// * fs::path::u8string() returns std::string instead of std::u8string
// #define GHC_FILESYSTEM_ENFORCE_CPP17_API
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// LWG #2682 disables the since then invalid use of the copy option create_symlinks on directories
// configure LWG conformance ()
#define LWG_2682_BEHAVIOUR
@ -189,7 +220,7 @@
// * else result of element wise comparison of path iteration where first comparison is != 0 or 0
// if all comparisons are 0 (on Windows this implementation does case insensitive root_name()
// comparison)
// #define LWG_2936_BEHAVIOUR
#define LWG_2936_BEHAVIOUR
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// LWG #2937 enforces that fs::equivalent emits an error, if !fs::exists(p1)||!exists(p2)
#define LWG_2937_BEHAVIOUR
@ -205,7 +236,7 @@
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// ghc::filesystem version in decimal (major * 10000 + minor * 100 + patch)
#define GHC_FILESYSTEM_VERSION 10310L
#define GHC_FILESYSTEM_VERSION 10399L
#if !defined(GHC_WITH_EXCEPTIONS) && (defined(__EXCEPTIONS) || defined(__cpp_exceptions) || defined(_CPPUNWIND))
#define GHC_WITH_EXCEPTIONS
@ -381,7 +412,11 @@ public:
std::basic_string<EcharT, traits, Allocator> string(const Allocator& a = Allocator()) const;
std::string string() const;
std::wstring wstring() const;
#if defined(__cpp_lib_char8_t) && !defined(GHC_FILESYSTEM_ENFORCE_CPP17_API)
std::u8string u8string() const;
#else
std::string u8string() const;
#endif
std::u16string u16string() const;
std::u32string u32string() const;
@ -390,7 +425,11 @@ public:
std::basic_string<EcharT, traits, Allocator> generic_string(const Allocator& a = Allocator()) const;
const std::string& generic_string() const; // this is different from the standard, that returns by value
std::wstring generic_wstring() const;
#if defined(__cpp_lib_char8_t) && !defined(GHC_FILESYSTEM_ENFORCE_CPP17_API)
std::u8string generic_u8string() const;
#else
std::string generic_u8string() const;
#endif
std::u16string generic_u16string() const;
std::u32string generic_u32string() const;
@ -480,13 +519,15 @@ private:
// 30.10.8.6 path non-member functions
GHC_FS_API void swap(path& lhs, path& rhs) noexcept;
GHC_FS_API size_t hash_value(const path& p) noexcept;
#ifdef GHC_HAS_THREEWAY_COMP
GHC_FS_API std::strong_ordering operator<=>( const path& lhs, const path& rhs ) noexcept;
#endif
GHC_FS_API bool operator==(const path& lhs, const path& rhs) noexcept;
GHC_FS_API bool operator!=(const path& lhs, const path& rhs) noexcept;
GHC_FS_API bool operator<(const path& lhs, const path& rhs) noexcept;
GHC_FS_API bool operator<=(const path& lhs, const path& rhs) noexcept;
GHC_FS_API bool operator>(const path& lhs, const path& rhs) noexcept;
GHC_FS_API bool operator>=(const path& lhs, const path& rhs) noexcept;
GHC_FS_API path operator/(const path& lhs, const path& rhs);
// 30.10.8.6.1 path inserter and extractor
@ -497,8 +538,14 @@ std::basic_istream<charT, traits>& operator>>(std::basic_istream<charT, traits>&
// 30.10.8.6.2 path factory functions
template <class Source, typename = path::path_from_string<Source>>
#if defined(__cpp_lib_char8_t) && !defined(GHC_FILESYSTEM_ENFORCE_CPP17_API)
[[deprecated("use ghc::filesystem::path::path() with std::u8string instead")]]
#endif
path u8path(const Source& source);
template <class InputIterator>
#if defined(__cpp_lib_char8_t) && !defined(GHC_FILESYSTEM_ENFORCE_CPP17_API)
[[deprecated("use ghc::filesystem::path::path() with std::u8string instead")]]
#endif
path u8path(InputIterator first, InputIterator last);
// 30.10.9 class filesystem_error
@ -677,15 +724,11 @@ public:
// 30.10.12.2 modifiers
#ifdef GHC_WITH_EXCEPTIONS
void assign(const path& p);
#endif
void assign(const path& p, std::error_code& ec);
#ifdef GHC_WITH_EXCEPTIONS
void replace_filename(const path& p);
#endif
void replace_filename(const path& p, std::error_code& ec);
#ifdef GHC_WITH_EXCEPTIONS
void refresh();
#endif
void assign(const path& p, std::error_code& ec);
void replace_filename(const path& p, std::error_code& ec);
void refresh(std::error_code& ec) noexcept;
// 30.10.12.3 observers
@ -693,44 +736,32 @@ public:
operator const filesystem::path&() const noexcept;
#ifdef GHC_WITH_EXCEPTIONS
bool exists() const;
bool is_block_file() const;
bool is_character_file() const;
bool is_directory() const;
bool is_fifo() const;
bool is_other() const;
bool is_regular_file() const;
bool is_socket() const;
bool is_symlink() const;
uintmax_t file_size() const;
file_time_type last_write_time() const;
file_status status() const;
file_status symlink_status() const;
#endif
bool exists(std::error_code& ec) const noexcept;
#ifdef GHC_WITH_EXCEPTIONS
bool is_block_file() const;
#endif
bool is_block_file(std::error_code& ec) const noexcept;
#ifdef GHC_WITH_EXCEPTIONS
bool is_character_file() const;
#endif
bool is_character_file(std::error_code& ec) const noexcept;
#ifdef GHC_WITH_EXCEPTIONS
bool is_directory() const;
#endif
bool is_directory(std::error_code& ec) const noexcept;
#ifdef GHC_WITH_EXCEPTIONS
bool is_fifo() const;
#endif
bool is_fifo(std::error_code& ec) const noexcept;
#ifdef GHC_WITH_EXCEPTIONS
bool is_other() const;
#endif
bool is_other(std::error_code& ec) const noexcept;
#ifdef GHC_WITH_EXCEPTIONS
bool is_regular_file() const;
#endif
bool is_regular_file(std::error_code& ec) const noexcept;
#ifdef GHC_WITH_EXCEPTIONS
bool is_socket() const;
#endif
bool is_socket(std::error_code& ec) const noexcept;
#ifdef GHC_WITH_EXCEPTIONS
bool is_symlink() const;
#endif
bool is_symlink(std::error_code& ec) const noexcept;
#ifdef GHC_WITH_EXCEPTIONS
uintmax_t file_size() const;
#endif
uintmax_t file_size(std::error_code& ec) const noexcept;
file_time_type last_write_time(std::error_code& ec) const noexcept;
file_status status(std::error_code& ec) const noexcept;
file_status symlink_status(std::error_code& ec) const noexcept;
#ifndef GHC_OS_WEB
#ifdef GHC_WITH_EXCEPTIONS
@ -739,20 +770,9 @@ public:
uintmax_t hard_link_count(std::error_code& ec) const noexcept;
#endif
#ifdef GHC_WITH_EXCEPTIONS
file_time_type last_write_time() const;
#ifdef GHC_HAS_THREEWAY_COMP
std::strong_ordering operator<=>(const directory_entry& rhs) const noexcept;
#endif
file_time_type last_write_time(std::error_code& ec) const noexcept;
#ifdef GHC_WITH_EXCEPTIONS
file_status status() const;
#endif
file_status status(std::error_code& ec) const noexcept;
#ifdef GHC_WITH_EXCEPTIONS
file_status symlink_status() const;
#endif
file_status symlink_status(std::error_code& ec) const noexcept;
bool operator<(const directory_entry& rhs) const noexcept;
bool operator==(const directory_entry& rhs) const noexcept;
bool operator!=(const directory_entry& rhs) const noexcept;
@ -917,225 +937,111 @@ GHC_FS_API recursive_directory_iterator end(const recursive_directory_iterator&)
// 30.10.15 filesystem operations
#ifdef GHC_WITH_EXCEPTIONS
GHC_FS_API path absolute(const path& p);
GHC_FS_API path canonical(const path& p);
GHC_FS_API void copy(const path& from, const path& to);
GHC_FS_API void copy(const path& from, const path& to, copy_options options);
GHC_FS_API bool copy_file(const path& from, const path& to);
GHC_FS_API bool copy_file(const path& from, const path& to, copy_options option);
GHC_FS_API void copy_symlink(const path& existing_symlink, const path& new_symlink);
GHC_FS_API bool create_directories(const path& p);
GHC_FS_API bool create_directory(const path& p);
GHC_FS_API bool create_directory(const path& p, const path& attributes);
GHC_FS_API void create_directory_symlink(const path& to, const path& new_symlink);
GHC_FS_API void create_symlink(const path& to, const path& new_symlink);
GHC_FS_API path current_path();
GHC_FS_API void current_path(const path& p);
GHC_FS_API bool exists(const path& p);
GHC_FS_API bool equivalent(const path& p1, const path& p2);
GHC_FS_API uintmax_t file_size(const path& p);
GHC_FS_API bool is_block_file(const path& p);
GHC_FS_API bool is_character_file(const path& p);
GHC_FS_API bool is_directory(const path& p);
GHC_FS_API bool is_empty(const path& p);
GHC_FS_API bool is_fifo(const path& p);
GHC_FS_API bool is_other(const path& p);
GHC_FS_API bool is_regular_file(const path& p);
GHC_FS_API bool is_socket(const path& p);
GHC_FS_API bool is_symlink(const path& p);
GHC_FS_API file_time_type last_write_time(const path& p);
GHC_FS_API void last_write_time(const path& p, file_time_type new_time);
GHC_FS_API void permissions(const path& p, perms prms, perm_options opts = perm_options::replace);
GHC_FS_API path proximate(const path& p, const path& base = current_path());
GHC_FS_API path read_symlink(const path& p);
GHC_FS_API path relative(const path& p, const path& base = current_path());
GHC_FS_API bool remove(const path& p);
GHC_FS_API uintmax_t remove_all(const path& p);
GHC_FS_API void rename(const path& from, const path& to);
GHC_FS_API void resize_file(const path& p, uintmax_t size);
GHC_FS_API space_info space(const path& p);
GHC_FS_API file_status status(const path& p);
GHC_FS_API file_status symlink_status(const path& p);
GHC_FS_API path temp_directory_path();
GHC_FS_API path weakly_canonical(const path& p);
#endif
GHC_FS_API path absolute(const path& p, std::error_code& ec);
#ifdef GHC_WITH_EXCEPTIONS
GHC_FS_API path canonical(const path& p);
#endif
GHC_FS_API path canonical(const path& p, std::error_code& ec);
#ifdef GHC_WITH_EXCEPTIONS
GHC_FS_API void copy(const path& from, const path& to);
#endif
GHC_FS_API void copy(const path& from, const path& to, std::error_code& ec) noexcept;
#ifdef GHC_WITH_EXCEPTIONS
GHC_FS_API void copy(const path& from, const path& to, copy_options options);
#endif
GHC_FS_API void copy(const path& from, const path& to, copy_options options, std::error_code& ec) noexcept;
#ifdef GHC_WITH_EXCEPTIONS
GHC_FS_API bool copy_file(const path& from, const path& to);
#endif
GHC_FS_API bool copy_file(const path& from, const path& to, std::error_code& ec) noexcept;
#ifdef GHC_WITH_EXCEPTIONS
GHC_FS_API bool copy_file(const path& from, const path& to, copy_options option);
#endif
GHC_FS_API bool copy_file(const path& from, const path& to, copy_options option, std::error_code& ec) noexcept;
#ifdef GHC_WITH_EXCEPTIONS
GHC_FS_API void copy_symlink(const path& existing_symlink, const path& new_symlink);
#endif
GHC_FS_API void copy_symlink(const path& existing_symlink, const path& new_symlink, std::error_code& ec) noexcept;
#ifdef GHC_WITH_EXCEPTIONS
GHC_FS_API bool create_directories(const path& p);
#endif
GHC_FS_API bool create_directories(const path& p, std::error_code& ec) noexcept;
#ifdef GHC_WITH_EXCEPTIONS
GHC_FS_API bool create_directory(const path& p);
#endif
GHC_FS_API bool create_directory(const path& p, std::error_code& ec) noexcept;
#ifdef GHC_WITH_EXCEPTIONS
GHC_FS_API bool create_directory(const path& p, const path& attributes);
#endif
GHC_FS_API bool create_directory(const path& p, const path& attributes, std::error_code& ec) noexcept;
#ifdef GHC_WITH_EXCEPTIONS
GHC_FS_API void create_directory_symlink(const path& to, const path& new_symlink);
#endif
GHC_FS_API void create_directory_symlink(const path& to, const path& new_symlink, std::error_code& ec) noexcept;
GHC_FS_API void create_symlink(const path& to, const path& new_symlink, std::error_code& ec) noexcept;
GHC_FS_API path current_path(std::error_code& ec);
GHC_FS_API void current_path(const path& p, std::error_code& ec) noexcept;
GHC_FS_API bool exists(file_status s) noexcept;
GHC_FS_API bool exists(const path& p, std::error_code& ec) noexcept;
GHC_FS_API bool equivalent(const path& p1, const path& p2, std::error_code& ec) noexcept;
GHC_FS_API uintmax_t file_size(const path& p, std::error_code& ec) noexcept;
GHC_FS_API bool is_block_file(file_status s) noexcept;
GHC_FS_API bool is_block_file(const path& p, std::error_code& ec) noexcept;
GHC_FS_API bool is_character_file(file_status s) noexcept;
GHC_FS_API bool is_character_file(const path& p, std::error_code& ec) noexcept;
GHC_FS_API bool is_directory(file_status s) noexcept;
GHC_FS_API bool is_directory(const path& p, std::error_code& ec) noexcept;
GHC_FS_API bool is_empty(const path& p, std::error_code& ec) noexcept;
GHC_FS_API bool is_fifo(file_status s) noexcept;
GHC_FS_API bool is_fifo(const path& p, std::error_code& ec) noexcept;
GHC_FS_API bool is_other(file_status s) noexcept;
GHC_FS_API bool is_other(const path& p, std::error_code& ec) noexcept;
GHC_FS_API bool is_regular_file(file_status s) noexcept;
GHC_FS_API bool is_regular_file(const path& p, std::error_code& ec) noexcept;
GHC_FS_API bool is_socket(file_status s) noexcept;
GHC_FS_API bool is_socket(const path& p, std::error_code& ec) noexcept;
GHC_FS_API bool is_symlink(file_status s) noexcept;
GHC_FS_API bool is_symlink(const path& p, std::error_code& ec) noexcept;
GHC_FS_API file_time_type last_write_time(const path& p, std::error_code& ec) noexcept;
GHC_FS_API void last_write_time(const path& p, file_time_type new_time, std::error_code& ec) noexcept;
GHC_FS_API void permissions(const path& p, perms prms, std::error_code& ec) noexcept;
GHC_FS_API void permissions(const path& p, perms prms, perm_options opts, std::error_code& ec) noexcept;
GHC_FS_API path proximate(const path& p, std::error_code& ec);
GHC_FS_API path proximate(const path& p, const path& base, std::error_code& ec);
GHC_FS_API path read_symlink(const path& p, std::error_code& ec);
GHC_FS_API path relative(const path& p, std::error_code& ec);
GHC_FS_API path relative(const path& p, const path& base, std::error_code& ec);
GHC_FS_API bool remove(const path& p, std::error_code& ec) noexcept;
GHC_FS_API uintmax_t remove_all(const path& p, std::error_code& ec) noexcept;
GHC_FS_API void rename(const path& from, const path& to, std::error_code& ec) noexcept;
GHC_FS_API void resize_file(const path& p, uintmax_t size, std::error_code& ec) noexcept;
GHC_FS_API space_info space(const path& p, std::error_code& ec) noexcept;
GHC_FS_API file_status status(const path& p, std::error_code& ec) noexcept;
GHC_FS_API bool status_known(file_status s) noexcept;
GHC_FS_API file_status symlink_status(const path& p, std::error_code& ec) noexcept;
GHC_FS_API path temp_directory_path(std::error_code& ec) noexcept;
GHC_FS_API path weakly_canonical(const path& p, std::error_code& ec) noexcept;
#ifndef GHC_OS_WEB
#ifdef GHC_WITH_EXCEPTIONS
GHC_FS_API void create_hard_link(const path& to, const path& new_hard_link);
#endif
GHC_FS_API void create_hard_link(const path& to, const path& new_hard_link, std::error_code& ec) noexcept;
#endif
#ifdef GHC_WITH_EXCEPTIONS
GHC_FS_API void create_symlink(const path& to, const path& new_symlink);
#endif
GHC_FS_API void create_symlink(const path& to, const path& new_symlink, std::error_code& ec) noexcept;
#ifdef GHC_WITH_EXCEPTIONS
GHC_FS_API path current_path();
#endif
GHC_FS_API path current_path(std::error_code& ec);
#ifdef GHC_WITH_EXCEPTIONS
GHC_FS_API void current_path(const path& p);
#endif
GHC_FS_API void current_path(const path& p, std::error_code& ec) noexcept;
GHC_FS_API bool exists(file_status s) noexcept;
#ifdef GHC_WITH_EXCEPTIONS
GHC_FS_API bool exists(const path& p);
#endif
GHC_FS_API bool exists(const path& p, std::error_code& ec) noexcept;
#ifdef GHC_WITH_EXCEPTIONS
GHC_FS_API bool equivalent(const path& p1, const path& p2);
#endif
GHC_FS_API bool equivalent(const path& p1, const path& p2, std::error_code& ec) noexcept;
#ifdef GHC_WITH_EXCEPTIONS
GHC_FS_API uintmax_t file_size(const path& p);
#endif
GHC_FS_API uintmax_t file_size(const path& p, std::error_code& ec) noexcept;
#ifndef GHC_OS_WEB
#ifdef GHC_WITH_EXCEPTIONS
GHC_FS_API uintmax_t hard_link_count(const path& p);
#endif
GHC_FS_API void create_hard_link(const path& to, const path& new_hard_link, std::error_code& ec) noexcept;
GHC_FS_API uintmax_t hard_link_count(const path& p, std::error_code& ec) noexcept;
#endif
GHC_FS_API bool is_block_file(file_status s) noexcept;
#ifdef GHC_WITH_EXCEPTIONS
GHC_FS_API bool is_block_file(const path& p);
#endif
GHC_FS_API bool is_block_file(const path& p, std::error_code& ec) noexcept;
GHC_FS_API bool is_character_file(file_status s) noexcept;
#ifdef GHC_WITH_EXCEPTIONS
GHC_FS_API bool is_character_file(const path& p);
#endif
GHC_FS_API bool is_character_file(const path& p, std::error_code& ec) noexcept;
GHC_FS_API bool is_directory(file_status s) noexcept;
#ifdef GHC_WITH_EXCEPTIONS
GHC_FS_API bool is_directory(const path& p);
#endif
GHC_FS_API bool is_directory(const path& p, std::error_code& ec) noexcept;
#ifdef GHC_WITH_EXCEPTIONS
GHC_FS_API bool is_empty(const path& p);
#endif
GHC_FS_API bool is_empty(const path& p, std::error_code& ec) noexcept;
GHC_FS_API bool is_fifo(file_status s) noexcept;
#ifdef GHC_WITH_EXCEPTIONS
GHC_FS_API bool is_fifo(const path& p);
#endif
GHC_FS_API bool is_fifo(const path& p, std::error_code& ec) noexcept;
GHC_FS_API bool is_other(file_status s) noexcept;
#ifdef GHC_WITH_EXCEPTIONS
GHC_FS_API bool is_other(const path& p);
#endif
GHC_FS_API bool is_other(const path& p, std::error_code& ec) noexcept;
GHC_FS_API bool is_regular_file(file_status s) noexcept;
#ifdef GHC_WITH_EXCEPTIONS
GHC_FS_API bool is_regular_file(const path& p);
#endif
GHC_FS_API bool is_regular_file(const path& p, std::error_code& ec) noexcept;
GHC_FS_API bool is_socket(file_status s) noexcept;
#ifdef GHC_WITH_EXCEPTIONS
GHC_FS_API bool is_socket(const path& p);
#endif
GHC_FS_API bool is_socket(const path& p, std::error_code& ec) noexcept;
GHC_FS_API bool is_symlink(file_status s) noexcept;
#ifdef GHC_WITH_EXCEPTIONS
GHC_FS_API bool is_symlink(const path& p);
#endif
GHC_FS_API bool is_symlink(const path& p, std::error_code& ec) noexcept;
#ifdef GHC_WITH_EXCEPTIONS
GHC_FS_API file_time_type last_write_time(const path& p);
#endif
GHC_FS_API file_time_type last_write_time(const path& p, std::error_code& ec) noexcept;
#ifdef GHC_WITH_EXCEPTIONS
GHC_FS_API void last_write_time(const path& p, file_time_type new_time);
#endif
GHC_FS_API void last_write_time(const path& p, file_time_type new_time, std::error_code& ec) noexcept;
#ifdef GHC_WITH_EXCEPTIONS
GHC_FS_API void permissions(const path& p, perms prms, perm_options opts = perm_options::replace);
#endif
GHC_FS_API void permissions(const path& p, perms prms, std::error_code& ec) noexcept;
GHC_FS_API void permissions(const path& p, perms prms, perm_options opts, std::error_code& ec);
#ifdef GHC_WITH_EXCEPTIONS
GHC_FS_API path proximate(const path& p, std::error_code& ec);
GHC_FS_API path proximate(const path& p, const path& base = current_path());
#endif
GHC_FS_API path proximate(const path& p, const path& base, std::error_code& ec);
#ifdef GHC_WITH_EXCEPTIONS
GHC_FS_API path read_symlink(const path& p);
#endif
GHC_FS_API path read_symlink(const path& p, std::error_code& ec);
GHC_FS_API path relative(const path& p, std::error_code& ec);
#ifdef GHC_WITH_EXCEPTIONS
GHC_FS_API path relative(const path& p, const path& base = current_path());
#endif
GHC_FS_API path relative(const path& p, const path& base, std::error_code& ec);
#ifdef GHC_WITH_EXCEPTIONS
GHC_FS_API bool remove(const path& p);
#endif
GHC_FS_API bool remove(const path& p, std::error_code& ec) noexcept;
#ifdef GHC_WITH_EXCEPTIONS
GHC_FS_API uintmax_t remove_all(const path& p);
#endif
GHC_FS_API uintmax_t remove_all(const path& p, std::error_code& ec) noexcept;
#ifdef GHC_WITH_EXCEPTIONS
GHC_FS_API void rename(const path& from, const path& to);
#endif
GHC_FS_API void rename(const path& from, const path& to, std::error_code& ec) noexcept;
#ifdef GHC_WITH_EXCEPTIONS
GHC_FS_API void resize_file(const path& p, uintmax_t size);
#endif
GHC_FS_API void resize_file(const path& p, uintmax_t size, std::error_code& ec) noexcept;
#ifdef GHC_WITH_EXCEPTIONS
GHC_FS_API space_info space(const path& p);
#endif
GHC_FS_API space_info space(const path& p, std::error_code& ec) noexcept;
#ifdef GHC_WITH_EXCEPTIONS
GHC_FS_API file_status status(const path& p);
#endif
GHC_FS_API file_status status(const path& p, std::error_code& ec) noexcept;
GHC_FS_API bool status_known(file_status s) noexcept;
#ifdef GHC_WITH_EXCEPTIONS
GHC_FS_API file_status symlink_status(const path& p);
#endif
GHC_FS_API file_status symlink_status(const path& p, std::error_code& ec) noexcept;
#ifdef GHC_WITH_EXCEPTIONS
GHC_FS_API path temp_directory_path();
#endif
GHC_FS_API path temp_directory_path(std::error_code& ec) noexcept;
#ifdef GHC_WITH_EXCEPTIONS
GHC_FS_API path weakly_canonical(const path& p);
#endif
GHC_FS_API path weakly_canonical(const path& p, std::error_code& ec) noexcept;
// Non-C++17 add-on std::fstream wrappers with path
template <class charT, class traits = std::char_traits<charT>>
class basic_filebuf : public std::basic_filebuf<charT, traits>
@ -1490,21 +1396,21 @@ GHC_INLINE bool validUtf8(const std::string& utf8String)
namespace detail {
template <class StringType, typename std::enable_if<(sizeof(typename StringType::value_type) == 1)>::type* = nullptr>
inline StringType fromUtf8(const std::string& utf8String, const typename StringType::allocator_type& alloc = typename StringType::allocator_type())
template <class StringType, class Utf8String, typename std::enable_if<path::_is_basic_string<Utf8String>::value && (sizeof(typename Utf8String::value_type) == 1) && (sizeof(typename StringType::value_type) == 1)>::type* = nullptr>
inline StringType fromUtf8(const Utf8String& utf8String, const typename StringType::allocator_type& alloc = typename StringType::allocator_type())
{
return StringType(utf8String.begin(), utf8String.end(), alloc);
}
template <class StringType, typename std::enable_if<(sizeof(typename StringType::value_type) == 2)>::type* = nullptr>
inline StringType fromUtf8(const std::string& utf8String, const typename StringType::allocator_type& alloc = typename StringType::allocator_type())
template <class StringType, class Utf8String, typename std::enable_if<path::_is_basic_string<Utf8String>::value && (sizeof(typename Utf8String::value_type) == 1) && (sizeof(typename StringType::value_type) == 2)>::type* = nullptr>
inline StringType fromUtf8(const Utf8String& utf8String, const typename StringType::allocator_type& alloc = typename StringType::allocator_type())
{
StringType result(alloc);
result.reserve(utf8String.length());
std::string::const_iterator iter = utf8String.begin();
auto iter = utf8String.cbegin();
unsigned utf8_state = S_STRT;
std::uint32_t codepoint = 0;
while (iter < utf8String.end()) {
while (iter < utf8String.cend()) {
if ((utf8_state = consumeUtf8Fragment(utf8_state, static_cast<uint8_t>(*iter++), codepoint)) == S_STRT) {
if (codepoint <= 0xffff) {
result += static_cast<typename StringType::value_type>(codepoint);
@ -1536,15 +1442,15 @@ inline StringType fromUtf8(const std::string& utf8String, const typename StringT
return result;
}
template <class StringType, typename std::enable_if<(sizeof(typename StringType::value_type) == 4)>::type* = nullptr>
inline StringType fromUtf8(const std::string& utf8String, const typename StringType::allocator_type& alloc = typename StringType::allocator_type())
template <class StringType, class Utf8String, typename std::enable_if<path::_is_basic_string<Utf8String>::value && (sizeof(typename Utf8String::value_type) == 1) && (sizeof(typename StringType::value_type) == 4)>::type* = nullptr>
inline StringType fromUtf8(const Utf8String& utf8String, const typename StringType::allocator_type& alloc = typename StringType::allocator_type())
{
StringType result(alloc);
result.reserve(utf8String.length());
std::string::const_iterator iter = utf8String.begin();
auto iter = utf8String.cbegin();
unsigned utf8_state = S_STRT;
std::uint32_t codepoint = 0;
while (iter < utf8String.end()) {
while (iter < utf8String.cend()) {
if ((utf8_state = consumeUtf8Fragment(utf8_state, static_cast<uint8_t>(*iter++), codepoint)) == S_STRT) {
result += static_cast<typename StringType::value_type>(codepoint);
codepoint = 0;
@ -1569,6 +1475,16 @@ inline StringType fromUtf8(const std::string& utf8String, const typename StringT
return result;
}
template<class StringType, typename charT, std::size_t N>
inline StringType fromUtf8(const charT (&utf8String)[N])
{
#ifdef __cpp_lib_string_view
return fromUtf8<StringType>(std::basic_string_view<charT>(utf8String, N-1));
#else
return fromUtf8<StringType>(std::basic_string<charT>(utf8String, N-1));
#endif
}
template <typename strT, typename std::enable_if<path::_is_basic_string<strT>::value && (sizeof(typename strT::value_type) == 1), int>::type size = 1>
inline std::string toUtf8(const strT& unicodeString)
{
@ -1695,41 +1611,6 @@ inline path::path(const Source& source, format fmt)
{
postprocess_path_with_format(_path, fmt);
}
template <>
inline path::path(const std::wstring& source, format fmt)
{
_path = detail::toUtf8(source);
postprocess_path_with_format(_path, fmt);
}
template <>
inline path::path(const std::u16string& source, format fmt)
{
_path = detail::toUtf8(source);
postprocess_path_with_format(_path, fmt);
}
template <>
inline path::path(const std::u32string& source, format fmt)
{
_path = detail::toUtf8(source);
postprocess_path_with_format(_path, fmt);
}
#ifdef __cpp_lib_string_view
template <>
inline path::path(const std::string_view& source, format fmt)
{
_path = detail::toUtf8(std::string(source));
postprocess_path_with_format(_path, fmt);
}
#ifdef GHC_USE_WCHAR_T
template <>
inline path::path(const std::wstring_view& source, format fmt)
{
_path = detail::toUtf8(std::wstring(source).c_str());
postprocess_path_with_format(_path, fmt);
}
#endif
#endif
template <class Source, typename>
inline path u8path(const Source& source)
@ -2360,7 +2241,7 @@ GHC_INLINE path& path::operator/=(const path& p)
}
return *this;
}
if ((p.is_absolute() && (_path != root_name() || p._path != "/")) || (p.has_root_name() && p.root_name() != root_name())) {
if ((p.is_absolute() && (_path != root_name()._path || p._path != "/")) || (p.has_root_name() && p.root_name() != root_name())) {
assign(p);
return *this;
}
@ -2630,10 +2511,17 @@ GHC_INLINE std::wstring path::wstring() const
#endif
}
#if defined(__cpp_lib_char8_t) && !defined(GHC_FILESYSTEM_ENFORCE_CPP17_API)
GHC_INLINE std::u8string path::u8string() const
{
return std::u8string(reinterpret_cast<const char8_t*>(native_impl().c_str()));
}
#else
GHC_INLINE std::string path::u8string() const
{
return native_impl();
}
#endif
GHC_INLINE std::u16string path::u16string() const
{
@ -2667,10 +2555,17 @@ GHC_INLINE std::wstring path::generic_wstring() const
return detail::fromUtf8<std::wstring>(_path);
}
#if defined(__cpp_lib_char8_t) && !defined(GHC_FILESYSTEM_ENFORCE_CPP17_API)
GHC_INLINE std::u8string path::generic_u8string() const
{
return std::u8string(reinterpret_cast<const char8_t*>(_path.c_str()));
}
#else
GHC_INLINE std::string path::generic_u8string() const
{
return _path;
}
#endif
GHC_INLINE std::u16string path::generic_u16string() const
{
@ -3202,6 +3097,13 @@ GHC_INLINE size_t hash_value(const path& p) noexcept
return std::hash<std::string>()(p.generic_string());
}
#ifdef GHC_HAS_THREEWAY_COMP
GHC_INLINE std::strong_ordering operator<=>( const path& lhs, const path& rhs ) noexcept
{
return lhs.compare(rhs) <=> 0;
}
#endif
GHC_INLINE bool operator==(const path& lhs, const path& rhs) noexcept
{
return lhs.compare(rhs) == 0;
@ -3232,6 +3134,7 @@ GHC_INLINE bool operator>=(const path& lhs, const path& rhs) noexcept
return lhs.compare(rhs) >= 0;
}
GHC_INLINE path operator/(const path& lhs, const path& rhs)
{
path result(lhs);
@ -3314,7 +3217,7 @@ GHC_INLINE filesystem_error::filesystem_error(const std::string& what_arg, const
, _p1(p1)
{
if (!_p1.empty()) {
_what_arg += ": '" + _p1.u8string() + "'";
_what_arg += ": '" + _p1.string() + "'";
}
}
@ -3326,10 +3229,10 @@ GHC_INLINE filesystem_error::filesystem_error(const std::string& what_arg, const
, _p2(p2)
{
if (!_p1.empty()) {
_what_arg += ": '" + _p1.u8string() + "'";
_what_arg += ": '" + _p1.string() + "'";
}
if (!_p2.empty()) {
_what_arg += ", '" + _p2.u8string() + "'";
_what_arg += ", '" + _p2.string() + "'";
}
}
@ -3491,14 +3394,7 @@ GHC_INLINE void copy(const path& from, const path& to)
{
copy(from, to, copy_options::none);
}
#endif
GHC_INLINE void copy(const path& from, const path& to, std::error_code& ec) noexcept
{
copy(from, to, copy_options::none, ec);
}
#ifdef GHC_WITH_EXCEPTIONS
GHC_INLINE void copy(const path& from, const path& to, copy_options options)
{
std::error_code ec;
@ -3509,6 +3405,11 @@ GHC_INLINE void copy(const path& from, const path& to, copy_options options)
}
#endif
GHC_INLINE void copy(const path& from, const path& to, std::error_code& ec) noexcept
{
copy(from, to, copy_options::none, ec);
}
GHC_INLINE void copy(const path& from, const path& to, copy_options options, std::error_code& ec) noexcept
{
std::error_code tec;
@ -3592,14 +3493,7 @@ GHC_INLINE bool copy_file(const path& from, const path& to)
{
return copy_file(from, to, copy_options::none);
}
#endif
GHC_INLINE bool copy_file(const path& from, const path& to, std::error_code& ec) noexcept
{
return copy_file(from, to, copy_options::none, ec);
}
#ifdef GHC_WITH_EXCEPTIONS
GHC_INLINE bool copy_file(const path& from, const path& to, copy_options option)
{
std::error_code ec;
@ -3611,6 +3505,11 @@ GHC_INLINE bool copy_file(const path& from, const path& to, copy_options option)
}
#endif
GHC_INLINE bool copy_file(const path& from, const path& to, std::error_code& ec) noexcept
{
return copy_file(from, to, copy_options::none, ec);
}
GHC_INLINE bool copy_file(const path& from, const path& to, copy_options options, std::error_code& ec) noexcept
{
std::error_code tecf, tect;
@ -4376,7 +4275,7 @@ GHC_INLINE void permissions(const path& p, perms prms, std::error_code& ec) noex
permissions(p, prms, perm_options::replace, ec);
}
GHC_INLINE void permissions(const path& p, perms prms, perm_options opts, std::error_code& ec)
GHC_INLINE void permissions(const path& p, perms prms, perm_options opts, std::error_code& ec) noexcept
{
if (static_cast<int>(opts & (perm_options::replace | perm_options::add | perm_options::remove)) == 0) {
ec = detail::make_error_code(detail::portable_error::invalid_argument);
@ -4425,7 +4324,11 @@ GHC_INLINE void permissions(const path& p, perms prms, perm_options opts, std::e
#ifdef GHC_WITH_EXCEPTIONS
GHC_INLINE path proximate(const path& p, std::error_code& ec)
{
return proximate(p, current_path(), ec);
auto cp = current_path(ec);
if(!ec) {
return proximate(p, cp, ec);
}
return path();
}
#endif
@ -5184,6 +5087,13 @@ GHC_INLINE file_status directory_entry::symlink_status(std::error_code& ec) cons
return filesystem::symlink_status(path(), ec);
}
#ifdef GHC_HAS_THREEWAY_COMP
GHC_INLINE std::strong_ordering directory_entry::operator<=>(const directory_entry& rhs) const noexcept
{
return _path <=> rhs._path;
}
#endif
GHC_INLINE bool directory_entry::operator<(const directory_entry& rhs) const noexcept
{
return _path < rhs._path;

View File

@ -45,21 +45,10 @@ else()
ParseAndAddCatchTests(filesystem_test_wchar)
endif()
if("cxx_std_17" IN_LIST CMAKE_CXX_COMPILE_FEATURES)
add_executable(filesystem_test_cpp17 filesystem_test.cpp catch.hpp)
set_property(TARGET filesystem_test_cpp17 PROPERTY CXX_STANDARD 17)
target_link_libraries(filesystem_test_cpp17 ghc_filesystem)
target_compile_options(filesystem_test_cpp17 PRIVATE
$<$<BOOL:${EMSCRIPTEN}>:-s DISABLE_EXCEPTION_CATCHING=0>
$<$<CXX_COMPILER_ID:Clang>:-Wall -Wextra -Wshadow -Wconversion -Wsign-conversion -Wpedantic -Werror>
$<$<CXX_COMPILER_ID:GNU>:-Wall -Wextra -Wshadow -Wconversion -Wsign-conversion -Wpedantic -Wno-psabi -Werror>
$<$<CXX_COMPILER_ID:MSVC>:/WX>)
if(CMAKE_CXX_COMPILER_ID MATCHES MSVC)
target_compile_definitions(filesystem_test_cpp17 PRIVATE _CRT_SECURE_NO_WARNINGS)
endif()
if(EMSCRIPTEN)
set_target_properties(filesystem_test_cpp17 PROPERTIES LINK_FLAGS "-g4 -s DISABLE_EXCEPTION_CATCHING=0 -s ALLOW_MEMORY_GROWTH=1")
endif()
ParseAndAddCatchTests(filesystem_test_cpp17)
AddTestExecutableWithStdCpp(17 filesystem_test.cpp catch.hpp)
endif()
if("cxx_std_20" IN_LIST CMAKE_CXX_COMPILE_FEATURES)
AddTestExecutableWithStdCpp(20 filesystem_test.cpp catch.hpp)
endif()
endif()

View File

@ -127,6 +127,14 @@ struct StringMaker<fs::perms>
static std::string convert(fs::perms const& value) { return std::to_string(static_cast<unsigned int>(value)); }
};
#ifdef __cpp_lib_char8_t
template <>
struct StringMaker<char8_t>
{
static std::string convert(char8_t const& value) { return std::to_string(static_cast<unsigned int>(value)); }
};
#endif
template <>
struct StringMaker<fs::file_time_type>
{
@ -320,7 +328,7 @@ TEST_CASE("fs::detail::fromUtf8", "[filesystem][fs.detail.utf8]")
CHECK(fs::detail::toUtf8(std::wstring(L"foobar")).length() == 6);
CHECK(fs::detail::toUtf8(std::wstring(L"foobar")) == "foobar");
CHECK(fs::detail::toUtf8(std::wstring(L"föobar")).length() == 7);
CHECK(fs::detail::toUtf8(std::wstring(L"föobar")) == u8"föobar");
//CHECK(fs::detail::toUtf8(std::wstring(L"föobar")) == u8"föobar");
#ifdef GHC_RAISE_UNICODE_ERRORS
CHECK_THROWS_AS(fs::detail::fromUtf8<std::u16string>(std::string("\xed\xa0\x80")), fs::filesystem_error);
@ -558,16 +566,24 @@ TEST_CASE("30.10.8.4.6 path native format observers", "[filesystem][path][fs.pat
CHECK((std::string)fs::u8path("\xc3\xa4\\\xe2\x82\xac") == std::string("\xc3\xa4\\\xe2\x82\xac"));
#endif
CHECK(fs::u8path("\xc3\xa4\\\xe2\x82\xac").wstring() == std::wstring(L"\u00E4\\\u20AC"));
#if defined(__cpp_lib_char8_t) && !defined(GHC_FILESYSTEM_ENFORCE_CPP17_API)
CHECK(fs::u8path("\xc3\xa4\\\xe2\x82\xac").u8string() == std::u8string(u8"\u00E4\\\u20AC"));
#else
CHECK(fs::u8path("\xc3\xa4\\\xe2\x82\xac").u8string() == std::string("\xc3\xa4\\\xe2\x82\xac"));
#endif
CHECK(fs::u8path("\xc3\xa4\\\xe2\x82\xac").u16string() == std::u16string(u"\u00E4\\\u20AC"));
CHECK(fs::u8path("\xc3\xa4\\\xe2\x82\xac").u32string() == std::u32string(U"\U000000E4\\\U000020AC"));
#else
CHECK(fs::u8path("\xc3\xa4/\xe2\x82\xac").native() == fs::path::string_type(u8"\xc3\xa4/\xe2\x82\xac"));
CHECK(!::strcmp(fs::u8path("\xc3\xa4/\xe2\x82\xac").c_str(), u8"\xc3\xa4/\xe2\x82\xac"));
CHECK((std::string)fs::u8path("\xc3\xa4/\xe2\x82\xac") == std::string(u8"\xc3\xa4/\xe2\x82\xac"));
CHECK(fs::u8path("\xc3\xa4/\xe2\x82\xac").string() == std::string(u8"\xc3\xa4/\xe2\x82\xac"));
CHECK(fs::u8path("\xc3\xa4/\xe2\x82\xac").native() == fs::path::string_type("\xc3\xa4/\xe2\x82\xac"));
CHECK(!::strcmp(fs::u8path("\xc3\xa4/\xe2\x82\xac").c_str(), "\xc3\xa4/\xe2\x82\xac"));
CHECK((std::string)fs::u8path("\xc3\xa4/\xe2\x82\xac") == std::string("\xc3\xa4/\xe2\x82\xac"));
CHECK(fs::u8path("\xc3\xa4/\xe2\x82\xac").string() == std::string("\xc3\xa4/\xe2\x82\xac"));
CHECK(fs::u8path("\xc3\xa4/\xe2\x82\xac").wstring() == std::wstring(L"ä/€"));
CHECK(fs::u8path("\xc3\xa4/\xe2\x82\xac").u8string() == std::string(u8"\xc3\xa4/\xe2\x82\xac"));
#if defined(__cpp_lib_char8_t) && !defined(GHC_FILESYSTEM_ENFORCE_CPP17_API)
CHECK(fs::u8path("\xc3\xa4/\xe2\x82\xac").u8string() == std::u8string(u8"\xc3\xa4/\xe2\x82\xac"));
#else
CHECK(fs::u8path("\xc3\xa4/\xe2\x82\xac").u8string() == std::string("\xc3\xa4/\xe2\x82\xac"));
#endif
CHECK(fs::u8path("\xc3\xa4/\xe2\x82\xac").u16string() == std::u16string(u"\u00E4/\u20AC"));
INFO("This check might fail on GCC8 (with \"Illegal byte sequence\") due to not detecting the valid unicode codepoint U+1D11E.");
CHECK(fs::u8path("\xc3\xa4/\xe2\x82\xac\xf0\x9d\x84\x9e").u16string() == std::u16string(u"\u00E4/\u20AC\U0001D11E"));
@ -586,17 +602,25 @@ TEST_CASE("30.10.8.4.7 path generic format observers", "[filesystem][path][fs.pa
CHECK(t.c_str() == std::string("\xc3\xa4/\xe2\x82\xac"));
#endif
CHECK(fs::u8path("\xc3\xa4\\\xe2\x82\xac").generic_wstring() == std::wstring(L"\U000000E4/\U000020AC"));
#if defined(__cpp_lib_char8_t) && !defined(GHC_FILESYSTEM_ENFORCE_CPP17_API)
CHECK(fs::u8path("\xc3\xa4\\\xe2\x82\xac").generic_u8string() == std::u8string(u8"\u00E4/\u20AC"));
#else
CHECK(fs::u8path("\xc3\xa4\\\xe2\x82\xac").generic_u8string() == std::string("\xc3\xa4/\xe2\x82\xac"));
#endif
CHECK(fs::u8path("\xc3\xa4\\\xe2\x82\xac").generic_u16string() == std::u16string(u"\u00E4/\u20AC"));
CHECK(fs::u8path("\xc3\xa4\\\xe2\x82\xac").generic_u32string() == std::u32string(U"\U000000E4/\U000020AC"));
#else
CHECK(fs::u8path("\xc3\xa4/\xe2\x82\xac").generic_string() == std::string(u8"\xc3\xa4/\xe2\x82\xac"));
CHECK(fs::u8path("\xc3\xa4/\xe2\x82\xac").generic_string() == std::string("\xc3\xa4/\xe2\x82\xac"));
#ifndef USE_STD_FS
auto t = fs::u8path("\xc3\xa4/\xe2\x82\xac").generic_string<char, std::char_traits<char>, TestAllocator<char>>();
CHECK(t.c_str() == std::string(u8"\xc3\xa4/\xe2\x82\xac"));
CHECK(t.c_str() == std::string("\xc3\xa4/\xe2\x82\xac"));
#endif
CHECK(fs::u8path("\xc3\xa4/\xe2\x82\xac").generic_wstring() == std::wstring(L"ä/€"));
CHECK(fs::u8path("\xc3\xa4/\xe2\x82\xac").generic_u8string() == std::string(u8"\xc3\xa4/\xe2\x82\xac"));
#if defined(__cpp_lib_char8_t) && !defined(GHC_FILESYSTEM_ENFORCE_CPP17_API)
CHECK(fs::u8path("\xc3\xa4/\xe2\x82\xac").generic_u8string() == std::u8string(u8"\xc3\xa4/\xe2\x82\xac"));
#else
CHECK(fs::u8path("\xc3\xa4/\xe2\x82\xac").generic_u8string() == std::string("\xc3\xa4/\xe2\x82\xac"));
#endif
CHECK(fs::u8path("\xc3\xa4/\xe2\x82\xac").generic_u16string() == std::u16string(u"\u00E4/\u20AC"));
CHECK(fs::u8path("\xc3\xa4/\xe2\x82\xac").generic_u32string() == std::u32string(U"\U000000E4/\U000020AC"));
#endif
@ -2726,7 +2750,8 @@ TEST_CASE("Windows: Long filename support", "[filesystem][path][fs.path.win.long
#ifdef GHC_OS_WINDOWS
TemporaryDirectory t(TempOpt::change_path);
char c = 'A';
fs::path dir = "\\\\?\\" + fs::current_path().u8string();
fs::path dir{"\\\\?\\"};
dir += fs::current_path().u8string();
for (; c <= 'Z'; ++c) {
std::string part = std::string(16, c);
dir /= part;
@ -2734,8 +2759,8 @@ TEST_CASE("Windows: Long filename support", "[filesystem][path][fs.path.win.long
CHECK(fs::exists(dir));
generateFile(dir / "f0");
CHECK(fs::exists(dir / "f0"));
std::string native = dir.u8string();
if (native.substr(0, 4) == "\\\\?\\") {
auto native = dir.u8string();
if (native.substr(0, 4) == u8"\\\\?\\") {
break;
}
}