Last active
October 16, 2015 17:09
-
-
Save windoze/f3cbba9ff2cd8fc63177 to your computer and use it in GitHub Desktop.
Random pick some IP address from a subnet
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
#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