这里的实际数据类型可能与发布答案无关。我在这里使用Qt类型,但这个问题也适用于其他结构化类型。
我使用QtSerialBus模块在Qt中通过can总线接收数据帧。我想查找每个接收到的帧,如果它与我在QList中维护的一个D4匹配。
为了查看一个过滤器是否与当前接收到的帧匹配,我最初想出了这些代码行。下面的编辑显示了代码的演变过程,这样任何人都可以看到进展。
bool MyCanClass::isFrameMatchedByFilter(const QCanBusFrame& frameToFilter)
{
if (mFilterList.isEmpty()) {
return true;
} else {
for (auto& filter : mFilterList) {
// Go down the chain as far as needed and proceed to the next list entry as soon as a mismatch comes up
// First ID/Mask filtering, format and type afterwards
if ((frameToFilter.frameId() & filter.frameId) != (filter.frameId & filter.frameIdMask)) {
continue;
}
// FrameFormat only matters if set either base or extended, not both
if (filter.format != QCanBusDevice::Filter::FormatFilter::MatchBaseAndExtendedFormat) {
if (!(frameToFilter.hasExtendedFrameFormat() == (filter.format == QCanBusDevice::Filter::FormatFilter::MatchExtendedFormat))) {
continue;
}
}
// Invalid frame is the default and matches every frame type
if (filter.type != QCanBusFrame::FrameType::InvalidFrame) {
if (filter.type != frameToFilter.frameType()) {
continue;
}
}
return true;
}
return false;
}
}我个人认为嵌套的水平和一般的方法在这里并不太不干净,但它可能会得到改进,以便它更容易理解,甚至更快。
经过几个步骤的重构,基于我得到的答案,我重构了所有的东西,使它更模块化,更容易理解。
我可能会事先对过滤器列表中的in进行排序,以便通过二进制搜索获得速度,但我不确定是否值得这样做,所以现在我将继续这样做:
bool MyCanClass::isFrameOfInterest(const QCanBusFrame& frame)
{
if (mFilterList.isEmpty()) {
return true;
} else {
return isCanFrameMatchingFilterList(frame, mFilterList);
}
}
bool isCanFrameMatchingFilterList(const QCanBusFrame& frame, const QList& filterList)
{
for (auto& filter : filterList) {
// Go down the chain as far as needed and proceed to the next list entry as soon as a mismatch comes up
// First ID/Mask filtering, format and type afterwards
if (!isCanIdMatchedByFilter(frame, filter)) {
continue;
}
// FrameFormat only matters if set either base or extended, not both
if (!isFrameFormatMatchedByFilter(frame, filter)) {
continue;
}
// Invalid frame is the default and matches every frame type
if (!isFrameTypeMatchedByFilter(frame, filter)) {
continue;
}
return true;
}
return false;
}
bool isCanIdMatchedByFilter(const QCanBusFrame& frame, const QCanBusDevice::Filter& filter)
{
return (frame.frameId() & filter.frameId) == (filter.frameId & filter.frameIdMask);
}
bool isFrameFormatMatchedByFilter(const QCanBusFrame& frame, const QCanBusDevice::Filter& filter)
{
if (filter.format == QCanBusDevice::Filter::FormatFilter::MatchBaseAndExtendedFormat) {
return true;
}
bool extended = frame.hasExtendedFrameFormat();
if (filter.format == QCanBusDevice::Filter::FormatFilter::MatchBaseFormat) {
return (extended) ? false : true;
} else {
return (extended) ? true : false;
}
}
bool isFrameTypeMatchedByFilter(const QCanBusFrame& frame, const QCanBusDevice::Filter& filter)
{
// invalid frame matches all frame types
if (filter.type != QCanBusFrame::FrameType::InvalidFrame) {
if (filter.type != frame.frameType()) {
return false;
}
}
return true;
}虽然新的isFrameFormatMatchedByFilter()在第一个视图中更容易理解,但我假设至少需要两个额外的指令来在CPU上执行该代码,我错了吗?
要弄清楚您自己的代码的哪一部分被认为“太聪明”而哪些不是:)总是有点困难。)
发布于 2019-04-26 12:24:50
当然,它可以更清洁、更清晰:
isFrameMatchedByFilter,但如果筛选列表中没有筛选器,则返回true :这是否意味着帧由一个空筛选器匹配?还不清楚,您需要找到另一个名称或更改函数的行为。frameToFilter,但这是个坏主意。首先,因为这个函数中只有一个框架,而且frame比frameToFilter短;其次,frameToFilter也可以被解释为一种从框架到过滤器的转换(例如,在to_string中)。std::any_of,或者,如果您稍微改变语义,std::find_if:返回匹配的过滤器可能会很有趣,而不是一个简单的bool。然后,您只需要将返回迭代器与filter_list.end()进行比较,就可以生成bool。(frameToFilter.frameId() & filter.frameId) != (filter.frameId & filter.frameIdMask)可能意味着什么,我没有什么实质性的想法。一个函数,甚至一个简单的λ来启发读者是很好的。它还将封装此计算,您可以将其更改为更健壮的系统(就像enum -but,我不知道上下文,因此可能不是正确的选择)。!(frameToFilter.hasExtendedFrameFormat() == (filter.format == QCanBusDevice::Filter::FormatFilter::MatchExtendedFormat))太聪明了。再一次,在它周围写一个一行,或者至少写一个凡人能读的方式(我的意思是,没有50%的机会不能正确理解它)。能再快一点吗?这取决于几个因素:您可以重新安排匹配条件,使其具有最快的*如果还没有完成,首先进行最有区别的选择(但它看起来是正确的顺序);您可以按id对筛选器进行排序,并执行二进制搜索,而不是平面搜索;如果存在大量的匹配条件,则可以并行。但是像往常一样,只有当它值得-measure的时候才能进行优化。
https://codereview.stackexchange.com/questions/219177
复制相似问题