ipaddress 1.2.0
Loading...
Searching...
No Matches
ip-functions.hpp
Go to the documentation of this file.
1/**
2 * @file ip-functions.hpp
3 * @brief Utility functions for IP address
4 * @author Vladimir Shaleev
5 * @copyright MIT License
6 *
7 * This file contains functions for processing IP address ranges and networks.
8 * It provides functionalities `summarize_address_range`. These utilities
9 * enable efficient handling and manipulation of IP address data.
10 */
11
12#ifndef IPADDRESS_IP_FUNCTIONS_HPP
13#define IPADDRESS_IP_FUNCTIONS_HPP
14
16#include "fixed-vector.hpp"
17
18namespace IPADDRESS_NAMESPACE {
19
20namespace internal {
21
22template <typename T1, typename T2>
23struct ip_address_type {
24 static_assert(
25 std::is_same<T1, ip_address>::value ||
26 std::is_same<T2, ip_address>::value ||
27 std::is_same<T1, T2>::value,
28 "The IP address versions must match or at least be ip_address."
29 );
30
31 using type = typename std::conditional<
32 std::is_same<T1, ip_address>::value || std::is_same<T2, ip_address>::value,
34 T1
35 >::type;
36};
37
38template <typename T1, typename T2>
39struct ip_network_type {
40 static_assert(
41 std::is_same<T1, ip_network>::value ||
42 std::is_same<T2, ip_network>::value ||
43 std::is_same<T1, T2>::value,
44 "The IP network versions must match or at least be ip_network."
45 );
46
47 using type = typename std::conditional<
48 std::is_same<T1, ip_network>::value || std::is_same<T2, ip_network>::value,
50 T1
51 >::type;
52};
53
54template <typename... Args>
55struct is_ip_network_types {
56 static constexpr bool value = false;
57};
58
59template <typename T, typename... Args>
60struct is_ip_network_types<T, Args...> {
61 static constexpr bool value = is_ip_network_types<T>::value && (sizeof...(Args) > 0 ? is_ip_network_types<Args...>::value : true);
62};
63
64template <typename T>
65struct is_ip_network_types<T> {
66 static constexpr bool value = std::is_same<T, ipv4_network>::value || std::is_same<T, ipv6_network>::value || std::is_same<T, ip_network>::value;
67};
68
69template <typename... Args>
70struct ip_network_type_extract;
71
72template <typename T1, typename T2, typename... Args>
73struct ip_network_type_extract<T1, T2, Args...> {
74 using type = typename ip_network_type<typename ip_network_type<T1, T2>::type, typename ip_network_type_extract<Args...>::type>::type;
75};
76
77template <typename T1, typename T2>
78struct ip_network_type_extract<T1, T2> {
79 using type = typename ip_network_type<T1, T2>::type;
80};
81
82template <typename T>
83struct ip_network_type_extract<T> {
84 using type = typename ip_network_type<T, T>::type;
85};
86
87template <typename>
88struct summarize_sequence_type;
89
90template <>
91struct summarize_sequence_type<ipv4_address> {
92 using type = summarize_sequence<ipv4_network>;
93};
94
95template <>
96struct summarize_sequence_type<ipv6_address> {
97 using type = summarize_sequence<ipv6_network>;
98};
99
100template <>
101struct summarize_sequence_type<ip_address> {
102 using type = summarize_sequence<ip_network, ip_any_summarize_iterator>;
103};
104
105template <typename Key, typename Value>
106struct key_value {
107 Key key;
108 Value value;
109};
110
111template <typename Key, typename Value>
112struct less_pair {
113 IPADDRESS_NODISCARD IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE bool operator()(const key_value<Key, Value>& item, const Key& key) const IPADDRESS_NOEXCEPT {
114 return item.key < key;
115 }
116};
117
118template <typename It, typename T, typename Cmp = std::less<T>>
119IPADDRESS_NODISCARD IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE It find_lower_bound(It first, It last, const T& value, Cmp&& cmp = {}) IPADDRESS_NOEXCEPT {
120 auto size = last - first;
121 while (size > 0) {
122 auto half = size / 2;
123 auto middle = first;
124 middle += half;
125 if (cmp(*middle, value)) {
126 first = middle;
127 ++first;
128 size = size - half - 1;
129 } else {
130 size = half;
131 }
132 }
133 return first;
134}
135
136IPADDRESS_NODISCARD IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE bool is_clang_8_and_below() IPADDRESS_NOEXCEPT {
137#if defined(__clang__) && !defined(__apple_build_version__) && __clang_major__ <= 8
138 return true;
139#else
140 return false;
141#endif
142}
143
144template <typename Ip>
145IPADDRESS_NODISCARD IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE typename summarize_sequence_type<Ip>::type summarize_address_range(const Ip& first, const Ip& last, error_code& code) IPADDRESS_NOEXCEPT {
147 if (first.version() != last.version()) {
149 return {};
150 }
151 if (first > last) {
153 return {};
154 }
155 return { first, last };
156}
157
158template <size_t N, typename It>
159IPADDRESS_NODISCARD IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE auto fixed_collapse_addresses(It first, It last, error_code& code) IPADDRESS_NOEXCEPT
160 -> fixed_vector<typename std::iterator_traits<It>::value_type, N> {
161 using network_type = typename std::iterator_traits<It>::value_type;
162 using address_type = typename network_type::ip_address_type;
163
164 const auto version = first->version();
165 const auto max_prefixlen = version == ip_version::V4
166 ? ipv4_network::base_max_prefixlen
167 : ipv6_network::base_max_prefixlen;
168
169 fixed_vector<network_type, N> nets;
170 fixed_vector<address_type, N> ips;
171 fixed_vector<key_value<network_type, network_type>, N> subnets;
172
173 for (auto it = first; it != last; ++it) {
174 const auto& net = *it;
175 if (net.version() != version) {
177 return {};
178 }
179 if (net.prefixlen() != max_prefixlen) {
180 nets.emplace_back(net);
181 } else {
182 const auto network_address = net.network_address();
183 auto lower = find_lower_bound(ips.begin(), ips.end(), network_address);
184 if (lower == ips.end() || *lower != network_address) {
185 ips.insert(lower, network_address);
186 }
187 }
188 }
189 if (!ips.empty()) {
190 auto it = ips.begin();
191 auto first = *it;
192 auto last = *it++;
193 auto lastUint = (typename network_type::uint_type) last;
194 for (; it != ips.end(); ++it) {
195 const auto ipUint = (typename network_type::uint_type) *it;
196 if (ipUint != lastUint + 1) {
197 auto range = summarize_address_range(first, last, code);
198 if (code != error_code::no_error) {
199 return {};
200 }
201 for (const auto& net : range) {
202 nets.emplace_back(net);
203 }
204 first = *it;
205 }
206 last = *it;
207 lastUint = ipUint;
208 }
209 auto range = summarize_address_range(first, last, code);
210 if (code != error_code::no_error) {
211 return {};
212 }
213 for (const auto& net : range) {
214 nets.emplace_back(net);
215 }
216 }
217 while (!nets.empty()) {
218 const auto net = nets.back();
219 const auto supernet = net.supernet();
220 nets.pop_back();
221 auto it = find_lower_bound(subnets.begin(), subnets.end(), supernet, less_pair<network_type, network_type>{});
222 if (it != subnets.end() && it->key == supernet) {
223 if (it->value != net) {
224 subnets.erase(it);
225 nets.emplace_back(supernet);
226 }
227 } else {
228 subnets.emplace(it, supernet, net);
229 }
230 }
231 fixed_vector<network_type, N> result;
232 if (!subnets.empty()) {
233 fixed_vector<network_type, N> subnet_values;
234 for (auto it = subnets.begin(); it != subnets.end(); ++it) {
235 auto lower = find_lower_bound(subnet_values.begin(), subnet_values.end(), it->key);
236 subnet_values.insert(lower, it->value);
237 }
238 auto it = subnet_values.begin();
239 auto last = *it;
240 result.emplace_back(last);
241 ++it;
242 for (; it != subnet_values.end(); ++it) {
243 if (last.broadcast_address() >= it->broadcast_address()) {
244 continue;
245 }
246 last = *it;
247 result.emplace_back(last);
248 }
249 }
250 return result;
251}
252
253template <typename Result, typename It>
254IPADDRESS_NODISCARD IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE Result runtime_collapse_addresses(It first, It last, error_code& code) IPADDRESS_NOEXCEPT {
255 using network_type = typename std::iterator_traits<It>::value_type;
256 using address_type = typename network_type::ip_address_type;
257
258 Result result;
259 if (first == last) {
260 return result;
261 }
262
263 const auto version = first->version();
264 const auto max_prefixlen = version == ip_version::V4
265 ? ipv4_network::base_max_prefixlen
266 : ipv6_network::base_max_prefixlen;
267
268 std::vector<network_type> nets;
269 std::set<address_type> ips;
270 std::map<network_type, network_type> subnets;
271
272 for (auto it = first; it != last; ++it) {
273 const auto& net = *it;
274 if (net.version() != version) {
276 return {};
277 }
278 if (net.prefixlen() != max_prefixlen) {
279 nets.emplace_back(net);
280 } else {
281 const auto network_address = net.network_address();
282 ips.insert(network_address);
283 }
284 }
285 if (!ips.empty()) {
286 auto it = ips.begin();
287 auto first = *it;
288 auto last = *it++;
289 auto lastUint = (typename network_type::uint_type) last;
290 for (; it != ips.end(); ++it) {
291 const auto ipUint = (typename network_type::uint_type) *it;
292 if (ipUint != lastUint + 1) {
293 auto range = summarize_address_range(first, last, code);
294 if (code != error_code::no_error) {
295 return {};
296 }
297 for (const auto& net : range) {
298 nets.emplace_back(net);
299 }
300 first = *it;
301 }
302 last = *it;
303 lastUint = ipUint;
304 }
305 auto range = summarize_address_range(first, last, code);
306 if (code != error_code::no_error) {
307 return {};
308 }
309 for (const auto& net : range) {
310 nets.emplace_back(net);
311 }
312 }
313 while (!nets.empty()) {
314 const auto net = nets.back();
315 const auto supernet = net.supernet();
316 nets.pop_back();
317 auto existing = subnets.find(supernet);
318 if (existing != subnets.end()) {
319 subnets.erase(existing);
320 nets.emplace_back(supernet);
321 } else {
322 subnets.emplace(std::make_pair(supernet, net));
323 }
324 }
325 if (!subnets.empty()) {
326 std::vector<network_type> subnet_values;
327 subnet_values.reserve(subnets.size());
328 for (auto it = subnets.begin(); it != subnets.end(); ++it) {
329 subnet_values.emplace_back(it->second);
330 }
331 std::sort(subnet_values.begin(), subnet_values.end());
332 auto it = subnet_values.begin();
333 auto last = *it;
334 result.emplace_back(last);
335 ++it;
336 for (; it != subnet_values.end(); ++it) {
337 if (last.broadcast_address() >= it->broadcast_address()) {
338 continue;
339 }
340 last = *it;
341 result.emplace_back(last);
342 }
343 }
344 return result;
345}
346
347template <size_t N, typename It>
348IPADDRESS_NODISCARD IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE auto collapse_addresses(It first, It last, error_code& code) IPADDRESS_NOEXCEPT
349 -> fixed_vector<typename std::iterator_traits<It>::value_type, N> {
350 using result_type = fixed_vector<typename std::iterator_traits<It>::value_type, N>;
351 // fixed_collapse_addresses is called in the following 3 cases:
352 // 1. the calculation is performed at compile time;
353 // 2. if the number of elements in the input collection is less than or equal to 16,
354 // fixed_collapse_addresses is used, even though it will be executed at runtime;
355 // in fact, fixed_collapse_addresses is usually faster than runtime_collapse_addresses,
356 // but due to the limited stack size, it should not be used for large N;
357 // 3. before clang 9 there was no clear way to tell if execution happens at compile time or
358 // runtime, so for clang 8 and below we always go with the fixed_collapse_addresses pipeline.
359 return IPADDRESS_IS_CONST_EVALUATED(code) || N <= 16 || is_clang_8_and_below()
360 ? fixed_collapse_addresses<N>(first, last, code)
361 : runtime_collapse_addresses<result_type>(first, last, code);
362}
363
364} // namespace IPADDRESS_NAMESPACE::internal
365
366/**
367 * Summarizes an IP address range into the smallest set of contiguous network blocks.
368 *
369 * This function is designed specifically for iterating over the minimal number of
370 * contiguous network blocks that fully cover a given IP address range. By summarizing
371 * the range, it reduces redundancy and enhances efficiency, making it ideal for
372 * scenarios like routing table generation or network optimization tasks.
373 *
374 * Example:
375 * @code{.cpp}
376 * error_code code{};
377 * auto summarized = summarize_address_range(
378 * ipv6_address::parse("2001:db8::1"),
379 * ipv6_address::parse("2001:db8::8"),
380 * code
381 * );
382 * if (code == error_code::no_error) {
383 * for (const auto& net : summarized) {
384 * std::cout << net << std::endl;
385 * }
386 * }
387 *
388 * // out:
389 * // 2001:db8::1/128
390 * // 2001:db8::2/127
391 * // 2001:db8::4/126
392 * // 2001:db8::8/128
393 *
394 * // When working with ip_address, you can also use ipv4_address or ipv6_address as one of the arguments.
395 * // In this case, this address will be interpreted as ip_address, and iteration will occur for ip_network
396 * // summarize_address_range(ipv6_address::parse("2001:db8::1"), ip_address::parse("2001:db8::8"), code); // OK
397 * @endcode
398 *
399 * @tparam FirstIp The type representing an IP address.
400 * @tparam LastIp The type representing an IP address.
401 * @param[in] first The starting IP address of the range.
402 * @param[in] last The ending IP address of the range.
403 * @param[out] code A reference to an `error_code` object that will be set if the operation is not possible.
404 * @return A container of summarized network blocks.
405 * @note This function performs an efficient summarization of IP ranges, but the computational
406 * complexity may depend on the size of the range.
407 */
408IPADDRESS_EXPORT template <typename FirstIp, typename LastIp>
409IPADDRESS_NODISCARD IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE auto summarize_address_range(const FirstIp& first, const LastIp& last, error_code& code) IPADDRESS_NOEXCEPT
410 -> decltype(internal::summarize_address_range(
411 typename internal::ip_address_type<FirstIp, LastIp>::type{first},
412 typename internal::ip_address_type<FirstIp, LastIp>::type{last},
413 code)) {
414 return internal::summarize_address_range(typename internal::ip_address_type<FirstIp, LastIp>::type{first}, typename internal::ip_address_type<FirstIp, LastIp>::type{last}, code);
415}
416
417/**
418 * Summarizes an IP address range into the smallest set of contiguous network blocks.
419 *
420 * This function is designed specifically for iterating over the minimal number of
421 * contiguous network blocks that fully cover a given IP address range. By summarizing
422 * the range, it reduces redundancy and enhances efficiency, making it ideal for
423 * scenarios like routing table generation or network optimization tasks.
424 *
425 * Example:
426 * @code{.cpp}
427 * for (const auto& net : summarize_address_range(ipv4_address::parse("192.0.2.0"), ipv4_address::parse("192.0.2.130"))) {
428 * std::cout << net << std::endl;
429 * }
430 *
431 * // out:
432 * // 192.0.2.0/25
433 * // 192.0.2.128/31
434 * // 192.0.2.130/32
435 *
436 * // When working with ip_address, you can also use ipv4_address or ipv6_address as one of the arguments.
437 * // In this case, this address will be interpreted as ip_address, and iteration will occur for ip_network
438 * // summarize_address_range(ipv4_address::parse("192.0.2.0"), ip_address::parse("192.0.2.130")); // OK
439 * @endcode
440 *
441 * @tparam FirstIp The type representing an IP address.
442 * @tparam LastIp The type representing an IP address.
443 * @param[in] first The starting IP address of the range.
444 * @param[in] last The ending IP address of the range.
445 * @return A container of summarized network blocks.
446 * @throw logic_error Thrown with a message corresponding to the error code.
447 * @note This function performs an efficient summarization of IP ranges, but the computational
448 * complexity may depend on the size of the range.
449 */
450IPADDRESS_EXPORT template <typename FirstIp, typename LastIp>
454 const auto result = summarize_address_range(first, last, code);
455 if (code != error_code::no_error) {
456 raise_error(code, 0, "", 0);
457 }
458 return result;
459}
460
461/**
462 * Collapses a collection of IP networks into the smallest set of contiguous networks.
463 *
464 * This function is designed to take a collection of IP networks and reduce them into the
465 * smallest number of contiguous networks. This is useful for optimizing routing tables or
466 * enhancing network efficiency.
467 *
468 * Example:
469 * @code{.cpp}
470 * consteval ipv4_network get_last_collapsed() {
471 * constexpr std::array nets = {
472 * ipv4_network::parse("192.0.2.0/25"),
473 * ipv4_network::parse("192.0.2.128/25")
474 * };
475 *
476 * error_code code{};
477 * constexpr auto collapsed = collapse_addresses(nets, code);
478 * return code == error_code::no_error ? collapsed.back() : ipv4_network{};
479 * }
480 *
481 * int main() {
482 * constexpr auto net = get_last_collapsed();
483 * std::cout << net << std::endl;
484 *
485 * // out:
486 * // 192.0.2.0/24
487 * return 0;
488 * }
489 * @endcode
490 *
491 * @tparam Net The type of the IP network.
492 * @tparam N The number of networks in the collection.
493 * @param[in] nets The collection of IP networks to be collapsed.
494 * @param[out] code A reference to an `error_code` object that will be set if the operation is not possible.
495 * @return A container of collapsed networks.
496 */
497IPADDRESS_EXPORT template <typename Net, size_t N>
498IPADDRESS_NODISCARD IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE fixed_vector<Net, N> collapse_addresses(const std::array<Net, N>& nets, error_code& code) IPADDRESS_NOEXCEPT {
499 return N != 0 ? internal::collapse_addresses<N>(&nets[0], &nets[0] + nets.size(), code) : fixed_vector<Net, N>{};
500}
501
502/**
503 * Collapses a collection of IP networks into the smallest set of contiguous networks.
504 *
505 * This function is designed to take a collection of IP networks and reduce them into the
506 * smallest number of contiguous networks. This is useful for optimizing routing tables or
507 * enhancing network efficiency.
508 *
509 * Example:
510 * @code{.cpp}
511 * consteval ip_network get_last_collapsed() {
512 * constexpr ip_network nets[] = {
513 * ip_network::parse("192.0.2.0/25"),
514 * ip_network::parse("192.0.2.128/25")
515 * };
516 *
517 * error_code code{};
518 * constexpr auto collapsed = collapse_addresses(nets, code);
519 * return code == error_code::no_error ? collapsed.back() : ip_network{};
520 * }
521 *
522 * int main() {
523 * constexpr auto net = get_last_collapsed();
524 * std::cout << net << std::endl;
525 *
526 * // out:
527 * // 192.0.2.0/24
528 * return 0;
529 * }
530 * @endcode
531 *
532 * @tparam Net The type of the IP network.
533 * @tparam N The number of networks in the collection.
534 * @param[in] nets The collection of IP networks to be collapsed.
535 * @param[out] code A reference to an `error_code` object that will be set if the operation is not possible.
536 * @return A container of collapsed networks.
537 */
538IPADDRESS_EXPORT template <typename Net, size_t N>
540 return internal::collapse_addresses<N>(&nets[0], &nets[0] + N, code);
541}
542
543/**
544 * Collapses a collection of IP networks into the smallest set of contiguous networks.
545 *
546 * This function is designed to take a collection of IP networks and reduce them into the
547 * smallest number of contiguous networks. This is useful for optimizing routing tables or
548 * enhancing network efficiency.
549 *
550 * Example:
551 * @code{.cpp}
552 * consteval ip_network get_last_collapsed() {
553 * error_code code{};
554 * auto collapsed = collapse_addresses(
555 * code,
556 * ipv4_network::parse("192.0.2.0/25"),
557 * ip_network::parse("192.0.2.128/25"),
558 * ip_network::parse("192.0.2.255/32"),
559 * ip_network::parse("192.0.2.255/32"));
560 * return code == error_code::no_error ? collapsed.back() : ip_network{};
561 * }
562 *
563 * int main() {
564 * constexpr auto net = get_collapsed_net();
565 * std::cout << net << std::endl;
566 *
567 * // out:
568 * // 192.0.2.0/24
569 * return 0;
570 * }
571 * @endcode
572 *
573 * @tparam Nets The types of the IP networks.
574 * @param[out] code A reference to an `error_code` object that will be set if the operation is not possible.
575 * @param[in] nets The collection of IP networks to be collapsed.
576 * @return A container of collapsed networks.
577 */
578IPADDRESS_EXPORT template <typename... Nets, typename std::enable_if<internal::is_ip_network_types<Nets...>::value, bool>::type = true>
580 -> fixed_vector<typename internal::ip_network_type_extract<Nets...>::type, sizeof...(Nets)> {
581 using Net = typename internal::ip_network_type_extract<Nets...>::type;
582 const Net net_array[] = { Net(nets)... };
583 return collapse_addresses(net_array, code);
584}
585
586/**
587 * Collapses a collection of IP networks into the smallest set of contiguous networks.
588 *
589 * This function is designed to take a collection of IP networks and reduce them into the
590 * smallest number of contiguous networks. This is useful for optimizing routing tables or
591 * enhancing network efficiency.
592 *
593 * Example:
594 * @code{.cpp}
595 * std::vector<ip_network> nets = {
596 * ip_network::parse("2001:db8::1/128"),
597 * ip_network::parse("2001:db8::2/128"),
598 * ip_network::parse("2001:db8::3/128"),
599 * ip_network::parse("2001:db8::5/128") };
600 *
601 * error_code code{};
602 * const auto collapsed = collapse_addresses(nets.begin(), nets.end(), code);
603 * if (code == error_code::no_error) {
604 * for (const auto& net : collapsed) {
605 * std::cout << net << std::endl;
606 * }
607 * }
608 *
609 * // out:
610 * // 2001:db8::1/128
611 * // 2001:db8::2/127
612 * // 2001:db8::5/128
613 * @endcode
614 *
615 * @tparam It The type of the iterator.
616 * @param[in] first The beginning of the range of IP networks to be collapsed.
617 * @param[in] last The end of the range of IP networks to be collapsed.
618 * @param[out] code A reference to an `error_code` object that will be set if the operation is not possible.
619 * @return A container of collapsed networks.
620 */
621IPADDRESS_EXPORT template <typename It>
623 -> std::vector<typename std::iterator_traits<It>::value_type> {
624 return internal::runtime_collapse_addresses<std::vector<typename std::iterator_traits<It>::value_type>>(first, last, code);
625}
626
627/**
628 * Collapses a collection of IP networks into the smallest set of contiguous networks.
629 *
630 * This function is designed to take a collection of IP networks and reduce them into the
631 * smallest number of contiguous networks. This is useful for optimizing routing tables or
632 * enhancing network efficiency.
633 *
634 * Example:
635 * @code{.cpp}
636 * constexpr std::array<ipv4_network, 2> nets = {
637 * ipv4_network::parse("192.0.2.0/25"),
638 * ipv4_network::parse("192.0.2.128/25")
639 * };
640 *
641 * constexpr auto collapsed = collapse_addresses(nets);
642 * for (const auto& net : collapsed) {
643 * std::cout << net << std::endl;
644 * }
645 *
646 * // out:
647 * // 192.0.2.0/24
648 * @endcode
649 *
650 * @tparam Net The type of the IP network.
651 * @tparam N The number of networks in the collection.
652 * @param[in] nets The collection of IP networks to be collapsed.
653 * @return A container of collapsed networks.
654 * @throw logic_error Thrown with a message corresponding to the error code.
655 */
656IPADDRESS_EXPORT template <typename Net, size_t N>
659 const auto result = collapse_addresses(nets, code);
660 if (code != error_code::no_error) {
661 raise_error(code, 0, "", 0);
662 }
663 return result;
664}
665
666/**
667 * Collapses a collection of IP networks into the smallest set of contiguous networks.
668 *
669 * This function is designed to take a collection of IP networks and reduce them into the
670 * smallest number of contiguous networks. This is useful for optimizing routing tables or
671 * enhancing network efficiency.
672 *
673 * Example:
674 * @code{.cpp}
675 * constexpr ip_network nets[] = {
676 * ip_network::parse("192.0.2.0/25"),
677 * ip_network::parse("192.0.2.128/25")
678 * };
679 *
680 * constexpr auto collapsed = collapse_addresses(nets);
681 * for (const auto& net : collapsed) {
682 * std::cout << net << std::endl;
683 * }
684 *
685 * // out:
686 * // 192.0.2.0/24
687 * @endcode
688 *
689 * @tparam Net The type of the IP network.
690 * @tparam N The number of networks in the collection.
691 * @param[in] nets The collection of IP networks to be collapsed.
692 * @return A container of collapsed networks.
693 * @throw logic_error Thrown with a message corresponding to the error code.
694 */
695IPADDRESS_EXPORT template <typename Net, size_t N>
698 const auto result = collapse_addresses(nets, code);
699 if (code != error_code::no_error) {
700 raise_error(code, 0, "", 0);
701 }
702 return result;
703}
704
705/**
706 * Collapses a collection of IP networks into the smallest set of contiguous networks.
707 *
708 * This function is designed to take a collection of IP networks and reduce them into the
709 * smallest number of contiguous networks. This is useful for optimizing routing tables or
710 * enhancing network efficiency.
711 *
712 * Example:
713 * @code{.cpp}
714 * constexpr auto collapsed = collapse_addresses(
715 * ip_network::parse("192.0.2.255/32"),
716 * ipv4_network::parse("192.0.2.0/25"),
717 * ipv4_network::parse("192.0.2.128/25"));
718 *
719 * for (const auto& net : collapsed) {
720 * std::cout << net << std::endl;
721 * }
722 *
723 * // out:
724 * // 192.0.2.0/24
725 * @endcode
726 *
727 * @tparam Nets The types of the IP networks.
728 * @param[in] nets The collection of IP networks to be collapsed.
729 * @return A container of collapsed networks.
730 * @throw logic_error Thrown with a message corresponding to the error code.
731 */
732IPADDRESS_EXPORT template <typename... Nets, typename std::enable_if<internal::is_ip_network_types<Nets...>::value, bool>::type = true>
734 -> fixed_vector<typename internal::ip_network_type_extract<Nets...>::type, sizeof...(Nets)> {
736 const auto result = collapse_addresses(code, nets...);
737 if (code != error_code::no_error) {
738 raise_error(code, 0, "", 0);
739 }
740 return result;
741}
742
743/**
744 * Collapses a collection of IP networks into the smallest set of contiguous networks.
745 *
746 * This function is designed to take a collection of IP networks and reduce them into the
747 * smallest number of contiguous networks. This is useful for optimizing routing tables or
748 * enhancing network efficiency.
749 *
750 * Example:
751 * @code{.cpp}
752 * std::vector<ip_network> nets = {
753 * ip_network::parse("2001:db8::1/128"),
754 * ip_network::parse("2001:db8::2/128"),
755 * ip_network::parse("2001:db8::3/128"),
756 * ip_network::parse("2001:db8::5/128") };
757 *
758 * const auto collapsed = collapse_addresses(nets.begin(), nets.end());
759 * for (const auto& net : collapsed) {
760 * std::cout << net << std::endl;
761 * }
762 *
763 * // out:
764 * // 2001:db8::1/128
765 * // 2001:db8::2/127
766 * // 2001:db8::5/128
767 * @endcode
768 *
769 * @tparam It The type of the iterator.
770 * @param[in] first The beginning of the range of IP networks to be collapsed.
771 * @param[in] last The end of the range of IP networks to be collapsed.
772 * @return A container of collapsed networks.
773 * @throw logic_error Thrown with a message corresponding to the error code.
774 */
775IPADDRESS_EXPORT template <typename It>
777 -> std::vector<typename std::iterator_traits<It>::value_type> {
779 const auto result = collapse_addresses(first, last, code);
780 if (code != error_code::no_error) {
781 raise_error(code, 0, "", 0);
782 }
783 return std::move(result);
784}
785
786} // namespace IPADDRESS_NAMESPACE
787
788#endif // IPADDRESS_IP_FUNCTIONS_HPP
A fixed-size vector class template.
Definition fixed-vector.hpp:308
A class that represents an IP address, supporting both IPv4 and IPv6 formats.
Definition ip-any-address.hpp:73
A class that encapsulates both IPv4 and IPv6 network functionalities.
Definition ip-any-network.hpp:67
#define IPADDRESS_NOEXCEPT_WHEN_NO_EXCEPTIONS
Definition config.hpp:96
#define IPADDRESS_EXPORT
Definition config.hpp:45
#define IPADDRESS_NODISCARD
Definition config.hpp:101
#define IPADDRESS_IS_CONST_EVALUATED(x)
Definition config.hpp:154
#define IPADDRESS_FORCE_INLINE
Definition config.hpp:115
#define IPADDRESS_NAMESPACE
Definition config.hpp:41
#define IPADDRESS_NOEXCEPT
Definition config.hpp:92
constexpr inline auto collapse_addresses(It first, It last) -> std::vector< typename std::iterator_traits< It >::value_type >
Collapses a collection of IP networks into the smallest set of contiguous networks.
Definition ip-functions.hpp:776
constexpr inline auto collapse_addresses(const Nets &... nets) -> fixed_vector< typename internal::ip_network_type_extract< Nets... >::type, sizeof...(Nets)>
Collapses a collection of IP networks into the smallest set of contiguous networks.
Definition ip-functions.hpp:733
constexpr inline auto summarize_address_range(const FirstIp &first, const LastIp &last) -> decltype(summarize_address_range(first, last, *std::declval< error_code * >()))
Summarizes an IP address range into the smallest set of contiguous network blocks.
Definition ip-functions.hpp:451
constexpr inline fixed_vector< Net, N > collapse_addresses(const std::array< Net, N > &nets)
Collapses a collection of IP networks into the smallest set of contiguous networks.
Definition ip-functions.hpp:657
constexpr inline auto collapse_addresses(It first, It last, error_code &code) noexcept -> std::vector< typename std::iterator_traits< It >::value_type >
Collapses a collection of IP networks into the smallest set of contiguous networks.
Definition ip-functions.hpp:622
constexpr inline auto summarize_address_range(const FirstIp &first, const LastIp &last, error_code &code) noexcept -> decltype(internal::summarize_address_range(typename internal::ip_address_type< FirstIp, LastIp >::type{first}, typename internal::ip_address_type< FirstIp, LastIp >::type{last}, code))
Summarizes an IP address range into the smallest set of contiguous network blocks.
Definition ip-functions.hpp:409
error_code
Enumeration of error codes for IP address parsing and validation.
Definition errors.hpp:52
@ last_address_must_be_greater_than_first
The last IP address in the range must be greater than the first IP address.
@ invalid_version
The IP address version does not match the expected version.
@ no_error
Indicates the absence of any errors.
constexpr inline fixed_vector< Net, N > collapse_addresses(const std::array< Net, N > &nets, error_code &code) noexcept
Collapses a collection of IP networks into the smallest set of contiguous networks.
Definition ip-functions.hpp:498
constexpr inline fixed_vector< Net, N > collapse_addresses(const Net(&nets)[N])
Collapses a collection of IP networks into the smallest set of contiguous networks.
Definition ip-functions.hpp:696
constexpr inline auto collapse_addresses(error_code &code, const Nets &... nets) noexcept -> fixed_vector< typename internal::ip_network_type_extract< Nets... >::type, sizeof...(Nets)>
Collapses a collection of IP networks into the smallest set of contiguous networks.
Definition ip-functions.hpp:579
constexpr inline fixed_vector< Net, N > collapse_addresses(const Net(&nets)[N], error_code &code) noexcept
Collapses a collection of IP networks into the smallest set of contiguous networks.
Definition ip-functions.hpp:539