data/RelationPath.cpp
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | #include "RelationPath.h" | ||
| 2 | |||
| 3 | #include "RelationVocabulary.h" | ||
| 4 | |||
| 5 | #include <QCoreApplication> | ||
| 6 | #include <QHash> | ||
| 7 | #include <QSet> | ||
| 8 | #include <map> | ||
| 9 | |||
| 10 | namespace RelationPath { | ||
| 11 | |||
| 12 | namespace { | ||
| 13 | |||
| 14 | 95 | int weightOf(const RelationGraph::StoredEdge &e) { | |
| 15 |
2/2✓ Branch 4 → 5 taken 31 times.
✓ Branch 4 → 6 taken 64 times.
|
95 | if (e.role == QLatin1String("via")) |
| 16 | 31 | return 1; | |
| 17 |
2/4✓ Branch 7 → 8 taken 48 times.
✓ Branch 7 → 9 taken 16 times.
✗ Branch 7 → 10 not taken.
✗ Branch 7 → 11 not taken.
|
64 | switch (RelationVocabulary::categoryOf(e.type)) { |
| 18 | 48 | case RelationVocabulary::Category::Family: | |
| 19 | case RelationVocabulary::Category::Friends: | ||
| 20 | 48 | return 2; | |
| 21 | 16 | case RelationVocabulary::Category::Work: | |
| 22 | 16 | return 3; | |
| 23 | ✗ | case RelationVocabulary::Category::Other: | |
| 24 | ✗ | break; | |
| 25 | } | ||
| 26 | ✗ | return 4; | |
| 27 | } | ||
| 28 | |||
| 29 | 7 | QString tr(const char *text) { return QCoreApplication::translate("RelationPath", text); } | |
| 30 | |||
| 31 | } // namespace | ||
| 32 | |||
| 33 | 11 | Path find(const RelationGraph::Input &input, qint64 from, qint64 to, int maxHops) { | |
| 34 | 11 | Path path; | |
| 35 |
2/4✓ Branch 2 → 3 taken 11 times.
✗ Branch 2 → 4 not taken.
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 11 times.
|
11 | if (from <= 0 || to <= 0) |
| 36 | ✗ | return path; | |
| 37 |
2/2✓ Branch 5 → 6 taken 1 time.
✓ Branch 5 → 8 taken 10 times.
|
11 | if (from == to) { |
| 38 | 1 | path.found = true; | |
| 39 |
1/1✓ Branch 6 → 7 taken 1 time.
|
1 | path.cards = {from}; |
| 40 | 1 | return path; | |
| 41 | } | ||
| 42 | // S106-275: only people of the graph carry a path — an edge to a card the | ||
| 43 | // graph does not hold (another kind, another scope) has no one to name. | ||
| 44 | 10 | QSet<qint64> people; | |
| 45 |
3/3✓ Branch 12 → 13 taken 98 times.
✓ Branch 15 → 11 taken 98 times.
✓ Branch 15 → 16 taken 10 times.
|
108 | for (const RelationGraph::Person &person : input.people) people.insert(person.cardId); |
| 46 | 10 | QHash<qint64, QList<int>> adjacency; | |
| 47 |
2/2✓ Branch 34 → 17 taken 87 times.
✓ Branch 34 → 35 taken 10 times.
|
97 | for (int i = 0; i < input.edges.size(); ++i) { |
| 48 | 87 | const RelationGraph::StoredEdge &e = input.edges.at(i); | |
| 49 |
6/8✓ Branch 18 → 19 taken 87 times.
✗ Branch 18 → 24 not taken.
✓ Branch 19 → 20 taken 87 times.
✗ Branch 19 → 24 not taken.
✓ Branch 21 → 22 taken 86 times.
✓ Branch 21 → 24 taken 1 time.
✓ Branch 26 → 27 taken 2 times.
✓ Branch 26 → 28 taken 85 times.
|
173 | if (e.toCardId <= 0 || e.fromCardId == e.toCardId || !people.contains(e.fromCardId) || |
| 50 |
2/2✓ Branch 23 → 24 taken 1 time.
✓ Branch 23 → 25 taken 85 times.
|
86 | !people.contains(e.toCardId)) |
| 51 | 2 | continue; | |
| 52 |
2/2✓ Branch 28 → 29 taken 85 times.
✓ Branch 29 → 30 taken 85 times.
|
85 | adjacency[e.fromCardId].append(i); |
| 53 |
2/2✓ Branch 30 → 31 taken 85 times.
✓ Branch 31 → 32 taken 85 times.
|
85 | adjacency[e.toCardId].append(i); |
| 54 | } | ||
| 55 | // (cost, hops, card) ordered: deterministic Dijkstra. | ||
| 56 | 10 | std::map<std::tuple<int, int, qint64>, bool> queue; | |
| 57 | 10 | QHash<qint64, int> cost; | |
| 58 | 10 | QHash<qint64, int> hops; | |
| 59 | 10 | QHash<qint64, int> via; // card → edge index that reached it | |
| 60 | 10 | QSet<qint64> done; | |
| 61 |
1/1✓ Branch 37 → 38 taken 10 times.
|
10 | cost.insert(from, 0); |
| 62 |
1/1✓ Branch 38 → 39 taken 10 times.
|
10 | hops.insert(from, 0); |
| 63 |
1/1✓ Branch 40 → 41 taken 10 times.
|
10 | queue[{0, 0, from}] = true; |
| 64 | 10 | int visited = 0; | |
| 65 |
5/6✓ Branch 93 → 94 taken 49 times.
✓ Branch 93 → 96 taken 4 times.
✓ Branch 94 → 95 taken 49 times.
✗ Branch 94 → 96 not taken.
✓ Branch 97 → 42 taken 49 times.
✓ Branch 97 → 98 taken 4 times.
|
53 | while (!queue.empty() && visited < RelationGraph::MaxVisited) { |
| 66 | 49 | const auto [c, h, card] = queue.begin()->first; | |
| 67 |
1/1✓ Branch 48 → 49 taken 49 times.
|
49 | queue.erase(queue.begin()); |
| 68 |
1/2✗ Branch 50 → 51 not taken.
✓ Branch 50 → 52 taken 49 times.
|
49 | if (done.contains(card)) |
| 69 | 2 | continue; | |
| 70 |
1/1✓ Branch 52 → 53 taken 49 times.
|
49 | done.insert(card); |
| 71 | 49 | ++visited; | |
| 72 |
2/2✓ Branch 53 → 54 taken 6 times.
✓ Branch 53 → 55 taken 43 times.
|
49 | if (card == to) |
| 73 | 6 | break; | |
| 74 |
2/2✓ Branch 55 → 56 taken 2 times.
✓ Branch 55 → 57 taken 41 times.
|
43 | if (h >= maxHops) |
| 75 | 2 | continue; | |
| 76 | 41 | QList<int> edges = adjacency.value(card); | |
| 77 |
3/3✓ Branch 58 → 59 taken 41 times.
✓ Branch 59 → 60 taken 41 times.
✓ Branch 60 → 61 taken 41 times.
|
41 | std::sort(edges.begin(), edges.end()); |
| 78 |
4/4✓ Branch 61 → 62 taken 41 times.
✓ Branch 62 → 63 taken 41 times.
✓ Branch 88 → 64 taken 95 times.
✓ Branch 88 → 89 taken 41 times.
|
136 | for (int index : edges) { |
| 79 | 95 | const RelationGraph::StoredEdge &e = input.edges.at(index); | |
| 80 |
2/2✓ Branch 66 → 67 taken 44 times.
✓ Branch 66 → 68 taken 51 times.
|
95 | const qint64 next = e.fromCardId == card ? e.toCardId : e.fromCardId; |
| 81 |
1/1✓ Branch 69 → 70 taken 95 times.
|
95 | const int nextCost = c + weightOf(e); |
| 82 |
8/8✓ Branch 71 → 72 taken 60 times.
✓ Branch 71 → 76 taken 35 times.
✓ Branch 73 → 74 taken 5 times.
✓ Branch 73 → 77 taken 55 times.
✓ Branch 75 → 76 taken 4 times.
✓ Branch 75 → 77 taken 1 time.
✓ Branch 78 → 79 taken 39 times.
✓ Branch 78 → 80 taken 56 times.
|
95 | if (done.contains(next) || (cost.contains(next) && cost.value(next) <= nextCost)) |
| 83 | 39 | continue; | |
| 84 |
1/1✓ Branch 80 → 81 taken 56 times.
|
56 | cost.insert(next, nextCost); |
| 85 |
1/1✓ Branch 81 → 82 taken 56 times.
|
56 | hops.insert(next, h + 1); |
| 86 |
1/1✓ Branch 82 → 83 taken 56 times.
|
56 | via.insert(next, index); |
| 87 |
1/1✓ Branch 84 → 85 taken 56 times.
|
56 | queue[{nextCost, h + 1, next}] = true; |
| 88 | } | ||
| 89 | 41 | } | |
| 90 |
2/2✓ Branch 99 → 100 taken 4 times.
✓ Branch 99 → 101 taken 6 times.
|
10 | if (!done.contains(to)) |
| 91 | 4 | return path; | |
| 92 | 6 | path.found = true; | |
| 93 |
2/2✓ Branch 110 → 102 taken 19 times.
✓ Branch 110 → 111 taken 6 times.
|
25 | for (qint64 card = to; card != from;) { |
| 94 | 19 | const RelationGraph::StoredEdge &e = input.edges.at(via.value(card)); | |
| 95 |
1/1✓ Branch 104 → 105 taken 19 times.
|
19 | path.cards.prepend(card); |
| 96 |
1/1✓ Branch 105 → 106 taken 19 times.
|
19 | path.steps.prepend(e); |
| 97 |
1/2✓ Branch 106 → 107 taken 19 times.
✗ Branch 106 → 108 not taken.
|
19 | card = e.fromCardId == card ? e.toCardId : e.fromCardId; |
| 98 | } | ||
| 99 |
1/1✓ Branch 111 → 112 taken 6 times.
|
6 | path.cards.prepend(from); |
| 100 | 6 | return path; | |
| 101 | 10 | } | |
| 102 | |||
| 103 | 3 | QString sentence(const Path &path, const QStringList &names) { | |
| 104 |
4/8✓ Branch 2 → 3 taken 3 times.
✗ Branch 2 → 8 not taken.
✓ Branch 4 → 5 taken 3 times.
✗ Branch 4 → 8 not taken.
✗ Branch 7 → 8 not taken.
✓ Branch 7 → 9 taken 3 times.
✗ Branch 10 → 11 not taken.
✓ Branch 10 → 12 taken 3 times.
|
3 | if (!path.found || path.cards.size() < 2 || names.size() != path.cards.size()) |
| 105 | ✗ | return {}; | |
| 106 | 3 | const QString target = names.last(); | |
| 107 |
2/2✓ Branch 15 → 16 taken 1 time.
✓ Branch 15 → 21 taken 2 times.
|
3 | if (path.cards.size() == 2) |
| 108 |
2/2✓ Branch 16 → 17 taken 1 time.
✓ Branch 18 → 19 taken 1 time.
|
2 | return tr("You know %1 directly.").arg(target); |
| 109 | // Walk backwards: target through n-1, whom you know through n-2, … | ||
| 110 |
2/2✓ Branch 21 → 22 taken 2 times.
✓ Branch 24 → 25 taken 2 times.
|
2 | QString text = tr("You know %1 through %2").arg(target, names.at(names.size() - 2)); |
| 111 |
2/2✓ Branch 36 → 28 taken 4 times.
✓ Branch 36 → 37 taken 2 times.
|
6 | for (int i = int(names.size()) - 3; i >= 1; --i) |
| 112 |
3/3✓ Branch 28 → 29 taken 4 times.
✓ Branch 31 → 32 taken 4 times.
✓ Branch 32 → 33 taken 4 times.
|
8 | text += tr(", whom you know through %1").arg(names.at(i)); |
| 113 |
1/1✓ Branch 39 → 40 taken 2 times.
|
2 | return text + QLatin1Char('.'); |
| 114 | 3 | } | |
| 115 | |||
| 116 | } // namespace RelationPath | ||
| 117 |