Created
August 15, 2021 09:25
-
-
Save ghtz08/f67e5868e6c45414d53a534fa4a1ae0d to your computer and use it in GitHub Desktop.
IPv4 的封装
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#define let auto const | |
class Ipv4 { | |
public: | |
using Value = std::array<uint8_t, 4>; | |
static constexpr auto ipv4_str_max_size = 3 + 1 + 3 + 1 + 3 + 1 + 3 + 1; | |
public: | |
explicit Ipv4(char const * ipv4, bool strict = false): | |
Ipv4(ipv4, -1, strict) {} | |
explicit Ipv4(std::string const & ipv4, bool strict = false): | |
Ipv4(ipv4.c_str(), ipv4.size(), strict) {} | |
public: | |
// IPv4 的大端表示 | |
explicit operator uint32_t() const noexcept { | |
return reinterpret_cast<uint32_t const &>(*ipv4_.data()); | |
} | |
explicit operator std::string() const; | |
auto to_string(std::string & ipv4) const noexcept -> void; | |
auto to_string(char * ipv4, size_t buf_size) const noexcept | |
-> size_t; | |
auto raw() const noexcept -> Value { return ipv4_; } | |
private: | |
explicit Ipv4(char const * ipv4, size_t size, bool strict); | |
auto to_string_safe(char (&ipv4)[Ipv4::ipv4_str_max_size]) const noexcept | |
-> size_t; | |
private: | |
Value ipv4_ = {}; // 大端 | |
private: | |
friend auto operator<<(std::ostream & out, Ipv4 & ipv4) -> std::ostream &; | |
friend auto operator>>(std::istream & out, Ipv4 & ipv4) -> std::istream &; | |
}; // class Ipv4 | |
Ipv4::Ipv4(char const * ipv4, size_t size, bool strict) { | |
auto ip = std::array<int, 4>(); | |
auto valid = | |
std::sscanf(ipv4, "%d.%d.%d.%d", &ip[0], &ip[1], &ip[2], &ip[3]) == 4; | |
for (auto n: ip) { | |
valid = valid && (0 <= n && n <= 255); | |
} | |
if (valid && strict) { | |
char buf[Ipv4::ipv4_str_max_size]; | |
valid = true | |
&& (this->to_string_safe(buf) == size || size == -1) | |
&& std::strcmp(ipv4, buf) | |
; | |
} | |
if (!valid) { throw std::invalid_argument(ipv4); } | |
for (auto i = 0; i != ipv4_.size(); ++i) { | |
ipv4_[i] = ip[i]; | |
} | |
} | |
Ipv4::operator std::string() const { | |
auto ipv4 = std::string(); | |
this->to_string(ipv4); | |
return ipv4; | |
} | |
auto Ipv4::to_string(std::string & ipv4) const noexcept -> void { | |
char buf[Ipv4::ipv4_str_max_size]; | |
let size = this->to_string_safe(buf); | |
ipv4.clear(); | |
ipv4.append(buf, size); | |
} | |
auto Ipv4::to_string(char * ipv4, size_t buf_size) const noexcept -> size_t { | |
char buf[Ipv4::ipv4_str_max_size]; | |
let size = this->to_string_safe(buf); | |
if (buf_size <= size) { return 0; } | |
std::copy_n(buf, size + 1, ipv4); // 末尾 '\0' | |
return size; | |
} | |
auto Ipv4::to_string_safe(char (&ipv4)[Ipv4::ipv4_str_max_size]) const noexcept | |
-> size_t { | |
let size = std::sprintf(ipv4, "%d.%d.%d.%d", | |
ipv4_[0], ipv4_[1], ipv4_[2], ipv4_[3]); | |
assert(size < std::size(ipv4)); | |
return size; | |
} | |
auto operator<<(std::ostream & out, Ipv4 & ipv4) -> std::ostream & { | |
char buf[Ipv4::ipv4_str_max_size]; | |
ipv4.to_string_safe(buf); | |
out << buf; | |
return out; | |
} | |
auto operator>>(std::istream & in, Ipv4 & ipv4) -> std::istream & { | |
auto buf = std::string(); | |
in >> buf; | |
ipv4.~Ipv4(); | |
new (&ipv4)Ipv4(buf); | |
return in; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment