bbox: pull out implementation

This commit is contained in:
Dustin L. Howett
2025-03-07 15:59:45 -06:00
parent 1b8163f42c
commit d764596b6a
3 changed files with 145 additions and 137 deletions

View File

@@ -1,6 +1,11 @@
#include "pch.h"
#include <til/spsc.h>
#include <til/unicode.h>
#include <til/u8u16convert.h>
#include "Blackbox.h"
#pragma warning(push)
#pragma warning(disable : 26446)
@@ -80,146 +85,33 @@ namespace
}
}
struct Blackbox : public std::enable_shared_from_this<Blackbox>
void Blackbox::Thread(til::spsc::consumer<Record> rx)
{
struct Record
Record queue[16];
wil::unique_hfile file;
do
{
Record() :
time{}, typecode{ 0 }, string{ nullptr } {}
Record(char type, HSTRING f) :
time{ std::chrono::high_resolution_clock::now() }, typecode{ type } { WindowsDuplicateString(f, &string); }
Record(HSTRING f) :
Record('o', f) {}
Record(Record&& r) :
time{ r.time },
typecode{ r.typecode },
string{ r.string }
int i = 0;
auto [sz, ok] = rx.pop_n(til::spsc::block_initially, queue, std::extent_v<decltype(queue)>);
while (sz--)
{
r.string = nullptr;
Record rec = std::move(queue[i++]);
auto timeDelta = (rec.time - _start).count() / 1e9f;
UINT32 length{ 0 };
auto buf = WindowsGetStringRawBuffer(rec.string, &length);
auto jsonLine{ fmt::format(FMT_COMPILE(R"-([{}, "{}", "{}"])-"
"\n"),
timeDelta,
(char)rec.typecode,
u16json8(std::wstring_view{ buf, length })) };
WriteFile(_file.get(), jsonLine.data(), (DWORD)jsonLine.size(), nullptr, nullptr);
}
Record& operator=(Record&& r)
if (!ok)
{
time = r.time;
typecode = r.typecode;
string = r.string;
r.string = nullptr;
return *this;
break; // FINISH IT OFF DAVE
}
~Record()
{
if (string)
{
WindowsDeleteString(string);
}
}
std::chrono::high_resolution_clock::time_point time;
char typecode{ 0 };
HSTRING string{ nullptr };
};
Blackbox(std::wstring_view filePath) :
_filePath{ filePath }
{
}
~Blackbox()
{
Close();
}
void Start()
{
_file.reset(CreateFileW(_filePath.c_str(), GENERIC_WRITE, FILE_SHARE_READ, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr));
THROW_LAST_ERROR_IF(!_file);
_start = std::chrono::high_resolution_clock::now();
auto [tx, rx] = til::spsc::channel<Record>(1024);
_chan = std::move(tx);
auto s{ fmt::format(R"-({{"version": 2, "width": 120, "height": 30}})-"
"\n") };
WriteFile(_file.get(), s.data(), (DWORD)s.size(), nullptr, nullptr);
_thread = std::thread([this, strong = shared_from_this(), rx = std::move(rx)]() mutable {
Thread(std::move(rx));
});
}
void Log(HSTRING h)
{
if (!_closed)
{
_chan.emplace(h);
}
}
void Log(const winrt::hstring& h) { Log((HSTRING)winrt::get_abi(h)); }
void LogResize(til::CoordType columns, til::CoordType rows)
{
if (!_closed)
{
//? TODO(DH) determine whether we should pass the size along as a string or just make Record a tagged union w/ typecode
winrt::hstring newSizeRecord{ fmt::format(FMT_COMPILE(L"{0}x{1}"), columns, rows) };
_chan.emplace('r', (HSTRING)winrt::get_abi(newSizeRecord));
}
}
void Close()
{
if (!std::exchange(_closed, true))
{
{
auto _ = std::move(_chan);
// the tx side of the channel closes at the end of this scope
}
// we may be getting destructed on the Thread thread.
if (_thread.get_id() != std::this_thread::get_id())
{
_thread.join(); // flush
}
}
}
void Thread(til::spsc::consumer<Record> rx)
{
Record queue[16];
wil::unique_hfile file;
do
{
int i = 0;
auto [sz, ok] = rx.pop_n(til::spsc::block_initially, queue, std::extent_v<decltype(queue)>);
while (sz--)
{
Record rec = std::move(queue[i++]);
auto timeDelta = (rec.time - _start).count() / 1e9f;
UINT32 length{ 0 };
auto buf = WindowsGetStringRawBuffer(rec.string, &length);
auto jsonLine{ fmt::format(FMT_COMPILE(R"-([{}, "{}", "{}"])-"
"\n"),
timeDelta,
(char)rec.typecode,
u16json8(std::wstring_view{ buf, length })) };
WriteFile(_file.get(), jsonLine.data(), (DWORD)jsonLine.size(), nullptr, nullptr);
}
if (!ok)
{
break; // FINISH IT OFF DAVE
}
} while (true);
_file.reset();
}
private:
std::thread _thread;
std::chrono::high_resolution_clock::time_point _start;
til::spsc::producer<Record> _chan{ nullptr };
bool _closed{ false };
std::wstring _filePath;
wil::unique_hfile _file;
};
#pragma warning(pop)
} while (true);
_file.reset();
}

