diff --git a/datalog/src/main/native/cpp/DataLogEditor.cpp b/datalog/src/main/native/cpp/DataLogEditor.cpp new file mode 100644 index 00000000000..89e72bf232e --- /dev/null +++ b/datalog/src/main/native/cpp/DataLogEditor.cpp @@ -0,0 +1,65 @@ +#include "wpi/datalog/DataLogEditor.hpp" +#include +#include +#include +#include +#include +#include +#include "wpi/datalog/DataLogReader.hpp" +#include "wpi/datalog/DataLogReaderThread.hpp" + +namespace wpi::log { + + DataLogEditor::DataLogEditor(std::unique_ptr datalog) { + state = std::make_shared(); + state->readerThread = std::move(datalog); + } + + DataLogEditor DataLogEditor::WithTimestamps(std::vector> timestamps) const { + state->filterTimestamps = true; + state->allowedTimestamps = timestamps; + return DataLogEditor{state}; + } + + DataLogEditor DataLogEditor::WithEntryNames(std::vector entryNames) const { + state->filterEntryNames = true; + state->allowedEntryNames = entryNames; + return DataLogEditor{state}; + } + + DataLogEditor DataLogEditor::WithRenamedEntries(std::map renames) const { + state->renameEntries = true; + state->entryRenames = std::move(renames); + return DataLogEditor{state}; + } + + std::vector DataLogEditor::ExecuteEdits() { + // we need to do the renames before we drop entries + const DataLogReaderEntry* entryData; + for (const DataLogRecord& record : state->records) { + entryData = state->readerThread->GetEntry(record.GetEntry()); + // exclude based on timestamp + auto timestamp = record.GetTimestamp(); + // if we allow this timestamp or it is a start/finish record, add it + if (std::ranges::any_of(state->allowedTimestamps, [timestamp](const std::pair& pair) { + return timestamp >= pair.first && timestamp <= pair.second; + }) || record.IsControl()) { + state->records.push_back(record); + } + + + if (record.IsStart() && state->entryRenames.contains(std::string{entryData->name})) { + // its the start record of the one we want and its guaranteed to be in the filtered list so lets replace it with a copy that includes the correct name + StartRecordData srd; + record.GetStartData(&srd); + srd.name = state->entryRenames[std::string{srd.name}]; + auto it = std::find_if(state->records.begin(), state->records.end(), [srd](DataLogRecord& targetRecord) { + return targetRecord.GetEntry() == srd.entry; + }); + ptrdiff_t idx = it - state->records.begin(); + state->records.at(idx) = DataLogRecord{entryData->entry, timestamp, reinterpret_cast>(srd)}; + } + } + return state->records; + } +} \ No newline at end of file diff --git a/datalog/src/main/native/include/wpi/datalog/DataLogEditor.hpp b/datalog/src/main/native/include/wpi/datalog/DataLogEditor.hpp new file mode 100644 index 00000000000..ee126c92dd0 --- /dev/null +++ b/datalog/src/main/native/include/wpi/datalog/DataLogEditor.hpp @@ -0,0 +1,46 @@ +#pragma once + +#include +#include +#include +#include +#include +#include "wpi/datalog/DataLogReader.hpp" +#include "wpi/datalog/DataLogReaderThread.hpp" + +namespace wpi::log { + class DataLogEditor { + public: + explicit DataLogEditor(std::unique_ptr datalog); + + DataLogEditor WithTimestamps(std::vector> timestamps) const; + + DataLogEditor WithEntryNames(std::vector entryNames) const; + + DataLogEditor WithRenamedEntries(std::map renames) const; + + std::vector ExecuteEdits(); + + private: + struct DataLogEditInfo { + // record list (input to the filter function) + std::vector records; + // used to get the initial record list and to check what entry a record is from + std::unique_ptr readerThread; + + // edit stage enable flags + bool filterTimestamps = false; + bool filterEntryNames = false; + bool renameEntries = false; + + // edit info + std::vector> allowedTimestamps; + std::vector allowedEntryNames; + std::map entryRenames; + }; + + explicit DataLogEditor(std::shared_ptr config) : state(std::move(config)) {} + + std::shared_ptr state; + }; +} \ No newline at end of file