Support locator methods with "with" on assoc arrays (#4335)

This commit is contained in:
Ryszard Rozak 2023-07-04 15:11:15 +02:00 committed by GitHub
parent 9249ffdb84
commit 97feba6898
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 76 additions and 1 deletions

View File

@ -830,6 +830,22 @@ public:
}
return out;
}
template <typename Func>
VlQueue<T_Value> unique(Func with_func) const {
VlQueue<T_Value> out;
T_Key default_key;
using WithType = decltype(with_func(m_map.begin()->first, m_map.begin()->second));
std::set<WithType> saw;
for (const auto& i : m_map) {
const auto i_mapped = with_func(default_key, i.second);
const auto it = saw.find(i_mapped);
if (it == saw.end()) {
saw.insert(it, i_mapped);
out.push_back(i.second);
}
}
return out;
}
VlQueue<T_Key> unique_index() const {
VlQueue<T_Key> out;
std::set<T_Key> saw;
@ -843,6 +859,21 @@ public:
return out;
}
template <typename Func>
VlQueue<T_Key> unique_index(Func with_func) const {
VlQueue<T_Key> out;
using WithType = decltype(with_func(m_map.begin()->first, m_map.begin()->second));
std::set<WithType> saw;
for (const auto& i : m_map) {
const auto i_mapped = with_func(i.first, i.second);
auto it = saw.find(i_mapped);
if (it == saw.end()) {
saw.insert(it, i_mapped);
out.push_back(i.first);
}
}
return out;
}
template <typename Func>
VlQueue<T_Value> find(Func with_func) const {
VlQueue<T_Value> out;
for (const auto& i : m_map)
@ -903,6 +934,16 @@ public:
});
return VlQueue<T_Value>::cons(it->second);
}
template <typename Func>
VlQueue<T_Value> min(Func with_func) const {
if (m_map.empty()) return VlQueue<T_Value>();
const auto it = std::min_element(
m_map.begin(), m_map.end(),
[&with_func](const std::pair<T_Key, T_Value>& a, const std::pair<T_Key, T_Value>& b) {
return with_func(a.first, a.second) < with_func(b.first, b.second);
});
return VlQueue<T_Value>::cons(it->second);
}
VlQueue<T_Value> max() const {
if (m_map.empty()) return VlQueue<T_Value>();
const auto it = std::max_element(
@ -912,6 +953,16 @@ public:
});
return VlQueue<T_Value>::cons(it->second);
}
template <typename Func>
VlQueue<T_Value> max(Func with_func) const {
if (m_map.empty()) return VlQueue<T_Value>();
const auto it = std::max_element(
m_map.begin(), m_map.end(),
[&with_func](const std::pair<T_Key, T_Value>& a, const std::pair<T_Key, T_Value>& b) {
return with_func(a.first, a.second) < with_func(b.first, b.second);
});
return VlQueue<T_Value>::cons(it->second);
}
T_Value r_sum() const {
T_Value out(0); // Type must have assignment operator

View File

@ -3219,10 +3219,12 @@ private:
if (!nodep->firstAbovep()) newp->dtypeSetVoid();
} else if (nodep->name() == "min" || nodep->name() == "max" || nodep->name() == "unique"
|| nodep->name() == "unique_index") {
AstWith* const withp = methodWithArgument(
nodep, false, true, nullptr, nodep->findUInt32DType(), adtypep->subDTypep());
methodOkArguments(nodep, 0, 0);
methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::READ);
newp = new AstCMethodHard{nodep->fileline(), nodep->fromp()->unlinkFrBack(),
nodep->name()};
nodep->name(), withp};
if (nodep->name() == "unique_index") {
newp->dtypep(queueDTypeIndexedBy(adtypep->keyDTypep()));
} else {

View File

@ -9,11 +9,14 @@
`define checks(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='%s' exp='%s'\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0);
module t (/*AUTOARG*/);
typedef struct { int x, y; } point;
initial begin
int q[int];
int qe[int]; // Empty
int qv[$]; // Value returns
int qi[$]; // Index returns
point points_q[int];
point points_qv[$];
int i;
string v;
@ -37,6 +40,16 @@ module t (/*AUTOARG*/);
qi = qe.unique_index;
v = $sformatf("%p", qi); `checks(v, "'{}");
points_q[0] = point'{1, 2};
points_q[1] = point'{2, 4};
points_q[5] = point'{1, 4};
points_qv = points_q.unique(p) with (p.x);
`checkh(points_qv.size, 2);
qi = points_q.unique_index(p) with (p.x + p.y);
qi.sort;
v = $sformatf("%p", qi); `checks(v, "'{'h0, 'h1, 'h5} ");
// These require an with clause or are illegal
// TODO add a lint check that with clause is provided
qv = q.find with (item == 2);
@ -74,13 +87,22 @@ module t (/*AUTOARG*/);
qv = q.min;
v = $sformatf("%p", qv); `checks(v, "'{'h1} ");
points_qv = points_q.min(p) with (p.x + p.y);
if (points_qv[0].x != 1 || points_qv[0].y != 2) $stop;
qv = q.max;
v = $sformatf("%p", qv); `checks(v, "'{'h4} ");
points_qv = points_q.max(p) with (p.x + p.y);
if (points_qv[0].x != 2 || points_qv[0].y != 4) $stop;
qv = qe.min;
v = $sformatf("%p", qv); `checks(v, "'{}");
qv = qe.min(x) with (x + 1);
v = $sformatf("%p", qv); `checks(v, "'{}");
qv = qe.max;
v = $sformatf("%p", qv); `checks(v, "'{}");
qv = qe.max(x) with (x + 1);
v = $sformatf("%p", qv); `checks(v, "'{}");
// Reduction methods