/* Copyright (C) 2019 * * This file is part of the osdev components suite * * 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 2, 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, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifndef OSDEV_COMPONENTS_MQTT_COMPILETIMEDIGITS_H #define OSDEV_COMPONENTS_MQTT_COMPILETIMEDIGITS_H // std #include #include "compiletimestring.h" namespace osdev { namespace components { namespace mqtt { /** * @brief Calculate the number of digits needed to represent a given value in a given base. * @tparam B The base to use. * @param value The value to represent. * @return The number of digits. */ template constexpr std::size_t numberOfDigits(unsigned value) noexcept { static_assert(B > 0, "base must be larger than zero"); return (value / B) == 0 ? 1 : (1 + numberOfDigits(value / B)); } /** * @return stringified digit that represents the given single digit value. * @note Values can range from 0 to 37 inclusive which maps on 0-9A-Z. */ template constexpr char digit() noexcept { static_assert(value <= 37, "Value must lie between 0 and 37 both inclusive"); return (value < 10 ? '0' + static_cast(value) : 'A' + static_cast(value) - 10); } /** * @brief Recursive template definition that is used to determine the value of a given number N in a given base B. * @tparam N The number to obtain the representation for. * @tparam B The base to use. * @tparam Len The length of the representation including the 0 terminator. * If not provided the length is calculated on first instantiation of this template. * @tparam remains Empty parameter pack on first instantiation. Will be filled further by every following instantiation. */ template (N) + 1, unsigned... remains> struct Digits { static constexpr auto create() noexcept -> std::array { static_assert(B > 0, "base must be larger than zero"); return Digits(), remains...>::create(); } }; /** * @brief Termination template that will return the actual hex digit array that represents the given value. * @tparam B The base to use. * @tparam Len The length of the hexadecimal representation including 0 terminator. * @tparam remains Parameter pack that contains the hexadecimal character representations. */ template struct Digits<0, B, Len, remains...> { static constexpr auto create() noexcept -> std::array { static_assert(sizeof...(remains) + 1 == Len, "Parameter 'Len' must be equal to the length of the parameter pack 'remains' including the termination zero"); return std::array{ { remains..., 0 } }; } }; /** * @brief Digits builder can be used in combination with the compiletime_string. * @tparam N The number to obtain the compile time string representation for. * @tparam B The base to use (up to 37). * This template struct defines a produce() method and the return type of that method. */ template struct ProduceDigits { /** * @brief Return type definition of the produce method. */ using return_t = std::array(N) + 1>; /** * @brief Produce the actual representation. */ static constexpr return_t produce() noexcept { return Digits::create(); } }; } // End namespace mqtt } // End namespace components } // End namespace osdev #endif // OSDEV_COMPONENTS_MQTT_COMPILETIMEDIGITS_H