Refactor to remove <Windows.h> from headers

This commit is contained in:
Luke Street 2022-02-22 00:48:11 -05:00
parent 2252e6c3c3
commit 32090b4d4a
7 changed files with 100 additions and 113 deletions

View File

@ -45,7 +45,6 @@ if(WIN32)
endif() endif()
target_sources(kabufuda PRIVATE target_sources(kabufuda PRIVATE
include/kabufuda/winsupport.hpp
lib/kabufuda/AsyncIOWin32.cpp lib/kabufuda/AsyncIOWin32.cpp
) )
elseif(NX) elseif(NX)

View File

@ -9,8 +9,7 @@ using SizeReturn = ssize_t;
using SizeReturn = ssize_t; using SizeReturn = ssize_t;
#endif #endif
#else #else
#include <windows.h> using SizeReturn = unsigned long;
using SizeReturn = DWORD;
#endif #endif
#include <cstddef> #include <cstddef>
@ -19,6 +18,9 @@ using SizeReturn = DWORD;
#include "kabufuda/Util.hpp" #include "kabufuda/Util.hpp"
namespace kabufuda { namespace kabufuda {
#if _WIN32
struct AsyncIOInner;
#endif
class AsyncIO { class AsyncIO {
#ifdef __SWITCH__ #ifdef __SWITCH__
@ -27,11 +29,10 @@ class AsyncIO {
int m_fd = -1; int m_fd = -1;
std::vector<std::pair<struct aiocb, SizeReturn>> m_queue; std::vector<std::pair<struct aiocb, SizeReturn>> m_queue;
#else #else
HANDLE m_fh = INVALID_HANDLE_VALUE; AsyncIOInner* m_inner;
std::vector<std::pair<OVERLAPPED, SizeReturn>> m_queue;
#endif #endif
void _waitForOperation(size_t qIdx) const; void _waitForOperation(size_t qIdx) const;
size_t m_maxBlock = 0; mutable size_t m_maxBlock = 0;
public: public:
AsyncIO() = default; AsyncIO() = default;
@ -41,11 +42,7 @@ public:
AsyncIO& operator=(AsyncIO&& other); AsyncIO& operator=(AsyncIO&& other);
AsyncIO(const AsyncIO* other) = delete; AsyncIO(const AsyncIO* other) = delete;
AsyncIO& operator=(const AsyncIO& other) = delete; AsyncIO& operator=(const AsyncIO& other) = delete;
void resizeQueue(size_t queueSz) { void resizeQueue(size_t queueSz);
#ifndef __SWITCH__
m_queue.resize(queueSz);
#endif
}
bool asyncRead(size_t qIdx, void* buf, size_t length, off_t offset); bool asyncRead(size_t qIdx, void* buf, size_t length, off_t offset);
bool asyncWrite(size_t qIdx, const void* buf, size_t length, off_t offset); bool asyncWrite(size_t qIdx, const void* buf, size_t length, off_t offset);
ECardResult pollStatus(size_t qIdx, SizeReturn* szRet = nullptr) const; ECardResult pollStatus(size_t qIdx, SizeReturn* szRet = nullptr) const;
@ -56,7 +53,7 @@ public:
#elif !defined(_WIN32) #elif !defined(_WIN32)
explicit operator bool() const { return m_fd != -1; } explicit operator bool() const { return m_fd != -1; }
#else #else
explicit operator bool() const { return m_fh != INVALID_HANDLE_VALUE; } explicit operator bool() const;
#endif #endif
}; };

View File

@ -11,15 +11,6 @@
#include <dirent.h> #include <dirent.h>
#include <fcntl.h> #include <fcntl.h>
#include <unistd.h> #include <unistd.h>
#else
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN 1
#endif
#ifndef NOMINMAX
#define NOMINMAX
#endif
#include <Windows.h>
#include "winsupport.hpp"
#endif #endif
#include <algorithm> #include <algorithm>
@ -188,35 +179,10 @@ uint64_t getGCTime();
#endif #endif
#if _WIN32 #if _WIN32
class WStringConv { int Stat(const char* path, Sstat* statOut);
std::wstring m_sys;
public:
explicit WStringConv(std::string_view str) {
int len = MultiByteToWideChar(CP_UTF8, 0, str.data(), str.size(), nullptr, 0);
m_sys.assign(len, L'\0');
MultiByteToWideChar(CP_UTF8, 0, str.data(), str.size(), &m_sys[0], len);
}
[[nodiscard]] std::wstring str() const { return m_sys; }
[[nodiscard]] const wchar_t* c_str() const { return m_sys.c_str(); }
};
#endif
inline int Stat(const char* path, Sstat* statOut) {
#if _WIN32
size_t pos;
WStringConv wpath(path);
const wchar_t* wpathP = wpath.c_str();
for (pos = 0; pos < 3 && wpathP[pos] != L'\0'; ++pos) {}
if (pos == 2 && wpathP[1] == L':') {
wchar_t fixPath[4] = {wpathP[0], L':', L'/', L'\0'};
return _wstat64(fixPath, statOut);
}
return _wstat64(wpath.c_str(), statOut);
#else #else
return stat(path, statOut); inline int Stat(const char* path, Sstat* statOut) { return stat(path, statOut); }
#endif #endif
}
/** /**
* @brief calculateChecksum * @brief calculateChecksum

View File

@ -1,34 +0,0 @@
#pragma once
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN 1
#endif
#ifndef NOMINMAX
#define NOMINMAX 1
#endif
#include "windows.h"
#include <cstdint>
#ifndef DEF_INLINE_MEMMEM
#define DEF_INLINE_MEMMEM
inline void* memmem(const void* haystack, size_t hlen, const void* needle, size_t nlen) {
int needle_first;
const uint8_t* p = static_cast<const uint8_t*>(haystack);
size_t plen = hlen;
if (!nlen)
return NULL;
needle_first = *(unsigned char*)needle;
while (plen >= nlen && (p = static_cast<const uint8_t*>(memchr(p, needle_first, plen - nlen + 1)))) {
if (!memcmp(p, needle, nlen))
return (void*)p;
p++;
plen = hlen - (p - static_cast<const uint8_t*>(haystack));
}
return NULL;
}
#endif

View File

@ -45,4 +45,6 @@ ECardResult AsyncIO::pollStatus() const { return ECardResult::READY; }
void AsyncIO::waitForCompletion() const {} void AsyncIO::waitForCompletion() const {}
void AsyncIO::resizeQueue(size_t queueSz) {}
} // namespace kabufuda } // namespace kabufuda

View File

@ -142,4 +142,8 @@ void AsyncIO::waitForCompletion() const {
const_cast<AsyncIO*>(this)->m_maxBlock = 0; const_cast<AsyncIO*>(this)->m_maxBlock = 0;
} }
void AsyncIO::resizeQueue(size_t queueSz) {
m_queue.resize(queueSz);
}
} // namespace kabufuda } // namespace kabufuda

View File

@ -1,12 +1,47 @@
#include "kabufuda/AsyncIO.hpp" #include "kabufuda/AsyncIO.hpp"
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN 1
#endif
#ifndef NOMINMAX
#define NOMINMAX 1
#endif
#include <Windows.h>
#include <algorithm> #include <algorithm>
#include <cstdio> #include <cstdio>
namespace kabufuda { namespace kabufuda {
#undef min class WStringConv {
#undef max std::wstring m_sys;
public:
explicit WStringConv(std::string_view str) {
int len = MultiByteToWideChar(CP_UTF8, 0, str.data(), str.size(), nullptr, 0);
m_sys.assign(len, L'\0');
MultiByteToWideChar(CP_UTF8, 0, str.data(), str.size(), &m_sys[0], len);
}
[[nodiscard]] std::wstring str() const { return m_sys; }
[[nodiscard]] const wchar_t* c_str() const { return m_sys.c_str(); }
};
int Stat(const char* path, Sstat* statOut) {
size_t pos;
WStringConv wpath(path);
const wchar_t* wpathP = wpath.c_str();
for (pos = 0; pos < 3 && wpathP[pos] != L'\0'; ++pos) {}
if (pos == 2 && wpathP[1] == L':') {
wchar_t fixPath[4] = {wpathP[0], L':', L'/', L'\0'};
return _wstat64(fixPath, statOut);
}
return _wstat64(wpath.c_str(), statOut);
}
struct AsyncIOInner {
HANDLE m_fh = INVALID_HANDLE_VALUE;
std::vector<std::pair<OVERLAPPED, SizeReturn>> m_queue;
};
static void ResetOverlapped(OVERLAPPED& aio, DWORD offset = 0) { static void ResetOverlapped(OVERLAPPED& aio, DWORD offset = 0) {
aio.Internal = 0; aio.Internal = 0;
@ -15,60 +50,70 @@ static void ResetOverlapped(OVERLAPPED& aio, DWORD offset = 0) {
aio.OffsetHigh = 0; aio.OffsetHigh = 0;
} }
AsyncIO::AsyncIO(std::string_view filename, bool truncate) { AsyncIO::AsyncIO(std::string_view filename, bool truncate) : m_inner(new AsyncIOInner) {
#if WINDOWS_STORE #if WINDOWS_STORE
CREATEFILE2_EXTENDED_PARAMETERS parms = {}; CREATEFILE2_EXTENDED_PARAMETERS parms = {};
parms.dwSize = sizeof(CREATEFILE2_EXTENDED_PARAMETERS); parms.dwSize = sizeof(CREATEFILE2_EXTENDED_PARAMETERS);
parms.dwFileAttributes = FILE_ATTRIBUTE_NORMAL; parms.dwFileAttributes = FILE_ATTRIBUTE_NORMAL;
parms.dwFileFlags = FILE_FLAG_OVERLAPPED; parms.dwFileFlags = FILE_FLAG_OVERLAPPED;
m_fh = CreateFile2(filename.data(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, m_inner->m_fh = CreateFile2(filename.data(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
truncate ? CREATE_ALWAYS : OPEN_ALWAYS, &parms); truncate ? CREATE_ALWAYS : OPEN_ALWAYS, &parms);
#else #else
WStringConv wfilename(filename); WStringConv wfilename(filename);
m_fh = CreateFileW(wfilename.c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, m_inner->m_fh =
truncate ? CREATE_ALWAYS : OPEN_ALWAYS, FILE_FLAG_OVERLAPPED | FILE_ATTRIBUTE_NORMAL, nullptr); CreateFileW(wfilename.c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr,
truncate ? CREATE_ALWAYS : OPEN_ALWAYS, FILE_FLAG_OVERLAPPED | FILE_ATTRIBUTE_NORMAL, nullptr);
#endif #endif
} }
AsyncIO::~AsyncIO() { AsyncIO::~AsyncIO() {
if (*this) { if (*this) {
if (CancelIoEx(m_fh, nullptr)) if (CancelIoEx(m_inner->m_fh, nullptr))
waitForCompletion(); waitForCompletion();
CloseHandle(m_fh); CloseHandle(m_inner->m_fh);
} }
delete m_inner;
} }
AsyncIO::AsyncIO(AsyncIO&& other) { AsyncIO::AsyncIO(AsyncIO&& other) {
m_fh = other.m_fh; if (*this) {
other.m_fh = INVALID_HANDLE_VALUE; if (CancelIoEx(m_inner->m_fh, nullptr))
m_queue = std::move(other.m_queue); waitForCompletion();
CloseHandle(m_inner->m_fh);
}
delete m_inner;
m_inner = other.m_inner;
other.m_inner = nullptr;
m_maxBlock = other.m_maxBlock; m_maxBlock = other.m_maxBlock;
} }
AsyncIO& AsyncIO::operator=(AsyncIO&& other) { AsyncIO& AsyncIO::operator=(AsyncIO&& other) {
if (*this) { if (*this) {
if (CancelIoEx(m_fh, nullptr)) if (CancelIoEx(m_inner->m_fh, nullptr))
waitForCompletion(); waitForCompletion();
CloseHandle(m_fh); CloseHandle(m_inner->m_fh);
} }
m_fh = other.m_fh; delete m_inner;
other.m_fh = INVALID_HANDLE_VALUE; m_inner = other.m_inner;
m_queue = std::move(other.m_queue); other.m_inner = nullptr;
m_maxBlock = other.m_maxBlock; m_maxBlock = other.m_maxBlock;
return *this; return *this;
} }
void AsyncIO::_waitForOperation(size_t qIdx) const { void AsyncIO::_waitForOperation(size_t qIdx) const {
auto& aio = const_cast<AsyncIO*>(this)->m_queue[qIdx]; if (m_inner == nullptr) {
return;
}
auto& aio = m_inner->m_queue[qIdx];
if (aio.first.hEvent == 0) if (aio.first.hEvent == 0)
return; return;
GetOverlappedResult(m_fh, &aio.first, &aio.second, TRUE); GetOverlappedResult(m_inner->m_fh, &aio.first, &aio.second, TRUE);
CloseHandle(aio.first.hEvent); CloseHandle(aio.first.hEvent);
aio.first.hEvent = 0; aio.first.hEvent = 0;
} }
bool AsyncIO::asyncRead(size_t qIdx, void* buf, size_t length, off_t offset) { bool AsyncIO::asyncRead(size_t qIdx, void* buf, size_t length, off_t offset) {
OVERLAPPED& aio = m_queue[qIdx].first; OVERLAPPED& aio = m_inner->m_queue[qIdx].first;
if (aio.hEvent) { if (aio.hEvent) {
#ifndef NDEBUG #ifndef NDEBUG
fprintf(stderr, "WARNING: synchronous kabufuda fallback, check access polling\n"); fprintf(stderr, "WARNING: synchronous kabufuda fallback, check access polling\n");
@ -79,12 +124,12 @@ bool AsyncIO::asyncRead(size_t qIdx, void* buf, size_t length, off_t offset) {
} }
ResetOverlapped(aio, DWORD(offset)); ResetOverlapped(aio, DWORD(offset));
m_maxBlock = std::max(m_maxBlock, qIdx + 1); m_maxBlock = std::max(m_maxBlock, qIdx + 1);
BOOL res = ReadFile(m_fh, buf, length, nullptr, &aio); BOOL res = ReadFile(m_inner->m_fh, buf, length, nullptr, &aio);
return res == TRUE || GetLastError() == ERROR_IO_PENDING; return res == TRUE || GetLastError() == ERROR_IO_PENDING;
} }
bool AsyncIO::asyncWrite(size_t qIdx, const void* buf, size_t length, off_t offset) { bool AsyncIO::asyncWrite(size_t qIdx, const void* buf, size_t length, off_t offset) {
OVERLAPPED& aio = m_queue[qIdx].first; OVERLAPPED& aio = m_inner->m_queue[qIdx].first;
if (aio.hEvent) { if (aio.hEvent) {
#ifndef NDEBUG #ifndef NDEBUG
fprintf(stderr, "WARNING: synchronous kabufuda fallback, check access polling\n"); fprintf(stderr, "WARNING: synchronous kabufuda fallback, check access polling\n");
@ -95,18 +140,18 @@ bool AsyncIO::asyncWrite(size_t qIdx, const void* buf, size_t length, off_t offs
} }
ResetOverlapped(aio, DWORD(offset)); ResetOverlapped(aio, DWORD(offset));
m_maxBlock = std::max(m_maxBlock, qIdx + 1); m_maxBlock = std::max(m_maxBlock, qIdx + 1);
BOOL res = WriteFile(m_fh, buf, length, nullptr, &aio); BOOL res = WriteFile(m_inner->m_fh, buf, length, nullptr, &aio);
return res == TRUE || GetLastError() == ERROR_IO_PENDING; return res == TRUE || GetLastError() == ERROR_IO_PENDING;
} }
ECardResult AsyncIO::pollStatus(size_t qIdx, SizeReturn* szRet) const { ECardResult AsyncIO::pollStatus(size_t qIdx, SizeReturn* szRet) const {
auto& aio = const_cast<AsyncIO*>(this)->m_queue[qIdx]; auto& aio = m_inner->m_queue[qIdx];
if (aio.first.hEvent == 0) { if (aio.first.hEvent == 0) {
if (szRet) if (szRet)
*szRet = aio.second; *szRet = aio.second;
return ECardResult::READY; return ECardResult::READY;
} }
if (GetOverlappedResult(m_fh, &aio.first, &aio.second, FALSE)) { if (GetOverlappedResult(m_inner->m_fh, &aio.first, &aio.second, FALSE)) {
CloseHandle(aio.first.hEvent); CloseHandle(aio.first.hEvent);
aio.first.hEvent = 0; aio.first.hEvent = 0;
if (szRet) if (szRet)
@ -124,12 +169,11 @@ ECardResult AsyncIO::pollStatus(size_t qIdx, SizeReturn* szRet) const {
ECardResult AsyncIO::pollStatus() const { ECardResult AsyncIO::pollStatus() const {
ECardResult result = ECardResult::READY; ECardResult result = ECardResult::READY;
for (auto it = const_cast<AsyncIO*>(this)->m_queue.begin(); for (auto it = m_inner->m_queue.begin(); it != m_inner->m_queue.begin() + m_maxBlock; ++it) {
it != const_cast<AsyncIO*>(this)->m_queue.begin() + m_maxBlock; ++it) {
auto& aio = *it; auto& aio = *it;
if (aio.first.hEvent == 0) if (aio.first.hEvent == 0)
continue; continue;
if (GetOverlappedResult(m_fh, &aio.first, &aio.second, FALSE)) { if (GetOverlappedResult(m_inner->m_fh, &aio.first, &aio.second, FALSE)) {
CloseHandle(aio.first.hEvent); CloseHandle(aio.first.hEvent);
aio.first.hEvent = 0; aio.first.hEvent = 0;
} else { } else {
@ -137,21 +181,30 @@ ECardResult AsyncIO::pollStatus() const {
if (result > ECardResult::BUSY) if (result > ECardResult::BUSY)
result = ECardResult::BUSY; result = ECardResult::BUSY;
} else { } else {
_waitForOperation(it - m_queue.cbegin()); _waitForOperation(it - m_inner->m_queue.cbegin());
if (result > ECardResult::IOERROR) if (result > ECardResult::IOERROR)
result = ECardResult::IOERROR; result = ECardResult::IOERROR;
} }
} }
} }
if (result == ECardResult::READY) if (result == ECardResult::READY)
const_cast<AsyncIO*>(this)->m_maxBlock = 0; m_maxBlock = 0;
return result; return result;
} }
void AsyncIO::waitForCompletion() const { void AsyncIO::waitForCompletion() const {
for (size_t i = 0; i < m_maxBlock; ++i) for (size_t i = 0; i < m_maxBlock; ++i)
_waitForOperation(i); _waitForOperation(i);
const_cast<AsyncIO*>(this)->m_maxBlock = 0; m_maxBlock = 0;
} }
void AsyncIO::resizeQueue(size_t queueSz) {
if (m_inner == nullptr) {
return;
}
m_inner->m_queue.resize(queueSz);
}
AsyncIO::operator bool() const { return m_inner != nullptr && m_inner->m_fh != INVALID_HANDLE_VALUE; }
} // namespace kabufuda } // namespace kabufuda