Skip to content

Commit d7d2d18

Browse files
committed
avoid moving SmallVector since it has sizable overhead
1 parent 01abf4c commit d7d2d18

File tree

4 files changed

+65
-45
lines changed

4 files changed

+65
-45
lines changed

lib/astutils.cpp

Lines changed: 44 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1139,134 +1139,143 @@ static void followVariableExpressionError(const Token *tok1, const Token *tok2,
11391139
errors->push_back(std::move(item));
11401140
}
11411141

1142-
SmallVector<ReferenceToken> followAllReferences(const Token* tok,
1143-
bool temporary,
1144-
bool inconclusive,
1145-
ErrorPath errors,
1146-
int depth)
1142+
void followAllReferences(const Token* tok,
1143+
SmallVectorBase<ReferenceToken>& refs_result,
1144+
bool temporary,
1145+
bool inconclusive,
1146+
ErrorPath errors,
1147+
int depth)
11471148
{
11481149
struct ReferenceTokenLess {
11491150
bool operator()(const ReferenceToken& x, const ReferenceToken& y) const {
11501151
return x.token < y.token;
11511152
}
11521153
};
1153-
SmallVector<ReferenceToken> refs_result;
11541154
if (!tok)
1155-
return refs_result;
1155+
return;
11561156
if (depth < 0) {
11571157
refs_result.push_back({tok, std::move(errors)});
1158-
return refs_result;
1158+
return;
11591159
}
11601160
const Variable *var = tok->variable();
11611161
if (var && var->declarationId() == tok->varId()) {
11621162
if (var->nameToken() == tok || isStructuredBindingVariable(var)) {
11631163
refs_result.push_back({tok, std::move(errors)});
1164-
return refs_result;
1164+
return;
11651165
} else if (var->isReference() || var->isRValueReference()) {
11661166
const Token * const varDeclEndToken = var->declEndToken();
11671167
if (!varDeclEndToken) {
11681168
refs_result.push_back({tok, std::move(errors)});
1169-
return refs_result;
1169+
return;
11701170
}
11711171
if (var->isArgument()) {
11721172
errors.emplace_back(varDeclEndToken, "Passed to reference.");
11731173
refs_result.push_back({tok, std::move(errors)});
1174-
return refs_result;
1174+
return;
11751175
} else if (Token::simpleMatch(varDeclEndToken, "=")) {
11761176
if (astHasToken(varDeclEndToken, tok))
1177-
return refs_result;
1177+
return;
11781178
errors.emplace_back(varDeclEndToken, "Assigned to reference.");
11791179
const Token *vartok = varDeclEndToken->astOperand2();
11801180
if (vartok == tok || (!temporary && isTemporary(true, vartok, nullptr, true) &&
11811181
(var->isConst() || var->isRValueReference()))) {
11821182
refs_result.push_back({tok, std::move(errors)});
1183-
return refs_result;
1183+
return;
1184+
}
1185+
if (vartok) {
1186+
followAllReferences(vartok, refs_result, temporary, inconclusive, std::move(errors), depth - 1);
1187+
return;
11841188
}
1185-
if (vartok)
1186-
return followAllReferences(vartok, temporary, inconclusive, std::move(errors), depth - 1);
11871189
} else {
11881190
refs_result.push_back({tok, std::move(errors)});
1189-
return refs_result;
1191+
return;
11901192
}
11911193
}
11921194
} else if (Token::simpleMatch(tok, "?") && Token::simpleMatch(tok->astOperand2(), ":")) {
11931195
std::set<ReferenceToken, ReferenceTokenLess> result;
11941196
const Token* tok2 = tok->astOperand2();
11951197

1196-
auto refs = followAllReferences(tok2->astOperand1(), temporary, inconclusive, errors, depth - 1);
1197-
result.insert(refs.begin(), refs.end());
1198-
refs = followAllReferences(tok2->astOperand2(), temporary, inconclusive, errors, depth - 1);
1199-
result.insert(refs.begin(), refs.end());
1198+
{
1199+
SmallVector<ReferenceToken> refs;
1200+
followAllReferences(tok2->astOperand1(), refs, temporary, inconclusive, errors, depth - 1);
1201+
result.insert(refs.begin(), refs.end());
1202+
}
1203+
{
1204+
SmallVector<ReferenceToken> refs;
1205+
followAllReferences(tok2->astOperand2(), refs, temporary, inconclusive, errors, depth - 1);
1206+
result.insert(refs.begin(), refs.end());
1207+
}
12001208

12011209
if (!inconclusive && result.size() != 1) {
12021210
refs_result.push_back({tok, std::move(errors)});
1203-
return refs_result;
1211+
return;
12041212
}
12051213

12061214
if (!result.empty()) {
12071215
refs_result.insert(refs_result.end(), result.begin(), result.end());
1208-
return refs_result;
1216+
return;
12091217
}
12101218

12111219
} else if (Token::Match(tok->previous(), "%name% (")) {
12121220
const Function *f = tok->previous()->function();
12131221
if (f) {
12141222
if (!Function::returnsReference(f)) {
12151223
refs_result.push_back({tok, std::move(errors)});
1216-
return refs_result;
1224+
return;
12171225
}
12181226
std::set<ReferenceToken, ReferenceTokenLess> result;
12191227
std::vector<const Token*> returns = Function::findReturns(f);
12201228
for (const Token* returnTok : returns) {
12211229
if (returnTok == tok)
12221230
continue;
1223-
for (const ReferenceToken& rt :
1224-
followAllReferences(returnTok, temporary, inconclusive, errors, depth - returns.size())) {
1231+
SmallVector<ReferenceToken> refs;
1232+
followAllReferences(returnTok, refs, temporary, inconclusive, errors, depth - returns.size());
1233+
for (const ReferenceToken& rt : refs) {
12251234
const Variable* argvar = rt.token->variable();
12261235
if (!argvar) {
12271236
refs_result.push_back({tok, std::move(errors)});
1228-
return refs_result;
1237+
return;
12291238
}
12301239
if (argvar->isArgument() && (argvar->isReference() || argvar->isRValueReference())) {
12311240
const int n = getArgumentPos(argvar, f);
12321241
if (n < 0) {
12331242
refs_result.push_back({tok, std::move(errors)});
1234-
return refs_result;
1243+
return;
12351244
}
12361245
std::vector<const Token*> args = getArguments(tok->previous());
12371246
if (n >= args.size()) {
12381247
refs_result.push_back({tok, std::move(errors)});
1239-
return refs_result;
1248+
return;
12401249
}
12411250
const Token* argTok = args[n];
12421251
ErrorPath er = errors;
12431252
er.emplace_back(returnTok, "Return reference.");
12441253
er.emplace_back(tok->previous(), "Called function passing '" + argTok->expressionString() + "'.");
1245-
auto refs =
1246-
followAllReferences(argTok, temporary, inconclusive, std::move(er), depth - returns.size());
1247-
result.insert(refs.begin(), refs.end());
1254+
SmallVector<ReferenceToken> refs2;
1255+
followAllReferences(argTok, refs2, temporary, inconclusive, std::move(er), depth - returns.size());
1256+
result.insert(refs2.begin(), refs2.end());
12481257
if (!inconclusive && result.size() > 1) {
12491258
refs_result.push_back({tok, std::move(errors)});
1250-
return refs_result;
1259+
return;
12511260
}
12521261
}
12531262
}
12541263
}
12551264
if (!result.empty()) {
12561265
refs_result.insert(refs_result.end(), result.begin(), result.end());
1257-
return refs_result;
1266+
return;
12581267
}
12591268
}
12601269
}
12611270
refs_result.push_back({tok, std::move(errors)});
1262-
return refs_result;
12631271
}
12641272

12651273
const Token* followReferences(const Token* tok, ErrorPath* errors)
12661274
{
12671275
if (!tok)
12681276
return nullptr;
1269-
auto refs = followAllReferences(tok, true, false);
1277+
SmallVector<ReferenceToken> refs;
1278+
followAllReferences(tok, refs, true, false);
12701279
if (refs.size() == 1) {
12711280
if (errors)
12721281
*errors = std::move(refs.front().errors);

lib/astutils.h

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -223,11 +223,12 @@ struct ReferenceToken {
223223
ErrorPath errors;
224224
};
225225

226-
SmallVector<ReferenceToken> followAllReferences(const Token* tok,
227-
bool temporary = true,
228-
bool inconclusive = true,
229-
ErrorPath errors = ErrorPath{},
230-
int depth = 20);
226+
void followAllReferences(const Token* tok,
227+
SmallVectorBase<ReferenceToken>& refs_result,
228+
bool temporary = true,
229+
bool inconclusive = true,
230+
ErrorPath errors = ErrorPath{},
231+
int depth = 20);
231232
const Token* followReferences(const Token* tok, ErrorPath* errors = nullptr);
232233

233234
bool isSameExpression(bool cpp, bool macro, const Token *tok1, const Token *tok2, const Library& library, bool pure, bool followVar, ErrorPath* errors=nullptr);

lib/smallvector.h

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ static constexpr std::size_t DefaultSmallVectorSize = 3;
2828

2929
template<typename T, std::size_t N = DefaultSmallVectorSize>
3030
using SmallVector = boost::container::small_vector<T, N>;
31+
32+
template<typename T>
33+
using SmallVectorBase = boost::container::small_vector_base<T>;
3134
#else
3235
#include <utility>
3336
#include <vector>
@@ -44,17 +47,20 @@ struct TaggedAllocator : std::allocator<T>
4447
};
4548

4649
template<typename T, std::size_t N = DefaultSmallVectorSize>
47-
class SmallVector : public std::vector<T, TaggedAllocator<T, N>>
50+
class SmallVectorBase : public std::vector<T, TaggedAllocator<T, N>>
4851
{
4952
public:
5053
template<class ... Ts>
5154
// NOLINTNEXTLINE(google-explicit-constructor)
52-
SmallVector(Ts&&... ts)
55+
SmallVectorBase(Ts&&... ts)
5356
: std::vector<T, TaggedAllocator<T, N>>(std::forward<Ts>(ts)...)
5457
{
5558
this->reserve(N);
5659
}
5760
};
61+
62+
template<typename T, std::size_t N = DefaultSmallVectorSize>
63+
using SmallVector = SmallVectorBase<T, N>;
5864
#endif
5965

6066
#endif

lib/valueflow.cpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2696,7 +2696,8 @@ struct ValueFlowAnalyzer : Analyzer {
26962696
if (invalid())
26972697
return Action::Invalid;
26982698
// Follow references
2699-
auto refs = followAllReferences(tok);
2699+
SmallVector<ReferenceToken> refs;
2700+
followAllReferences(tok, refs);
27002701
const bool inconclusiveRefs = refs.size() != 1;
27012702
if (std::none_of(refs.begin(), refs.end(), [&](const ReferenceToken& ref) {
27022703
return tok == ref.token;
@@ -4693,7 +4694,9 @@ static void valueFlowLifetime(TokenList *tokenlist, SymbolDatabase* /*db*/, Erro
46934694
}
46944695

46954696
for (const Token* tok2 : toks) {
4696-
for (const ReferenceToken& rt : followAllReferences(tok2, false)) {
4697+
SmallVector<ReferenceToken> refs;
4698+
followAllReferences(tok2, refs, false);
4699+
for (const ReferenceToken& rt : refs) {
46974700
ValueFlow::Value value = master;
46984701
value.tokvalue = rt.token;
46994702
value.errorPath.insert(value.errorPath.begin(), rt.errors.begin(), rt.errors.end());
@@ -5333,7 +5336,8 @@ static void valueFlowForwardConst(Token* start,
53335336
} else {
53345337
[&] {
53355338
// Follow references
5336-
auto refs = followAllReferences(tok);
5339+
SmallVector<ReferenceToken> refs;
5340+
followAllReferences(tok, refs);
53375341
auto it = std::find_if(refs.begin(), refs.end(), [&](const ReferenceToken& ref) {
53385342
return ref.token->varId() == var->declarationId();
53395343
});

0 commit comments

Comments
 (0)