net/addr/subnet: Add string literals
Change-Id: Ibb6f97c3aa9b3fd7ef5c0c81e527741e7d26590f
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 05464e6..2a91ed8 100644
--- a/include/stdplus/net/addr/subnet.hpp
+++ b/include/stdplus/net/addr/subnet.hpp
@@ -270,6 +270,87 @@
}
};
+namespace detail
+{
+
+template <Subnet Sub>
+struct CompileInAddrInt<Sub> : CompileInAddrInt<typename Sub::Addr>
+{
+ Sub::Pfx pfx = 0;
+
+ template <typename CharT>
+ constexpr void compile(std::basic_string_view<CharT> sv) noexcept
+ {
+ const auto pos = sv.rfind('/');
+ if (pos == sv.npos)
+ {
+ this->valid = false;
+ }
+ static_cast<CompileInAddrInt<typename Sub::Addr>&>(*this).compile(
+ sv.substr(0, pos));
+ try
+ {
+ pfx = StrToInt<10, typename Sub::Pfx>{}(sv.substr(pos + 1));
+ }
+ catch (...)
+ {
+ this->valid = false;
+ }
+ }
+};
+
+template <typename CharT, std::size_t N>
+struct CompileSubnet4 : CompileInAddr<Subnet4, CharT, N>
+{
+ constexpr CompileSubnet4(const CharT (&str)[N]) noexcept :
+ CompileInAddr<Subnet4, CharT, N>(str)
+ {}
+};
+
+template <typename CharT, std::size_t N>
+struct CompileSubnet6 : CompileInAddr<Subnet6, CharT, N>
+{
+ constexpr CompileSubnet6(const CharT (&str)[N]) noexcept :
+ CompileInAddr<Subnet6, CharT, N>(str)
+ {}
+};
+
+template <typename CharT, std::size_t N>
+struct CompileSubnetAny : CompileInAddr<SubnetAny, CharT, N>
+{
+ constexpr CompileSubnetAny(const CharT (&str)[N]) noexcept :
+ CompileInAddr<SubnetAny, CharT, N>(str)
+ {}
+};
+
+} // namespace detail
+
+inline namespace subnet_literals
+{
+
+template <detail::CompileSubnet4 Str>
+constexpr auto operator"" _sub4() noexcept
+{
+ static_assert(Str.valid, "stdplus::Subnet4");
+ return Subnet4(Str.addr, Str.pfx);
+}
+
+template <detail::CompileSubnet6 Str>
+constexpr auto operator"" _sub6() noexcept
+{
+ static_assert(Str.valid, "stdplus::Subnet6");
+ return Subnet6(Str.addr, Str.pfx);
+}
+
+template <detail::CompileSubnetAny Str>
+constexpr auto operator"" _sub() noexcept
+{
+ static_assert(Str.valid, "stdplus::SubnetAny");
+ return Str.v4 ? SubnetAny(Str.u.addr4, Str.pfx)
+ : SubnetAny(Str.u.addr6, Str.pfx);
+}
+
+} // namespace subnet_literals
} // namespace stdplus
template <stdplus::Subnet Sub, typename CharT>
diff --git a/test/net/addr/subnet.cpp b/test/net/addr/subnet.cpp
index ca2fa20..31bad90 100644
--- a/test/net/addr/subnet.cpp
+++ b/test/net/addr/subnet.cpp
@@ -64,6 +64,7 @@
EXPECT_THROW(fs("0.0.0.0/"sv), std::invalid_argument);
EXPECT_THROW(fs("::/80"sv), std::invalid_argument);
EXPECT_EQ((SubnetAny{in_addr{}, 30}), fs("0.0.0.0/30"sv));
+ EXPECT_EQ((SubnetAny{in_addr{}, 30}), "0.0.0.0/30"_sub4);
}
TEST(Subnet4, ToStr)
@@ -135,6 +136,7 @@
EXPECT_THROW(fs("::/"sv), std::invalid_argument);
EXPECT_THROW(fs("0.0.0.0/0"sv), std::invalid_argument);
EXPECT_EQ((Subnet6{in6_addr{}, 80}), fs("::/80"sv));
+ EXPECT_EQ((Subnet6{in6_addr{}, 80}), "::/80"_sub6);
}
TEST(Subnet6, ToStr)
@@ -210,7 +212,9 @@
EXPECT_THROW(fs("0.0.0.0/"sv), std::invalid_argument);
EXPECT_EQ((SubnetAny{in_addr{}, 0}), fs("0.0.0.0/0"sv));
EXPECT_EQ((SubnetAny{in_addr{}, 30}), fs("0.0.0.0/30"sv));
+ EXPECT_EQ((SubnetAny{in_addr{}, 30}), "0.0.0.0/30"_sub);
EXPECT_EQ((SubnetAny{in6_addr{}, 80}), fs("::/80"sv));
+ EXPECT_EQ((SubnetAny{in6_addr{}, 80}), "::/80"_sub);
}
TEST(SubnetAny, ToStr)