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_view>
26#include <string>
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 std::uint64_t v{i};
54
55 // map v such that: even v --> v+1
56 // odd v --> v.
57 //
58 // The number of digits in v remains unchanged after this mapping.
59 // However, the purpose of the mapping is to eliminate the need
60 // for a branch to handle the case when v equals 0.
61 v |= 1;
62 [[assume(v != 0)]];
63
64 // The number of digits in a *positive* base-10 number v is exactly:
65 // 1+floor(log_2(v) / log_2(10))
66
67 // 4096/1233 is a well known approximation to log_2(10).
68 // (dividing by 4096 is equivalent to shifting right by 12).
69 int digits = ((std::bit_width(v) * 1233) >> 12);
70
71 // Due to the nature of approximations, the calculation is
72 // of by 1 in the intervals: [10^k, next_pow2(10^k)).
73 return digits + int{v >= pow10(digits)};
74}
75
80template <typename ValueT>
81 requires std::signed_integral<ValueT>
82constexpr int dec_digits(ValueT i) noexcept {
83 std::int64_t v{i};
84
85 // abs(min value of int64_t) cannot be stored in int64_t
86 // so handle it separately.
87 if (v == std::numeric_limits<std::int64_t>::min()) [[unlikely]] {
88 return 19;
89 } else {
90 std::int64_t abs_v = (v < 0) ? -v : v;
91 return dec_digits(static_cast<std::uint64_t>(abs_v));
92 }
93}
94
101template <typename UIntegerT>
102 requires std::unsigned_integral<UIntegerT>
103constexpr int hex_digits(UIntegerT i) noexcept
104{
105 constexpr auto Bits = sizeof(i) * 8;
106 return 1 + ((Bits - std::countl_zero(i | 1) - 1) >> 2);
107}
108
109static_assert(hex_digits(0x0U) == 1);
110static_assert(hex_digits(0x1U) == 1);
111static_assert(hex_digits(std::uint64_t{0xffffffffffff}) == 12);
112
113TOOLBOX_API bool stob(std::string_view sv, bool dfl = false) noexcept;
114TOOLBOX_API double stod(std::string_view sv, double dfl = {}) noexcept;
115
116template <typename ValueT>
117 requires std::integral<ValueT> || std::same_as<ValueT, double>
118constexpr ValueT ston(std::string_view sv) noexcept
119{
120 if constexpr (std::is_same_v<ValueT, double>) {
121 return stod(sv);
122 } else if constexpr (std::is_integral_v<ValueT>) {
123 auto it = sv.begin(), end = sv.end();
124 if (it == end) {
125 return 0;
126 }
127 bool neg{false};
128 if constexpr (std::is_signed_v<ValueT>) {
129 // Handle sign.
130 if (*it == '-') {
131 if (++it == end) {
132 return 0;
133 }
134 neg = true;
135 }
136 }
137 std::uint64_t n{0};
138 if (isdigit(*it)) {
139 n = *it++ - '0';
140 while (it != end && isdigit(*it)) {
141 n *= 10;
142 n += *it++ - '0';
143 }
144 }
145 return neg ? -n : n;
146 } else {
147 static_assert(AlwaysFalse<ValueT>::value);
148 }
149}
150static_assert(ston<int>(std::string_view{"-123"}) == -123);
151
154 std::size_t operator()(std::string_view txt) const
155 {
156 return std::hash<std::string_view>{}(txt);
157 }
158 std::size_t operator()(const char* txt) const
159 {
160 return std::hash<std::string_view>{}(txt);
161 }
162 std::size_t operator()(const std::string& txt) const
163 {
164 return std::hash<std::string>{}(txt);
165 }
166};
167
168inline constexpr std::string_view bool_to_alpha(bool b) noexcept
169{
170 return b ? "true" : "false";
171}
172
173} // namespace util
174} // namespace toolbox
175
176#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:26
auto & remove_const(const ValueT &ref)
Definition Utility.hpp:35
constexpr int dec_digits(ValueT i) noexcept
Definition Utility.hpp:52
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:103
std::string_view sv
Definition Tokeniser.hpp:26
constexpr ValueT ston(std::string_view sv) noexcept
Definition Utility.hpp:118
constexpr std::string_view bool_to_alpha(bool b) noexcept
Definition Utility.hpp:168
double stod(std::string_view sv, double dfl) noexcept
Definition Utility.cpp:89
constexpr auto bind() noexcept
Definition Slot.hpp:92
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:154
std::size_t operator()(const char *txt) const
Definition Utility.hpp:158