View File

@@ -0,0 +1,114 @@
struct Blackbox : public std::enable_shared_from_this<Blackbox>
{
struct Record
{
Record() :
time{}, typecode{ 0 }, string{ nullptr } {}
Record(char type, HSTRING f) :
time{ std::chrono::high_resolution_clock::now() }, typecode{ type } { WindowsDuplicateString(f, &string); }
Record(HSTRING f) :
Record('o', f) {}
Record(Record&& r) :
time{ r.time },
typecode{ r.typecode },
string{ r.string }
{
r.string = nullptr;
}
Record& operator=(Record&& r)
{
time = r.time;
typecode = r.typecode;
string = r.string;
r.string = nullptr;
return *this;
}
~Record()
{
if (string)
{
WindowsDeleteString(string);
}
}
std::chrono::high_resolution_clock::time_point time;
char typecode{ 0 };
HSTRING string{ nullptr };
};
Blackbox(std::wstring_view filePath) :
_filePath{ filePath }
{
}
~Blackbox()
{
Close();
}
void Start()
{
_file.reset(CreateFileW(_filePath.c_str(), GENERIC_WRITE, FILE_SHARE_READ, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr));
THROW_LAST_ERROR_IF(!_file);
_start = std::chrono::high_resolution_clock::now();
auto [tx, rx] = til::spsc::channel<Record>(1024);
_chan = std::move(tx);
auto s{ fmt::format(R"-({{"version": 2, "width": 120, "height": 30}})-"
"\n") };
WriteFile(_file.get(), s.data(), (DWORD)s.size(), nullptr, nullptr);
_thread = std::thread([this, strong = shared_from_this(), rx = std::move(rx)]() mutable {
Thread(std::move(rx));
});
}
void Log(HSTRING h)
{
if (!_closed)
{
_chan.emplace(h);
}
}
void Log(const winrt::hstring& h) { Log((HSTRING)winrt::get_abi(h)); }
void LogResize(til::CoordType columns, til::CoordType rows)
{
if (!_closed)
{
//? TODO(DH) determine whether we should pass the size along as a string or just make Record a tagged union w/ typecode
winrt::hstring newSizeRecord{ fmt::format(FMT_COMPILE(L"{0}x{1}"), columns, rows) };
_chan.emplace('r', (HSTRING)winrt::get_abi(newSizeRecord));
}
}
void Close()
{
if (!std::exchange(_closed, true))
{
{
auto _ = std::move(_chan);
// the tx side of the channel closes at the end of this scope
}
// we may be getting destructed on the Thread thread.
if (_thread.get_id() != std::this_thread::get_id())
{
_thread.join(); // flush
}
}
}
void Thread(til::spsc::consumer<Record> rx);
private:
std::thread _thread;
std::chrono::high_resolution_clock::time_point _start;
til::spsc::producer<Record> _chan{ nullptr };
bool _closed{ false };
std::wstring _filePath;
wil::unique_hfile _file;
};
#pragma warning(pop)

View File

@@ -84,6 +84,7 @@
<ClInclude Include="ActionPaletteItem.h" />
<ClInclude Include="App.base.h" />
<ClInclude Include="AppCommandlineArgs.h" />
<ClInclude Include="Blackbox.h" />
<ClInclude Include="Commandline.h" />
<ClInclude Include="CommandLinePaletteItem.h" />
<ClInclude Include="Jumplist.h" />
@@ -193,6 +194,7 @@
<ItemGroup>
<ClCompile Include="ActionPaletteItem.cpp" />
<ClCompile Include="CommandLinePaletteItem.cpp" />
<ClCompile Include="Blackbox.cpp" />
<ClCompile Include="init.cpp" />
<ClCompile Include="AppCommandlineArgs.cpp" />
<ClCompile Include="Commandline.cpp" />