// SPDX-License-Identifier: MIT #ifndef MULTIPLEX_GRAPH_H #define MULTIPLEX_GRAPH_H #include "multiplexing.h" #include #include namespace dbc_detail { /** Validation failure associated with a signal in declaration order. */ class MultiplexError : public std::invalid_argument { public: MultiplexError(std::size_t signalIndex, const std::string &message) : std::invalid_argument(message), index(signalIndex) {} std::size_t index; }; /** Resolved parent links shared by parser validation and runtime decoding. */ class MultiplexGraph { public: template explicit MultiplexGraph(const std::vector &signals) : parents(signals.size(), signals.size()), ranges(signals.size()) { const std::size_t count = signals.size(); for (std::size_t index = 0U; index < count; ++index) { const Multiplexing &mux = signals[index].multiplexing; if (mux.role != MultiplexRole::Unconditional && mux.role != MultiplexRole::Selector && mux.role != MultiplexRole::Branch && mux.role != MultiplexRole::BranchSelector) throw MultiplexError(index, "Invalid multiplexing role."); if (mux.selector.empty() != mux.ranges.empty()) throw MultiplexError(index, "Selector name and ranges must be supplied together."); if (mux.selector.empty() && !IsMultiplexBranch(mux.role)) continue; std::size_t parent = count; for (std::size_t candidate = 0U; candidate < count; ++candidate) { const Multiplexing &other = signals[candidate].multiplexing; const bool matches = !mux.selector.empty() ? signals[candidate].name == mux.selector : other.role == MultiplexRole::Selector && other.selector.empty(); if (!matches) continue; if (parent != count) throw MultiplexError(index, "Ambiguous multiplex selector; use SG_MUL_VAL_."); parent = candidate; } if (parent == count) throw MultiplexError(index, "Multiplexed branch has no selector."); if (!IsMultiplexSelector(signals[parent].multiplexing.role)) throw MultiplexError(index, "Referenced signal is not a multiplex selector."); parents[index] = parent; ranges[index] = mux.selector.empty() ? std::vector{{mux.value, mux.value}} : mux.ranges; for (const MultiplexRange &range: ranges[index]) { if (range.minimum > range.maximum) throw MultiplexError(index, "Reversed multiplex range."); if (signals[parent].length < 64U && range.maximum >= (std::uint64_t(1U) << signals[parent].length)) throw MultiplexError(index, "Branch value exceeds selector raw range."); } } for (std::size_t index = 0U; index < count; ++index) { std::size_t current = index; for (std::size_t depth = 0U; current != count; ++depth) { if (depth >= count) throw MultiplexError(index, "Cyclic multiplex selector dependency."); current = parents[current]; } } } bool Matches(std::size_t index, std::uint64_t value) const { for (const MultiplexRange &range: ranges[index]) { if (range.minimum <= value && value <= range.maximum) return true; } return false; } bool AreMutuallyExclusive(std::size_t first, std::size_t second) const { const std::size_t count = parents.size(); for (std::size_t left = first; parents[left] != count; left = parents[left]) { for (std::size_t right = second; parents[right] != count; right = parents[right]) { if (parents[left] != parents[right]) continue; bool intersects = false; for (const MultiplexRange &a: ranges[left]) { for (const MultiplexRange &b: ranges[right]) { if (a.minimum <= b.maximum && b.minimum <= a.maximum) intersects = true; } } if (!intersects) return true; } } return false; } std::vector parents; std::vector> ranges; }; }// namespace dbc_detail #endif