This commit is contained in:
deeaitch committed 2026-10-11 06:30:18 -04:00
1 parent 51fcdb88ac
commit 0708316a37
155 files changed
+5190 -2691

No files matched your search

+87 -20
View File
@@ -321,7 +321,7 @@ This structure is used directly by the decoder.
## `FrameKey`
Fast lookup key for runtime frame matching.
Stable identifier for runtime frame matching and application state.
Fields:
@@ -334,22 +334,20 @@ This matters because the same numeric identifier must not be confused between st
## `DecodeDatabase`
Top-level runtime decode container.
Immutable runtime snapshot with a private frame index. Build it with
`DbcDecodeBuilder::Build(parsed)` or construct it from `std::vector<DecodeFrame>`.
Construction rejects duplicate frame keys and duplicate signal names within a
frame with `std::invalid_argument`, including manually supplied metadata.
Fields:
- `GetFrames()` returns a borrowed `const std::vector<DecodeFrame>&`.
- `FindFrame(FrameKey)` returns `std::shared_ptr<const DecodeFrame>`.
- `FindSignal(SignalKey)` returns `std::shared_ptr<const DecodeSignal>`.
- Missing definitions return an empty handle.
- Copying a database shares its snapshot; replacing it installs another snapshot.
- `frames`
- `frameIndexByKey`
Conceptually:
```text
DecodeDatabase
├── vector<DecodeFrame>
└── unordered_map<FrameKey, index>
```
This gives the decoder fast access to a frame definition using CAN ID and frame type.
Frame lookup uses a hash index; signal lookup scans the matched frame's signals.
Decoding shares the snapshot without copying definitions or allocating ownership
objects per signal.
---
@@ -380,6 +378,7 @@ Represents one decoded signal result.
Fields:
- `definition`
- `key`
- `rawValue`
- `physicalValue`
- `valid`
@@ -426,6 +425,7 @@ Represents one decoded frame result.
Fields:
- `definition`
- `key`
- `signals`
- `valid`
@@ -433,10 +433,77 @@ Fields:
`valid` separately: insufficient payload data can leave individual signals
invalid even when the frame is valid. An unknown frame returns `valid == false`.
The frame and signal `definition` pointers refer into `DecodeDatabase`. Keep
that database alive and avoid changes that invalidate its frame or signal
storage while using decoded results. The decoder applies factor and offset;
it does not clamp physical values to the declared minimum and maximum.
The decoder applies factor and offset; it does not clamp physical values to the
declared minimum and maximum.
### Definition ownership and reload
`DecodedFrameValue::definition` and `DecodedSignalValue::definition` are owning
`std::shared_ptr<const ...>` handles. Each handle retains the immutable runtime
snapshot. Definitions remain valid until the last database copy, lookup handle,
or decoded result owning that snapshot is released. An independently copied
signal result retains its definition even after the parent frame result is
removed. Copying or moving results preserves ownership.
Reload by assigning a newly built database. Stored results continue to describe
the old DBC, including its units, scaling, comments, and `VAL_` descriptions;
subsequent decoding uses the new DBC. Removed definitions cannot be found in the
new database, but old results safely retain their old definitions. Keeping even
one signal handle retains the whole old snapshot; release stored results when
that metadata is no longer needed.
`GetFrames()` is a borrowed view. References, iterators, and raw pointers obtained
from it or from a handle's `.get()` do not retain ownership. Keep an owning handle
or an unchanged database copy while using them. Do not retain mutable aliases
into a vector moved into the database constructor. The raw string pointer from
`GetValueDescription()` follows the same rule: keep the signal definition handle
alive while using the string.
Parsed `DbcDatabase`/`FrameInfo`/`SignalInfo` remain ordinary mutable value
containers: borrowed pointers follow standard vector invalidation rules. Builders
copy their metadata, so parsed input may be changed or destroyed after building.
Tree nodes own metadata copies; the Qt model owns its tree and invalidates model
indexes on reset. Runtime handles do not depend on the parsed database or tree.
Synchronize replacement of a shared database variable with decoding; immutable
snapshots do not make concurrent assignment to the same object safe.
### Stable frame and signal identifiers
`DecodedFrameValue::key` is a `FrameKey` (normalized `canId`, `isExtended`), also
available through `DecodeFrame::GetKey()`. `DecodedSignalValue::key` is a
`SignalKey` (frame key, exact case-sensitive signal name). Both are value types
with equality and hashers (`FrameKeyHasher`, `SignalKeyHasher`) for application
maps and saved selections. Construct the same keys from parsed metadata when
needed; do not use addresses or vector positions as identifiers.
Keys stay equal across reloads and reordering when their components stay equal.
Frame renaming and changes to units, bit layout, scaling, or descriptions do not
change a key. Changing a CAN ID/frame type or renaming a signal produces a new
key. The same name in different frames and standard/extended frames with the
same numeric CAN ID remain distinct. Keys identify definitions within one logical
DBC database; applications combining databases must add their own database ID.
A key is not a version identifier: matching keys in different snapshots may have
different metadata. Use `valid`/the definition handle to distinguish a matched
result; default keys alone do not indicate successful decoding.
```cpp
DecodeDatabase runtime = DbcDecodeBuilder().Build(parsed);
DecodedFrameValue stored = DbcDecoder().Decode(runtime, rawFrame);
if (stored.valid && !stored.signals.empty()) {
DecodedSignalValue saved = stored.signals.front();
SignalKey selection = saved.key;
runtime = DbcDecodeBuilder().Build(parser.ParseFile("updated.dbc"));
std::shared_ptr<const DecodeSignal> current = runtime.FindSignal(selection);
// saved.definition retains old metadata; current holds new metadata or is empty.
}
```
**API migration:** replace reads of `runtime.frames` with `runtime.GetFrames()`.
To edit runtime definitions, prepare a vector and construct a new database;
`frameIndexByKey` is now private and built automatically. `DbcDecoder::FindFrame`
and result `definition` fields now use owning handles instead of raw pointers;
`definition->name`, boolean/null checks, and existing decode calls remain usable.
Use `.get()` only for temporary raw-pointer interoperation with an owner alive.
---
@@ -986,7 +1053,7 @@ if (const std::string *description = value.GetValueDescription()) {
It returns `nullptr` for an invalid decode or an unknown value; numeric decoding
and `physicalValue` are unchanged. A mapped empty string returns a non-null
pointer. The pointer belongs to the signal definition and stays valid while that
definition and mapping remain alive and unchanged.
definition remains alive. A decoded signal owns its immutable definition across reload.
For metadata or standalone raw values, use
`FindValueDescription(signal.valueDescriptions, rawValue)`, where `rawValue` is