net/addr/subnet: Add netmask functions
Change-Id: I1319e02655796a842769c2f01869b21d0a2151f4
Signed-off-by: William A. Kennington III <wak@google.com>
diff --git a/include/stdplus/net/addr/subnet.hpp b/include/stdplus/net/addr/subnet.hpp
index 8a783ff..5bcc17d 100644
--- a/include/stdplus/net/addr/subnet.hpp
+++ b/include/stdplus/net/addr/subnet.hpp
@@ -5,6 +5,7 @@
#include <stdplus/numeric/str.hpp>
#include <stdplus/str/conv.hpp>
+#include <bit>
#include <limits>
#include <type_traits>
@@ -123,6 +124,25 @@
} // namespace detail
+template <typename T>
+constexpr T pfxToMask(std::uint8_t pfx);
+
+template <>
+constexpr In4Addr pfxToMask<In4Addr>(std::uint8_t pfx)
+{
+ return in_addr{detail::addr32Mask(pfx)};
+}
+
+constexpr std::uint8_t maskToPfx(In4Addr mask)
+{
+ uint32_t x = ntoh(mask.s4_addr32);
+ if ((~x & (~x + 1)) != 0)
+ {
+ throw std::invalid_argument("Invalid netmask");
+ }
+ return 32 - std::countr_zero(x);
+}
+
using Subnet4 = detail::Subnet46<In4Addr, std::uint8_t>;
using Subnet6 = detail::Subnet46<In6Addr, std::uint8_t>;
diff --git a/test/net/addr/subnet.cpp b/test/net/addr/subnet.cpp
index 319a514..ca2fa20 100644
--- a/test/net/addr/subnet.cpp
+++ b/test/net/addr/subnet.cpp
@@ -224,4 +224,15 @@
fmt::format("a {} b", SubnetAny(In4Addr{1, 2, 3, 4}, 32)));
}
+TEST(Ops, MaskToPfx)
+{
+ EXPECT_EQ(32, maskToPfx(In4Addr{0xff, 0xff, 0xff, 0xff}));
+ EXPECT_EQ(28, maskToPfx(In4Addr{0xff, 0xff, 0xff, 0xf0}));
+ EXPECT_EQ(16, maskToPfx(In4Addr{0xff, 0xff, 0, 0}));
+ EXPECT_EQ(0, maskToPfx(In4Addr{}));
+
+ EXPECT_THROW(maskToPfx(In4Addr{0, 0x8}), std::invalid_argument);
+ EXPECT_THROW(maskToPfx(In4Addr{0x40}), std::invalid_argument);
+}
+
} // namespace stdplus