Skip to content

Commit fa23c19

Browse files
author
MacroFake
committed
univalue: Avoid narrowing and verbose int constructors
As UniValue provides several constructors for integral types, the compiler is unable to select one if the passed type does not exactly match. This is unintuitive for developers and forces them to write verbose and brittle code. For example, there are many places where an unsigned int is cast to a signed int. While the cast is safe in practice, it is still needlessly verbose and confusing as the value can never be negative. In fact it might even be unsafe if the unsigned value is large enough to map to a negative signed one.
1 parent fa3a9a1 commit fa23c19

File tree

2 files changed

+23
-25
lines changed

2 files changed

+23
-25
lines changed

src/rpc/net.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ static RPCHelpMan getconnectioncount()
6060
NodeContext& node = EnsureAnyNodeContext(request.context);
6161
const CConnman& connman = EnsureConnman(node);
6262

63-
return (int)connman.GetNodeCount(ConnectionDirection::Both);
63+
return connman.GetNodeCount(ConnectionDirection::Both);
6464
},
6565
};
6666
}
@@ -639,9 +639,9 @@ static RPCHelpMan getnetworkinfo()
639639
obj.pushKV("timeoffset", GetTimeOffset());
640640
if (node.connman) {
641641
obj.pushKV("networkactive", node.connman->GetNetworkActive());
642-
obj.pushKV("connections", (int)node.connman->GetNodeCount(ConnectionDirection::Both));
643-
obj.pushKV("connections_in", (int)node.connman->GetNodeCount(ConnectionDirection::In));
644-
obj.pushKV("connections_out", (int)node.connman->GetNodeCount(ConnectionDirection::Out));
642+
obj.pushKV("connections", node.connman->GetNodeCount(ConnectionDirection::Both));
643+
obj.pushKV("connections_in", node.connman->GetNodeCount(ConnectionDirection::In));
644+
obj.pushKV("connections_out", node.connman->GetNodeCount(ConnectionDirection::Out));
645645
}
646646
obj.pushKV("networks", GetNetworksInfo());
647647
obj.pushKV("relayfee", ValueFromAmount(::minRelayTxFee.GetFeePerK()));

src/univalue/include/univalue.h

Lines changed: 19 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -24,27 +24,25 @@ class UniValue {
2424
typ = initialType;
2525
val = initialStr;
2626
}
27-
UniValue(uint64_t val_) {
28-
setInt(val_);
29-
}
30-
UniValue(int64_t val_) {
31-
setInt(val_);
32-
}
33-
UniValue(bool val_) {
34-
setBool(val_);
35-
}
36-
UniValue(int val_) {
37-
setInt(val_);
38-
}
39-
UniValue(double val_) {
40-
setFloat(val_);
41-
}
42-
UniValue(const std::string& val_) {
43-
setStr(val_);
44-
}
45-
UniValue(const char *val_) {
46-
std::string s(val_);
47-
setStr(s);
27+
template <typename Ref, typename T = std::remove_cv_t<std::remove_reference_t<Ref>>,
28+
std::enable_if_t<std::is_floating_point_v<T> || // setFloat
29+
std::is_same_v<bool, T> || // setBool
30+
std::is_signed_v<T> || std::is_unsigned_v<T> || // setInt
31+
std::is_constructible_v<std::string, T>, // setStr
32+
bool> = true>
33+
UniValue(Ref&& val)
34+
{
35+
if constexpr (std::is_floating_point_v<T>) {
36+
setFloat(val);
37+
} else if constexpr (std::is_same_v<bool, T>) {
38+
setBool(val);
39+
} else if constexpr (std::is_signed_v<T>) {
40+
setInt(int64_t{val});
41+
} else if constexpr (std::is_unsigned_v<T>) {
42+
setInt(uint64_t{val});
43+
} else {
44+
setStr(std::string{std::forward<Ref>(val)});
45+
}
4846
}
4947

5048
void clear();

0 commit comments

Comments
 (0)