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.
This commit is contained in:
MacroFake 2022-07-14 11:20:31 +02:00
parent fa3a9a1e8d
commit fa23c19750
No known key found for this signature in database
GPG Key ID: CE2B75697E69A548
2 changed files with 23 additions and 25 deletions

View File

@ -60,7 +60,7 @@ static RPCHelpMan getconnectioncount()
NodeContext& node = EnsureAnyNodeContext(request.context);
const CConnman& connman = EnsureConnman(node);
return (int)connman.GetNodeCount(ConnectionDirection::Both);
return connman.GetNodeCount(ConnectionDirection::Both);
},
};
}
@ -639,9 +639,9 @@ static RPCHelpMan getnetworkinfo()
obj.pushKV("timeoffset", GetTimeOffset());
if (node.connman) {
obj.pushKV("networkactive", node.connman->GetNetworkActive());
obj.pushKV("connections", (int)node.connman->GetNodeCount(ConnectionDirection::Both));
obj.pushKV("connections_in", (int)node.connman->GetNodeCount(ConnectionDirection::In));
obj.pushKV("connections_out", (int)node.connman->GetNodeCount(ConnectionDirection::Out));
obj.pushKV("connections", node.connman->GetNodeCount(ConnectionDirection::Both));
obj.pushKV("connections_in", node.connman->GetNodeCount(ConnectionDirection::In));
obj.pushKV("connections_out", node.connman->GetNodeCount(ConnectionDirection::Out));
}
obj.pushKV("networks", GetNetworksInfo());
obj.pushKV("relayfee", ValueFromAmount(::minRelayTxFee.GetFeePerK()));

View File

@ -24,27 +24,25 @@ public:
typ = initialType;
val = initialStr;
}
UniValue(uint64_t val_) {
setInt(val_);
}
UniValue(int64_t val_) {
setInt(val_);
}
UniValue(bool val_) {
setBool(val_);
}
UniValue(int val_) {
setInt(val_);
}
UniValue(double val_) {
setFloat(val_);
}
UniValue(const std::string& val_) {
setStr(val_);
}
UniValue(const char *val_) {
std::string s(val_);
setStr(s);
template <typename Ref, typename T = std::remove_cv_t<std::remove_reference_t<Ref>>,
std::enable_if_t<std::is_floating_point_v<T> || // setFloat
std::is_same_v<bool, T> || // setBool
std::is_signed_v<T> || std::is_unsigned_v<T> || // setInt
std::is_constructible_v<std::string, T>, // setStr
bool> = true>
UniValue(Ref&& val)
{
if constexpr (std::is_floating_point_v<T>) {
setFloat(val);
} else if constexpr (std::is_same_v<bool, T>) {
setBool(val);
} else if constexpr (std::is_signed_v<T>) {
setInt(int64_t{val});
} else if constexpr (std::is_unsigned_v<T>) {
setInt(uint64_t{val});
} else {
setStr(std::string{std::forward<Ref>(val)});
}
}
void clear();