1 // Copyright 2019 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14
15 #include "pw_string/type_to_string.h"
16
17 #include <array>
18 #include <cmath>
19 #include <cstddef>
20 #include <cstring>
21 #include <limits>
22
23 #include "lib/stdcompat/bit.h"
24
25 namespace pw::string {
26
IntToHexString(uint64_t value,span<char> buffer,uint_fast8_t min_width)27 StatusWithSize IntToHexString(uint64_t value,
28 span<char> buffer,
29 uint_fast8_t min_width) {
30 const uint_fast8_t digits = std::max(HexDigitCount(value), min_width);
31
32 if (digits >= buffer.size()) {
33 return internal::HandleExhaustedBuffer(buffer);
34 }
35
36 for (int i = static_cast<int>(digits) - 1; i >= 0; --i) {
37 buffer[static_cast<size_t>(i)] = "0123456789abcdef"[value & 0xF];
38 value >>= 4;
39 }
40
41 buffer[digits] = '\0';
42 return StatusWithSize(digits);
43 }
44
FloatAsIntToString(float value,span<char> buffer)45 StatusWithSize FloatAsIntToString(float value, span<char> buffer) {
46 // If it's finite and fits in an int64_t, print it as a rounded integer.
47 if (std::isfinite(value) &&
48 std::abs(value) <
49 static_cast<float>(std::numeric_limits<int64_t>::max())) {
50 return IntToString<int64_t>(static_cast<int64_t>(std::roundf(value)),
51 buffer);
52 }
53
54 // Otherwise, print inf or NaN, if they fit.
55 if (const size_t written = 3 + std::signbit(value); written < buffer.size()) {
56 char* out = buffer.data();
57 if (std::signbit(value)) {
58 *out++ = '-';
59 }
60 std::memcpy(out, std::isnan(value) ? "NaN" : "inf", sizeof("NaN"));
61 return StatusWithSize(written);
62 }
63
64 return internal::HandleExhaustedBuffer(buffer);
65 }
66
BoolToString(bool value,span<char> buffer)67 StatusWithSize BoolToString(bool value, span<char> buffer) {
68 return CopyEntireStringOrNull(value ? "true" : "false", buffer);
69 }
70
PointerToString(const void * pointer,span<char> buffer)71 StatusWithSize PointerToString(const void* pointer, span<char> buffer) {
72 if (pointer == nullptr) {
73 return CopyEntireStringOrNull(kNullPointerString, buffer);
74 }
75 return IntToHexString(reinterpret_cast<uintptr_t>(pointer), buffer);
76 }
77
CopyEntireStringOrNull(std::string_view value,span<char> buffer)78 StatusWithSize CopyEntireStringOrNull(std::string_view value,
79 span<char> buffer) {
80 if (value.size() >= buffer.size()) {
81 return internal::HandleExhaustedBuffer(buffer);
82 }
83
84 std::memcpy(buffer.data(), value.data(), value.size());
85 buffer[value.size()] = '\0';
86 return StatusWithSize(value.size());
87 }
88
89 } // namespace pw::string
90