first successfull compile/test on macOS with g++-9 in c++20 mode

This commit is contained in:
Steffen Schuemann 2019-12-27 20:06:18 +01:00
parent 10937ca294
commit 115b7c5c64
6 changed files with 141 additions and 14 deletions

View File

@ -481,6 +481,11 @@ to the expected behavior.
## Release Notes
### v1.3.0 (wip)
* Initial support for C++20 - `ghc::filesystem` now supports interfacing with
`char8_t` based `std::u8string`, when compiled in C++20 mode.
### [v1.2.10](https://github.com/gulrak/filesystem/releases/tag/v1.2.10)
* The Visual Studio 2019 compiler, GCC 9.2 and Clang 9.0 where added to the

View File

@ -31,6 +31,11 @@ if (CMAKE_COMPILER_IS_GNUCXX AND (CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL 8.0 O
endif()
target_compile_definitions(${targetName} PRIVATE USE_STD_FS)
endif()
if (CMAKE_COMPILER_IS_GNUCXX AND (CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL 9.0 OR CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 9.0))
add_executable(${targetName}_20 ${ARGN})
set_property(TARGET ${targetName}_20 PROPERTY CXX_STANDARD 20)
target_compile_definitions(${targetName}_20 PRIVATE USE_STD_FS)
endif()
if(CMAKE_CXX_COMPILER_ID MATCHES MSVC AND (CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL 19.15 OR CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 19.15))
add_executable(${targetName} ${ARGN})
@ -41,3 +46,14 @@ if(CMAKE_CXX_COMPILER_ID MATCHES MSVC AND (CMAKE_CXX_COMPILER_VERSION VERSION_EQ
endif()
endmacro()
macro(AddExecutableWithCppStd targetName cppStd)
if ((CMAKE_COMPILER_IS_GNUCXX AND (CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL 9.0 OR CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 9.0)) OR
("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" AND (CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL 9.0 OR CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 9.0)))
add_executable(${targetName} ${ARGN})
set_property(TARGET ${targetName} PROPERTY CXX_STANDARD ${cppStd})
set_property(TARGET ${targetName} PROPERTY CXX_STANDARD_REQUIRED ON)
target_link_libraries(${targetName} ghc_filesystem)
target_compile_options(${targetName} PRIVATE -fchar8_t -Wall -Wextra -Wshadow -Wconversion -Wsign-conversion -Wpedantic -Werror)
endif()
endmacro()

View File

@ -260,9 +260,15 @@ public:
path>::type;
template <typename T>
using path_type_EcharT = typename std::enable_if<std::is_same<T, char>::value || std::is_same<T, char16_t>::value || std::is_same<T, char32_t>::value, path>::type;
#else
#ifdef __cpp_lib_char8_t
template <typename T>
using path_from_string = typename std::enable_if<_is_basic_string<T>::value || std::is_same<char const*, typename std::decay<T>::type>::value || std::is_same<char*, typename std::decay<T>::type>::value
|| std::is_same<char8_t const*, typename std::decay<T>::type>::value || std::is_same<char8_t*, typename std::decay<T>::type>::value, path>::type;
#else
template <typename T>
using path_from_string = typename std::enable_if<_is_basic_string<T>::value || std::is_same<char const*, typename std::decay<T>::type>::value || std::is_same<char*, typename std::decay<T>::type>::value, path>::type;
#endif
template <typename T>
using path_type_EcharT = typename std::enable_if<std::is_same<T, char>::value || std::is_same<T, char16_t>::value || std::is_same<T, char32_t>::value || std::is_same<T, wchar_t>::value, path>::type;
#endif
@ -335,7 +341,11 @@ public:
std::basic_string<EcharT, traits, Allocator> string(const Allocator& a = Allocator()) const;
std::string string() const;
std::wstring wstring() const;
#ifdef __cpp_lib_char8_t
std::u8string u8string() const;
#else
std::string u8string() const;
#endif
std::u16string u16string() const;
std::u32string u32string() const;
@ -344,7 +354,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;
#ifdef __cpp_lib_char8_t
std::u8string generic_u8string() const;
#else
std::string generic_u8string() const;
#endif
std::u16string generic_u16string() const;
std::u32string generic_u32string() const;
@ -1297,12 +1311,20 @@ 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>
template <class StringType, typename std::enable_if<std::is_same<typename StringType::value_type, char>::value>::type* = nullptr>
inline StringType fromUtf8(const std::string& utf8String, const typename StringType::allocator_type& alloc = typename StringType::allocator_type())
{
return StringType(utf8String.begin(), utf8String.end(), alloc);
}
#ifdef __cpp_lib_char8_t
template <class StringType, typename std::enable_if<std::is_same<typename StringType::value_type, char8_t>::value>::type* = nullptr>
inline StringType fromUtf8(const std::string& utf8String, const typename StringType::allocator_type& alloc = typename StringType::allocator_type())
{
return StringType(reinterpret_cast<const char8_t*>(utf8String.data()), utf8String.length(), alloc);
}
#endif
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())
{
@ -1376,12 +1398,20 @@ inline StringType fromUtf8(const std::string& utf8String, const typename StringT
return result;
}
template <typename charT, typename traits, typename Alloc, typename std::enable_if<(sizeof(charT) == 1), int>::type size = 1>
template <typename charT, typename traits, typename Alloc, typename std::enable_if<std::is_same<charT,char>::value, int>::type size = 1>
inline std::string toUtf8(const std::basic_string<charT, traits, Alloc>& unicodeString)
{
return std::string(unicodeString.begin(), unicodeString.end());
}
#ifdef __cpp_lib_char8_t
template <typename charT, typename traits, typename Alloc, typename std::enable_if<std::is_same<charT,char8_t>::value, int>::type size = 1>
inline std::string toUtf8(const std::basic_string<charT, traits, Alloc>& unicodeString)
{
return std::string(reinterpret_cast<const char*>(unicodeString.data()), unicodeString.length());
}
#endif
template <typename charT, typename traits, typename Alloc, typename std::enable_if<(sizeof(charT) == 2), int>::type size = 2>
inline std::string toUtf8(const std::basic_string<charT, traits, Alloc>& unicodeString)
{
@ -2400,10 +2430,17 @@ GHC_INLINE std::wstring path::wstring() const
#endif
}
#ifdef __cpp_lib_char8_t
GHC_INLINE std::u8string path::u8string() const
{
return detail::fromUtf8<std::u8string>(native_impl());
}
#else
GHC_INLINE std::string path::u8string() const
{
return native_impl();
}
#endif
GHC_INLINE std::u16string path::u16string() const
{
@ -2437,10 +2474,17 @@ GHC_INLINE std::wstring path::generic_wstring() const
return detail::fromUtf8<std::wstring>(_path);
}
#ifdef __cpp_lib_char8_t
GHC_INLINE std::u8string path::generic_u8string() const
{
return detail::fromUtf8<std::u8string>(_path);
}
#else
GHC_INLINE std::string path::generic_u8string() const
{
return _path;
}
#endif
GHC_INLINE std::u16string path::generic_u16string() const
{
@ -2999,7 +3043,11 @@ GHC_INLINE filesystem_error::filesystem_error(const std::string& what_arg, const
, _p1(p1)
{
if (!_p1.empty()) {
#ifdef __cpp_lib_char8_t
_what_arg += ": '" + detail::toUtf8(_p1.u8string()) + "'";
#else
_what_arg += ": '" + _p1.u8string() + "'";
#endif
}
}
@ -3011,10 +3059,18 @@ GHC_INLINE filesystem_error::filesystem_error(const std::string& what_arg, const
, _p2(p2)
{
if (!_p1.empty()) {
#ifdef __cpp_lib_char8_t
_what_arg += ": '" + detail::toUtf8(_p1.u8string()) + "'";
#else
_what_arg += ": '" + _p1.u8string() + "'";
#endif
}
if (!_p2.empty()) {
#ifdef __cpp_lib_char8_t
_what_arg += ", '" + detail::toUtf8(_p2.u8string()) + "'";
#else
_what_arg += ", '" + _p2.u8string() + "'";
#endif
}
}

View File

@ -25,6 +25,7 @@ else()
target_compile_definitions(filesystem_test PRIVATE _CRT_SECURE_NO_WARNINGS)
endif()
ParseAndAddCatchTests(filesystem_test)
AddExecutableWithCppStd(filesystem_test_20 20 filesystem_test.cpp catch.hpp)
AddExecutableWithStdFS(std_filesystem_test filesystem_test.cpp catch.hpp)
if(WIN32)
add_executable(filesystem_test_wchar filesystem_test.cpp catch.hpp)

View File

@ -29,8 +29,9 @@
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//---------------------------------------------------------------------------------------
#include <algorithm>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <fstream>
#include <functional>
@ -48,6 +49,7 @@
#ifdef USE_STD_FS
#include <filesystem>
#include <codecvt>
namespace fs {
using namespace std::filesystem;
using ifstream = std::ifstream;
@ -89,6 +91,7 @@ using fstream = ghc::filesystem::fstream;
#ifndef GHC_FILESYSTEM_FWD_TEST
#define CATCH_CONFIG_MAIN
#endif
#define CATCH_CONFIG_NO_WCHAR
#include "catch.hpp"
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -135,6 +138,25 @@ struct StringMaker<fs::perms>
static std::string convert(fs::perms const& value) { return std::to_string(static_cast<unsigned int>(value)); }
};
template <>
struct StringMaker<std::wstring>
{
static std::string convert(std::wstring const& value)
{
#ifdef USE_STD_FS
#ifdef GHC_OS_WINDOWS
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> wcu8;
#else
std::wstring_convert<std::codecvt_utf8<wchar_t>> wcu8;
#endif
return wcu8.to_bytes( value );
#else
return ghc::filesystem::detail::toUtf8(value);
#endif
}
};
template <>
struct StringMaker<fs::file_time_type>
{
@ -269,6 +291,27 @@ static bool has_host_root_name_support()
return fs::path("//host").has_root_name();
}
#ifdef __cpp_char8_t
inline std::string U8S(const std::u8string& str)
{
std::string result(reinterpret_cast<const std::string::value_type*>(str.data()), str.length());
return result;
}
inline const char* U8C(const char8_t* str)
{
return reinterpret_cast<const char*>(str);
}
#else
inline std::string U8S(const std::string& str)
{
return str;
}
inline const char* U8C(const char* str)
{
return str;
}
#endif
template <class T>
class TestAllocator
{
@ -315,13 +358,13 @@ TEST_CASE("fs::detail::fromUtf8", "[filesystem][fs.detail.utf8]")
{
CHECK(fs::detail::fromUtf8<std::wstring>("foobar").length() == 6);
CHECK(fs::detail::fromUtf8<std::wstring>("foobar") == L"foobar");
CHECK(fs::detail::fromUtf8<std::wstring>(u8"föobar").length() == 6);
CHECK(fs::detail::fromUtf8<std::wstring>(u8"föobar") == L"föobar");
CHECK(fs::detail::fromUtf8<std::wstring>(U8S(u8"föobar")).length() == 6);
CHECK(fs::detail::fromUtf8<std::wstring>(U8S(u8"föobar")) == L"föobar");
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")) == U8C(u8"föobar"));
#ifdef GHC_RAISE_UNICODE_ERRORS
CHECK_THROWS_AS(fs::detail::fromUtf8<std::u16string>(std::string("\xed\xa0\x80")), fs::filesystem_error);
@ -563,16 +606,21 @@ TEST_CASE("30.10.8.4.6 path native format observers", "[filesystem][path][fs.pat
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(U8S(u8"\xc3\xa4/\xe2\x82\xac")));
CHECK(!::strcmp(fs::u8path("\xc3\xa4/\xe2\x82\xac").c_str(), U8C(u8"\xc3\xa4/\xe2\x82\xac")));
CHECK((std::string)fs::u8path("\xc3\xa4/\xe2\x82\xac") == std::string(U8C(u8"\xc3\xa4/\xe2\x82\xac")));
CHECK(fs::u8path("\xc3\xa4/\xe2\x82\xac").string() == std::string(U8C(u8"\xc3\xa4/\xe2\x82\xac")));
CHECK(fs::u8path("\xc3\xa4/\xe2\x82\xac").wstring() == std::wstring(L"\u00E4/\u20AC"));
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"));
CHECK(fs::u8path("\xc3\xa4/\xe2\x82\xac").wstring().length() == std::wstring(L"\u00E4/\u20AC").length());
CHECK(fs::u8path("\xc3\xa4/\xe2\x82\xac").u8string() == (u8"\xc3\xa4/\xe2\x82\xac"));
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"));
CHECK(fs::u8path("\xc3\xa4/\xe2\x82\xac").u32string() == std::u32string(U"\U000000E4/\U000020AC"));
#ifdef __cpp_char8_t
CHECK(fs::path(u8"\xc3\xa4/\xe2\x82\xac").u8string() == u8"\xc3\xa4/\xe2\x82\xac");
#endif
#endif
}
@ -591,13 +639,13 @@ TEST_CASE("30.10.8.4.7 path generic format observers", "[filesystem][path][fs.pa
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(U8S(u8"\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(U8S(u8"\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"));
CHECK(fs::u8path("\xc3\xa4/\xe2\x82\xac").generic_u8string() == (u8"\xc3\xa4/\xe2\x82\xac"));
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

View File

@ -4,6 +4,7 @@
// fs_fwd.hpp (to test this with maximum functionality, the unit tests
// are included here, signaling they should only include the fs_fwd.hpp)
#define NOMINMAX
#include <cstdio>
#include <ghc/fs_impl.hpp>
#define CATCH_CONFIG_MAIN
#include "catch.hpp"