Skip to content

Commit 1eeb975

Browse files
author
Zachary DeBruine
committed
fix: remove <windows.h> entirely to avoid MinGW std::byte conflict
platform.hpp: return 0 (unknown) for RAM on Windows platform_io.hpp: use mutex-based _lseeki64+_read instead of ReadFile file_reader.hpp: use _open/_read/_lseeki64/_close instead of Win32 API All three files previously included <windows.h> which caused rpcndr.h byte typedef to collide with std::byte in C++17+ mode on MinGW (rtools45). Completely avoiding <windows.h> eliminates the ambiguity.
1 parent 5223758 commit 1eeb975

4 files changed

Lines changed: 43 additions & 91 deletions

File tree

inst/build_config

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,4 @@ cuda_version=
44
cuda_home=
55
nvcc_path=
66
gpu_arch=
7-
build_date=2026-03-14T16:07:22Z
7+
build_date=2026-03-14T19:31:56Z

inst/include/FactorNet/core/platform.hpp

Lines changed: 4 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,9 @@
1616
#include <string>
1717

1818
#if defined(_WIN32)
19-
// Workaround for MinGW C++17+: std::byte (from <cstddef>) conflicts
20-
// with rpcndr.h "typedef unsigned char byte;" inside <windows.h>.
21-
// Temporarily rename the Windows byte to avoid the ambiguity.
22-
#define WIN32_LEAN_AND_MEAN
23-
#ifndef NOMINMAX
24-
#define NOMINMAX
25-
#endif
26-
#define byte win_byte_override
27-
#include <windows.h>
28-
#undef byte
19+
// On Windows we avoid <windows.h> entirely because MinGW C++17+
20+
// introduces std::byte which conflicts with rpcndr.h's byte typedef.
21+
// RAM detection is unavailable; callers handle 0 gracefully.
2922
#elif defined(__APPLE__)
3023
#include <sys/sysctl.h>
3124
#include <unistd.h>
@@ -48,11 +41,7 @@ namespace FactorNet {
4841
*/
4942
inline uint64_t get_available_ram_bytes() {
5043
#if defined(_WIN32)
51-
MEMORYSTATUSEX status;
52-
status.dwLength = sizeof(status);
53-
if (GlobalMemoryStatusEx(&status))
54-
return static_cast<uint64_t>(status.ullAvailPhys);
55-
return 0;
44+
return 0; // Windows: <windows.h> avoided; callers treat 0 as "unknown"
5645
#elif defined(__APPLE__)
5746
int64_t page_size = sysconf(_SC_PAGE_SIZE);
5847
int64_t free_pages = 0;

inst/include/FactorNet/io/file_reader.hpp

Lines changed: 28 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,12 @@
1717
#include <string>
1818

1919
#ifdef _WIN32
20-
# ifndef WIN32_LEAN_AND_MEAN
21-
# define WIN32_LEAN_AND_MEAN
22-
# endif
23-
# include <windows.h>
20+
// Avoid <windows.h> entirely — MinGW C++17+ std::byte conflicts with
21+
// rpcndr.h byte typedef. Use POSIX-compat _open/_read/_lseeki64 instead.
22+
# include <io.h>
23+
# include <fcntl.h>
24+
# include <sys/stat.h>
25+
# include <mutex>
2426
#else
2527
# include <fcntl.h>
2628
# include <unistd.h>
@@ -33,35 +35,22 @@ namespace streampress {
3335
/// Platform-agnostic random-access file reader.
3436
/// Supports positional reads without moving any file cursor.
3537
/// Thread-safe for concurrent pread() calls on POSIX platforms.
38+
/// On Windows, uses a mutex to serialise _lseeki64 + _read.
3639
class FileReader {
3740
public:
3841
explicit FileReader(const std::string& path) {
3942
#ifdef _WIN32
40-
// Convert UTF-8 path to wide string
41-
int wlen = MultiByteToWideChar(CP_UTF8, 0, path.c_str(), -1, nullptr, 0);
42-
if (wlen <= 0)
43-
throw std::runtime_error("Cannot convert path to wide string: " + path);
44-
std::wstring wpath(wlen, L'\0');
45-
MultiByteToWideChar(CP_UTF8, 0, path.c_str(), -1, &wpath[0], wlen);
46-
47-
hFile_ = CreateFileW(
48-
wpath.c_str(),
49-
GENERIC_READ,
50-
FILE_SHARE_READ,
51-
nullptr,
52-
OPEN_EXISTING,
53-
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
54-
nullptr);
55-
if (hFile_ == INVALID_HANDLE_VALUE)
43+
fd_ = _open(path.c_str(), _O_RDONLY | _O_BINARY);
44+
if (fd_ < 0)
5645
throw std::runtime_error("Cannot open file: " + path);
57-
58-
LARGE_INTEGER li;
59-
if (!GetFileSizeEx(hFile_, &li)) {
60-
CloseHandle(hFile_);
61-
hFile_ = INVALID_HANDLE_VALUE;
46+
__int64 sz = _lseeki64(fd_, 0, SEEK_END);
47+
if (sz < 0) {
48+
_close(fd_);
49+
fd_ = -1;
6250
throw std::runtime_error("Cannot get file size: " + path);
6351
}
64-
file_size_ = static_cast<uint64_t>(li.QuadPart);
52+
file_size_ = static_cast<uint64_t>(sz);
53+
_lseeki64(fd_, 0, SEEK_SET);
6554
#else
6655
fd_ = ::open(path.c_str(), O_RDONLY);
6756
if (fd_ < 0)
@@ -86,31 +75,18 @@ class FileReader {
8675
// Movable
8776
FileReader(FileReader&& other) noexcept
8877
: file_size_(other.file_size_)
89-
#ifdef _WIN32
90-
, hFile_(other.hFile_)
91-
#else
9278
, fd_(other.fd_)
93-
#endif
9479
{
9580
other.file_size_ = 0;
96-
#ifdef _WIN32
97-
other.hFile_ = INVALID_HANDLE_VALUE;
98-
#else
9981
other.fd_ = -1;
100-
#endif
10182
}
10283

10384
FileReader& operator=(FileReader&& other) noexcept {
10485
if (this != &other) {
10586
close();
10687
file_size_ = other.file_size_;
107-
#ifdef _WIN32
108-
hFile_ = other.hFile_;
109-
other.hFile_ = INVALID_HANDLE_VALUE;
110-
#else
11188
fd_ = other.fd_;
11289
other.fd_ = -1;
113-
#endif
11490
other.file_size_ = 0;
11591
}
11692
return *this;
@@ -121,13 +97,13 @@ class FileReader {
12197
size_t pread(uint64_t offset, void* buf, size_t size) const {
12298
if (size == 0) return 0;
12399
#ifdef _WIN32
124-
OVERLAPPED ov = {};
125-
ov.Offset = static_cast<DWORD>(offset & 0xFFFFFFFF);
126-
ov.OffsetHigh = static_cast<DWORD>(offset >> 32);
127-
DWORD bytes_read = 0;
128-
if (!ReadFile(hFile_, buf, static_cast<DWORD>(size), &bytes_read, &ov))
129-
throw std::runtime_error("ReadFile failed at offset " + std::to_string(offset));
130-
return static_cast<size_t>(bytes_read);
100+
std::lock_guard<std::mutex> lock(mtx_);
101+
if (_lseeki64(fd_, static_cast<__int64>(offset), SEEK_SET) < 0)
102+
throw std::runtime_error("_lseeki64 failed at offset " + std::to_string(offset));
103+
int n = _read(fd_, buf, static_cast<unsigned int>(size));
104+
if (n < 0)
105+
throw std::runtime_error("_read failed at offset " + std::to_string(offset));
106+
return static_cast<size_t>(n);
131107
#else
132108
ssize_t n = ::pread(fd_, buf, size, static_cast<off_t>(offset));
133109
if (n < 0)
@@ -139,19 +115,13 @@ class FileReader {
139115

140116
uint64_t file_size() const { return file_size_; }
141117

142-
bool is_open() const {
143-
#ifdef _WIN32
144-
return hFile_ != INVALID_HANDLE_VALUE;
145-
#else
146-
return fd_ >= 0;
147-
#endif
148-
}
118+
bool is_open() const { return fd_ >= 0; }
149119

150120
void close() {
151121
#ifdef _WIN32
152-
if (hFile_ != INVALID_HANDLE_VALUE) {
153-
CloseHandle(hFile_);
154-
hFile_ = INVALID_HANDLE_VALUE;
122+
if (fd_ >= 0) {
123+
_close(fd_);
124+
fd_ = -1;
155125
}
156126
#else
157127
if (fd_ >= 0) {
@@ -163,10 +133,9 @@ class FileReader {
163133

164134
private:
165135
uint64_t file_size_ = 0;
166-
#ifdef _WIN32
167-
HANDLE hFile_ = INVALID_HANDLE_VALUE;
168-
#else
169136
int fd_ = -1;
137+
#ifdef _WIN32
138+
mutable std::mutex mtx_;
170139
#endif
171140
};
172141

inst/include/streampress/core/platform_io.hpp

Lines changed: 10 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -12,30 +12,24 @@
1212
#include <cstddef>
1313

1414
#ifdef _WIN32
15-
// Workaround for MinGW C++17+: std::byte vs rpcndr.h byte collision
16-
#define WIN32_LEAN_AND_MEAN
17-
#ifndef NOMINMAX
18-
#define NOMINMAX
19-
#endif
20-
#define byte win_byte_override
21-
#include <windows.h>
22-
#undef byte
15+
// Avoid <windows.h> entirely — MinGW C++17+ std::byte conflicts with
16+
// rpcndr.h byte typedef. Use _lseeki64 + _read under a mutex instead.
2317
#include <io.h>
18+
#include <fcntl.h>
19+
#include <mutex>
2420
#else
2521
#include <unistd.h>
2622
#endif
2723

2824
namespace streampress {
2925

3026
#ifdef _WIN32
31-
static inline ssize_t safe_pread(int fd, void* buf, size_t count, uint64_t offset) {
32-
HANDLE h = (HANDLE)_get_osfhandle(fd);
33-
OVERLAPPED ov = {};
34-
ov.Offset = static_cast<DWORD>(offset & 0xFFFFFFFFULL);
35-
ov.OffsetHigh = static_cast<DWORD>(offset >> 32);
36-
DWORD nread = 0;
37-
if (!ReadFile(h, buf, static_cast<DWORD>(count), &nread, &ov)) return -1;
38-
return static_cast<ssize_t>(nread);
27+
inline ssize_t safe_pread(int fd, void* buf, size_t count, uint64_t offset) {
28+
static std::mutex mtx;
29+
std::lock_guard<std::mutex> lock(mtx);
30+
if (_lseeki64(fd, static_cast<__int64>(offset), SEEK_SET) < 0) return -1;
31+
int n = _read(fd, buf, static_cast<unsigned int>(count));
32+
return static_cast<ssize_t>(n);
3933
}
4034
#else
4135
static inline ssize_t safe_pread(int fd, void* buf, size_t count, uint64_t offset) {

0 commit comments

Comments
 (0)