mirror of https://github.com/oxen-io/lokinet
Fix multi-field < ordering
Lots and lots of places in the code had broken < operators because they are returning something like: foo < other.foo or bar < other.bar; but this breaks both the strict weak ordering requirements that are required for the "Compare" requirement for things like std::map/set/priority_queue. For example: a = {.foo=1, .bar=3} b = {.foo=3, .bar=1} does not have an ordering over a and b (both `a < b` and `b < a` are satisfied at the same time). This needs to be instead something like: foo < other.foo or (foo == other.foo and bar < other.bar) but that's a bit clunkier, and it is easier to use std::tie for tuple's built-in < comparison which does the right thing: std::tie(foo, bar) < std::tie(other.foo, other.bar) (Initially I noticed this in SockAddr/sockaddr_in6, but upon further investigation this extends to the major of multi-field `operator<`'s.) This fixes it by using std::tie (or something similar) everywhere we are doing multi-field inequalities.
This commit is contained in:
parent
54fba30516
commit
36792d4337
|
@ -10,7 +10,7 @@
|
|||
|
||||
namespace llarp::dns
|
||||
{
|
||||
typedef std::tuple<std::string, uint16_t, uint16_t, uint16_t, std::string> SRVTuple;
|
||||
using SRVTuple = std::tuple<std::string, uint16_t, uint16_t, uint16_t, std::string>;
|
||||
|
||||
struct SRVData
|
||||
{
|
||||
|
@ -38,19 +38,23 @@ namespace llarp::dns
|
|||
SRVTuple
|
||||
toTuple() const;
|
||||
|
||||
auto
|
||||
toTupleRef() const
|
||||
{
|
||||
return std::tie(service_proto, priority, weight, port, target);
|
||||
}
|
||||
|
||||
/// so we can put SRVData in a std::set
|
||||
bool
|
||||
operator<(const SRVData& other) const
|
||||
{
|
||||
return service_proto < other.service_proto or priority < other.priority
|
||||
or weight < other.weight or port < other.port or target < other.target;
|
||||
return toTupleRef() < other.toTupleRef();
|
||||
}
|
||||
|
||||
bool
|
||||
operator==(const SRVData& other) const
|
||||
{
|
||||
return service_proto == other.service_proto and priority == other.priority
|
||||
and weight == other.weight and port == other.port and target == other.target;
|
||||
return toTupleRef() == other.toTupleRef();
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
|
@ -26,7 +26,7 @@ namespace llarp::iwp
|
|||
, m_Inbound{allowInbound}
|
||||
{}
|
||||
|
||||
const char*
|
||||
std::string_view
|
||||
LinkLayer::Name() const
|
||||
{
|
||||
return "iwp";
|
||||
|
|
|
@ -35,7 +35,7 @@ namespace llarp::iwp
|
|||
std::shared_ptr<ILinkSession>
|
||||
NewOutboundSession(const RouterContact& rc, const AddressInfo& ai) override;
|
||||
|
||||
const char*
|
||||
std::string_view
|
||||
Name() const override;
|
||||
|
||||
uint16_t
|
||||
|
|
|
@ -53,11 +53,12 @@ namespace llarp
|
|||
uint16_t m_ResendPriority;
|
||||
|
||||
bool
|
||||
operator<(const OutboundMessage& msg) const
|
||||
operator<(const OutboundMessage& other) const
|
||||
{
|
||||
// yes, the first order is reversed as higher means more important
|
||||
// second part is for queue order
|
||||
return msg.m_ResendPriority < m_ResendPriority or m_MsgID < msg.m_MsgID;
|
||||
int prioA = -m_ResendPriority, prioB = -other.m_ResendPriority;
|
||||
return std::tie(prioA, m_MsgID) < std::tie(prioB, other.m_MsgID);
|
||||
}
|
||||
|
||||
ILinkSession::Packet_t
|
||||
|
|
|
@ -249,7 +249,7 @@ namespace llarp
|
|||
bool
|
||||
ILinkLayer::PickAddress(const RouterContact& rc, llarp::AddressInfo& picked) const
|
||||
{
|
||||
std::string OurDialect = Name();
|
||||
auto OurDialect = Name();
|
||||
for (const auto& addr : rc.addrs)
|
||||
{
|
||||
if (addr.dialect == OurDialect)
|
||||
|
|
|
@ -135,7 +135,7 @@ namespace llarp
|
|||
virtual void
|
||||
Stop();
|
||||
|
||||
virtual const char*
|
||||
virtual std::string_view
|
||||
Name() const = 0;
|
||||
|
||||
util::StatusObject
|
||||
|
@ -179,7 +179,7 @@ namespace llarp
|
|||
bool
|
||||
IsCompatable(const llarp::RouterContact& other) const
|
||||
{
|
||||
const std::string us = Name();
|
||||
const auto us = Name();
|
||||
for (const auto& ai : other.addrs)
|
||||
if (ai.dialect == us)
|
||||
return true;
|
||||
|
@ -207,7 +207,9 @@ namespace llarp
|
|||
bool
|
||||
operator<(const ILinkLayer& other) const
|
||||
{
|
||||
return Rank() < other.Rank() || Name() < other.Name() || m_ourAddr < other.m_ourAddr;
|
||||
auto rankA = Rank(), rankB = other.Rank();
|
||||
auto nameA = Name(), nameB = other.Name();
|
||||
return std::tie(rankA, nameA, m_ourAddr) < std::tie(rankB, nameB, other.m_ourAddr);
|
||||
}
|
||||
|
||||
/// called by link session to remove a pending session who is timed out
|
||||
|
|
|
@ -23,7 +23,7 @@ namespace llarp
|
|||
bool
|
||||
operator<(const AddressInfo& lhs, const AddressInfo& rhs)
|
||||
{
|
||||
return lhs.rank < rhs.rank || lhs.ip < rhs.ip || lhs.port < rhs.port;
|
||||
return std::tie(lhs.rank, lhs.ip, lhs.port) < std::tie(rhs.rank, rhs.ip, rhs.port);
|
||||
}
|
||||
|
||||
std::variant<nuint32_t, nuint128_t>
|
||||
|
|
|
@ -117,8 +117,8 @@ namespace llarp
|
|||
bool
|
||||
operator<(const IPRange& other) const
|
||||
{
|
||||
return (this->addr & this->netmask_bits) < (other.addr & other.netmask_bits)
|
||||
|| this->netmask_bits < other.netmask_bits;
|
||||
auto maskedA = addr & netmask_bits, maskedB = other.addr & other.netmask_bits;
|
||||
return std::tie(maskedA, netmask_bits) < std::tie(maskedB, other.netmask_bits);
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
|
@ -34,62 +34,16 @@
|
|||
|
||||
namespace llarp
|
||||
{
|
||||
inline bool
|
||||
operator==(const in_addr& a, const in_addr& b)
|
||||
inline int
|
||||
cmp(const in_addr& a, const in_addr& b)
|
||||
{
|
||||
return memcmp(&a, &b, sizeof(in_addr)) == 0;
|
||||
return memcmp(&a, &b, sizeof(in_addr));
|
||||
}
|
||||
|
||||
inline bool
|
||||
operator==(const in6_addr& a, const in6_addr& b)
|
||||
inline int
|
||||
cmp(const in6_addr& a, const in6_addr& b)
|
||||
{
|
||||
return memcmp(&a, &b, sizeof(in6_addr)) == 0;
|
||||
}
|
||||
|
||||
inline bool
|
||||
operator==(const sockaddr_in& a, const sockaddr_in& b)
|
||||
{
|
||||
return a.sin_port == b.sin_port and a.sin_addr.s_addr == b.sin_addr.s_addr;
|
||||
}
|
||||
|
||||
inline bool
|
||||
operator==(const sockaddr_in6& a, const sockaddr_in6& b)
|
||||
{
|
||||
return a.sin6_port == b.sin6_port and a.sin6_addr == b.sin6_addr;
|
||||
}
|
||||
|
||||
inline bool
|
||||
operator==(const sockaddr& a, const sockaddr& b)
|
||||
{
|
||||
if (a.sa_family != b.sa_family)
|
||||
return false;
|
||||
switch (a.sa_family)
|
||||
{
|
||||
case AF_INET:
|
||||
return reinterpret_cast<const sockaddr_in&>(a) == reinterpret_cast<const sockaddr_in&>(b);
|
||||
case AF_INET6:
|
||||
return reinterpret_cast<const sockaddr_in6&>(a) == reinterpret_cast<const sockaddr_in6&>(b);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
inline bool
|
||||
operator<(const in_addr& a, const in_addr& b)
|
||||
{
|
||||
return memcmp(&a, &b, sizeof(in_addr)) < 0;
|
||||
}
|
||||
|
||||
inline bool
|
||||
operator<(const in6_addr& a, const in6_addr& b)
|
||||
{
|
||||
return memcmp(&a, &b, sizeof(in6_addr)) < 0;
|
||||
}
|
||||
|
||||
inline bool
|
||||
operator<(const sockaddr_in6& a, const sockaddr_in6& b)
|
||||
{
|
||||
return a.sin6_addr < b.sin6_addr or a.sin6_port < b.sin6_port;
|
||||
return memcmp(&a, &b, sizeof(in6_addr));
|
||||
}
|
||||
|
||||
namespace net
|
||||
|
@ -261,3 +215,61 @@ namespace llarp
|
|||
} // namespace net
|
||||
|
||||
} // namespace llarp
|
||||
|
||||
inline bool
|
||||
operator==(const in_addr& a, const in_addr& b)
|
||||
{
|
||||
return llarp::cmp(a, b) == 0;
|
||||
}
|
||||
|
||||
inline bool
|
||||
operator==(const in6_addr& a, const in6_addr& b)
|
||||
{
|
||||
return llarp::cmp(a, b) == 0;
|
||||
}
|
||||
|
||||
inline bool
|
||||
operator==(const sockaddr_in& a, const sockaddr_in& b)
|
||||
{
|
||||
return a.sin_port == b.sin_port and a.sin_addr.s_addr == b.sin_addr.s_addr;
|
||||
}
|
||||
|
||||
inline bool
|
||||
operator==(const sockaddr_in6& a, const sockaddr_in6& b)
|
||||
{
|
||||
return a.sin6_port == b.sin6_port and a.sin6_addr == b.sin6_addr;
|
||||
}
|
||||
|
||||
inline bool
|
||||
operator==(const sockaddr& a, const sockaddr& b)
|
||||
{
|
||||
if (a.sa_family != b.sa_family)
|
||||
return false;
|
||||
switch (a.sa_family)
|
||||
{
|
||||
case AF_INET:
|
||||
return reinterpret_cast<const sockaddr_in&>(a) == reinterpret_cast<const sockaddr_in&>(b);
|
||||
case AF_INET6:
|
||||
return reinterpret_cast<const sockaddr_in6&>(a) == reinterpret_cast<const sockaddr_in6&>(b);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
inline bool
|
||||
operator<(const in_addr& a, const in_addr& b)
|
||||
{
|
||||
return llarp::cmp(a, b) < 0;
|
||||
}
|
||||
|
||||
inline bool
|
||||
operator<(const in6_addr& a, const in6_addr& b)
|
||||
{
|
||||
return llarp::cmp(a, b) < 0;
|
||||
}
|
||||
|
||||
inline bool
|
||||
operator<(const sockaddr_in6& a, const sockaddr_in6& b)
|
||||
{
|
||||
return std::tie(a.sin6_addr, a.sin6_port) < std::tie(b.sin6_addr, b.sin6_port);
|
||||
}
|
||||
|
|
|
@ -206,15 +206,13 @@ namespace llarp
|
|||
bool
|
||||
SockAddr::operator<(const SockAddr& other) const
|
||||
{
|
||||
return (m_addr.sin6_addr < other.m_addr.sin6_addr)
|
||||
or (m_addr.sin6_port < other.m_addr.sin6_port);
|
||||
return m_addr < other.m_addr;
|
||||
}
|
||||
|
||||
bool
|
||||
SockAddr::operator==(const SockAddr& other) const
|
||||
{
|
||||
return m_addr.sin6_addr == other.m_addr.sin6_addr
|
||||
and m_addr.sin6_port == other.m_addr.sin6_port;
|
||||
return m_addr == other.m_addr;
|
||||
}
|
||||
|
||||
huint128_t
|
||||
|
|
|
@ -33,11 +33,7 @@ namespace llarp::net
|
|||
bool
|
||||
operator<(const ProtocolInfo& other) const
|
||||
{
|
||||
if (port and other.port)
|
||||
{
|
||||
return protocol < other.protocol or *port < *other.port;
|
||||
}
|
||||
return protocol < other.protocol;
|
||||
return std::tie(protocol, port) < std::tie(other.protocol, other.port);
|
||||
}
|
||||
|
||||
ProtocolInfo() = default;
|
||||
|
|
|
@ -141,25 +141,25 @@ namespace llarp
|
|||
constexpr bool
|
||||
operator<(const uint128_t& b) const
|
||||
{
|
||||
return upper < b.upper || (upper == b.upper && lower < b.lower);
|
||||
return std::tie(upper, lower) < std::tie(b.upper, b.lower);
|
||||
}
|
||||
|
||||
constexpr bool
|
||||
operator<=(const uint128_t& b) const
|
||||
{
|
||||
return upper < b.upper || (upper == b.upper && lower <= b.lower);
|
||||
return std::tie(upper, lower) <= std::tie(b.upper, b.lower);
|
||||
}
|
||||
|
||||
constexpr bool
|
||||
operator>(const uint128_t& b) const
|
||||
{
|
||||
return upper > b.upper || (upper == b.upper && lower > b.lower);
|
||||
return std::tie(upper, lower) > std::tie(b.upper, b.lower);
|
||||
}
|
||||
|
||||
constexpr bool
|
||||
operator>=(const uint128_t& b) const
|
||||
{
|
||||
return upper > b.upper || (upper == b.upper && lower >= b.lower);
|
||||
return std::tie(upper, lower) >= std::tie(b.upper, b.lower);
|
||||
}
|
||||
|
||||
constexpr uint128_t&
|
||||
|
|
|
@ -41,7 +41,7 @@ namespace llarp
|
|||
bool
|
||||
operator<(const RouterVersion& other) const
|
||||
{
|
||||
return m_ProtoVersion < other.m_ProtoVersion || m_Version < other.m_Version;
|
||||
return std::tie(m_ProtoVersion, m_Version) < std::tie(other.m_ProtoVersion, other.m_Version);
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
|
@ -55,8 +55,8 @@ namespace llarp
|
|||
bool
|
||||
operator<(const Introduction& other) const
|
||||
{
|
||||
return expiresAt < other.expiresAt || pathID < other.pathID || router < other.router
|
||||
|| version < other.version || latency < other.latency;
|
||||
return std::tie(expiresAt, pathID, router, version, latency)
|
||||
< std::tie(other.expiresAt, other.pathID, other.router, other.version, other.latency);
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
|
@ -25,7 +25,7 @@ namespace llarp::vpn
|
|||
bool
|
||||
operator<(const InterfaceAddress& other) const
|
||||
{
|
||||
return range < other.range or fam < other.fam;
|
||||
return std::tie(range, fam) < std::tie(other.range, other.fam);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue