Closes #29
This commit is contained in:
1 parent
a702cffd93
commit
8d06165979
18 files changed
+611
-215
No files matched your search
@@ -0,0 +1,101 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#ifndef MULTIPLEX_GRAPH_H
|
||||
#define MULTIPLEX_GRAPH_H
|
||||
|
||||
#include "multiplexing.h"
|
||||
#include <cstddef>
|
||||
#include <stdexcept>
|
||||
|
||||
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<class Signal>
|
||||
explicit MultiplexGraph(const std::vector<Signal> &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<MultiplexRange>{{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<std::size_t> parents;
|
||||
std::vector<std::vector<MultiplexRange>> ranges;
|
||||
};
|
||||
}// namespace dbc_detail
|
||||
#endif
|
||||
Reference in new issue
Block a user