Toolbox snapshot
The Reactive C++ Toolbox
Loading...
Searching...
No Matches
Utility.hpp
Go to the documentation of this file.
1// The Reactive C++ Toolbox.
2// Copyright (C) 2013-2019 Swirly Cloud Limited
3// Copyright (C) 2022 Reactive Markets Limited
4//
5// Licensed under the Apache License, Version 2.0 (the "License");
6// you may not use this file except in compliance with the License.
7// You may obtain a copy of the License at
8//
9// http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing, software
12// distributed under the License is distributed on an "AS IS" BASIS,
13// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14// See the License for the specific language governing permissions and
15// limitations under the License.
16
17#ifndef TOOLBOX_UTIL_UTILITY_HPP
18#define TOOLBOX_UTIL_UTILITY_HPP
19
20#include <toolbox/Config.h>
21#include <toolbox/util/Math.hpp>
22
23#include <bit>
24#include <cstdint>
25#include <string>
26#include <string_view>
27
28namespace toolbox {
29inline namespace util {
30
31template <typename T>
32struct AlwaysFalse : std::false_type {};
33
34template <typename ValueT>
35inline auto& remove_const(const ValueT& ref)
36{
37 return const_cast<ValueT&>(ref);
38}
39
40constexpr bool isdigit(int c) noexcept
41{
42 return c >= '0' && c <= '9';
43}
44static_assert(isdigit('0') && isdigit('9') && !isdigit('A'));
45
50template <typename ValueT>
51 requires std::unsigned_integral<ValueT>
52constexpr int dec_digits(ValueT i) noexcept
53{
54 std::uint64_t v{i};
55
56 // map v such that: even v --> v+1
57 // odd v --> v.
58 //
59 // The number of digits in v remains unchanged after this mapping.
60 // However, the purpose of the mapping is to eliminate the need
61 // for a branch to handle the case when v equals 0.
62 v |= 1;
63 [[assume(v != 0)]];
64
65 // The number of digits in a *positive* base-10 number v is exactly:
66 // 1+floor(log_2(v) / log_2(10))
67
68 // 4096/1233 is a well known approximation to log_2(10).
69 // (dividing by 4096 is equivalent to shifting right by 12).
70 int digits = ((std::bit_width(v) * 1233) >> 12);
71
72 // Due to the nature of approximations, the calculation is
73 // of by 1 in the intervals: [10^k, next_pow2(10^k)).
74 return digits + int{v >= pow10(digits)};
75}
76
81template <typename ValueT>
82 requires std::signed_integral<ValueT>
83constexpr int dec_digits(ValueT i) noexcept
84{
85 std::int64_t v{i};
86
87 // abs(min value of int64_t) cannot be stored in int64_t
88 // so handle it separately.
89 if (v == std::numeric_limits<std::int64_t>::min()) [[unlikely]] {
90 return 19;
91 } else {
92 std::int64_t abs_v = (v < 0) ? -v : v;
93 return dec_digits(static_cast<std::uint64_t>(abs_v));
94 }
95}
96
103template <typename UIntegerT>
104 requires std::unsigned_integral<UIntegerT>
105constexpr int hex_digits(UIntegerT i) noexcept
106{
107 constexpr auto Bits = sizeof(i) * 8;
108 return 1 + ((Bits - std::countl_zero(i | 1) - 1) >> 2);
109}
110
111static_assert(hex_digits(0x0U) == 1);
112static_assert(hex_digits(0x1U) == 1);
113static_assert(hex_digits(std::uint64_t{0xffffffffffff}) == 12);
114
115TOOLBOX_API bool stob(std::string_view sv, bool dfl = false) noexcept;
116TOOLBOX_API double stod(std::string_view sv, double dfl = {}) noexcept;
117TOOLBOX_API double fast_stod(std::string_view sv, double dfl = {}) noexcept;
118
119template <typename ValueT>
120 requires std::integral<ValueT> || std::same_as<ValueT, double>
121constexpr ValueT ston(std::string_view sv) noexcept
122{
123 if constexpr (std::is_same_v<ValueT, double>) {
124 return stod(sv);
125 } else if constexpr (std::is_integral_v<ValueT>) {
126 auto it = sv.begin(), end = sv.end();
127 if (it == end) {
128 return 0;
129 }
130 bool neg{false};
131 if constexpr (std::is_signed_v<ValueT>) {
132 // Handle sign.
133 if (*it == '-') {
134 if (++it == end) {
135 return 0;
136 }
137 neg = true;
138 }
139 }
140 std::uint64_t n{0};
141 if (isdigit(*it)) {
142 n = *it++ - '0';
143 while (it != end && isdigit(*it)) {
144 n *= 10;
145 n += *it++ - '0';
146 }
147 }
148 return neg ? -n : n;
149 } else {
150 static_assert(AlwaysFalse<ValueT>::value);
151 }
152}
153static_assert(ston<int>(std::string_view{"-123"}) == -123);
154
157 std::size_t operator()(std::string_view txt) const
158 {
159 return std::hash<std::string_view>{}(txt);
160 }
161 std::size_t operator()(const char* txt) const { return std::hash<std::string_view>{}(txt); }
162 std::size_t operator()(const std::string& txt) const { return std::hash<std::string>{}(txt); }
163};
164
165inline constexpr std::string_view bool_to_alpha(bool b) noexcept
166{
167 return b ? "true" : "false";
168}
169
170} // namespace util
171} // namespace toolbox
172
173#endif // TOOLBOX_UTIL_UTILITY_HPP
#define TOOLBOX_API
Definition Config.h:39
STL namespace.
bool stob(string_view sv, bool dfl) noexcept
Definition Utility.cpp:28
auto & remove_const(const ValueT &ref)
Definition Utility.hpp:35
constexpr int dec_digits(ValueT i) noexcept
Definition Utility.hpp:52
double fast_stod(std::string_view sv, double dfl) noexcept
Definition Utility.cpp:101
constexpr bool isdigit(int c) noexcept
Definition Utility.hpp:40
constexpr std::uint64_t pow10(int n) noexcept
Definition Math.hpp:161
constexpr int hex_digits(UIntegerT i) noexcept
Definition Utility.hpp:105
std::string_view sv
Definition Tokeniser.hpp:26
constexpr ValueT ston(std::string_view sv) noexcept
Definition Utility.hpp:121
constexpr std::string_view bool_to_alpha(bool b) noexcept
Definition Utility.hpp:165
double stod(std::string_view sv, double dfl) noexcept
Definition Utility.cpp:91
constexpr auto bind() noexcept
Definition Slot.hpp:97
std::size_t operator()(const std::string &txt) const
Definition Utility.hpp:162
std::size_t operator()(std::string_view txt) const
Definition Utility.hpp:157
std::size_t operator()(const char *txt) const
Definition Utility.hpp:161