Merge topic 'filesystem-path-enhancements'

b86a77e8c8 cm::filesystem::path: ensure independence from the program locale.

Acked-by: Kitware Robot <kwrobot@kitware.com>
Merge-request: !11583
This commit is contained in:
Brad King 2026-01-16 15:04:52 +00:00 committed by Kitware Robot
commit e9b2f1ff5e
5 changed files with 1088 additions and 220 deletions

View File

@ -61,6 +61,11 @@ are accessible under the ``cm/`` directory. The headers under ``cm/`` can
be used in place of the standard ones when extended features are needed.
For example ``<cm/memory>`` can be used in place of ``<memory>``.
The class ``cm::filesystem::path``, from the ``<cm/filesystem>`` header, is
fully compatible with the class ``std::filesystem::path`` regarding the API but
is a specific implementation (derived from the ``std::filesystem::path`` class)
to ensure a behavior independent of the current locale.
Available features are:
* From ``C++14``:

View File

@ -31,6 +31,17 @@ int main()
b1.lexically_normal()) {
return 1;
}
// LWG 3070 not implemented on some old Visual Studio compilers (2017, for
// example)
if (!std::filesystem::path("/a:/b:").lexically_relative("/a:/c:").empty()) {
return 1;
}
// LWG 3096 not implemented on some old Visual Studio compilers (2017, for
// example)
if (fs::path("/a").lexically_relative("/a/.") != ".") {
return 1;
}
#endif
// If std::string is copy-on-write, the std::filesystem::path

View File

@ -37,6 +37,7 @@ set(CMakeLib_TESTS
testCMExtAlgorithm.cxx
testCMExtEnumSet.cxx
testList.cxx
testCMFilesystemPath.cxx
testCMakePath.cxx
)
if(CMake_ENABLE_DEBUGGER)
@ -50,9 +51,6 @@ if(CMake_ENABLE_DEBUGGER)
testDebuggerThread.cxx
)
endif()
if (CMake_TEST_FILESYSTEM_PATH OR NOT CMake_HAVE_CXX_FILESYSTEM)
list(APPEND CMakeLib_TESTS testCMFilesystemPath.cxx)
endif()
add_executable(testUVProcessChainHelper testUVProcessChainHelper.cxx)
target_link_libraries(testUVProcessChainHelper CMakeLib)

View File

@ -24,10 +24,45 @@
# include <cm/string_view>
# include <cmext/string_view>
#endif
namespace cm {
namespace filesystem {
namespace internals {
// class unicode_helper
unicode_helper::utf8_state unicode_helper::decode(utf8_state const state,
std::uint8_t const fragment,
std::uint32_t& codepoint)
{
std::uint32_t const utf8_state_info[] = {
// encoded states
0x11111111u, 0x11111111u, 0x77777777u, 0x77777777u, 0x88888888u,
0x88888888u, 0x88888888u, 0x88888888u, 0x22222299u, 0x22222222u,
0x22222222u, 0x22222222u, 0x3333333au, 0x33433333u, 0x9995666bu,
0x99999999u, 0x88888880u, 0x22818108u, 0x88888881u, 0x88888882u,
0x88888884u, 0x88888887u, 0x88888886u, 0x82218108u, 0x82281108u,
0x88888888u, 0x88888883u, 0x88888885u, 0u, 0u,
0u, 0u,
};
std::uint8_t category = fragment < 128
? 0
: (utf8_state_info[(fragment >> 3) & 0xf] >> ((fragment & 7) << 2)) & 0xf;
codepoint = (state ? (codepoint << 6) | (fragment & 0x3fu)
: (0xffu >> category) & fragment);
return state == s_reject
? s_reject
: static_cast<utf8_state>(
(utf8_state_info[category + 16] >> (state << 2)) & 0xf);
}
}
}
#if !defined(CMake_HAVE_CXX_FILESYSTEM)
namespace filesystem {
namespace internals {
class path_parser
{
# if defined(__SUNPRO_CC) && defined(__sparc)
@ -480,54 +515,6 @@ private:
cm::string_view Entry;
};
// class unicode_helper
void unicode_helper::append(std::string& str, std::uint32_t codepoint)
{
if (codepoint <= 0x7f) {
str.push_back(static_cast<char>(codepoint));
} else if (codepoint >= 0x80 && codepoint <= 0x7ff) {
str.push_back(static_cast<char>((codepoint >> 6) + 192));
str.push_back(static_cast<char>((codepoint & 0x3f) + 128));
} else if ((codepoint >= 0x800 && codepoint <= 0xd7ff) ||
(codepoint >= 0xe000 && codepoint <= 0xffff)) {
str.push_back(static_cast<char>((codepoint >> 12) + 224));
str.push_back(static_cast<char>(((codepoint & 0xfff) >> 6) + 128));
str.push_back(static_cast<char>((codepoint & 0x3f) + 128));
} else if (codepoint >= 0x10000 && codepoint <= 0x10ffff) {
str.push_back(static_cast<char>((codepoint >> 18) + 240));
str.push_back(static_cast<char>(((codepoint & 0x3ffff) >> 12) + 128));
str.push_back(static_cast<char>(((codepoint & 0xfff) >> 6) + 128));
str.push_back(static_cast<char>((codepoint & 0x3f) + 128));
} else {
append(str, 0xfffd);
}
}
unicode_helper::utf8_state unicode_helper::decode(utf8_state const state,
std::uint8_t const fragment,
std::uint32_t& codepoint)
{
std::uint32_t const utf8_state_info[] = {
// encoded states
0x11111111u, 0x11111111u, 0x77777777u, 0x77777777u, 0x88888888u,
0x88888888u, 0x88888888u, 0x88888888u, 0x22222299u, 0x22222222u,
0x22222222u, 0x22222222u, 0x3333333au, 0x33433333u, 0x9995666bu,
0x99999999u, 0x88888880u, 0x22818108u, 0x88888881u, 0x88888882u,
0x88888884u, 0x88888887u, 0x88888886u, 0x82218108u, 0x82281108u,
0x88888888u, 0x88888883u, 0x88888885u, 0u, 0u,
0u, 0u,
};
std::uint8_t category = fragment < 128
? 0
: (utf8_state_info[(fragment >> 3) & 0xf] >> ((fragment & 7) << 2)) & 0xf;
codepoint = (state ? (codepoint << 6) | (fragment & 0x3fu)
: (0xffu >> category) & fragment);
return state == s_reject
? s_reject
: static_cast<utf8_state>(
(utf8_state_info[category + 16] >> (state << 2)) & 0xf);
}
} // internals
// Class path
@ -1018,13 +1005,5 @@ std::size_t hash_value(path const& p) noexcept
return value;
}
} // filesystem
} // cm
#else
// Avoid empty translation unit.
void cm_filesystem_path_cxx()
{
}
#endif
} // cm

File diff suppressed because it is too large Load Diff