Skip to content

Instantly share code, notes, and snippets.

@windoze
Last active October 16, 2015 17:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save windoze/f3cbba9ff2cd8fc63177 to your computer and use it in GitHub Desktop.
Save windoze/f3cbba9ff2cd8fc63177 to your computer and use it in GitHub Desktop.
Random pick some IP address from a subnet
#include <cstdint>
#include <array>
#include <vector>
#include <iostream>
#include <random>
inline constexpr uint32_t subnet_mask(int len) {
return 0xFFFFFFFF >> (32-len) << (32-len);
}
inline uint8_t read_segment(const std::string &s, size_t start_pos) {
return 0;
}
struct IP_addr {
uint32_t data;
// NOTE: Hardcoded little endian u32
uint8_t &operator[](size_t index)
{ return reinterpret_cast<uint8_t *>(&data)[3-index]; }
// NOTE: Hardcoded little endian u32
const uint8_t &operator[](size_t index) const
{ return reinterpret_cast<const uint8_t *>(&data)[3-index]; }
IP_addr mask(int len) const { return IP_addr{data & subnet_mask(len)}; }
template<typename Iterator>
static IP_addr parse(Iterator begin, Iterator end) {
// NOTE: No validation
IP_addr ret{0};
size_t index = 0;
while (begin!=end) {
if (isdigit((unsigned char)*begin)) {
ret[index] *= 10;
ret[index] += *begin - '0';
} else {
++index;
}
++begin;
}
return ret;
}
};
inline std::ostream &operator << (std::ostream &os, const IP_addr &addr) {
os << int(addr[0]) << '.' << int(addr[1]) << '.' << int(addr[2]) << '.' << int(addr[3]);
return os;
}
struct IP_subnet {
IP_addr subnet_base;
int mask_len;
size_t size() const {
// .0 and .255 are not valid IP address unless it's a single address subnet
if (mask_len==32) {
return 1;
}
return (~subnet_mask(mask_len)) + 1 - 2;
}
IP_addr operator[](size_t index) const {
if(mask_len==32)
return IP_addr{static_cast<uint32_t>(subnet_base.data+index)};
return IP_addr{static_cast<uint32_t>(subnet_base.data+index+1)};
}
template<typename Iterator>
static IP_subnet parse(Iterator begin, Iterator end) {
// NOTE: No validation
IP_subnet ret{0, 0};
Iterator slash=std::find(begin, end, '/');
ret.subnet_base=IP_addr::parse(begin, slash);
ret.mask_len=0;
++slash;
while(slash!=end) {
ret.mask_len *= 10;
ret.mask_len += *slash - '0';
++slash;
}
ret.subnet_base=ret.subnet_base.mask(ret.mask_len);
return ret;
}
};
// O(N) random pick algorithm, randomly pick K elements from N elements, not good for very large N
template<typename InputContainer, typename OutputContainer>
size_t random_pick(InputContainer input, OutputContainer &output) {
size_t n=input.size();
size_t k=output.size();
k=std::min(n, k);
for (size_t i=0; i<k; i++) {
output[i]=input[i];
}
std::random_device rd;
std::default_random_engine e(rd());
for (size_t i=k; i<n; i++) {
size_t j=std::uniform_int_distribution<size_t>(0, i+1)(e);
if(j<k)
output[j]=input[i];
}
return k;
}
inline std::ostream &operator << (std::ostream &os, const IP_subnet &subnet) {
os << subnet.subnet_base << '/' << subnet.mask_len;
return os;
}
int main(int argc, const char * argv[]) {
std::string ip("192.168.2.234");
IP_addr addr=IP_addr::parse(ip.begin(), ip.end());
std::cout << addr << std::endl;
std::string ip_subnet("192.168.2.58/24");
IP_subnet sn=IP_subnet::parse(ip_subnet.begin(), ip_subnet.end());
std::cout <<sn << std::endl;
std::cout <<sn[0] << std::endl;
std::vector<IP_addr> out(20);
random_pick(sn, out);
std::cout << "---------------------\n";
for(auto &&e: out) {
std::cout << e << std::endl;
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment