/* **************************************************************************** * Copyright 2019 Open Systems Development BV * * * * Permission is hereby granted, free of charge, to any person obtaining a * * copy of this software and associated documentation files (the "Software"), * * to deal in the Software without restriction, including without limitation * * the rights to use, copy, modify, merge, publish, distribute, sublicense, * * and/or sell copies of the Software, and to permit persons to whom the * * Software is furnished to do so, subject to the following conditions: * * * * The above copyright notice and this permission notice shall be included in * * all copies or substantial portions of the Software. * * * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * * DEALINGS IN THE SOFTWARE. * * ***************************************************************************/ #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