* @brief Native span fast lane: parses byte views directly into the claimed pool slot; @p frame * stays a structural template. Returns frames published, or -1 to use the QList path. */
| 1012 | * stays a structural template. Returns frames published, or -1 to use the QList path. |
| 1013 | */ |
| 1014 | int DataModel::FrameBuilder::trySpanLane(int sourceId, |
| 1015 | bool applyPerSourceOverride, |
| 1016 | DataModel::Frame& frame, |
| 1017 | const IO::CapturedDataPtr& data) |
| 1018 | { |
| 1019 | Q_ASSERT(sourceId >= 0); |
| 1020 | Q_ASSERT(data); |
| 1021 | |
| 1022 | if (m_playerOpen) [[unlikely]] |
| 1023 | return -1; |
| 1024 | |
| 1025 | if (frame.groups.empty()) [[unlikely]] |
| 1026 | return -1; |
| 1027 | |
| 1028 | if (resolveDecoderMethod(sourceId, applyPerSourceOverride) != SerialStudio::PlainText) |
| 1029 | return -1; |
| 1030 | |
| 1031 | static auto& parser = DataModel::FrameParser::instance(); |
| 1032 | const qsizetype tokens = |
| 1033 | parser.parseSpansUtf8(data->data, sourceId, m_spanScratch.data(), kMaxSpanFields); |
| 1034 | if (tokens < 0) |
| 1035 | return -1; |
| 1036 | |
| 1037 | if (tokens == 0) |
| 1038 | return 0; |
| 1039 | |
| 1040 | if (m_captureLatestFrame) [[unlikely]] |
| 1041 | captureLatestChannelSpans(sourceId, m_spanScratch.data(), tokens); |
| 1042 | |
| 1043 | TransformFrameInfo info; |
| 1044 | info.sourceId = sourceId; |
| 1045 | |
| 1046 | if (!m_transformEngines.empty()) [[unlikely]] { |
| 1047 | info.frameNumber = ++m_sourceFrameCounters[sourceId]; |
| 1048 | info.timestampMs = |
| 1049 | std::chrono::duration_cast<std::chrono::milliseconds>(data->timestamp.time_since_epoch()) |
| 1050 | .count(); |
| 1051 | } |
| 1052 | |
| 1053 | const size_t idx = claimPoolSlot(); |
| 1054 | if (idx == kInvalidSlotIdx) [[unlikely]] { |
| 1055 | notePoolExhausted(); |
| 1056 | auto heap = std::make_shared<TimestampedFrame>(frame, data->timestamp); |
| 1057 | heap->structureGeneration = m_framePoolGeneration; |
| 1058 | applyDatasetValuesSpans(heap->data, m_spanScratch.data(), tokens, info); |
| 1059 | hotpathTxFrame(heap); |
| 1060 | return 1; |
| 1061 | } |
| 1062 | |
| 1063 | const auto& slotOwner = m_framePool[idx]; |
| 1064 | auto* slotRaw = slotOwner.get(); |
| 1065 | |
| 1066 | (void)preparePooledSlot(slotRaw, frame); |
| 1067 | applyDatasetValuesSpans(slotRaw->flat.data(), |
| 1068 | static_cast<qsizetype>(slotRaw->flat.size()), |
| 1069 | m_spanScratch.data(), |
| 1070 | tokens, |
| 1071 | info); |