• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #pragma once
15 
16 // This file provides functions for writing string representations of a few
17 // types to character buffers. Generally, the generic ToString function defined
18 // in "pw_string/to_string.h" should be used instead of these functions.
19 
20 #include <cstdint>
21 #include <span>
22 #include <string_view>
23 #include <type_traits>
24 
25 #include "pw_status/status_with_size.h"
26 
27 namespace pw::string {
28 
29 // Returns the number of digits in the decimal representation of the provided
30 // non-negative integer. Returns 1 for 0 or 1 + log base 10 for other numbers.
31 uint_fast8_t DecimalDigitCount(uint64_t integer);
32 
33 // Returns the number of digits in the hexadecimal representation of the
34 // provided non-negative integer.
HexDigitCount(uint64_t integer)35 constexpr uint_fast8_t HexDigitCount(uint64_t integer) {
36   return (64u - __builtin_clzll(integer | 1u) + 3u) / 4u;
37 }
38 
39 // Writes an integer as a null-terminated string in base 10. Returns the number
40 // of characters written, excluding the null terminator, and the status.
41 //
42 // Numbers are never truncated; if the entire number does not fit, only a null
43 // terminator is written and the status is RESOURCE_EXHAUSTED.
44 //
45 // IntToString is templated, but a single 64-bit integer implementation is used
46 // for all integer types. The template is used for two reasons:
47 //
48 //   1. IntToString(int64_t) and IntToString(uint64_t) overloads are ambiguous
49 //      when called with types other than int64_t or uint64_t. Using the
50 //      template allows IntToString to be called with any integral type.
51 //
52 //   2. Templating IntToString allows the compiler to emit small functions like
53 //      IntToString<int> or IntToString<short> that perform casting / sign
54 //      extension on the various integer types. This saves code size, since call
55 //      sites pass their arguments directly and casting instructions are shared.
56 //
57 template <typename T>
IntToString(T value,std::span<char> buffer)58 StatusWithSize IntToString(T value, std::span<char> buffer) {
59   if constexpr (std::is_signed_v<T>) {
60     return IntToString<int64_t>(value, buffer);
61   } else {
62     return IntToString<uint64_t>(value, buffer);
63   }
64 }
65 
66 template <>
67 StatusWithSize IntToString(uint64_t value, std::span<char> buffer);
68 
69 template <>
70 StatusWithSize IntToString(int64_t value, std::span<char> buffer);
71 
72 // Writes an integer as a hexadecimal string. Semantics match IntToString. The
73 // output is lowercase without a leading 0x. min_width adds leading zeroes such
74 // that the final string is at least the specified number of characters wide.
75 StatusWithSize IntToHexString(uint64_t value,
76                               std::span<char> buffer,
77                               uint_fast8_t min_width = 0);
78 
79 // Rounds a floating point number to an integer and writes it as a
80 // null-terminated string. Returns the number of characters written, excluding
81 // the null terminator, and the status.
82 //
83 // Numbers are never truncated; if the entire number does not fit, only a null
84 // terminator is written and the status is RESOURCE_EXHAUSTED.
85 //
86 // WARNING: This is NOT a fully-functioning float-printing implementation! It
87 // simply outputs the closest integer, "inf", or "NaN". Floating point numbers
88 // too large to represent as a 64-bit int are treated as infinite.
89 //
90 // Examples:
91 //
92 //   FloatAsIntToString(1.25, buffer)     -> writes "1" to the buffer
93 //   FloatAsIntToString(-4.9, buffer)     -> writes "-5" to the buffer
94 //   FloatAsIntToString(3.5e20, buffer)   -> writes "inf" to the buffer
95 //   FloatAsIntToString(INFINITY, buffer) -> writes "-inf" to the buffer
96 //   FloatAsIntToString(-NAN, buffer)     -> writes "-NaN" to the buffer
97 //
98 StatusWithSize FloatAsIntToString(float value, std::span<char> buffer);
99 
100 // Writes a bool as "true" or "false". Semantics match CopyEntireString.
101 StatusWithSize BoolToString(bool value, std::span<char> buffer);
102 
103 // String used to represent null pointers.
104 inline constexpr std::string_view kNullPointerString("(null)");
105 
106 // Writes the pointer's address or kNullPointerString. Semantics match
107 // CopyEntireString.
108 StatusWithSize PointerToString(const void* pointer, std::span<char> buffer);
109 
110 // Copies the string to the buffer, truncating if the full string does not fit.
111 // Always null terminates if buffer.size() > 0.
112 //
113 // Returns the number of characters written, excluding the null terminator. If
114 // the string is truncated, the status is RESOURCE_EXHAUSTED.
115 StatusWithSize CopyString(const std::string_view& value,
116                           std::span<char> buffer);
117 
CopyString(const char * value,std::span<char> buffer)118 inline StatusWithSize CopyString(const char* value, std::span<char> buffer) {
119   if (value == nullptr) {
120     return PointerToString(value, buffer);
121   }
122   return CopyString(std::string_view(value), buffer);
123 }
124 
125 // Copies the string to the buffer, if the entire string fits. Always null
126 // terminates if buffer.size() > 0.
127 //
128 // Returns the number of characters written, excluding the null terminator. If
129 // the full string does not fit, only a null terminator is written and the
130 // status is RESOURCE_EXHAUSTED.
131 StatusWithSize CopyEntireString(const std::string_view& value,
132                                 std::span<char> buffer);
133 
CopyEntireString(const char * value,std::span<char> buffer)134 inline StatusWithSize CopyEntireString(const char* value,
135                                        std::span<char> buffer) {
136   if (value == nullptr) {
137     return PointerToString(value, buffer);
138   }
139   return CopyEntireString(std::string_view(value), buffer);
140 }
141 
142 // This function is a fallback that is called if by ToString if no overload
143 // matches. No definition is provided, so attempting to print an unsupported
144 // type causes a linker error.
145 //
146 // Applications may define pw::string::UnknownTypeToString to support generic
147 // printing for unknown types, if desired. Implementations must follow the
148 // ToString semantics.
149 template <typename T>
150 StatusWithSize UnknownTypeToString(const T& value, std::span<char> buffer);
151 
152 }  // namespace pw::string
153