31template <
typename EventVariant>
33 constexpr size_t numTypes = std::variant_size_v<EventVariant>;
34 uint64_t hash = 0xcbf29ce484222325ULL;
35 hash ^=
static_cast<uint64_t
>(numTypes);
36 hash *= 0x100000001b3ULL;
67template <
typename EventVariant,
size_t BufferCapacity = 4096>
87 template <
typename Event>
89 static_assert(std::is_trivially_copyable_v<Event>,
"Event must be trivially copyable for journal serialization.");
90 constexpr size_t typeIdx = corium::variant_index_v<Event, EventVariant>;
91 static_assert(typeIdx !=
static_cast<size_t>(-1),
"Event type is not in the specified EventVariant.");
94 if (m_offset + recordSize > BufferCapacity) {
100 recHeader.typeIndex =
static_cast<uint32_t
>(typeIdx);
101 recHeader.payloadLength =
static_cast<uint32_t
>(
sizeof(
Event));
102 recHeader.priority =
static_cast<uint8_t
>(priority);
103 recHeader.typeSignature = computeTypeSignature<Event>();
105 reinterpret_cast<const uint8_t*
>(&event),
sizeof(
Event)));
112 std::memcpy(&m_buffer[m_offset], &event,
sizeof(
Event));
113 m_offset +=
sizeof(
Event);
122 return m_recordCount;
131 [[nodiscard]] std::span<const uint8_t>
data() const noexcept {
132 return std::span<const uint8_t>(m_buffer.data(), m_offset);
136 void initHeader() noexcept {
140 hdr.schemaHash = computeVariantSchemaHash<EventVariant>();
143 std::memcpy(&m_buffer[0], &hdr,
sizeof(JournalHeader));
144 m_offset =
sizeof(JournalHeader);
147 void updateHeaderCount() noexcept {
148 auto* hdr =
reinterpret_cast<JournalHeader*
>(&m_buffer[0]);
149 hdr->recordCount =
static_cast<uint32_t
>(m_recordCount);
152 std::array<uint8_t, BufferCapacity> m_buffer{};
154 size_t m_recordCount{0};
160template <
typename EventVariant>
165 : m_data(journalData) {
166 validateAndParseHeader();
188 template <
typename Sink>
202 if (payloadStart + recHeader.payloadLength > m_data.size()) {
208 &m_data[payloadStart], recHeader.payloadLength));
209 if (recHeader.checksum != expectedCrc) {
214 constexpr size_t numTypes = std::variant_size_v<EventVariant>;
215 if (recHeader.typeIndex < numTypes) {
216 bool pushed = deserializeIndex<Sink>(
218 &m_data[payloadStart],
220 std::make_index_sequence<numTypes>{}
227 m_cursor = payloadStart + recHeader.payloadLength;
234 void validateAndParseHeader() noexcept {
240 std::memcpy(&m_header, m_data.data(),
sizeof(JournalHeader));
250 if (m_header.
schemaHash != computeVariantSchemaHash<EventVariant>()) {
256 m_cursor =
sizeof(JournalHeader);
259 template <
typename Sink,
size_t... Is>
260 bool deserializeIndex(
261 const JournalRecordHeader& recHeader,
262 const uint8_t* payload,
264 std::index_sequence<Is...>
266 bool handled =
false;
267 (void)((recHeader.typeIndex == Is ? (handled = deserializeExact<Is, Sink>(recHeader, payload, sink),
true) : false) || ...);
271 template <
size_t Index,
typename Sink>
272 bool deserializeExact(
273 const JournalRecordHeader& recHeader,
274 const uint8_t* payload,
277 using TargetEvent = std::variant_alternative_t<Index, EventVariant>;
278 if (recHeader.payloadLength !=
sizeof(TargetEvent)) {
282 if (recHeader.typeSignature != 0 && recHeader.typeSignature != computeTypeSignature<TargetEvent>()) {
287 std::memcpy(&evt, payload,
sizeof(TargetEvent));
289 sink.post(EventVariant{std::move(evt)}, prio);
293 std::span<const uint8_t> m_data;
294 JournalHeader m_header{};
Bounded and multi-tier priority MPSC queueing policies.
Compile-time type index resolution for std::variant alternative types.
Binary packet framing with CRC-16 checksum and schema versioning.
Zero-heap event journal reader and deterministic player into Corium EventSinks.
Definition EventJournal.hpp:161
void rewind() noexcept
Rewind playback cursor to the first record.
Definition EventJournal.hpp:180
bool isValid() const noexcept
Returns true if the journal header is valid (magic, version, schema match).
Definition EventJournal.hpp:170
size_t totalRecords() const noexcept
Total number of records declared in the header.
Definition EventJournal.hpp:175
EventJournalReader(std::span< const uint8_t > journalData) noexcept
Construct reader over a byte span.
Definition EventJournal.hpp:164
size_t replayInto(Sink &sink) noexcept
Replay all valid records in the journal directly into an EventSink.
Definition EventJournal.hpp:189
Statically allocated binary event journal writer for zero-heap post-mortem logging and record playbac...
Definition EventJournal.hpp:68
void reset() noexcept
Reset journal to initial empty state.
Definition EventJournal.hpp:75
constexpr EventJournalWriter() noexcept
Definition EventJournal.hpp:70
std::span< const uint8_t > data() const noexcept
Read-only view of the serialized journal data.
Definition EventJournal.hpp:131
size_t bytesWritten() const noexcept
Total bytes written into buffer (header + all records).
Definition EventJournal.hpp:126
size_t recordCount() const noexcept
Number of records written.
Definition EventJournal.hpp:121
bool record(const Event &event, uint64_t timestampUs, EventPriority priority=EventPriority::Normal) noexcept
Record a concrete typed event into the journal.
Definition EventJournal.hpp:88
Definition EventJournal.hpp:22
constexpr uint64_t computeVariantSchemaHash() noexcept
Computes a deterministic 64-bit ABI hash for an EventVariant type.
Definition EventJournal.hpp:32
constexpr uint32_t CORIUM_JOURNAL_MAGIC
Magic identifier for Corium binary event journals ("JOUR" in hex: 0x4a4f5552).
Definition EventJournal.hpp:25
constexpr uint32_t CORIUM_JOURNAL_VERSION
Current schema version for Corium event journals.
Definition EventJournal.hpp:28
constexpr uint16_t calculateCrc16(std::span< const uint8_t > data) noexcept
Calculate CRC-16-CCITT checksum over a byte span without lookup tables.
Definition WirePacket.hpp:21
EventPriority
Event priority levels for multi-priority queue policies.
Definition QueuePolicies.hpp:32
DefaultEvents Event
Alias for DefaultEvents.
Definition Events.hpp:65