Skip to content

Instantly share code, notes, and snippets.

@ghtz08
Created August 15, 2021 09:25
Show Gist options
  • Save ghtz08/f67e5868e6c45414d53a534fa4a1ae0d to your computer and use it in GitHub Desktop.
Save ghtz08/f67e5868e6c45414d53a534fa4a1ae0d to your computer and use it in GitHub Desktop.
IPv4 的封装
#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