/* ***************************************************************************** * kblib is a general utility library for C++14 and C++17, intended to provide * performant high-level abstractions and more expressive ways to do simple * things. * * Copyright (c) 2021 killerbee * * This program 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, either version 3 of the License, or * (at your option) any later version. * * 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 . * ****************************************************************************/ /** * @file * @brief Contains some utilities for manipulating and querying string * representations. * * @author killerbee * @date 2019-2021 * @copyright GNU General Public Licence v3.0 */ #ifndef KBLIB_FORMAT_H #define KBLIB_FORMAT_H #include "fakestd.h" #include #include namespace KBLIB_NS { /** * @brief Calculates the number of decimal digits needed to represent a number, * plus one for negative numbers. * * @param val The number to be checked. * @return int The number of digits needed to represent a number. */ template constexpr auto count_digits(Number val) -> enable_if_t::value, int> { if (val == 0) { return 1; } else { return std::numeric_limits::digits10; } } /** * @brief Calculates the number of decimal digits needed to represent a number, * plus one for negative numbers. * * @param val The number to be checked. * @return int The number of digits needed to represent a number. */ template constexpr auto count_digits(Number val) -> enable_if_t::value and std::is_signed::value, int> { if (val == 0 or val == 1) { return 1; } else { return static_cast(std::ceil( std::nextafter(std::log10(std::fabs(val)), INFINITY))) + (val < 0); } } /** * @brief Calculates the number of decimal digits needed to represent a number. * * @param val The number to be checked. * @return int The number of digits needed to represent a number. */ template constexpr auto count_digits(Number val) -> enable_if_t::value, int> { if (val == 0) { return 1; } else if (val == static_cast(-1)) { return static_cast(std::ceil(std::log10(val))); } else { return static_cast(std::ceil(std::log10(val + 1))); } } /** * @brief Calculates the number of digits needed to represent a number in a * given base, plus one for negative numbers. * * @param val The number to be checked. * @param base The base to be used for calculation. * @return int The number of digits needed to represent a number. */ template constexpr auto count_digits(Number val, int base) -> int { if (val == 0) { return 1; } else if (std::is_floating_point::value) { return static_cast( std::ceil(std::numeric_limits::digits * std::logb(base))); } else { return static_cast( std::ceil(std::log(std::abs(val) + 1) / std::log(base))) + (val < 0); } } /** * @brief Returns the necessary number of digits to represent the largest value * in an input range. * * @param first The beginning of the input range. * @param last The end of the input range. * @return int The necessary number of digits to represent any value in the * input. */ template auto max_count_digits(ForwardIt first, ForwardIt last) -> int { if (first == last) { return 0; } return count_digits(*std::max_element(first, last)); } /** * @brief Returns the necessary number of digits to represent the largest value * in an input range. * * @param first The beginning of the input range. * @param last The end of the input range. * @param base The base to be used for calculation. * @return int The necessary number of digits to represent any value in the * input. */ template auto max_count_digits(ForwardIt first, ForwardIt last, int base) -> int { if (first == last) { return 0; } return count_digits(*std::max_element(first, last), base); } } // namespace KBLIB_NS #endif // KBLIB_FORMAT_H