Arene Base
Fundamental Utilities For Safety Critical C++
Loading...
Searching...
No Matches
to_inline_string.hpp
Go to the documentation of this file.
1// parasoft-begin-suppress AUTOSAR-A2_8_1-a-2 "False positive: also defines arene::base::to_inline_string"
2
3// Copyright 2024, Toyota Motor Corporation
4//
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6
7#ifndef INCLUDE_GUARD_ARENE_BASE_ARENE_BASE_STRINGS_FORMAT_TO_INLINE_STRING_HPP_
8#define INCLUDE_GUARD_ARENE_BASE_ARENE_BASE_STRINGS_FORMAT_TO_INLINE_STRING_HPP_
9
10// IWYU pragma: private, include "arene/base/inline_string.hpp"
11// IWYU pragma: friend "arene/base/strings/.*"
12
13// parasoft-begin-suppress AUTOSAR-A16_2_2-a-2 "Arene Base aggregate headers permitted by A16-2-2 Permit #1"
14#include "arene/base/array/array.hpp"
15#include "arene/base/constraints/constraints.hpp"
16#include "arene/base/contracts/contract.hpp"
17#include "arene/base/detail/raw_c_string.hpp"
18#include "arene/base/math/power_of_2.hpp"
19#include "arene/base/stdlib_choice/climits.hpp"
20#include "arene/base/stdlib_choice/cstddef.hpp"
21#include "arene/base/stdlib_choice/cstdint.hpp"
22#include "arene/base/stdlib_choice/enable_if.hpp"
23#include "arene/base/stdlib_choice/ignore.hpp"
24#include "arene/base/stdlib_choice/integral_constant.hpp"
25#include "arene/base/stdlib_choice/is_integral.hpp"
26#include "arene/base/stdlib_choice/is_signed.hpp"
27#include "arene/base/stdlib_choice/is_unsigned.hpp"
28#include "arene/base/stdlib_choice/make_unsigned.hpp"
29#include "arene/base/stdlib_choice/numeric_limits.hpp"
30#include "arene/base/strings/inline_string.hpp"
31// parasoft-end-suppress AUTOSAR-A16_2_2-a-2
32
33// parasoft-begin-suppress AUTOSAR-A7_1_5-a-2 "Trailing return syntax permitted by A7-1-5 Permit #1 v1.0.0"
34
35namespace arene {
36namespace base {
37
38namespace to_string_detail {
39
40/// @brief Determine the number of digits required to represent all values of a given integral type
41/// @tparam T The type to get the digit count for
42/// @return The minimum number of characters needed to represent a given type.
43template <typename T>
44inline constexpr auto digits_for_integral_value() -> std::size_t {
45 constexpr std::size_t twenty_five{25U};
46 constexpr std::size_t two_to_the_25th{::arene::base::power_of_2(twenty_five)};
47 /// log2(10) scaled by 2^25, to allow integer calculations for required decimal digits
48 constexpr std::size_t log2_of_10_scaled_by_2_to_25{111465410U};
49 constexpr std::size_t signed_digit_size{std::is_signed<T>::value ? 1U : 0U};
50 return ((sizeof(T) * static_cast<std::size_t>(CHAR_BIT) - signed_digit_size) * two_to_the_25th +
51 log2_of_10_scaled_by_2_to_25 - 1U) /
52 log2_of_10_scaled_by_2_to_25 +
53 signed_digit_size;
54}
55
56/// @brief Trait that represents the number of decimal digits required to represent all values of type @c T as a string.
57/// @tparam T The type to get the digit count for
58template <typename T, typename = constraints<>>
59class required_decimal_digits;
60
61/// @brief Trait that represents the number of decimal digits required to represent all values of an integral type @c T
62/// as a string.
63/// @tparam T The type to get the digit count for
64template <typename T>
65class required_decimal_digits<T, constraints<std::enable_if_t<std::is_integral<T>::value>>>
66 : public std::integral_constant<std::size_t, digits_for_integral_value<T>()> {};
67
68/// @brief Trait that represents the number of decimal digits required to represent all values of @c bool as a string
69template <>
70// NOLINTNEXTLINE(readability-magic-numbers) This is making it not a magic number, clang-tidy just can't see it.
71class required_decimal_digits<bool> : public std::integral_constant<std::size_t, 5> {};
72
73/// @brief The number of decimal digits required to represent all values of an integral type @c T as a string.
74/// @tparam T The type to get the digit count for
75template <typename T>
76extern constexpr auto required_decimal_digits_v = required_decimal_digits<T>::value;
77
78/// @brief Check if a given number of characters is enough to hold the string representation of any value of the given
79/// type
80/// @return true if @c S is a sufficient number of characters to represent all values of @c T
81/// @return false otherwise
82template <typename T, std::size_t S>
83extern constexpr bool is_large_enough_for{S >= required_decimal_digits_v<T>};
84
85/// @brief Check if a given value is negative: this is always @c false for unsigned values
86/// @tparam T The type of value to check
87/// @return Always returns @c false
88template <typename T, constraints<std::enable_if_t<std::is_unsigned<T>::value>> = nullptr>
89constexpr auto is_negative_value(T) noexcept -> bool {
90 return false;
91}
92
93/// @brief Check if a given value is negative
94/// @tparam T The type of value to check
95/// @param value The value to check
96/// @return If the value is negative, returns @c true, else returns @c false
97template <typename T, constraints<std::enable_if_t<std::is_signed<T>::value>> = nullptr>
98constexpr auto is_negative_value(T value) noexcept -> bool {
99 return value < 0;
100}
101
102// parasoft-begin-suppress AUTOSAR-A15_4_5-a "False positive: Does not throw"
103/// @brief Obtain the character corresponding to a digit
104/// @param value The digit value
105/// @return The corresponding character
106inline constexpr auto digit(std::uintmax_t const value) noexcept -> arene::base::detail::character {
107 /// @brief A list of characters corresponding to the digits 0-9
108 constexpr array<arene::base::detail::character, 10> digits{{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'}};
109
110 ARENE_PRECONDITION(value < std::uintmax_t{digits.size()});
111 return digits[static_cast<std::size_t>(value)];
112}
113// parasoft-end-suppress AUTOSAR-A15_4_5-a
114
115/// @brief A zero value of the specified type
116/// @tparam T The type to get zero for
117template <typename T>
118extern constexpr T zero_v{0};
119
120} // namespace to_string_detail
121
122/// @brief Produces a string representation of an input integral value in base-10.
123///
124/// @tparam T The type of the value to convert.
125/// @tparam S The size of the inline string to write the result to. Must be large enough to hold T.
126/// @param value The value to convert.
127/// @return inline_string with a character representation of the input value in base-10, with no padding.
128template <
129 typename T,
134inline constexpr auto to_inline_string(T value) noexcept -> inline_string<S> {
135 if (value == to_string_detail::zero_v<T>) {
136 return inline_string<S>{"0"};
137 }
141 if (is_negative && (value == std::numeric_limits<T>::min())) {
142 unsigned_value = static_cast<unsigned_t>(power_of_2((sizeof(T) * static_cast<std::size_t>(CHAR_BIT)) - 1U));
143 } else if (is_negative) {
144 unsigned_value = static_cast<unsigned_t>(-value);
145 } else {
146 unsigned_value = static_cast<unsigned_t>(value);
147 }
148 constexpr unsigned_t base_divisor{10U};
150
153 std::size_t pos{num_digits - 1U};
154 while (unsigned_value != 0U) {
157 --pos;
158 }
159 // remove unused digits since we filled from right to left, and insert '-' if needed.
160 if (is_negative) {
161 std::ignore = result.erase(0U, pos);
162 result[0U] = '-';
163 } else {
164 std::ignore = result.erase(0U, pos + 1U);
165 }
166 return result;
167}
168
169/// @brief Produces a string representation of an input boolean value.
170///
171/// @tparam S The size of the inline string to write the result to. Must be at least 5 characters.
172/// @param value The value to convert.
173/// @return inline_string with the boolean represented as either "true" or "false".
174template <
175 typename T = bool,
178inline constexpr auto to_inline_string(bool value) noexcept -> inline_string<S> {
179 return inline_string<S>{value ? "true" : "false"};
180}
181
182} // namespace base
183} // namespace arene
184#endif // INCLUDE_GUARD_ARENE_BASE_ARENE_BASE_STRINGS_FORMAT_TO_INLINE_STRING_HPP_
Definition array_exceptions_disabled.cpp:11
Copyright 2026, Toyota Motor Corporation.
Definition array_exceptions_disabled.cpp:10