Merge pull request #136 from phprus/win-smart-ptr

Performance optimization for Windows.
This commit is contained in:
gulrak 2021-10-23 15:50:33 +02:00 committed by GitHub
commit 09908b7241
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -424,7 +424,8 @@ public:
template <typename T> template <typename T>
using path_type_EcharT = typename std::enable_if<std::is_same<T, char>::value || std::is_same<T, char8_t>::value || std::is_same<T, char16_t>::value || std::is_same<T, char32_t>::value || std::is_same<T, wchar_t>::value, path>::type; using path_type_EcharT = typename std::enable_if<std::is_same<T, char>::value || std::is_same<T, char8_t>::value || std::is_same<T, char16_t>::value || std::is_same<T, char32_t>::value || std::is_same<T, wchar_t>::value, path>::type;
#else #else
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 || 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<char16_t const*, typename std::decay<T>::type>::value || std::is_same<char16_t*, typename std::decay<T>::type>::value || std::is_same<char32_t const*, typename std::decay<T>::type>::value || std::is_same<char16_t const*, typename std::decay<T>::type>::value || std::is_same<char16_t*, typename std::decay<T>::type>::value || std::is_same<char32_t const*, typename std::decay<T>::type>::value ||
std::is_same<char32_t*, typename std::decay<T>::type>::value || std::is_same<wchar_t const*, typename std::decay<T>::type>::value || std::is_same<wchar_t*, typename std::decay<T>::type>::value, std::is_same<char32_t*, typename std::decay<T>::type>::value || std::is_same<wchar_t const*, typename std::decay<T>::type>::value || std::is_same<wchar_t*, typename std::decay<T>::type>::value,
path>::type; path>::type;
@ -800,6 +801,7 @@ public:
file_type type() const noexcept; file_type type() const noexcept;
perms permissions() const noexcept; perms permissions() const noexcept;
friend bool operator==(const file_status& lhs, const file_status& rhs) noexcept { return lhs.type() == rhs.type() && lhs.permissions() == rhs.permissions(); } friend bool operator==(const file_status& lhs, const file_status& rhs) noexcept { return lhs.type() == rhs.type() && lhs.permissions() == rhs.permissions(); }
private: private:
file_type _type; file_type _type;
perms _perms; perms _perms;
@ -2005,6 +2007,52 @@ GHC_INLINE file_status file_status_from_st_mode(T mode)
} }
#ifdef GHC_OS_WINDOWS #ifdef GHC_OS_WINDOWS
class unique_handle
{
public:
typedef HANDLE element_type;
unique_handle() noexcept
: handle_(INVALID_HANDLE_VALUE)
{
}
explicit unique_handle(element_type h) noexcept
: handle_(h)
{
}
unique_handle(unique_handle&& u) noexcept
: handle_(u.release())
{
}
~unique_handle() { reset(); }
unique_handle& operator=(unique_handle&& u) noexcept
{
reset(u.release());
return *this;
}
element_type get() const noexcept { return handle_; }
explicit operator bool() const noexcept { return handle_ != INVALID_HANDLE_VALUE; }
element_type release() noexcept
{
element_type tmp = handle_;
handle_ = INVALID_HANDLE_VALUE;
return tmp;
}
void reset(element_type h = INVALID_HANDLE_VALUE) noexcept
{
element_type tmp = handle_;
handle_ = h;
if (tmp != INVALID_HANDLE_VALUE) {
CloseHandle(tmp);
}
}
void swap(unique_handle& u) noexcept { std::swap(handle_, u.handle_); }
private:
element_type handle_;
};
#ifndef REPARSE_DATA_BUFFER_HEADER_SIZE #ifndef REPARSE_DATA_BUFFER_HEADER_SIZE
typedef struct _REPARSE_DATA_BUFFER typedef struct _REPARSE_DATA_BUFFER
{ {
@ -2041,15 +2089,21 @@ typedef struct _REPARSE_DATA_BUFFER
#endif #endif
#endif #endif
GHC_INLINE std::shared_ptr<REPARSE_DATA_BUFFER> getReparseData(const path& p, std::error_code& ec) template <class T>
struct free_deleter
{ {
std::shared_ptr<void> file(CreateFileW(GHC_NATIVEWP(p), 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 0, OPEN_EXISTING, FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, 0), CloseHandle); void operator()(T* p) const { std::free(p); }
if (file.get() == INVALID_HANDLE_VALUE) { };
GHC_INLINE std::unique_ptr<REPARSE_DATA_BUFFER, free_deleter<REPARSE_DATA_BUFFER>> getReparseData(const path& p, std::error_code& ec)
{
unique_handle file(CreateFileW(GHC_NATIVEWP(p), 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 0, OPEN_EXISTING, FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, 0));
if (!file) {
ec = detail::make_system_error(); ec = detail::make_system_error();
return nullptr; return nullptr;
} }
std::shared_ptr<REPARSE_DATA_BUFFER> reparseData((REPARSE_DATA_BUFFER*)std::calloc(1, MAXIMUM_REPARSE_DATA_BUFFER_SIZE), std::free); std::unique_ptr<REPARSE_DATA_BUFFER, free_deleter<REPARSE_DATA_BUFFER>> reparseData(reinterpret_cast<REPARSE_DATA_BUFFER*>(std::calloc(1, MAXIMUM_REPARSE_DATA_BUFFER_SIZE)));
ULONG bufferUsed; ULONG bufferUsed;
if (DeviceIoControl(file.get(), FSCTL_GET_REPARSE_POINT, 0, 0, reparseData.get(), MAXIMUM_REPARSE_DATA_BUFFER_SIZE, &bufferUsed, 0)) { if (DeviceIoControl(file.get(), FSCTL_GET_REPARSE_POINT, 0, 0, reparseData.get(), MAXIMUM_REPARSE_DATA_BUFFER_SIZE, &bufferUsed, 0)) {
return reparseData; return reparseData;
@ -3057,7 +3111,8 @@ GHC_INLINE bool has_executable_extension(const path& p)
return false; return false;
} }
const path::value_type* ext = fn._path.c_str() + pos + 1; const path::value_type* ext = fn._path.c_str() + pos + 1;
if (detail::equals_simple_insensitive(ext, GHC_PLATFORM_LITERAL("exe")) || detail::equals_simple_insensitive(ext, GHC_PLATFORM_LITERAL("cmd")) || detail::equals_simple_insensitive(ext, GHC_PLATFORM_LITERAL("bat")) || detail::equals_simple_insensitive(ext, GHC_PLATFORM_LITERAL("com"))) { if (detail::equals_simple_insensitive(ext, GHC_PLATFORM_LITERAL("exe")) || detail::equals_simple_insensitive(ext, GHC_PLATFORM_LITERAL("cmd")) || detail::equals_simple_insensitive(ext, GHC_PLATFORM_LITERAL("bat")) ||
detail::equals_simple_insensitive(ext, GHC_PLATFORM_LITERAL("com"))) {
return true; return true;
} }
} }
@ -4153,10 +4208,10 @@ GHC_INLINE bool equivalent(const path& p1, const path& p2, std::error_code& ec)
{ {
ec.clear(); ec.clear();
#ifdef GHC_OS_WINDOWS #ifdef GHC_OS_WINDOWS
std::shared_ptr<void> file1(::CreateFileW(GHC_NATIVEWP(p1), 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0), CloseHandle); detail::unique_handle file1(::CreateFileW(GHC_NATIVEWP(p1), 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0));
auto e1 = ::GetLastError(); auto e1 = ::GetLastError();
std::shared_ptr<void> file2(::CreateFileW(GHC_NATIVEWP(p2), 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0), CloseHandle); detail::unique_handle file2(::CreateFileW(GHC_NATIVEWP(p2), 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0));
if (file1.get() == INVALID_HANDLE_VALUE || file2.get() == INVALID_HANDLE_VALUE) { if (!file1 || !file2) {
#ifdef LWG_2937_BEHAVIOUR #ifdef LWG_2937_BEHAVIOUR
ec = detail::make_system_error(e1 ? e1 : ::GetLastError()); ec = detail::make_system_error(e1 ? e1 : ::GetLastError());
#else #else
@ -4246,9 +4301,9 @@ GHC_INLINE uintmax_t hard_link_count(const path& p, std::error_code& ec) noexcep
ec.clear(); ec.clear();
#ifdef GHC_OS_WINDOWS #ifdef GHC_OS_WINDOWS
uintmax_t result = static_cast<uintmax_t>(-1); uintmax_t result = static_cast<uintmax_t>(-1);
std::shared_ptr<void> file(::CreateFileW(GHC_NATIVEWP(p), 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0), CloseHandle); detail::unique_handle file(::CreateFileW(GHC_NATIVEWP(p), 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0));
BY_HANDLE_FILE_INFORMATION inf; BY_HANDLE_FILE_INFORMATION inf;
if (file.get() == INVALID_HANDLE_VALUE) { if (!file) {
ec = detail::make_system_error(); ec = detail::make_system_error();
} }
else { else {
@ -4477,7 +4532,7 @@ GHC_INLINE void last_write_time(const path& p, file_time_type new_time, std::err
ec.clear(); ec.clear();
auto d = new_time.time_since_epoch(); auto d = new_time.time_since_epoch();
#ifdef GHC_OS_WINDOWS #ifdef GHC_OS_WINDOWS
std::shared_ptr<void> file(::CreateFileW(GHC_NATIVEWP(p), FILE_WRITE_ATTRIBUTES, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL), ::CloseHandle); detail::unique_handle file(::CreateFileW(GHC_NATIVEWP(p), FILE_WRITE_ATTRIBUTES, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL));
FILETIME ft; FILETIME ft;
auto tt = std::chrono::duration_cast<std::chrono::microseconds>(d).count() * 10 + 116444736000000000; auto tt = std::chrono::duration_cast<std::chrono::microseconds>(d).count() * 10 + 116444736000000000;
ft.dwLowDateTime = static_cast<DWORD>(tt); ft.dwLowDateTime = static_cast<DWORD>(tt);
@ -4831,8 +4886,8 @@ GHC_INLINE void resize_file(const path& p, uintmax_t size, std::error_code& ec)
#endif #endif
return; return;
} }
std::shared_ptr<void> file(CreateFileW(GHC_NATIVEWP(p), GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL), CloseHandle); detail::unique_handle file(CreateFileW(GHC_NATIVEWP(p), GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL));
if (file.get() == INVALID_HANDLE_VALUE) { if (!file) {
ec = detail::make_system_error(); ec = detail::make_system_error();
} }
else if (SetFilePointerEx(file.get(), lisize, NULL, FILE_BEGIN) == 0 || SetEndOfFile(file.get()) == 0) { else if (SetFilePointerEx(file.get(), lisize, NULL, FILE_BEGIN) == 0 || SetEndOfFile(file.get()) == 0) {
@ -5609,15 +5664,33 @@ public:
#else #else
_dir_entry._symlink_status.permissions(perms::unknown); _dir_entry._symlink_status.permissions(perms::unknown);
switch (_entry->d_type) { switch (_entry->d_type) {
case DT_BLK: _dir_entry._symlink_status.type(file_type::block); break; case DT_BLK:
case DT_CHR: _dir_entry._symlink_status.type(file_type::character); break; _dir_entry._symlink_status.type(file_type::block);
case DT_DIR: _dir_entry._symlink_status.type(file_type::directory); break; break;
case DT_FIFO: _dir_entry._symlink_status.type(file_type::fifo); break; case DT_CHR:
case DT_LNK: _dir_entry._symlink_status.type(file_type::symlink); break; _dir_entry._symlink_status.type(file_type::character);
case DT_REG: _dir_entry._symlink_status.type(file_type::regular); break; break;
case DT_SOCK: _dir_entry._symlink_status.type(file_type::socket); break; case DT_DIR:
case DT_UNKNOWN: _dir_entry._symlink_status.type(file_type::none); break; _dir_entry._symlink_status.type(file_type::directory);
default: _dir_entry._symlink_status.type(file_type::unknown); break; break;
case DT_FIFO:
_dir_entry._symlink_status.type(file_type::fifo);
break;
case DT_LNK:
_dir_entry._symlink_status.type(file_type::symlink);
break;
case DT_REG:
_dir_entry._symlink_status.type(file_type::regular);
break;
case DT_SOCK:
_dir_entry._symlink_status.type(file_type::socket);
break;
case DT_UNKNOWN:
_dir_entry._symlink_status.type(file_type::none);
break;
default:
_dir_entry._symlink_status.type(file_type::unknown);
break;
} }
if (_entry->d_type != DT_LNK) { if (_entry->d_type != DT_LNK) {
_dir_entry._status = _dir_entry._symlink_status; _dir_entry._status = _dir_entry._symlink_status;