Add and use mapTuple helper.

This commit is contained in:
Daniel Kirchner 2021-01-13 17:23:27 +01:00
parent 91cdb606a5
commit f34d7120a2
2 changed files with 49 additions and 16 deletions

View File

@ -265,6 +265,39 @@ decltype(auto) valueOrDefault(MapType&& _map, KeyType const& _key, ValueType&& _
return (it == _map.end()) ? _defaultValue : it->second;
}
namespace detail
{
template<typename Callable>
struct MapTuple
{
Callable callable;
template<typename TupleType>
decltype(auto) operator()(TupleType&& _tuple) {
using PlainTupleType = std::remove_cv_t<std::remove_reference_t<TupleType>>;
return operator()(
std::forward<TupleType>(_tuple),
std::make_index_sequence<std::tuple_size_v<PlainTupleType>>{}
);
}
private:
template<typename TupleType, size_t... I>
decltype(auto) operator()(TupleType&& _tuple, std::index_sequence<I...>)
{
return callable(std::get<I>(std::forward<TupleType>(_tuple))...);
}
};
}
/// Wraps @a _callable, which takes multiple arguments, into a callable that takes a single tuple of arguments.
/// Since structured binding in lambdas is not allowed, i.e. [](auto&& [key, value]) { ... } is invalid, this allows
/// to instead use mapTuple([](auto&& key, auto&& value) { ... }).
template<typename Callable>
decltype(auto) mapTuple(Callable&& _callable)
{
return detail::MapTuple<Callable>{std::forward<Callable>(_callable)};
}
// String conversion functions, mainly to/from hex/nibble/byte representations.
enum class WhenError

View File

@ -63,19 +63,19 @@ void DataFlowAnalyzer::operator()(ExpressionStatement& _statement)
if (auto vars = isSimpleStore(StoreLoadLocation::Storage, _statement))
{
ASTModifier::operator()(_statement);
cxx20::erase_if(m_storage, [&](auto const& entry) {
cxx20::erase_if(m_storage, mapTuple([&](auto&& key, auto&& value) {
return
!m_knowledgeBase.knownToBeDifferent(vars->first, entry.first) &&
!m_knowledgeBase.knownToBeEqual(vars->second, entry.second);
});
!m_knowledgeBase.knownToBeDifferent(vars->first, key) &&
!m_knowledgeBase.knownToBeEqual(vars->second, value);
}));
m_storage[vars->first] = vars->second;
}
else if (auto vars = isSimpleStore(StoreLoadLocation::Memory, _statement))
{
ASTModifier::operator()(_statement);
cxx20::erase_if(m_memory, [&](auto const& entry) {
return !m_knowledgeBase.knownToBeDifferentByAtLeast32(vars->first, entry.first);
});
cxx20::erase_if(m_memory, mapTuple([&](auto&& key, auto&& /* value */) {
return !m_knowledgeBase.knownToBeDifferentByAtLeast32(vars->first, key);
}));
m_memory[vars->first] = vars->second;
}
else
@ -261,11 +261,11 @@ void DataFlowAnalyzer::handleAssignment(set<YulString> const& _variables, Expres
// assignment to slot denoted by "name"
m_storage.erase(name);
// assignment to slot contents denoted by "name"
cxx20::erase_if(m_storage, [&](auto const& entry) { return entry.second == name; });
cxx20::erase_if(m_storage, mapTuple([&name](auto&& /* key */, auto&& value) { return value == name; }));
// assignment to slot denoted by "name"
m_memory.erase(name);
// assignment to slot contents denoted by "name"
cxx20::erase_if(m_memory, [&](auto const& entry) { return entry.second == name; });
cxx20::erase_if(m_memory, mapTuple([&name](auto&& /* key */, auto&& value) { return value == name; }));
}
}
@ -318,9 +318,9 @@ void DataFlowAnalyzer::clearValues(set<YulString> _variables)
// First clear storage knowledge, because we do not have to clear
// storage knowledge of variables whose expression has changed,
// since the value is still unchanged.
auto eraseCondition = [&](auto const& entry) {
return _variables.count(entry.first) || _variables.count(entry.second);
};
auto eraseCondition = mapTuple([&_variables](auto&& key, auto&& value) {
return _variables.count(key) || _variables.count(value);
});
cxx20::erase_if(m_storage, eraseCondition);
cxx20::erase_if(m_memory, eraseCondition);
@ -379,10 +379,10 @@ void DataFlowAnalyzer::joinKnowledgeHelper(
// This also works for memory because _older is an "older version"
// of m_memory and thus any overlapping write would have cleared the keys
// that are not known to be different inside m_memory already.
cxx20::erase_if(_this, [&](auto const& entry){
YulString const* value = valueOrNullptr(_older, entry.first);
return !value || *value != entry.second;
});
cxx20::erase_if(_this, mapTuple([&_older](auto&& key, auto&& currentValue){
YulString const* oldValue = valueOrNullptr(_older, key);
return !oldValue || *oldValue != currentValue;
}));
}
bool DataFlowAnalyzer::inScope(YulString _variableName) const