@@ -20,292 +20,11 @@ limitations under the License.
2020// more code.
2121
2222#include " tensorflow/lite/micro/micro_string.h"
23-
24- #include < cstdarg>
25- #include < cstdint>
26- #include < cstring>
27-
28- namespace {
29-
30- // Int formats can need up to 10 bytes for the value plus a single byte for the
31- // sign.
32- constexpr int kMaxIntCharsNeeded = 10 + 1 ;
33- // Hex formats can need up to 8 bytes for the value plus two bytes for the "0x".
34- constexpr int kMaxHexCharsNeeded = 8 + 2 ;
35-
36- // Float formats can need up to 7 bytes for the fraction plus 3 bytes for "x2^"
37- // plus 3 bytes for the exponent and a single sign bit.
38- constexpr float kMaxFloatCharsNeeded = 7 + 3 + 3 + 1 ;
39-
40- // All input buffers to the number conversion functions must be this long.
41- const int kFastToBufferSize = 48 ;
42-
43- // Reverses a zero-terminated string in-place.
44- char * ReverseStringInPlace (char * start, char * end) {
45- char * p1 = start;
46- char * p2 = end - 1 ;
47- while (p1 < p2) {
48- char tmp = *p1;
49- *p1++ = *p2;
50- *p2-- = tmp;
51- }
52- return start;
53- }
54-
55- // Appends a string to a string, in-place. You need to pass in the maximum
56- // string length as the second argument.
57- char * StrCatStr (char * main, int main_max_length, const char * to_append) {
58- char * current = main;
59- while (*current != 0 ) {
60- ++current;
61- }
62- char * current_end = main + (main_max_length - 1 );
63- while ((*to_append != 0 ) && (current < current_end)) {
64- *current = *to_append;
65- ++current;
66- ++to_append;
67- }
68- *current = 0 ;
69- return current;
70- }
71-
72- // Populates the provided buffer with an ASCII representation of the number.
73- char * FastUInt32ToBufferLeft (uint32_t i, char * buffer, int base) {
74- char * start = buffer;
75- do {
76- int32_t digit = i % base;
77- char character;
78- if (digit < 10 ) {
79- character = ' 0' + digit;
80- } else {
81- character = ' a' + (digit - 10 );
82- }
83- *buffer++ = character;
84- i /= base;
85- } while (i > 0 );
86- *buffer = 0 ;
87- ReverseStringInPlace (start, buffer);
88- return buffer;
89- }
90-
91- // Populates the provided buffer with an ASCII representation of the number.
92- char * FastInt32ToBufferLeft (int32_t i, char * buffer) {
93- uint32_t u = i;
94- if (i < 0 ) {
95- *buffer++ = ' -' ;
96- u = -u;
97- }
98- return FastUInt32ToBufferLeft (u, buffer, 10 );
99- }
100-
101- // Converts a number to a string and appends it to another.
102- char * StrCatInt32 (char * main, int main_max_length, int32_t number) {
103- char number_string[kFastToBufferSize ];
104- FastInt32ToBufferLeft (number, number_string);
105- return StrCatStr (main, main_max_length, number_string);
106- }
107-
108- // Converts a number to a string and appends it to another.
109- char * StrCatUInt32 (char * main, int main_max_length, uint32_t number, int base) {
110- char number_string[kFastToBufferSize ];
111- FastUInt32ToBufferLeft (number, number_string, base);
112- return StrCatStr (main, main_max_length, number_string);
113- }
114-
115- // Populates the provided buffer with ASCII representation of the float number.
116- // Avoids the use of any floating point instructions (since these aren't
117- // supported on many microcontrollers) and as a consequence prints values with
118- // power-of-two exponents.
119- char * FastFloatToBufferLeft (float f, char * buffer) {
120- char * current = buffer;
121- char * current_end = buffer + (kFastToBufferSize - 1 );
122- // Access the bit fields of the floating point value to avoid requiring any
123- // float instructions. These constants are derived from IEEE 754.
124- const uint32_t sign_mask = 0x80000000 ;
125- const uint32_t exponent_mask = 0x7f800000 ;
126- const int32_t exponent_shift = 23 ;
127- const int32_t exponent_bias = 127 ;
128- const uint32_t fraction_mask = 0x007fffff ;
129- uint32_t u;
130- memcpy (&u, &f, sizeof (int32_t ));
131- const int32_t exponent =
132- ((u & exponent_mask) >> exponent_shift) - exponent_bias;
133- const uint32_t fraction = (u & fraction_mask);
134- // Expect ~0x2B1B9D3 for fraction.
135- if (u & sign_mask) {
136- *current = ' -' ;
137- current += 1 ;
138- }
139- *current = 0 ;
140- // These are special cases for infinities and not-a-numbers.
141- if (exponent == 128 ) {
142- if (fraction == 0 ) {
143- current = StrCatStr (current, (current_end - current), " Inf" );
144- return current;
145- } else {
146- current = StrCatStr (current, (current_end - current), " NaN" );
147- return current;
148- }
149- }
150- // 0x007fffff (8388607) represents 0.99... for the fraction, so to print the
151- // correct decimal digits we need to scale our value before passing it to the
152- // conversion function. This scale should be 10000000/8388608 = 1.1920928955.
153- // We can approximate this using multiply-adds and right-shifts using the
154- // values in this array. The 1. portion of the number string is printed out
155- // in a fixed way before the fraction, below.
156- const int32_t scale_shifts_size = 13 ;
157- const int8_t scale_shifts[13 ] = {3 , 4 , 8 , 11 , 13 , 14 , 17 ,
158- 18 , 19 , 20 , 21 , 22 , 23 };
159- uint32_t scaled_fraction = fraction;
160- for (int i = 0 ; i < scale_shifts_size; ++i) {
161- scaled_fraction += (fraction >> scale_shifts[i]);
162- }
163- *current = ' 1' ;
164- current += 1 ;
165- *current = ' .' ;
166- current += 1 ;
167- *current = 0 ;
168-
169- // Prepend leading zeros to fill in all 7 bytes of the fraction. Truncate
170- // zeros off the end of the fraction. Every fractional value takes 7 bytes.
171- // For example, 2500 would be written into the buffer as 0002500 since it
172- // represents .00025.
173- constexpr int kMaxFractionalDigits = 7 ;
174-
175- // Abort early if there is not enough space in the buffer.
176- if (current_end - current <= kMaxFractionalDigits ) {
177- return current;
178- }
179-
180- // Pre-fill buffer with zeros to ensure zero-truncation works properly.
181- for (int i = 1 ; i < kMaxFractionalDigits ; i++) {
182- *(current + i) = ' 0' ;
183- }
184-
185- // Track how large the fraction is to add leading zeros.
186- char * previous = current;
187- current = StrCatUInt32 (current, (current_end - current), scaled_fraction, 10 );
188- int fraction_digits = current - previous;
189- int leading_zeros = kMaxFractionalDigits - fraction_digits;
190-
191- // Overwrite the null terminator from StrCatUInt32 to ensure zero-trunctaion
192- // works properly.
193- *current = ' 0' ;
194-
195- // Shift fraction values and prepend zeros if necessary.
196- if (leading_zeros != 0 ) {
197- for (int i = 0 ; i < fraction_digits; i++) {
198- current--;
199- *(current + leading_zeros) = *current;
200- *current = ' 0' ;
201- }
202- current += kMaxFractionalDigits ;
203- }
204-
205- // Truncate trailing zeros for cleaner logs. Ensure we leave at least one
206- // fractional character for the case when scaled_fraction is 0.
207- while (*(current - 1 ) == ' 0' && (current - 1 ) > previous) {
208- current--;
209- }
210- *current = 0 ;
211- current = StrCatStr (current, (current_end - current), " *2^" );
212- current = StrCatInt32 (current, (current_end - current), exponent);
213- return current;
214- }
215-
216- int FormatInt32 (char * output, int32_t i) {
217- return static_cast <int >(FastInt32ToBufferLeft (i, output) - output);
218- }
219-
220- int FormatUInt32 (char * output, uint32_t i) {
221- return static_cast <int >(FastUInt32ToBufferLeft (i, output, 10 ) - output);
222- }
223-
224- int FormatHex (char * output, uint32_t i) {
225- return static_cast <int >(FastUInt32ToBufferLeft (i, output, 16 ) - output);
226- }
227-
228- int FormatFloat (char * output, float i) {
229- return static_cast <int >(FastFloatToBufferLeft (i, output) - output);
230- }
231-
232- } // namespace
23+ #include < rtthread.h>
23324
23425extern " C" int MicroVsnprintf (char * output, int len, const char * format,
23526 va_list args) {
236- int output_index = 0 ;
237- const char * current = format;
238- // One extra character must be left for the null terminator.
239- const int usable_length = len - 1 ;
240- while (*current != ' \0 ' && output_index < usable_length) {
241- if (*current == ' %' ) {
242- current++;
243- switch (*current) {
244- case ' d' :
245- // Cut off log message if format could exceed log buffer length.
246- if (usable_length - output_index < kMaxIntCharsNeeded ) {
247- output[output_index++] = ' \0 ' ;
248- return output_index;
249- }
250- output_index +=
251- FormatInt32 (&output[output_index], va_arg (args, int32_t ));
252- current++;
253- break ;
254- case ' u' :
255- if (usable_length - output_index < kMaxIntCharsNeeded ) {
256- output[output_index++] = ' \0 ' ;
257- return output_index;
258- }
259- output_index +=
260- FormatUInt32 (&output[output_index], va_arg (args, uint32_t ));
261- current++;
262- break ;
263- case ' x' :
264- if (usable_length - output_index < kMaxHexCharsNeeded ) {
265- output[output_index++] = ' \0 ' ;
266- return output_index;
267- }
268- output[output_index++] = ' 0' ;
269- output[output_index++] = ' x' ;
270- output_index +=
271- FormatHex (&output[output_index], va_arg (args, uint32_t ));
272- current++;
273- break ;
274- case ' f' :
275- if (usable_length - output_index < kMaxFloatCharsNeeded ) {
276- output[output_index++] = ' \0 ' ;
277- return output_index;
278- }
279- output_index +=
280- FormatFloat (&output[output_index], va_arg (args, double ));
281- current++;
282- break ;
283- case ' %' :
284- output[output_index++] = *current++;
285- break ;
286- case ' c' :
287- if (usable_length - output_index < 1 ) {
288- output[output_index++] = ' \0 ' ;
289- return output_index;
290- }
291- output[output_index++] = va_arg (args, int32_t );
292- current++;
293- break ;
294- case ' s' :
295- char * string = va_arg (args, char *);
296- int string_idx = 0 ;
297- while (string_idx + output_index < usable_length &&
298- string[string_idx] != ' \0 ' ) {
299- output[output_index++] = string[string_idx++];
300- }
301- current++;
302- }
303- } else {
304- output[output_index++] = *current++;
305- }
306- }
307- output[output_index++] = ' \0 ' ;
308- return output_index;
27+ return rt_vsnprintf (output, len, format, args);
30928}
31029
31130extern " C" int MicroSnprintf (char * output, int len, const char * format, ...) {
0 commit comments