#include #include namespace drvutil { static void strerror_safe(int errnum, char errbuf[256]) { int status = strerror_s(errbuf, 256, errnum); if (status != 0) { snprintf(errbuf, 256, "unknown errno %d", errnum); } } std::string strerror_str(int errnum) { char buf[256]; strerror_safe(errnum, buf); return buf; } class MonoClock { public: double freq_; LONGLONG base_; inline LONGLONG qpc() { LARGE_INTEGER x; BOOL status = QueryPerformanceCounter(&x); assert(status != 0); return x.QuadPart; } MonoClock() { LARGE_INTEGER x; BOOL status = QueryPerformanceFrequency(&x); assert(status != 0); freq_ = 1.0 / double(x.QuadPart); base_ = qpc(); } double get() { return (qpc() - base_) * freq_; } }; static MonoClock monoclock; double get_monotonic_clock() { return monoclock.get(); } void console_write(const std::u32string &cps) { if (cps.size() == 0) return; // Convert to wstring. Any character not representable as a single wchar_t // is replaced with a box. It's not ideal, but it's pretty good. std::wstring ws(cps.size(), 0); for (int i = 0; i < int(cps.size()); i++) { char32_t c = cps[i]; if (drvutil::is_single_wchar_t(c)) ws[i] = (wchar_t)c; else ws[i] = 0x2610; } HANDLE hstdout = GetStdHandle(STD_OUTPUT_HANDLE); assert(hstdout != INVALID_HANDLE_VALUE); DWORD nwrote; std::wstring_view v(ws); while (v.size() > 0) { int nwrite = v.size(); if (nwrite > 10000) nwrite = 10000; assert(WriteConsoleW(hstdout, v.data(), nwrite, &nwrote, nullptr)); assert(nwrote > 0); v.remove_prefix(nwrote); } } std::u32string console_read() { HANDLE hstdin = GetStdHandle(STD_INPUT_HANDLE); assert(hstdin != INVALID_HANDLE_VALUE); INPUT_RECORD inrecords[512]; DWORD nread, nevents; if (GetNumberOfConsoleInputEvents(hstdin, &nevents)) { if (int(nevents) > 0) { if (int(nevents) > 512) nevents = 512; ReadConsoleInputW(hstdin, inrecords, nevents, &nread); std::u32string result(nread, 0); int len = 0; for (int i = 0; i < int(nread); i++) { const INPUT_RECORD &inr = inrecords[i]; if (inr.EventType != KEY_EVENT) continue; const KEY_EVENT_RECORD &key = inr.Event.KeyEvent; if (!key.bKeyDown) continue; result[len++] = key.uChar.UnicodeChar; } return result.substr(0, len); } } return std::u32string(); } } // namespace drvutil