/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2026 Sadie Powell * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include namespace insp { /** Converts a number into a string with a binary suffix (e.g. 3,292,549.12 -> 3.14 mebibytes). * @param value The value to convert. * @param bits Whether the value is bits or bytes. */ inline std::string binary_suffix(uintmax_t value, bool bits = false) { static const std::map> suffixes = { { 1ULL<<40, "tebi" }, { 1ULL<<30, "gibi" }, { 1ULL<<20, "mebi" }, { 1ULL<<10, "kibi" }, }; const auto* unit = bits ? "bits" : "bytes"; for (const auto& [threshold, suffix] : suffixes) { if (value >= threshold) return FMT::format("{:.5} {}{}", double(value) / threshold, suffix, unit); } return FMT::format("{} {}", value, unit); } /** Calculates the percentage of \p total that \p part makes up. This can be called without zero * checks. * @param part The partial value. * @param total The total value. */ inline double percentage(double part, double total) { if (total == 0) return 0.0; return (part / total) * 100.0; } /** Adds two integers saturating the return type on overflow. * @param lhs The first integer. * @param rhs The second integer. * @return The largest amount of the two integers added together that is representable by the * return type on overflow. */ template constexpr R saturating_add(T1 lhs, T2 rhs) noexcept { using CommonType = std::common_type_t; if (std::cmp_greater(rhs, 0) && std::cmp_greater(lhs, std::numeric_limits::max() - rhs)) return std::numeric_limits::max(); // Too big for R. if (std::cmp_less(rhs, 0) && std::cmp_less(lhs, std::numeric_limits::min() - rhs)) return std::numeric_limits::min(); // Too small for R. const auto result = static_cast(lhs) + static_cast(rhs); if constexpr (std::is_signed_v != std::is_signed_v || std::is_signed_v != std::is_signed_v) { if (!std::in_range(result)) { return (std::cmp_less(lhs, 0) || std::cmp_less(rhs, 0)) ? std::numeric_limits::min() : std::numeric_limits::max(); } } return static_cast(result); } /** Subtracts two integers saturating the return type on overflow. * @param lhs The first integer. * @param rhs The second integer. * @return The largest amount of the two integers added together that is representable by the * return type on underflow. */ template constexpr R saturating_sub(T1 lhs, T2 rhs) noexcept { using CommonType = std::common_type_t; if (std::cmp_greater(rhs, 0) && std::cmp_less(lhs, std::numeric_limits::min() + rhs)) return std::numeric_limits::min(); // Too small for R. if (std::cmp_less(rhs, 0) && std::cmp_greater(lhs, std::numeric_limits::max() + rhs)) return std::numeric_limits::max(); // Too big for R. const auto result = static_cast(lhs) - static_cast(rhs); if constexpr (std::is_signed_v != std::is_signed_v || std::is_signed_v != std::is_signed_v) { if (!std::in_range(result)) { return (std::cmp_less(lhs, 0) || std::cmp_greater(rhs, 0)) ? std::numeric_limits::min() : std::numeric_limits::max(); } } return static_cast(result); } }